From 486bdfeb2ae2285f0ec44c6db54b2c8c197ab530 Mon Sep 17 00:00:00 2001 From: aMannus Date: Tue, 7 Jul 2026 13:47:22 +0200 Subject: [PATCH 001/131] Custom collectible --- include/enums.h | 2 + src/core2/ba/ba_marker.c | 3 + .../CustomCollectible/CustomCollectible.cpp | 55 +++++++++++++++++++ .../CustomCollectible/CustomCollectible.h | 15 +++++ 4 files changed, 75 insertions(+) create mode 100644 src/port/Rando/CustomCollectible/CustomCollectible.cpp create mode 100644 src/port/Rando/CustomCollectible/CustomCollectible.h diff --git a/include/enums.h b/include/enums.h index 90de73ab1..d80dba45e 100644 --- a/include/enums.h +++ b/include/enums.h @@ -2392,6 +2392,7 @@ typedef enum actor_e ACTOR_3CB_UNKNOWN, ACTOR_3CC_DUMMY_PLAYER_ANCHOR = 0x3CC, + ACTOR_3CD_CUSTOM_COLLECTIBLE = 0x3CD, } ActorID; enum bundle_e { @@ -5829,6 +5830,7 @@ enum marker_e{ MARKER_29E_BIGBUTT_KNOCKED_DOWN, MARKER_29F_DUMMY_PLAYER_ANCHOR, + MARKER_300_CUSTOM_COLLECTIBLE, }; enum hitbox_e{ diff --git a/src/core2/ba/ba_marker.c b/src/core2/ba/ba_marker.c index 843b4a6a8..ec29412e6 100644 --- a/src/core2/ba/ba_marker.c +++ b/src/core2/ba/ba_marker.c @@ -818,6 +818,9 @@ void __baMarker_resolveCollision(Prop *other_prop){ if (plyr_hitbox_type == HITBOX_1_BEAK_BUSTER) obj_collision_type = MARKER_COLLISION_FUNC_1; break; + case MARKER_300_CUSTOM_COLLECTIBLE: + marker_callCollisionFunc(playerMarker, marker, plyr_collision_type); + break; }//L8028D034 if (baiFrame_getState() == 3) { plyr_collision_type = MARKER_COLLISION_FUNC_0; diff --git a/src/port/Rando/CustomCollectible/CustomCollectible.cpp b/src/port/Rando/CustomCollectible/CustomCollectible.cpp new file mode 100644 index 000000000..c3ad6941c --- /dev/null +++ b/src/port/Rando/CustomCollectible/CustomCollectible.cpp @@ -0,0 +1,55 @@ +#include "CustomCollectible.h" +#include "actor.h" + +void CustomCollectible_Update(Actor* actor) { + ActorLocal_CustomCollectible* customLocal = (ActorLocal_CustomCollectible*)&actor->local; + + if (!actor->initialized) { + actor->initialized = true; + actor->marker->collidable = true; + } + + actor->yaw += 5.0f; +} + +void CustomCollectible_Draw(ActorMarker* marker, Gfx** gdl, Mtx** mptr, Vtx** arg3) { + Actor* actor = marker_getActor(marker); + actor = actor_draw(actor->marker, gdl, mptr, arg3); +} + +ActorInfo customActorInfo = { MARKER_300_CUSTOM_COLLECTIBLE, + ACTOR_3CD_CUSTOM_COLLECTIBLE, + ASSET_35F_MODEL_JIGGY, + 1, + NULL, + CustomCollectible_Update, + NULL, + NULL, + 0, + 0, + 0.9f, + 0 }; + +Actor* CustomCollectible::AttachLocalStruct(int32_t randoItemId, Actor* customCollectible) { + ActorLocal_CustomCollectible* customLocal = (ActorLocal_CustomCollectible*)&customCollectible->local; + + customLocal->randoItemId = randoItemId; + + return customCollectible; +} + +Actor* CustomCollectible::Spawn(int32_t position[3], int32_t flags) { + int32_t spawnPosition[3] = { position[0], position[1], position[2] }; + + int32_t flags = ACTOR_FLAG_UNKNOWN_6 | ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_21; + + Actor* customCollectible = actor_new(position, 0, &customActorInfo, flags); + customCollectible->marker->collisionFunc = CustomCollectible::OnCollect; + customCollectible = CustomCollectible::AttachLocalStruct(RI_EMPTY_HONEYCOMB_BUBBLEGLOOP_SWAMP, customCollectible); + + return customCollectible; +} + +void CustomCollectible::OnCollect(struct actorMarker_s* self, struct actorMarker_s* other) { + marker_despawn(self); +} diff --git a/src/port/Rando/CustomCollectible/CustomCollectible.h b/src/port/Rando/CustomCollectible/CustomCollectible.h new file mode 100644 index 000000000..b672bef5a --- /dev/null +++ b/src/port/Rando/CustomCollectible/CustomCollectible.h @@ -0,0 +1,15 @@ +#pragma once +extern "C" { +#include "functions.h" +} + +typedef struct { + u32 randoItemId = 0; +} ActorLocal_CustomCollectible; + +class CustomCollectible { +private: + Actor* AttachLocalStruct(int32_t randoItemId, Actor* customCollectible); + Actor* Spawn(int32_t position[3], int32_t flags); + static void OnCollect(struct actorMarker_s* self, struct actorMarker_s* other); +}; From a922ba2e5352c723c30a7dfe8bf3b90f5a1ba828 Mon Sep 17 00:00:00 2001 From: aMannus Date: Tue, 7 Jul 2026 16:01:47 +0200 Subject: [PATCH 002/131] it builds now --- .../CustomCollectible/CustomCollectible.cpp | 35 +++++++++++-------- .../CustomCollectible/CustomCollectible.h | 16 +++++---- src/port/UI/DeveloperTools/GameplayTools.cpp | 6 ++++ 3 files changed, 37 insertions(+), 20 deletions(-) diff --git a/src/port/Rando/CustomCollectible/CustomCollectible.cpp b/src/port/Rando/CustomCollectible/CustomCollectible.cpp index c3ad6941c..06351ddf9 100644 --- a/src/port/Rando/CustomCollectible/CustomCollectible.cpp +++ b/src/port/Rando/CustomCollectible/CustomCollectible.cpp @@ -1,6 +1,26 @@ #include "CustomCollectible.h" #include "actor.h" +extern "C" { +Actor* actor_new(s32 position[3], s32 yaw, ActorInfo* actorInfo, u32 flags); +Actor* actor_draw(ActorMarker* marker, Gfx** gfx, Mtx** mtx, Vtx** vtx); +Actor* marker_getActor(ActorMarker* thisx); +void marker_despawn(ActorMarker* marker); +} + +ActorInfo customActorInfo = { MARKER_300_CUSTOM_COLLECTIBLE, + ACTOR_3CD_CUSTOM_COLLECTIBLE, + ASSET_35F_MODEL_JIGGY, + 1, + NULL, + CustomCollectible_Update, + NULL, + (Actor*(*)(ActorMarker*, Gfx**, Mtx**, Vtx**)) CustomCollectible_Draw, + 0, + 0, + 0.9f, + 0 }; + void CustomCollectible_Update(Actor* actor) { ActorLocal_CustomCollectible* customLocal = (ActorLocal_CustomCollectible*)&actor->local; @@ -17,19 +37,6 @@ void CustomCollectible_Draw(ActorMarker* marker, Gfx** gdl, Mtx** mptr, Vtx** ar actor = actor_draw(actor->marker, gdl, mptr, arg3); } -ActorInfo customActorInfo = { MARKER_300_CUSTOM_COLLECTIBLE, - ACTOR_3CD_CUSTOM_COLLECTIBLE, - ASSET_35F_MODEL_JIGGY, - 1, - NULL, - CustomCollectible_Update, - NULL, - NULL, - 0, - 0, - 0.9f, - 0 }; - Actor* CustomCollectible::AttachLocalStruct(int32_t randoItemId, Actor* customCollectible) { ActorLocal_CustomCollectible* customLocal = (ActorLocal_CustomCollectible*)&customCollectible->local; @@ -38,7 +45,7 @@ Actor* CustomCollectible::AttachLocalStruct(int32_t randoItemId, Actor* customCo return customCollectible; } -Actor* CustomCollectible::Spawn(int32_t position[3], int32_t flags) { +Actor* CustomCollectible::Spawn(int32_t position[3], RandoItemId randoItemId) { int32_t spawnPosition[3] = { position[0], position[1], position[2] }; int32_t flags = ACTOR_FLAG_UNKNOWN_6 | ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_21; diff --git a/src/port/Rando/CustomCollectible/CustomCollectible.h b/src/port/Rando/CustomCollectible/CustomCollectible.h index b672bef5a..11f307203 100644 --- a/src/port/Rando/CustomCollectible/CustomCollectible.h +++ b/src/port/Rando/CustomCollectible/CustomCollectible.h @@ -1,15 +1,19 @@ #pragma once -extern "C" { -#include "functions.h" -} +#include "prop.h" +#include "port/Rando/Types.h" typedef struct { - u32 randoItemId = 0; + uint32_t randoItemId; } ActorLocal_CustomCollectible; +void CustomCollectible_Update(Actor* actor); +void CustomCollectible_Draw(ActorMarker* marker, Gfx** gdl, Mtx** mptr, Vtx** arg3); + class CustomCollectible { private: - Actor* AttachLocalStruct(int32_t randoItemId, Actor* customCollectible); - Actor* Spawn(int32_t position[3], int32_t flags); + static Actor* AttachLocalStruct(int32_t randoItemId, Actor* customCollectible); static void OnCollect(struct actorMarker_s* self, struct actorMarker_s* other); + +public: + static Actor* Spawn(int32_t position[3], RandoItemId randoItemId); }; diff --git a/src/port/UI/DeveloperTools/GameplayTools.cpp b/src/port/UI/DeveloperTools/GameplayTools.cpp index d1b7d1af3..6e838a3d3 100644 --- a/src/port/UI/DeveloperTools/GameplayTools.cpp +++ b/src/port/UI/DeveloperTools/GameplayTools.cpp @@ -2,6 +2,7 @@ #include "port/Rando/Rando.h" #include "port/Rando/Logic/Logic.h" #include "port/Rando/CustomObject/CustomObject.h" +#include "port/Rando/CustomCollectible/CustomCollectible.h" #include "port/Enhancements/Events/Hooks/Events.h" #include "port/UI/UIWidgets.hpp" @@ -400,6 +401,11 @@ void GameplayTools_ObjectSpawner() { ImGui::EndTable(); } + + ImGui::SeparatorText("Custom Collectible Testing"); + if (UIWidgets::Button("Spawn Custom Collectible", { .color = THEME_COLOR })) { + Actor* newActor = CustomCollectible::Spawn(spawnPosition, RI_EMPTY_HONEYCOMB_BUBBLEGLOOP_SWAMP); + } } void DrawGameplayToolsWarpList() { From c636e263f351c3e7b8f72c78dc2ae24addb70af4 Mon Sep 17 00:00:00 2001 From: aMannus Date: Tue, 7 Jul 2026 17:11:50 +0200 Subject: [PATCH 003/131] Fix spawn code under Gameplay Tools --- src/port/UI/DeveloperTools/GameplayTools.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/port/UI/DeveloperTools/GameplayTools.cpp b/src/port/UI/DeveloperTools/GameplayTools.cpp index 6e838a3d3..4a26144b3 100644 --- a/src/port/UI/DeveloperTools/GameplayTools.cpp +++ b/src/port/UI/DeveloperTools/GameplayTools.cpp @@ -219,7 +219,7 @@ void GameplayTools_UpdateSnsCheckboxes(StopNSwop_Item selectedSnsId) { } void GameplayTools_SpawnPosition() { - for (int i = 0; i < 2; i++) { + for (int i = 0; i <= 2; i++) { spawnPosition[i] = playerPosition[i] + spawnOffset[i]; } } From 6348bd247ce18679659910ab249dc2b068e652c4 Mon Sep 17 00:00:00 2001 From: aMannus Date: Tue, 7 Jul 2026 21:12:28 +0200 Subject: [PATCH 004/131] Not working pulling functions from map --- .../CustomCollectible/CustomCollectible.cpp | 23 +++++++++++++++---- .../CustomCollectible/CustomCollectible.h | 8 ++++++- 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/src/port/Rando/CustomCollectible/CustomCollectible.cpp b/src/port/Rando/CustomCollectible/CustomCollectible.cpp index 06351ddf9..c5aafe52e 100644 --- a/src/port/Rando/CustomCollectible/CustomCollectible.cpp +++ b/src/port/Rando/CustomCollectible/CustomCollectible.cpp @@ -1,5 +1,6 @@ #include "CustomCollectible.h" #include "actor.h" +#include extern "C" { Actor* actor_new(s32 position[3], s32 yaw, ActorInfo* actorInfo, u32 flags); @@ -8,14 +9,20 @@ Actor* marker_getActor(ActorMarker* thisx); void marker_despawn(ActorMarker* marker); } +using DrawFunc = Actor* (*)(ActorMarker*, Gfx**, Mtx**, Vtx**); + +std::unordered_map customCollectibleDrawList = { + { RI_EMPTY_HONEYCOMB_BUBBLEGLOOP_SWAMP, { ASSET_35F_MODEL_JIGGY, CustomCollectible_Draw } }, +}; + ActorInfo customActorInfo = { MARKER_300_CUSTOM_COLLECTIBLE, ACTOR_3CD_CUSTOM_COLLECTIBLE, - ASSET_35F_MODEL_JIGGY, + ASSET_0_NONE, 1, NULL, - CustomCollectible_Update, NULL, - (Actor*(*)(ActorMarker*, Gfx**, Mtx**, Vtx**)) CustomCollectible_Draw, + NULL, + NULL, 0, 0, 0.9f, @@ -32,9 +39,10 @@ void CustomCollectible_Update(Actor* actor) { actor->yaw += 5.0f; } -void CustomCollectible_Draw(ActorMarker* marker, Gfx** gdl, Mtx** mptr, Vtx** arg3) { +Actor* CustomCollectible_Draw(ActorMarker* marker, Gfx** gdl, Mtx** mptr, Vtx** arg3) { Actor* actor = marker_getActor(marker); actor = actor_draw(actor->marker, gdl, mptr, arg3); + return actor; } Actor* CustomCollectible::AttachLocalStruct(int32_t randoItemId, Actor* customCollectible) { @@ -50,9 +58,14 @@ Actor* CustomCollectible::Spawn(int32_t position[3], RandoItemId randoItemId) { int32_t flags = ACTOR_FLAG_UNKNOWN_6 | ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_21; + auto drawData = customCollectibleDrawList.find(randoItemId); + ActorInfo collectibleInfo = customActorInfo; + collectibleInfo.modelId = drawData->second.drawModel; + collectibleInfo.draw_func = drawData->second.drawFunction; + Actor* customCollectible = actor_new(position, 0, &customActorInfo, flags); customCollectible->marker->collisionFunc = CustomCollectible::OnCollect; - customCollectible = CustomCollectible::AttachLocalStruct(RI_EMPTY_HONEYCOMB_BUBBLEGLOOP_SWAMP, customCollectible); + customCollectible = CustomCollectible::AttachLocalStruct(randoItemId, customCollectible); return customCollectible; } diff --git a/src/port/Rando/CustomCollectible/CustomCollectible.h b/src/port/Rando/CustomCollectible/CustomCollectible.h index 11f307203..0c7a99e01 100644 --- a/src/port/Rando/CustomCollectible/CustomCollectible.h +++ b/src/port/Rando/CustomCollectible/CustomCollectible.h @@ -1,13 +1,19 @@ #pragma once #include "prop.h" #include "port/Rando/Types.h" +#include typedef struct { uint32_t randoItemId; } ActorLocal_CustomCollectible; +typedef struct { + asset_e drawModel; + std::function drawFunction; +} CustomCollecticleDrawData; + void CustomCollectible_Update(Actor* actor); -void CustomCollectible_Draw(ActorMarker* marker, Gfx** gdl, Mtx** mptr, Vtx** arg3); +Actor* CustomCollectible_Draw(ActorMarker* marker, Gfx** gdl, Mtx** mptr, Vtx** arg3); class CustomCollectible { private: From cf12defacb3450a733e3e0f667242d4bf04e72c6 Mon Sep 17 00:00:00 2001 From: aMannus Date: Tue, 7 Jul 2026 22:46:33 +0200 Subject: [PATCH 005/131] Added semi working draw stuff --- .../CustomCollectible/CustomCollectible.cpp | 129 ++++++++++++++++-- .../CustomCollectible/CustomCollectible.h | 11 +- src/port/UI/DeveloperTools/GameplayTools.cpp | 20 ++- 3 files changed, 136 insertions(+), 24 deletions(-) diff --git a/src/port/Rando/CustomCollectible/CustomCollectible.cpp b/src/port/Rando/CustomCollectible/CustomCollectible.cpp index c5aafe52e..ee7b8c7e3 100644 --- a/src/port/Rando/CustomCollectible/CustomCollectible.cpp +++ b/src/port/Rando/CustomCollectible/CustomCollectible.cpp @@ -11,16 +11,12 @@ void marker_despawn(ActorMarker* marker); using DrawFunc = Actor* (*)(ActorMarker*, Gfx**, Mtx**, Vtx**); -std::unordered_map customCollectibleDrawList = { - { RI_EMPTY_HONEYCOMB_BUBBLEGLOOP_SWAMP, { ASSET_35F_MODEL_JIGGY, CustomCollectible_Draw } }, -}; - ActorInfo customActorInfo = { MARKER_300_CUSTOM_COLLECTIBLE, ACTOR_3CD_CUSTOM_COLLECTIBLE, ASSET_0_NONE, 1, NULL, - NULL, + CustomCollectible_Update, NULL, NULL, 0, @@ -39,15 +35,15 @@ void CustomCollectible_Update(Actor* actor) { actor->yaw += 5.0f; } -Actor* CustomCollectible_Draw(ActorMarker* marker, Gfx** gdl, Mtx** mptr, Vtx** arg3) { +Actor* CustomCollectible_DrawGeneric(ActorMarker* marker, Gfx** gdl, Mtx** mptr, Vtx** arg3) { Actor* actor = marker_getActor(marker); actor = actor_draw(actor->marker, gdl, mptr, arg3); + return actor; } -Actor* CustomCollectible::AttachLocalStruct(int32_t randoItemId, Actor* customCollectible) { +Actor* CustomCollectible::AttachCustomVariables(int32_t randoItemId, Actor* customCollectible) { ActorLocal_CustomCollectible* customLocal = (ActorLocal_CustomCollectible*)&customCollectible->local; - customLocal->randoItemId = randoItemId; return customCollectible; @@ -58,18 +54,123 @@ Actor* CustomCollectible::Spawn(int32_t position[3], RandoItemId randoItemId) { int32_t flags = ACTOR_FLAG_UNKNOWN_6 | ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_21; - auto drawData = customCollectibleDrawList.find(randoItemId); - ActorInfo collectibleInfo = customActorInfo; - collectibleInfo.modelId = drawData->second.drawModel; - collectibleInfo.draw_func = drawData->second.drawFunction; + ActorInfo collectibleInfo = CustomCollectible::GetActorAndDrawInfo(randoItemId); - Actor* customCollectible = actor_new(position, 0, &customActorInfo, flags); + Actor* customCollectible = actor_new(position, 0, &collectibleInfo, flags); customCollectible->marker->collisionFunc = CustomCollectible::OnCollect; - customCollectible = CustomCollectible::AttachLocalStruct(randoItemId, customCollectible); + customCollectible = CustomCollectible::AttachCustomVariables(randoItemId, customCollectible); return customCollectible; } +ActorInfo CustomCollectible::GetActorAndDrawInfo(RandoItemId randoItemId) { + ActorInfo collectibleInfo = customActorInfo; + + // Empty Honeycomb + if (randoItemId >= RI_EMPTY_HONEYCOMB_BUBBLEGLOOP_SWAMP && randoItemId <= RI_EMPTY_HONEYCOMB_TREASURE_TROVE_COVE) { + collectibleInfo.modelId = ASSET_363_MODEL_HONEYCOMB; + collectibleInfo.draw_func = CustomCollectible_DrawGeneric; + } + + // Jiggy + else if (randoItemId >= RI_JIGGY_BUBBLEGLOOP_SWAMP && randoItemId <= RI_JIGGY_TREASURE_TROVE_COVE) { + collectibleInfo.modelId = ASSET_35F_MODEL_JIGGY; + collectibleInfo.draw_func = CustomCollectible_DrawGeneric; + } + + // Jinjo (Blue) + else if (randoItemId >= RI_JINJO_BLUE_BUBBLEGLOOP_SWAMP && randoItemId <= RI_JINJO_BLUE_TREASURE_TROVE_COVE) { + collectibleInfo.modelId = ASSET_3C0_MODEL_JINJO_BLUE; + collectibleInfo.draw_func = CustomCollectible_DrawGeneric; + } + + // Jinjo (Green) + else if (randoItemId >= RI_JINJO_GREEN_BUBBLEGLOOP_SWAMP && randoItemId <= RI_JINJO_GREEN_TREASURE_TROVE_COVE) { + collectibleInfo.modelId = ASSET_3C2_MODEL_JINJO_GREEN; + collectibleInfo.draw_func = CustomCollectible_DrawGeneric; + } + + // Jinjo (Orange) + else if (randoItemId >= RI_JINJO_ORANGE_BUBBLEGLOOP_SWAMP && randoItemId <= RI_JINJO_ORANGE_TREASURE_TROVE_COVE) { + collectibleInfo.modelId = ASSET_3BC_MODEL_JINJO_ORANGE; + collectibleInfo.draw_func = CustomCollectible_DrawGeneric; + } + + // Jinjo (Pink) + else if (randoItemId >= RI_JINJO_PINK_BUBBLEGLOOP_SWAMP && randoItemId <= RI_JINJO_PINK_TREASURE_TROVE_COVE) { + collectibleInfo.modelId = ASSET_3C1_MODEL_JINJO_PINK; + collectibleInfo.draw_func = CustomCollectible_DrawGeneric; + } + + // Jinjo (Yellow) + else if (randoItemId >= RI_JINJO_YELLOW_BUBBLEGLOOP_SWAMP && randoItemId <= RI_JINJO_YELLOW_TREASURE_TROVE_COVE) { + collectibleInfo.modelId = ASSET_3BB_MODEL_JINJO_YELLOW; + collectibleInfo.draw_func = CustomCollectible_DrawGeneric; + } + + // Molehill + else if (randoItemId >= RI_MOLEHILL_BARGE && randoItemId <= RI_MOLEHILL_WONDERWING) { + collectibleInfo.modelId = ASSET_388_MODEL_MOLEHILL; + collectibleInfo.draw_func = CustomCollectible_DrawGeneric; + } + + // Mumbo Token + else if (randoItemId >= RI_MUMBO_TOKEN_BUBBLEGLOOP_SWAMP && randoItemId <= RI_MUMBO_TOKEN_TREASURE_TROVE_COVE) { + collectibleInfo.modelId = ASSET_41A_SPRITE_MUMBO_TOKEN; + collectibleInfo.draw_func = CustomCollectible_DrawGeneric; + } + + // Music Note + else if (randoItemId >= RI_MUSIC_NOTE_BUBBLEGLOOP_SWAMP && randoItemId <= RI_MUSIC_NOTE_TREASURE_TROVE_COVE) { + collectibleInfo.modelId = ASSET_6D6_SPRITE_MUSIC_NOTE; + collectibleInfo.draw_func = CustomCollectible_DrawGeneric; + } + + // StopNSwop Egg (Blue) + else if (randoItemId == RI_STOP_N_SWOP_EGG_BLUE) { + collectibleInfo.modelId = ASSET_36D_SPRITE_BLUE_EGG; + collectibleInfo.draw_func = CustomCollectible_DrawGeneric; + } + + // StopNSwop Egg (Cyan) + else if (randoItemId == RI_STOP_N_SWOP_EGG_CYAN) { + collectibleInfo.modelId = ASSET_36D_SPRITE_BLUE_EGG; + collectibleInfo.draw_func = CustomCollectible_DrawGeneric; + } + + // StopNSwop Egg (Green) + else if (randoItemId == RI_STOP_N_SWOP_EGG_GREEN) { + collectibleInfo.modelId = ASSET_36D_SPRITE_BLUE_EGG; + collectibleInfo.draw_func = CustomCollectible_DrawGeneric; + } + + // StopNSwop Egg (Pink) + else if (randoItemId == RI_STOP_N_SWOP_EGG_PINK) { + collectibleInfo.modelId = ASSET_36D_SPRITE_BLUE_EGG; + collectibleInfo.draw_func = CustomCollectible_DrawGeneric; + } + + // StopNSwop Egg (Red) + else if (randoItemId == RI_STOP_N_SWOP_EGG_RED) { + collectibleInfo.modelId = ASSET_36D_SPRITE_BLUE_EGG; + collectibleInfo.draw_func = CustomCollectible_DrawGeneric; + } + + // StopNSwop Egg (Yellow) + else if (randoItemId == RI_STOP_N_SWOP_EGG_YELLOW) { + collectibleInfo.modelId = ASSET_36D_SPRITE_BLUE_EGG; + collectibleInfo.draw_func = CustomCollectible_DrawGeneric; + } + + // StopNSwop Ice Key + else if (randoItemId == RI_STOP_N_SWOP_ICE_KEY) { + collectibleInfo.modelId = ASSET_36D_SPRITE_BLUE_EGG; + collectibleInfo.draw_func = CustomCollectible_DrawGeneric; + } + + return collectibleInfo; +} + void CustomCollectible::OnCollect(struct actorMarker_s* self, struct actorMarker_s* other) { marker_despawn(self); } diff --git a/src/port/Rando/CustomCollectible/CustomCollectible.h b/src/port/Rando/CustomCollectible/CustomCollectible.h index 0c7a99e01..f14508108 100644 --- a/src/port/Rando/CustomCollectible/CustomCollectible.h +++ b/src/port/Rando/CustomCollectible/CustomCollectible.h @@ -1,24 +1,19 @@ #pragma once #include "prop.h" #include "port/Rando/Types.h" -#include typedef struct { uint32_t randoItemId; } ActorLocal_CustomCollectible; -typedef struct { - asset_e drawModel; - std::function drawFunction; -} CustomCollecticleDrawData; - void CustomCollectible_Update(Actor* actor); -Actor* CustomCollectible_Draw(ActorMarker* marker, Gfx** gdl, Mtx** mptr, Vtx** arg3); +Actor* CustomCollectible_DrawGeneric(ActorMarker* marker, Gfx** gdl, Mtx** mptr, Vtx** arg3); class CustomCollectible { private: - static Actor* AttachLocalStruct(int32_t randoItemId, Actor* customCollectible); + static Actor* AttachCustomVariables(int32_t randoItemId, Actor* customCollectible); static void OnCollect(struct actorMarker_s* self, struct actorMarker_s* other); + static ActorInfo GetActorAndDrawInfo(RandoItemId randoItemId); public: static Actor* Spawn(int32_t position[3], RandoItemId randoItemId); diff --git a/src/port/UI/DeveloperTools/GameplayTools.cpp b/src/port/UI/DeveloperTools/GameplayTools.cpp index 4a26144b3..adefee27c 100644 --- a/src/port/UI/DeveloperTools/GameplayTools.cpp +++ b/src/port/UI/DeveloperTools/GameplayTools.cpp @@ -70,6 +70,7 @@ int32_t selectedSnsItem = SNS_ITEM_EGG_YELLOW; int32_t selectedJiggy = JIGGY_01_MM_JINJO; int32_t selectedHoneycomb = HONEYCOMB_1_MM_HILL; int32_t selectedToken = MUMBOTOKEN_01_MM_STUMP_NEAR_CONGA; +int32_t selectedCustomCollectible = RI_EMPTY_HONEYCOMB_BUBBLEGLOOP_SWAMP; const char* mapNames[] = { "Mumbo's Mountain", "Treasure Trove Cove", "Clanker's Cavern", "Bubblegloop Swamp", "Freezeezy Peak", @@ -403,8 +404,23 @@ void GameplayTools_ObjectSpawner() { } ImGui::SeparatorText("Custom Collectible Testing"); - if (UIWidgets::Button("Spawn Custom Collectible", { .color = THEME_COLOR })) { - Actor* newActor = CustomCollectible::Spawn(spawnPosition, RI_EMPTY_HONEYCOMB_BUBBLEGLOOP_SWAMP); + if (ImGui::BeginTable("ObjectSpawner", 2, ImGuiTableFlags_SizingStretchSame)) { + ImGui::TableNextColumn(); + if (UIWidgets::Button("Spawn Custom Collectible", { .color = THEME_COLOR })) { + Actor* newActor = CustomCollectible::Spawn(spawnPosition, (RandoItemId)selectedCustomCollectible); + } + ImGui::TableNextColumn(); + std::string customCollectibleText = Rando::StaticData::Items[(RandoItemId)selectedCustomCollectible].name; + + UIWidgets::SliderInt("##customCollectibleIndex", &selectedCustomCollectible, + UIWidgets::IntSliderOptions() + .Color(THEME_COLOR) + .Min(RI_EMPTY_HONEYCOMB_BUBBLEGLOOP_SWAMP) + .Max(RI_STOP_N_SWOP_ICE_KEY) + .DefaultValue(RI_EMPTY_HONEYCOMB_BUBBLEGLOOP_SWAMP) + .Format(customCollectibleText.c_str()) + .LabelPosition(UIWidgets::LabelPositions::None)); + ImGui::EndTable(); } } From cc0abc20a734c9198526709f6ee75a23f0fb91f1 Mon Sep 17 00:00:00 2001 From: aMannus Date: Wed, 8 Jul 2026 12:59:45 +0200 Subject: [PATCH 006/131] Vanilla sprites and models work now --- src/core2/actor_cubepropsystem.c | 4 +- .../CustomCollectible/CustomCollectible.cpp | 46 ++++++++++--------- .../CustomCollectible/CustomCollectible.h | 1 - 3 files changed, 27 insertions(+), 24 deletions(-) diff --git a/src/core2/actor_cubepropsystem.c b/src/core2/actor_cubepropsystem.c index 466e31455..1f0c1ea07 100644 --- a/src/core2/actor_cubepropsystem.c +++ b/src/core2/actor_cubepropsystem.c @@ -1785,7 +1785,7 @@ BKSpriteDisplayData *func_80330E54(ActorMarker *marker, BKSprite **sprite_ptr) { return 0; } model_cache_ptr = &modelCache[marker_getActor(marker)->modelCacheIndex]; - if (model_cache_ptr->unk4 == 0) { + if (model_cache_ptr->unk4 == 0 || marker->id == MARKER_300_CUSTOM_COLLECTIBLE) { model_cache_ptr->unk4 = codeB3A80_getSprite(marker->modelId, &model_cache_ptr->unk8); } model_cache_ptr->unk10 = globalTimer_getTime(); @@ -2200,7 +2200,7 @@ f32 func_80331E34(Prop *arg0){ f32 func_80331E64(ActorMarker *marker) { f32 sp24; - if (marker->modelId == 0) { + if (marker->modelId == 0 || marker->id == MARKER_300_CUSTOM_COLLECTIBLE) { return 0.0f; } sp24 = func_80331D20(func_80330F50(marker)); diff --git a/src/port/Rando/CustomCollectible/CustomCollectible.cpp b/src/port/Rando/CustomCollectible/CustomCollectible.cpp index ee7b8c7e3..f6a49dabb 100644 --- a/src/port/Rando/CustomCollectible/CustomCollectible.cpp +++ b/src/port/Rando/CustomCollectible/CustomCollectible.cpp @@ -5,12 +5,11 @@ extern "C" { Actor* actor_new(s32 position[3], s32 yaw, ActorInfo* actorInfo, u32 flags); Actor* actor_draw(ActorMarker* marker, Gfx** gfx, Mtx** mtx, Vtx** vtx); +Actor* fxTouchSparkle_draw(ActorMarker* marker, Gfx** gfx, Mtx** mtx, Vtx** vtx); Actor* marker_getActor(ActorMarker* thisx); void marker_despawn(ActorMarker* marker); } -using DrawFunc = Actor* (*)(ActorMarker*, Gfx**, Mtx**, Vtx**); - ActorInfo customActorInfo = { MARKER_300_CUSTOM_COLLECTIBLE, ACTOR_3CD_CUSTOM_COLLECTIBLE, ASSET_0_NONE, @@ -30,14 +29,19 @@ void CustomCollectible_Update(Actor* actor) { if (!actor->initialized) { actor->initialized = true; actor->marker->collidable = true; + + if (customLocal->randoItemId >= RI_MUSIC_NOTE_BUBBLEGLOOP_SWAMP && + customLocal->randoItemId <= RI_MUSIC_NOTE_TREASURE_TROVE_COVE) { + actor->scale = 0.42857143f; + } } actor->yaw += 5.0f; } -Actor* CustomCollectible_DrawGeneric(ActorMarker* marker, Gfx** gdl, Mtx** mptr, Vtx** arg3) { +Actor* CustomCollectible_DrawCustom(ActorMarker* marker, Gfx** gdl, Mtx** mptr, Vtx** vtx) { Actor* actor = marker_getActor(marker); - actor = actor_draw(actor->marker, gdl, mptr, arg3); + actor = actor_draw(actor->marker, gdl, mptr, vtx); return actor; } @@ -69,103 +73,103 @@ ActorInfo CustomCollectible::GetActorAndDrawInfo(RandoItemId randoItemId) { // Empty Honeycomb if (randoItemId >= RI_EMPTY_HONEYCOMB_BUBBLEGLOOP_SWAMP && randoItemId <= RI_EMPTY_HONEYCOMB_TREASURE_TROVE_COVE) { collectibleInfo.modelId = ASSET_363_MODEL_HONEYCOMB; - collectibleInfo.draw_func = CustomCollectible_DrawGeneric; + collectibleInfo.draw_func = actor_draw; } // Jiggy else if (randoItemId >= RI_JIGGY_BUBBLEGLOOP_SWAMP && randoItemId <= RI_JIGGY_TREASURE_TROVE_COVE) { collectibleInfo.modelId = ASSET_35F_MODEL_JIGGY; - collectibleInfo.draw_func = CustomCollectible_DrawGeneric; + collectibleInfo.draw_func = actor_draw; } // Jinjo (Blue) else if (randoItemId >= RI_JINJO_BLUE_BUBBLEGLOOP_SWAMP && randoItemId <= RI_JINJO_BLUE_TREASURE_TROVE_COVE) { collectibleInfo.modelId = ASSET_3C0_MODEL_JINJO_BLUE; - collectibleInfo.draw_func = CustomCollectible_DrawGeneric; + collectibleInfo.draw_func = actor_draw; } // Jinjo (Green) else if (randoItemId >= RI_JINJO_GREEN_BUBBLEGLOOP_SWAMP && randoItemId <= RI_JINJO_GREEN_TREASURE_TROVE_COVE) { collectibleInfo.modelId = ASSET_3C2_MODEL_JINJO_GREEN; - collectibleInfo.draw_func = CustomCollectible_DrawGeneric; + collectibleInfo.draw_func = actor_draw; } // Jinjo (Orange) else if (randoItemId >= RI_JINJO_ORANGE_BUBBLEGLOOP_SWAMP && randoItemId <= RI_JINJO_ORANGE_TREASURE_TROVE_COVE) { collectibleInfo.modelId = ASSET_3BC_MODEL_JINJO_ORANGE; - collectibleInfo.draw_func = CustomCollectible_DrawGeneric; + collectibleInfo.draw_func = actor_draw; } // Jinjo (Pink) else if (randoItemId >= RI_JINJO_PINK_BUBBLEGLOOP_SWAMP && randoItemId <= RI_JINJO_PINK_TREASURE_TROVE_COVE) { collectibleInfo.modelId = ASSET_3C1_MODEL_JINJO_PINK; - collectibleInfo.draw_func = CustomCollectible_DrawGeneric; + collectibleInfo.draw_func = actor_draw; } // Jinjo (Yellow) else if (randoItemId >= RI_JINJO_YELLOW_BUBBLEGLOOP_SWAMP && randoItemId <= RI_JINJO_YELLOW_TREASURE_TROVE_COVE) { collectibleInfo.modelId = ASSET_3BB_MODEL_JINJO_YELLOW; - collectibleInfo.draw_func = CustomCollectible_DrawGeneric; + collectibleInfo.draw_func = actor_draw; } // Molehill else if (randoItemId >= RI_MOLEHILL_BARGE && randoItemId <= RI_MOLEHILL_WONDERWING) { collectibleInfo.modelId = ASSET_388_MODEL_MOLEHILL; - collectibleInfo.draw_func = CustomCollectible_DrawGeneric; + collectibleInfo.draw_func = actor_draw; } // Mumbo Token else if (randoItemId >= RI_MUMBO_TOKEN_BUBBLEGLOOP_SWAMP && randoItemId <= RI_MUMBO_TOKEN_TREASURE_TROVE_COVE) { collectibleInfo.modelId = ASSET_41A_SPRITE_MUMBO_TOKEN; - collectibleInfo.draw_func = CustomCollectible_DrawGeneric; + collectibleInfo.draw_func = fxTouchSparkle_draw; } // Music Note else if (randoItemId >= RI_MUSIC_NOTE_BUBBLEGLOOP_SWAMP && randoItemId <= RI_MUSIC_NOTE_TREASURE_TROVE_COVE) { collectibleInfo.modelId = ASSET_6D6_SPRITE_MUSIC_NOTE; - collectibleInfo.draw_func = CustomCollectible_DrawGeneric; + collectibleInfo.draw_func = fxTouchSparkle_draw; } // StopNSwop Egg (Blue) else if (randoItemId == RI_STOP_N_SWOP_EGG_BLUE) { collectibleInfo.modelId = ASSET_36D_SPRITE_BLUE_EGG; - collectibleInfo.draw_func = CustomCollectible_DrawGeneric; + collectibleInfo.draw_func = fxTouchSparkle_draw; } // StopNSwop Egg (Cyan) else if (randoItemId == RI_STOP_N_SWOP_EGG_CYAN) { collectibleInfo.modelId = ASSET_36D_SPRITE_BLUE_EGG; - collectibleInfo.draw_func = CustomCollectible_DrawGeneric; + collectibleInfo.draw_func = fxTouchSparkle_draw; } // StopNSwop Egg (Green) else if (randoItemId == RI_STOP_N_SWOP_EGG_GREEN) { collectibleInfo.modelId = ASSET_36D_SPRITE_BLUE_EGG; - collectibleInfo.draw_func = CustomCollectible_DrawGeneric; + collectibleInfo.draw_func = fxTouchSparkle_draw; } // StopNSwop Egg (Pink) else if (randoItemId == RI_STOP_N_SWOP_EGG_PINK) { collectibleInfo.modelId = ASSET_36D_SPRITE_BLUE_EGG; - collectibleInfo.draw_func = CustomCollectible_DrawGeneric; + collectibleInfo.draw_func = fxTouchSparkle_draw; } // StopNSwop Egg (Red) else if (randoItemId == RI_STOP_N_SWOP_EGG_RED) { collectibleInfo.modelId = ASSET_36D_SPRITE_BLUE_EGG; - collectibleInfo.draw_func = CustomCollectible_DrawGeneric; + collectibleInfo.draw_func = fxTouchSparkle_draw; } // StopNSwop Egg (Yellow) else if (randoItemId == RI_STOP_N_SWOP_EGG_YELLOW) { collectibleInfo.modelId = ASSET_36D_SPRITE_BLUE_EGG; - collectibleInfo.draw_func = CustomCollectible_DrawGeneric; + collectibleInfo.draw_func = fxTouchSparkle_draw; } // StopNSwop Ice Key else if (randoItemId == RI_STOP_N_SWOP_ICE_KEY) { collectibleInfo.modelId = ASSET_36D_SPRITE_BLUE_EGG; - collectibleInfo.draw_func = CustomCollectible_DrawGeneric; + collectibleInfo.draw_func = fxTouchSparkle_draw; } return collectibleInfo; diff --git a/src/port/Rando/CustomCollectible/CustomCollectible.h b/src/port/Rando/CustomCollectible/CustomCollectible.h index f14508108..eea79127e 100644 --- a/src/port/Rando/CustomCollectible/CustomCollectible.h +++ b/src/port/Rando/CustomCollectible/CustomCollectible.h @@ -7,7 +7,6 @@ typedef struct { } ActorLocal_CustomCollectible; void CustomCollectible_Update(Actor* actor); -Actor* CustomCollectible_DrawGeneric(ActorMarker* marker, Gfx** gdl, Mtx** mptr, Vtx** arg3); class CustomCollectible { private: From 1d085e2c432b21d60951fd5fb2f1d8a24249eecb Mon Sep 17 00:00:00 2001 From: aMannus Date: Thu, 9 Jul 2026 00:15:17 +0200 Subject: [PATCH 007/131] Custom models working but update function doesn't always --- .../gArchipelagoItemDL | 16 ++ .../gArchipelagoItemDL_tri_0 | 56 ++++++ .../gArchipelagoItemDL_tri_1 | 57 ++++++ .../gArchipelagoItemDL_tri_2 | 57 ++++++ .../gArchipelagoItemDL_tri_3 | 57 ++++++ .../gArchipelagoItemDL_tri_4 | 57 ++++++ .../gArchipelagoItemDL_tri_5 | 56 ++++++ .../gArchipelagoItemDL_tri_6 | 56 ++++++ .../gArchipelagoItemDL_vtx_0 | 64 ++++++ .../gArchipelagoItemDL_vtx_1 | 77 ++++++++ .../gArchipelagoItemDL_vtx_2 | 70 +++++++ .../gArchipelagoItemDL_vtx_3 | 68 +++++++ .../gArchipelagoItemDL_vtx_4 | 69 +++++++ .../gArchipelagoItemDL_vtx_5 | 64 ++++++ .../gArchipelagoItemDL_vtx_6 | 64 ++++++ .../gArchipelagoJunkDL | 16 ++ .../gArchipelagoJunkDL_tri_0 | 56 ++++++ .../gArchipelagoJunkDL_tri_1 | 57 ++++++ .../gArchipelagoJunkDL_tri_2 | 57 ++++++ .../gArchipelagoJunkDL_tri_3 | 57 ++++++ .../gArchipelagoJunkDL_tri_4 | 57 ++++++ .../gArchipelagoJunkDL_tri_5 | 56 ++++++ .../gArchipelagoJunkDL_tri_6 | 56 ++++++ .../gArchipelagoJunkDL_vtx_0 | 64 ++++++ .../gArchipelagoJunkDL_vtx_1 | 77 ++++++++ .../gArchipelagoJunkDL_vtx_2 | 70 +++++++ .../gArchipelagoJunkDL_vtx_3 | 68 +++++++ .../gArchipelagoJunkDL_vtx_4 | 69 +++++++ .../gArchipelagoJunkDL_vtx_5 | 64 ++++++ .../gArchipelagoJunkDL_vtx_6 | 64 ++++++ .../gArchipelagoProgressiveDL | 18 ++ .../gArchipelagoProgressiveDL_tri_0 | 56 ++++++ .../gArchipelagoProgressiveDL_tri_1 | 57 ++++++ .../gArchipelagoProgressiveDL_tri_2 | 57 ++++++ .../gArchipelagoProgressiveDL_tri_3 | 57 ++++++ .../gArchipelagoProgressiveDL_tri_4 | 57 ++++++ .../gArchipelagoProgressiveDL_tri_5 | 56 ++++++ .../gArchipelagoProgressiveDL_tri_6 | 41 ++++ .../gArchipelagoProgressiveDL_tri_7 | 41 ++++ .../gArchipelagoProgressiveDL_vtx_0 | 64 ++++++ .../gArchipelagoProgressiveDL_vtx_1 | 77 ++++++++ .../gArchipelagoProgressiveDL_vtx_2 | 70 +++++++ .../gArchipelagoProgressiveDL_vtx_3 | 68 +++++++ .../gArchipelagoProgressiveDL_vtx_4 | 69 +++++++ .../gArchipelagoProgressiveDL_vtx_5 | 64 ++++++ .../gArchipelagoProgressiveDL_vtx_6 | 39 ++++ .../gArchipelagoProgressiveDL_vtx_7 | 39 ++++ .../mat_gArchipelagoItemDL_black | 12 ++ .../mat_gArchipelagoItemDL_blue | 12 ++ .../mat_gArchipelagoItemDL_green | 12 ++ .../mat_gArchipelagoItemDL_orange | 12 ++ .../mat_gArchipelagoItemDL_outline | 12 ++ .../mat_gArchipelagoItemDL_pink | 12 ++ .../mat_gArchipelagoItemDL_purple | 12 ++ .../mat_gArchipelagoItemDL_red | 12 ++ .../mat_gArchipelagoItemDL_yellow | 12 ++ .../mat_gArchipelagoJunkDL_black_junk | 12 ++ .../mat_gArchipelagoJunkDL_blue_junk | 12 ++ .../mat_gArchipelagoJunkDL_green_junk | 12 ++ .../mat_gArchipelagoJunkDL_grey_blue | 12 ++ .../mat_gArchipelagoJunkDL_grey_green | 12 ++ .../mat_gArchipelagoJunkDL_grey_orange | 12 ++ .../mat_gArchipelagoJunkDL_grey_outline | 12 ++ .../mat_gArchipelagoJunkDL_grey_pink | 12 ++ .../mat_gArchipelagoJunkDL_grey_red | 12 ++ .../mat_gArchipelagoJunkDL_grey_yellow | 12 ++ .../mat_gArchipelagoJunkDL_orange_junk | 12 ++ .../mat_gArchipelagoJunkDL_purple_junk | 12 ++ .../mat_gArchipelagoJunkDL_red_junk | 12 ++ .../mat_gArchipelagoJunkDL_yellow_junk | 12 ++ ...pelagoProgressiveDL_arrow_gold_progressive | 12 ++ ...ArchipelagoProgressiveDL_black_progressive | 12 ++ ...gArchipelagoProgressiveDL_blue_progressive | 12 ++ ...ArchipelagoProgressiveDL_green_progressive | 12 ++ ...rchipelagoProgressiveDL_orange_progressive | 12 ++ ...ArchipelagoProgressiveDL_progressive_arrow | 12 ++ ...gArchipelagoProgressiveDL_progressive_blue | 12 ++ ...ArchipelagoProgressiveDL_progressive_green | 12 ++ ...rchipelagoProgressiveDL_progressive_orange | 12 ++ ...chipelagoProgressiveDL_progressive_outline | 12 ++ ...gArchipelagoProgressiveDL_progressive_pink | 12 ++ ..._gArchipelagoProgressiveDL_progressive_red | 12 ++ ...rchipelagoProgressiveDL_progressive_yellow | 12 ++ ...rchipelagoProgressiveDL_purple_progressive | 12 ++ ..._gArchipelagoProgressiveDL_red_progressive | 12 ++ ...rchipelagoProgressiveDL_yellow_progressive | 12 ++ .../objects/object_archipelago_item/model.xml | 0 .../CustomCollectible/CustomCollectible.cpp | 183 ++++++++---------- .../CustomCollectible/CustomCollectible.h | 10 +- .../CustomCollectibleDrawCustom.cpp | 107 ++++++++++ .../CustomCollectibleDrawCustom.h | 36 ++++ src/port/ResourceHelpers.h | 1 + 92 files changed, 3403 insertions(+), 108 deletions(-) create mode 100644 port/objects/object_archipelago_item/gArchipelagoItemDL create mode 100644 port/objects/object_archipelago_item/gArchipelagoItemDL_tri_0 create mode 100644 port/objects/object_archipelago_item/gArchipelagoItemDL_tri_1 create mode 100644 port/objects/object_archipelago_item/gArchipelagoItemDL_tri_2 create mode 100644 port/objects/object_archipelago_item/gArchipelagoItemDL_tri_3 create mode 100644 port/objects/object_archipelago_item/gArchipelagoItemDL_tri_4 create mode 100644 port/objects/object_archipelago_item/gArchipelagoItemDL_tri_5 create mode 100644 port/objects/object_archipelago_item/gArchipelagoItemDL_tri_6 create mode 100644 port/objects/object_archipelago_item/gArchipelagoItemDL_vtx_0 create mode 100644 port/objects/object_archipelago_item/gArchipelagoItemDL_vtx_1 create mode 100644 port/objects/object_archipelago_item/gArchipelagoItemDL_vtx_2 create mode 100644 port/objects/object_archipelago_item/gArchipelagoItemDL_vtx_3 create mode 100644 port/objects/object_archipelago_item/gArchipelagoItemDL_vtx_4 create mode 100644 port/objects/object_archipelago_item/gArchipelagoItemDL_vtx_5 create mode 100644 port/objects/object_archipelago_item/gArchipelagoItemDL_vtx_6 create mode 100644 port/objects/object_archipelago_item/gArchipelagoJunkDL create mode 100644 port/objects/object_archipelago_item/gArchipelagoJunkDL_tri_0 create mode 100644 port/objects/object_archipelago_item/gArchipelagoJunkDL_tri_1 create mode 100644 port/objects/object_archipelago_item/gArchipelagoJunkDL_tri_2 create mode 100644 port/objects/object_archipelago_item/gArchipelagoJunkDL_tri_3 create mode 100644 port/objects/object_archipelago_item/gArchipelagoJunkDL_tri_4 create mode 100644 port/objects/object_archipelago_item/gArchipelagoJunkDL_tri_5 create mode 100644 port/objects/object_archipelago_item/gArchipelagoJunkDL_tri_6 create mode 100644 port/objects/object_archipelago_item/gArchipelagoJunkDL_vtx_0 create mode 100644 port/objects/object_archipelago_item/gArchipelagoJunkDL_vtx_1 create mode 100644 port/objects/object_archipelago_item/gArchipelagoJunkDL_vtx_2 create mode 100644 port/objects/object_archipelago_item/gArchipelagoJunkDL_vtx_3 create mode 100644 port/objects/object_archipelago_item/gArchipelagoJunkDL_vtx_4 create mode 100644 port/objects/object_archipelago_item/gArchipelagoJunkDL_vtx_5 create mode 100644 port/objects/object_archipelago_item/gArchipelagoJunkDL_vtx_6 create mode 100644 port/objects/object_archipelago_item/gArchipelagoProgressiveDL create mode 100644 port/objects/object_archipelago_item/gArchipelagoProgressiveDL_tri_0 create mode 100644 port/objects/object_archipelago_item/gArchipelagoProgressiveDL_tri_1 create mode 100644 port/objects/object_archipelago_item/gArchipelagoProgressiveDL_tri_2 create mode 100644 port/objects/object_archipelago_item/gArchipelagoProgressiveDL_tri_3 create mode 100644 port/objects/object_archipelago_item/gArchipelagoProgressiveDL_tri_4 create mode 100644 port/objects/object_archipelago_item/gArchipelagoProgressiveDL_tri_5 create mode 100644 port/objects/object_archipelago_item/gArchipelagoProgressiveDL_tri_6 create mode 100644 port/objects/object_archipelago_item/gArchipelagoProgressiveDL_tri_7 create mode 100644 port/objects/object_archipelago_item/gArchipelagoProgressiveDL_vtx_0 create mode 100644 port/objects/object_archipelago_item/gArchipelagoProgressiveDL_vtx_1 create mode 100644 port/objects/object_archipelago_item/gArchipelagoProgressiveDL_vtx_2 create mode 100644 port/objects/object_archipelago_item/gArchipelagoProgressiveDL_vtx_3 create mode 100644 port/objects/object_archipelago_item/gArchipelagoProgressiveDL_vtx_4 create mode 100644 port/objects/object_archipelago_item/gArchipelagoProgressiveDL_vtx_5 create mode 100644 port/objects/object_archipelago_item/gArchipelagoProgressiveDL_vtx_6 create mode 100644 port/objects/object_archipelago_item/gArchipelagoProgressiveDL_vtx_7 create mode 100644 port/objects/object_archipelago_item/mat_gArchipelagoItemDL_black create mode 100644 port/objects/object_archipelago_item/mat_gArchipelagoItemDL_blue create mode 100644 port/objects/object_archipelago_item/mat_gArchipelagoItemDL_green create mode 100644 port/objects/object_archipelago_item/mat_gArchipelagoItemDL_orange create mode 100644 port/objects/object_archipelago_item/mat_gArchipelagoItemDL_outline create mode 100644 port/objects/object_archipelago_item/mat_gArchipelagoItemDL_pink create mode 100644 port/objects/object_archipelago_item/mat_gArchipelagoItemDL_purple create mode 100644 port/objects/object_archipelago_item/mat_gArchipelagoItemDL_red create mode 100644 port/objects/object_archipelago_item/mat_gArchipelagoItemDL_yellow create mode 100644 port/objects/object_archipelago_item/mat_gArchipelagoJunkDL_black_junk create mode 100644 port/objects/object_archipelago_item/mat_gArchipelagoJunkDL_blue_junk create mode 100644 port/objects/object_archipelago_item/mat_gArchipelagoJunkDL_green_junk create mode 100644 port/objects/object_archipelago_item/mat_gArchipelagoJunkDL_grey_blue create mode 100644 port/objects/object_archipelago_item/mat_gArchipelagoJunkDL_grey_green create mode 100644 port/objects/object_archipelago_item/mat_gArchipelagoJunkDL_grey_orange create mode 100644 port/objects/object_archipelago_item/mat_gArchipelagoJunkDL_grey_outline create mode 100644 port/objects/object_archipelago_item/mat_gArchipelagoJunkDL_grey_pink create mode 100644 port/objects/object_archipelago_item/mat_gArchipelagoJunkDL_grey_red create mode 100644 port/objects/object_archipelago_item/mat_gArchipelagoJunkDL_grey_yellow create mode 100644 port/objects/object_archipelago_item/mat_gArchipelagoJunkDL_orange_junk create mode 100644 port/objects/object_archipelago_item/mat_gArchipelagoJunkDL_purple_junk create mode 100644 port/objects/object_archipelago_item/mat_gArchipelagoJunkDL_red_junk create mode 100644 port/objects/object_archipelago_item/mat_gArchipelagoJunkDL_yellow_junk create mode 100644 port/objects/object_archipelago_item/mat_gArchipelagoProgressiveDL_arrow_gold_progressive create mode 100644 port/objects/object_archipelago_item/mat_gArchipelagoProgressiveDL_black_progressive create mode 100644 port/objects/object_archipelago_item/mat_gArchipelagoProgressiveDL_blue_progressive create mode 100644 port/objects/object_archipelago_item/mat_gArchipelagoProgressiveDL_green_progressive create mode 100644 port/objects/object_archipelago_item/mat_gArchipelagoProgressiveDL_orange_progressive create mode 100644 port/objects/object_archipelago_item/mat_gArchipelagoProgressiveDL_progressive_arrow create mode 100644 port/objects/object_archipelago_item/mat_gArchipelagoProgressiveDL_progressive_blue create mode 100644 port/objects/object_archipelago_item/mat_gArchipelagoProgressiveDL_progressive_green create mode 100644 port/objects/object_archipelago_item/mat_gArchipelagoProgressiveDL_progressive_orange create mode 100644 port/objects/object_archipelago_item/mat_gArchipelagoProgressiveDL_progressive_outline create mode 100644 port/objects/object_archipelago_item/mat_gArchipelagoProgressiveDL_progressive_pink create mode 100644 port/objects/object_archipelago_item/mat_gArchipelagoProgressiveDL_progressive_red create mode 100644 port/objects/object_archipelago_item/mat_gArchipelagoProgressiveDL_progressive_yellow create mode 100644 port/objects/object_archipelago_item/mat_gArchipelagoProgressiveDL_purple_progressive create mode 100644 port/objects/object_archipelago_item/mat_gArchipelagoProgressiveDL_red_progressive create mode 100644 port/objects/object_archipelago_item/mat_gArchipelagoProgressiveDL_yellow_progressive create mode 100644 port/objects/object_archipelago_item/model.xml create mode 100644 src/port/Rando/CustomCollectible/CustomCollectibleDrawCustom.cpp create mode 100644 src/port/Rando/CustomCollectible/CustomCollectibleDrawCustom.h diff --git a/port/objects/object_archipelago_item/gArchipelagoItemDL b/port/objects/object_archipelago_item/gArchipelagoItemDL new file mode 100644 index 000000000..33e22a85f --- /dev/null +++ b/port/objects/object_archipelago_item/gArchipelagoItemDL @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/port/objects/object_archipelago_item/gArchipelagoItemDL_tri_0 b/port/objects/object_archipelago_item/gArchipelagoItemDL_tri_0 new file mode 100644 index 000000000..42e911411 --- /dev/null +++ b/port/objects/object_archipelago_item/gArchipelagoItemDL_tri_0 @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/port/objects/object_archipelago_item/gArchipelagoItemDL_tri_1 b/port/objects/object_archipelago_item/gArchipelagoItemDL_tri_1 new file mode 100644 index 000000000..259b27c4e --- /dev/null +++ b/port/objects/object_archipelago_item/gArchipelagoItemDL_tri_1 @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/port/objects/object_archipelago_item/gArchipelagoItemDL_tri_2 b/port/objects/object_archipelago_item/gArchipelagoItemDL_tri_2 new file mode 100644 index 000000000..dc680a34a --- /dev/null +++ b/port/objects/object_archipelago_item/gArchipelagoItemDL_tri_2 @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/port/objects/object_archipelago_item/gArchipelagoItemDL_tri_3 b/port/objects/object_archipelago_item/gArchipelagoItemDL_tri_3 new file mode 100644 index 000000000..a134560fb --- /dev/null +++ b/port/objects/object_archipelago_item/gArchipelagoItemDL_tri_3 @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/port/objects/object_archipelago_item/gArchipelagoItemDL_tri_4 b/port/objects/object_archipelago_item/gArchipelagoItemDL_tri_4 new file mode 100644 index 000000000..65134138f --- /dev/null +++ b/port/objects/object_archipelago_item/gArchipelagoItemDL_tri_4 @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/port/objects/object_archipelago_item/gArchipelagoItemDL_tri_5 b/port/objects/object_archipelago_item/gArchipelagoItemDL_tri_5 new file mode 100644 index 000000000..3b458b736 --- /dev/null +++ b/port/objects/object_archipelago_item/gArchipelagoItemDL_tri_5 @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/port/objects/object_archipelago_item/gArchipelagoItemDL_tri_6 b/port/objects/object_archipelago_item/gArchipelagoItemDL_tri_6 new file mode 100644 index 000000000..b21f2c4b7 --- /dev/null +++ b/port/objects/object_archipelago_item/gArchipelagoItemDL_tri_6 @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/port/objects/object_archipelago_item/gArchipelagoItemDL_vtx_0 b/port/objects/object_archipelago_item/gArchipelagoItemDL_vtx_0 new file mode 100644 index 000000000..9f4483ec6 --- /dev/null +++ b/port/objects/object_archipelago_item/gArchipelagoItemDL_vtx_0 @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/port/objects/object_archipelago_item/gArchipelagoItemDL_vtx_1 b/port/objects/object_archipelago_item/gArchipelagoItemDL_vtx_1 new file mode 100644 index 000000000..9339e42f0 --- /dev/null +++ b/port/objects/object_archipelago_item/gArchipelagoItemDL_vtx_1 @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/port/objects/object_archipelago_item/gArchipelagoItemDL_vtx_2 b/port/objects/object_archipelago_item/gArchipelagoItemDL_vtx_2 new file mode 100644 index 000000000..e1122533a --- /dev/null +++ b/port/objects/object_archipelago_item/gArchipelagoItemDL_vtx_2 @@ -0,0 +1,70 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/port/objects/object_archipelago_item/gArchipelagoItemDL_vtx_3 b/port/objects/object_archipelago_item/gArchipelagoItemDL_vtx_3 new file mode 100644 index 000000000..29c025d0f --- /dev/null +++ b/port/objects/object_archipelago_item/gArchipelagoItemDL_vtx_3 @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/port/objects/object_archipelago_item/gArchipelagoItemDL_vtx_4 b/port/objects/object_archipelago_item/gArchipelagoItemDL_vtx_4 new file mode 100644 index 000000000..c3c88918b --- /dev/null +++ b/port/objects/object_archipelago_item/gArchipelagoItemDL_vtx_4 @@ -0,0 +1,69 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/port/objects/object_archipelago_item/gArchipelagoItemDL_vtx_5 b/port/objects/object_archipelago_item/gArchipelagoItemDL_vtx_5 new file mode 100644 index 000000000..70117ba12 --- /dev/null +++ b/port/objects/object_archipelago_item/gArchipelagoItemDL_vtx_5 @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/port/objects/object_archipelago_item/gArchipelagoItemDL_vtx_6 b/port/objects/object_archipelago_item/gArchipelagoItemDL_vtx_6 new file mode 100644 index 000000000..70117ba12 --- /dev/null +++ b/port/objects/object_archipelago_item/gArchipelagoItemDL_vtx_6 @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/port/objects/object_archipelago_item/gArchipelagoJunkDL b/port/objects/object_archipelago_item/gArchipelagoJunkDL new file mode 100644 index 000000000..4beef5eb3 --- /dev/null +++ b/port/objects/object_archipelago_item/gArchipelagoJunkDL @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/port/objects/object_archipelago_item/gArchipelagoJunkDL_tri_0 b/port/objects/object_archipelago_item/gArchipelagoJunkDL_tri_0 new file mode 100644 index 000000000..f2137f135 --- /dev/null +++ b/port/objects/object_archipelago_item/gArchipelagoJunkDL_tri_0 @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/port/objects/object_archipelago_item/gArchipelagoJunkDL_tri_1 b/port/objects/object_archipelago_item/gArchipelagoJunkDL_tri_1 new file mode 100644 index 000000000..ae92327e4 --- /dev/null +++ b/port/objects/object_archipelago_item/gArchipelagoJunkDL_tri_1 @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/port/objects/object_archipelago_item/gArchipelagoJunkDL_tri_2 b/port/objects/object_archipelago_item/gArchipelagoJunkDL_tri_2 new file mode 100644 index 000000000..bbbc96439 --- /dev/null +++ b/port/objects/object_archipelago_item/gArchipelagoJunkDL_tri_2 @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/port/objects/object_archipelago_item/gArchipelagoJunkDL_tri_3 b/port/objects/object_archipelago_item/gArchipelagoJunkDL_tri_3 new file mode 100644 index 000000000..6d11e6b1c --- /dev/null +++ b/port/objects/object_archipelago_item/gArchipelagoJunkDL_tri_3 @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/port/objects/object_archipelago_item/gArchipelagoJunkDL_tri_4 b/port/objects/object_archipelago_item/gArchipelagoJunkDL_tri_4 new file mode 100644 index 000000000..827df8c0d --- /dev/null +++ b/port/objects/object_archipelago_item/gArchipelagoJunkDL_tri_4 @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/port/objects/object_archipelago_item/gArchipelagoJunkDL_tri_5 b/port/objects/object_archipelago_item/gArchipelagoJunkDL_tri_5 new file mode 100644 index 000000000..6714bf7a4 --- /dev/null +++ b/port/objects/object_archipelago_item/gArchipelagoJunkDL_tri_5 @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/port/objects/object_archipelago_item/gArchipelagoJunkDL_tri_6 b/port/objects/object_archipelago_item/gArchipelagoJunkDL_tri_6 new file mode 100644 index 000000000..3980be483 --- /dev/null +++ b/port/objects/object_archipelago_item/gArchipelagoJunkDL_tri_6 @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/port/objects/object_archipelago_item/gArchipelagoJunkDL_vtx_0 b/port/objects/object_archipelago_item/gArchipelagoJunkDL_vtx_0 new file mode 100644 index 000000000..9f4483ec6 --- /dev/null +++ b/port/objects/object_archipelago_item/gArchipelagoJunkDL_vtx_0 @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/port/objects/object_archipelago_item/gArchipelagoJunkDL_vtx_1 b/port/objects/object_archipelago_item/gArchipelagoJunkDL_vtx_1 new file mode 100644 index 000000000..9339e42f0 --- /dev/null +++ b/port/objects/object_archipelago_item/gArchipelagoJunkDL_vtx_1 @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/port/objects/object_archipelago_item/gArchipelagoJunkDL_vtx_2 b/port/objects/object_archipelago_item/gArchipelagoJunkDL_vtx_2 new file mode 100644 index 000000000..e1122533a --- /dev/null +++ b/port/objects/object_archipelago_item/gArchipelagoJunkDL_vtx_2 @@ -0,0 +1,70 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/port/objects/object_archipelago_item/gArchipelagoJunkDL_vtx_3 b/port/objects/object_archipelago_item/gArchipelagoJunkDL_vtx_3 new file mode 100644 index 000000000..29c025d0f --- /dev/null +++ b/port/objects/object_archipelago_item/gArchipelagoJunkDL_vtx_3 @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/port/objects/object_archipelago_item/gArchipelagoJunkDL_vtx_4 b/port/objects/object_archipelago_item/gArchipelagoJunkDL_vtx_4 new file mode 100644 index 000000000..c3c88918b --- /dev/null +++ b/port/objects/object_archipelago_item/gArchipelagoJunkDL_vtx_4 @@ -0,0 +1,69 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/port/objects/object_archipelago_item/gArchipelagoJunkDL_vtx_5 b/port/objects/object_archipelago_item/gArchipelagoJunkDL_vtx_5 new file mode 100644 index 000000000..70117ba12 --- /dev/null +++ b/port/objects/object_archipelago_item/gArchipelagoJunkDL_vtx_5 @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/port/objects/object_archipelago_item/gArchipelagoJunkDL_vtx_6 b/port/objects/object_archipelago_item/gArchipelagoJunkDL_vtx_6 new file mode 100644 index 000000000..70117ba12 --- /dev/null +++ b/port/objects/object_archipelago_item/gArchipelagoJunkDL_vtx_6 @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/port/objects/object_archipelago_item/gArchipelagoProgressiveDL b/port/objects/object_archipelago_item/gArchipelagoProgressiveDL new file mode 100644 index 000000000..ed07b28c9 --- /dev/null +++ b/port/objects/object_archipelago_item/gArchipelagoProgressiveDL @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/port/objects/object_archipelago_item/gArchipelagoProgressiveDL_tri_0 b/port/objects/object_archipelago_item/gArchipelagoProgressiveDL_tri_0 new file mode 100644 index 000000000..1a679a463 --- /dev/null +++ b/port/objects/object_archipelago_item/gArchipelagoProgressiveDL_tri_0 @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/port/objects/object_archipelago_item/gArchipelagoProgressiveDL_tri_1 b/port/objects/object_archipelago_item/gArchipelagoProgressiveDL_tri_1 new file mode 100644 index 000000000..f49d299ef --- /dev/null +++ b/port/objects/object_archipelago_item/gArchipelagoProgressiveDL_tri_1 @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/port/objects/object_archipelago_item/gArchipelagoProgressiveDL_tri_2 b/port/objects/object_archipelago_item/gArchipelagoProgressiveDL_tri_2 new file mode 100644 index 000000000..ea82a9347 --- /dev/null +++ b/port/objects/object_archipelago_item/gArchipelagoProgressiveDL_tri_2 @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/port/objects/object_archipelago_item/gArchipelagoProgressiveDL_tri_3 b/port/objects/object_archipelago_item/gArchipelagoProgressiveDL_tri_3 new file mode 100644 index 000000000..8cfca6524 --- /dev/null +++ b/port/objects/object_archipelago_item/gArchipelagoProgressiveDL_tri_3 @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/port/objects/object_archipelago_item/gArchipelagoProgressiveDL_tri_4 b/port/objects/object_archipelago_item/gArchipelagoProgressiveDL_tri_4 new file mode 100644 index 000000000..639c5aea4 --- /dev/null +++ b/port/objects/object_archipelago_item/gArchipelagoProgressiveDL_tri_4 @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/port/objects/object_archipelago_item/gArchipelagoProgressiveDL_tri_5 b/port/objects/object_archipelago_item/gArchipelagoProgressiveDL_tri_5 new file mode 100644 index 000000000..99a4852cb --- /dev/null +++ b/port/objects/object_archipelago_item/gArchipelagoProgressiveDL_tri_5 @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/port/objects/object_archipelago_item/gArchipelagoProgressiveDL_tri_6 b/port/objects/object_archipelago_item/gArchipelagoProgressiveDL_tri_6 new file mode 100644 index 000000000..e7ab8546c --- /dev/null +++ b/port/objects/object_archipelago_item/gArchipelagoProgressiveDL_tri_6 @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/port/objects/object_archipelago_item/gArchipelagoProgressiveDL_tri_7 b/port/objects/object_archipelago_item/gArchipelagoProgressiveDL_tri_7 new file mode 100644 index 000000000..0f50ed430 --- /dev/null +++ b/port/objects/object_archipelago_item/gArchipelagoProgressiveDL_tri_7 @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/port/objects/object_archipelago_item/gArchipelagoProgressiveDL_vtx_0 b/port/objects/object_archipelago_item/gArchipelagoProgressiveDL_vtx_0 new file mode 100644 index 000000000..9f4483ec6 --- /dev/null +++ b/port/objects/object_archipelago_item/gArchipelagoProgressiveDL_vtx_0 @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/port/objects/object_archipelago_item/gArchipelagoProgressiveDL_vtx_1 b/port/objects/object_archipelago_item/gArchipelagoProgressiveDL_vtx_1 new file mode 100644 index 000000000..9339e42f0 --- /dev/null +++ b/port/objects/object_archipelago_item/gArchipelagoProgressiveDL_vtx_1 @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/port/objects/object_archipelago_item/gArchipelagoProgressiveDL_vtx_2 b/port/objects/object_archipelago_item/gArchipelagoProgressiveDL_vtx_2 new file mode 100644 index 000000000..e1122533a --- /dev/null +++ b/port/objects/object_archipelago_item/gArchipelagoProgressiveDL_vtx_2 @@ -0,0 +1,70 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/port/objects/object_archipelago_item/gArchipelagoProgressiveDL_vtx_3 b/port/objects/object_archipelago_item/gArchipelagoProgressiveDL_vtx_3 new file mode 100644 index 000000000..29c025d0f --- /dev/null +++ b/port/objects/object_archipelago_item/gArchipelagoProgressiveDL_vtx_3 @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/port/objects/object_archipelago_item/gArchipelagoProgressiveDL_vtx_4 b/port/objects/object_archipelago_item/gArchipelagoProgressiveDL_vtx_4 new file mode 100644 index 000000000..c3c88918b --- /dev/null +++ b/port/objects/object_archipelago_item/gArchipelagoProgressiveDL_vtx_4 @@ -0,0 +1,69 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/port/objects/object_archipelago_item/gArchipelagoProgressiveDL_vtx_5 b/port/objects/object_archipelago_item/gArchipelagoProgressiveDL_vtx_5 new file mode 100644 index 000000000..70117ba12 --- /dev/null +++ b/port/objects/object_archipelago_item/gArchipelagoProgressiveDL_vtx_5 @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/port/objects/object_archipelago_item/gArchipelagoProgressiveDL_vtx_6 b/port/objects/object_archipelago_item/gArchipelagoProgressiveDL_vtx_6 new file mode 100644 index 000000000..b76b5b312 --- /dev/null +++ b/port/objects/object_archipelago_item/gArchipelagoProgressiveDL_vtx_6 @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/port/objects/object_archipelago_item/gArchipelagoProgressiveDL_vtx_7 b/port/objects/object_archipelago_item/gArchipelagoProgressiveDL_vtx_7 new file mode 100644 index 000000000..b76b5b312 --- /dev/null +++ b/port/objects/object_archipelago_item/gArchipelagoProgressiveDL_vtx_7 @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/port/objects/object_archipelago_item/mat_gArchipelagoItemDL_black b/port/objects/object_archipelago_item/mat_gArchipelagoItemDL_black new file mode 100644 index 000000000..7ef279db5 --- /dev/null +++ b/port/objects/object_archipelago_item/mat_gArchipelagoItemDL_black @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/port/objects/object_archipelago_item/mat_gArchipelagoItemDL_blue b/port/objects/object_archipelago_item/mat_gArchipelagoItemDL_blue new file mode 100644 index 000000000..770d70e48 --- /dev/null +++ b/port/objects/object_archipelago_item/mat_gArchipelagoItemDL_blue @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/port/objects/object_archipelago_item/mat_gArchipelagoItemDL_green b/port/objects/object_archipelago_item/mat_gArchipelagoItemDL_green new file mode 100644 index 000000000..9a57f3f8c --- /dev/null +++ b/port/objects/object_archipelago_item/mat_gArchipelagoItemDL_green @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/port/objects/object_archipelago_item/mat_gArchipelagoItemDL_orange b/port/objects/object_archipelago_item/mat_gArchipelagoItemDL_orange new file mode 100644 index 000000000..c3da3eff1 --- /dev/null +++ b/port/objects/object_archipelago_item/mat_gArchipelagoItemDL_orange @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/port/objects/object_archipelago_item/mat_gArchipelagoItemDL_outline b/port/objects/object_archipelago_item/mat_gArchipelagoItemDL_outline new file mode 100644 index 000000000..d39d1af92 --- /dev/null +++ b/port/objects/object_archipelago_item/mat_gArchipelagoItemDL_outline @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/port/objects/object_archipelago_item/mat_gArchipelagoItemDL_pink b/port/objects/object_archipelago_item/mat_gArchipelagoItemDL_pink new file mode 100644 index 000000000..e3b896b02 --- /dev/null +++ b/port/objects/object_archipelago_item/mat_gArchipelagoItemDL_pink @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/port/objects/object_archipelago_item/mat_gArchipelagoItemDL_purple b/port/objects/object_archipelago_item/mat_gArchipelagoItemDL_purple new file mode 100644 index 000000000..64f362026 --- /dev/null +++ b/port/objects/object_archipelago_item/mat_gArchipelagoItemDL_purple @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/port/objects/object_archipelago_item/mat_gArchipelagoItemDL_red b/port/objects/object_archipelago_item/mat_gArchipelagoItemDL_red new file mode 100644 index 000000000..8cc9fec5e --- /dev/null +++ b/port/objects/object_archipelago_item/mat_gArchipelagoItemDL_red @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/port/objects/object_archipelago_item/mat_gArchipelagoItemDL_yellow b/port/objects/object_archipelago_item/mat_gArchipelagoItemDL_yellow new file mode 100644 index 000000000..1b0d4be92 --- /dev/null +++ b/port/objects/object_archipelago_item/mat_gArchipelagoItemDL_yellow @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/port/objects/object_archipelago_item/mat_gArchipelagoJunkDL_black_junk b/port/objects/object_archipelago_item/mat_gArchipelagoJunkDL_black_junk new file mode 100644 index 000000000..7ef279db5 --- /dev/null +++ b/port/objects/object_archipelago_item/mat_gArchipelagoJunkDL_black_junk @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/port/objects/object_archipelago_item/mat_gArchipelagoJunkDL_blue_junk b/port/objects/object_archipelago_item/mat_gArchipelagoJunkDL_blue_junk new file mode 100644 index 000000000..b8f17f3bf --- /dev/null +++ b/port/objects/object_archipelago_item/mat_gArchipelagoJunkDL_blue_junk @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/port/objects/object_archipelago_item/mat_gArchipelagoJunkDL_green_junk b/port/objects/object_archipelago_item/mat_gArchipelagoJunkDL_green_junk new file mode 100644 index 000000000..05312bc76 --- /dev/null +++ b/port/objects/object_archipelago_item/mat_gArchipelagoJunkDL_green_junk @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/port/objects/object_archipelago_item/mat_gArchipelagoJunkDL_grey_blue b/port/objects/object_archipelago_item/mat_gArchipelagoJunkDL_grey_blue new file mode 100644 index 000000000..a55a1459a --- /dev/null +++ b/port/objects/object_archipelago_item/mat_gArchipelagoJunkDL_grey_blue @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/port/objects/object_archipelago_item/mat_gArchipelagoJunkDL_grey_green b/port/objects/object_archipelago_item/mat_gArchipelagoJunkDL_grey_green new file mode 100644 index 000000000..20d667aa3 --- /dev/null +++ b/port/objects/object_archipelago_item/mat_gArchipelagoJunkDL_grey_green @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/port/objects/object_archipelago_item/mat_gArchipelagoJunkDL_grey_orange b/port/objects/object_archipelago_item/mat_gArchipelagoJunkDL_grey_orange new file mode 100644 index 000000000..ad2a5ac38 --- /dev/null +++ b/port/objects/object_archipelago_item/mat_gArchipelagoJunkDL_grey_orange @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/port/objects/object_archipelago_item/mat_gArchipelagoJunkDL_grey_outline b/port/objects/object_archipelago_item/mat_gArchipelagoJunkDL_grey_outline new file mode 100644 index 000000000..d39d1af92 --- /dev/null +++ b/port/objects/object_archipelago_item/mat_gArchipelagoJunkDL_grey_outline @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/port/objects/object_archipelago_item/mat_gArchipelagoJunkDL_grey_pink b/port/objects/object_archipelago_item/mat_gArchipelagoJunkDL_grey_pink new file mode 100644 index 000000000..a3d546483 --- /dev/null +++ b/port/objects/object_archipelago_item/mat_gArchipelagoJunkDL_grey_pink @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/port/objects/object_archipelago_item/mat_gArchipelagoJunkDL_grey_red b/port/objects/object_archipelago_item/mat_gArchipelagoJunkDL_grey_red new file mode 100644 index 000000000..78236fa28 --- /dev/null +++ b/port/objects/object_archipelago_item/mat_gArchipelagoJunkDL_grey_red @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/port/objects/object_archipelago_item/mat_gArchipelagoJunkDL_grey_yellow b/port/objects/object_archipelago_item/mat_gArchipelagoJunkDL_grey_yellow new file mode 100644 index 000000000..8def121b7 --- /dev/null +++ b/port/objects/object_archipelago_item/mat_gArchipelagoJunkDL_grey_yellow @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/port/objects/object_archipelago_item/mat_gArchipelagoJunkDL_orange_junk b/port/objects/object_archipelago_item/mat_gArchipelagoJunkDL_orange_junk new file mode 100644 index 000000000..17867ed9c --- /dev/null +++ b/port/objects/object_archipelago_item/mat_gArchipelagoJunkDL_orange_junk @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/port/objects/object_archipelago_item/mat_gArchipelagoJunkDL_purple_junk b/port/objects/object_archipelago_item/mat_gArchipelagoJunkDL_purple_junk new file mode 100644 index 000000000..7a880f3e9 --- /dev/null +++ b/port/objects/object_archipelago_item/mat_gArchipelagoJunkDL_purple_junk @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/port/objects/object_archipelago_item/mat_gArchipelagoJunkDL_red_junk b/port/objects/object_archipelago_item/mat_gArchipelagoJunkDL_red_junk new file mode 100644 index 000000000..20b763643 --- /dev/null +++ b/port/objects/object_archipelago_item/mat_gArchipelagoJunkDL_red_junk @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/port/objects/object_archipelago_item/mat_gArchipelagoJunkDL_yellow_junk b/port/objects/object_archipelago_item/mat_gArchipelagoJunkDL_yellow_junk new file mode 100644 index 000000000..7e88e53d7 --- /dev/null +++ b/port/objects/object_archipelago_item/mat_gArchipelagoJunkDL_yellow_junk @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/port/objects/object_archipelago_item/mat_gArchipelagoProgressiveDL_arrow_gold_progressive b/port/objects/object_archipelago_item/mat_gArchipelagoProgressiveDL_arrow_gold_progressive new file mode 100644 index 000000000..fa76abb08 --- /dev/null +++ b/port/objects/object_archipelago_item/mat_gArchipelagoProgressiveDL_arrow_gold_progressive @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/port/objects/object_archipelago_item/mat_gArchipelagoProgressiveDL_black_progressive b/port/objects/object_archipelago_item/mat_gArchipelagoProgressiveDL_black_progressive new file mode 100644 index 000000000..7ef279db5 --- /dev/null +++ b/port/objects/object_archipelago_item/mat_gArchipelagoProgressiveDL_black_progressive @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/port/objects/object_archipelago_item/mat_gArchipelagoProgressiveDL_blue_progressive b/port/objects/object_archipelago_item/mat_gArchipelagoProgressiveDL_blue_progressive new file mode 100644 index 000000000..770d70e48 --- /dev/null +++ b/port/objects/object_archipelago_item/mat_gArchipelagoProgressiveDL_blue_progressive @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/port/objects/object_archipelago_item/mat_gArchipelagoProgressiveDL_green_progressive b/port/objects/object_archipelago_item/mat_gArchipelagoProgressiveDL_green_progressive new file mode 100644 index 000000000..9a57f3f8c --- /dev/null +++ b/port/objects/object_archipelago_item/mat_gArchipelagoProgressiveDL_green_progressive @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/port/objects/object_archipelago_item/mat_gArchipelagoProgressiveDL_orange_progressive b/port/objects/object_archipelago_item/mat_gArchipelagoProgressiveDL_orange_progressive new file mode 100644 index 000000000..c3da3eff1 --- /dev/null +++ b/port/objects/object_archipelago_item/mat_gArchipelagoProgressiveDL_orange_progressive @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/port/objects/object_archipelago_item/mat_gArchipelagoProgressiveDL_progressive_arrow b/port/objects/object_archipelago_item/mat_gArchipelagoProgressiveDL_progressive_arrow new file mode 100644 index 000000000..c41b05db9 --- /dev/null +++ b/port/objects/object_archipelago_item/mat_gArchipelagoProgressiveDL_progressive_arrow @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/port/objects/object_archipelago_item/mat_gArchipelagoProgressiveDL_progressive_blue b/port/objects/object_archipelago_item/mat_gArchipelagoProgressiveDL_progressive_blue new file mode 100644 index 000000000..c9073d0cf --- /dev/null +++ b/port/objects/object_archipelago_item/mat_gArchipelagoProgressiveDL_progressive_blue @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/port/objects/object_archipelago_item/mat_gArchipelagoProgressiveDL_progressive_green b/port/objects/object_archipelago_item/mat_gArchipelagoProgressiveDL_progressive_green new file mode 100644 index 000000000..84e26fe7a --- /dev/null +++ b/port/objects/object_archipelago_item/mat_gArchipelagoProgressiveDL_progressive_green @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/port/objects/object_archipelago_item/mat_gArchipelagoProgressiveDL_progressive_orange b/port/objects/object_archipelago_item/mat_gArchipelagoProgressiveDL_progressive_orange new file mode 100644 index 000000000..076acfe28 --- /dev/null +++ b/port/objects/object_archipelago_item/mat_gArchipelagoProgressiveDL_progressive_orange @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/port/objects/object_archipelago_item/mat_gArchipelagoProgressiveDL_progressive_outline b/port/objects/object_archipelago_item/mat_gArchipelagoProgressiveDL_progressive_outline new file mode 100644 index 000000000..d39d1af92 --- /dev/null +++ b/port/objects/object_archipelago_item/mat_gArchipelagoProgressiveDL_progressive_outline @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/port/objects/object_archipelago_item/mat_gArchipelagoProgressiveDL_progressive_pink b/port/objects/object_archipelago_item/mat_gArchipelagoProgressiveDL_progressive_pink new file mode 100644 index 000000000..e3b896b02 --- /dev/null +++ b/port/objects/object_archipelago_item/mat_gArchipelagoProgressiveDL_progressive_pink @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/port/objects/object_archipelago_item/mat_gArchipelagoProgressiveDL_progressive_red b/port/objects/object_archipelago_item/mat_gArchipelagoProgressiveDL_progressive_red new file mode 100644 index 000000000..930fb41e6 --- /dev/null +++ b/port/objects/object_archipelago_item/mat_gArchipelagoProgressiveDL_progressive_red @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/port/objects/object_archipelago_item/mat_gArchipelagoProgressiveDL_progressive_yellow b/port/objects/object_archipelago_item/mat_gArchipelagoProgressiveDL_progressive_yellow new file mode 100644 index 000000000..383d9441c --- /dev/null +++ b/port/objects/object_archipelago_item/mat_gArchipelagoProgressiveDL_progressive_yellow @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/port/objects/object_archipelago_item/mat_gArchipelagoProgressiveDL_purple_progressive b/port/objects/object_archipelago_item/mat_gArchipelagoProgressiveDL_purple_progressive new file mode 100644 index 000000000..64f362026 --- /dev/null +++ b/port/objects/object_archipelago_item/mat_gArchipelagoProgressiveDL_purple_progressive @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/port/objects/object_archipelago_item/mat_gArchipelagoProgressiveDL_red_progressive b/port/objects/object_archipelago_item/mat_gArchipelagoProgressiveDL_red_progressive new file mode 100644 index 000000000..8cc9fec5e --- /dev/null +++ b/port/objects/object_archipelago_item/mat_gArchipelagoProgressiveDL_red_progressive @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/port/objects/object_archipelago_item/mat_gArchipelagoProgressiveDL_yellow_progressive b/port/objects/object_archipelago_item/mat_gArchipelagoProgressiveDL_yellow_progressive new file mode 100644 index 000000000..1b0d4be92 --- /dev/null +++ b/port/objects/object_archipelago_item/mat_gArchipelagoProgressiveDL_yellow_progressive @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/port/objects/object_archipelago_item/model.xml b/port/objects/object_archipelago_item/model.xml new file mode 100644 index 000000000..e69de29bb diff --git a/src/port/Rando/CustomCollectible/CustomCollectible.cpp b/src/port/Rando/CustomCollectible/CustomCollectible.cpp index f6a49dabb..202baba6e 100644 --- a/src/port/Rando/CustomCollectible/CustomCollectible.cpp +++ b/src/port/Rando/CustomCollectible/CustomCollectible.cpp @@ -1,15 +1,35 @@ #include "CustomCollectible.h" +#include "CustomCollectibleDrawCustom.h" #include "actor.h" #include +#include "port/Rando/Rando.h" +#include extern "C" { +#include "core1/sns.h" Actor* actor_new(s32 position[3], s32 yaw, ActorInfo* actorInfo, u32 flags); Actor* actor_draw(ActorMarker* marker, Gfx** gfx, Mtx** mtx, Vtx** vtx); Actor* fxTouchSparkle_draw(ActorMarker* marker, Gfx** gfx, Mtx** mtx, Vtx** vtx); Actor* marker_getActor(ActorMarker* thisx); void marker_despawn(ActorMarker* marker); +Actor* func_802D41C4(ActorMarker* marker, Gfx** gfx, Mtx** mtx, Vtx** vtx); } +std::unordered_map customCollectibleDrawInfo = { + { ACTOR_47_EMPTY_HONEYCOMB, { ASSET_361_MODEL_EMPTY_HONEYCOMB, CCT_VANILLA_MODEL } }, + { ACTOR_46_JIGGY, { ASSET_35F_MODEL_JIGGY, CCT_VANILLA_MODEL } }, + { ACTOR_60_JINJO_BLUE, { ASSET_3C0_MODEL_JINJO_BLUE, CCT_VANILLA_MODEL } }, + { ACTOR_62_JINJO_GREEN, { ASSET_3C2_MODEL_JINJO_GREEN, CCT_VANILLA_MODEL } }, + { ACTOR_5F_JINJO_ORANGE, { ASSET_3BC_MODEL_JINJO_ORANGE, CCT_VANILLA_MODEL } }, + { ACTOR_61_JINJO_PINK, { ASSET_3C1_MODEL_JINJO_PINK, CCT_VANILLA_MODEL } }, + { ACTOR_5E_JINJO_YELLOW, { ASSET_3BB_MODEL_JINJO_YELLOW, CCT_VANILLA_MODEL } }, + { ACTOR_12C_MOLEHILL, { ASSET_388_MODEL_MOLEHILL, CCT_VANILLA_MODEL } }, + { ACTOR_2D_MUMBO_TOKEN, { ASSET_41A_SPRITE_MUMBO_TOKEN, CCT_VANILLA_SPRITE } }, + { ACTOR_51_MUSIC_NOTE, { ASSET_6D6_SPRITE_MUSIC_NOTE, CCT_VANILLA_SPRITE } }, + { ACTOR_25E_SNS_EGG, { ASSET_50D_MODEL_SNS_EGG, CCT_VANILLA_SNS_EGG } }, + { ACTOR_25D_ICE_KEY, { ASSET_0_NONE, CCT_CUSTOM_MODEL } }, +}; + ActorInfo customActorInfo = { MARKER_300_CUSTOM_COLLECTIBLE, ACTOR_3CD_CUSTOM_COLLECTIBLE, ASSET_0_NONE, @@ -23,7 +43,7 @@ ActorInfo customActorInfo = { MARKER_300_CUSTOM_COLLECTIBLE, 0.9f, 0 }; -void CustomCollectible_Update(Actor* actor) { +void Update(Actor* actor) { ActorLocal_CustomCollectible* customLocal = (ActorLocal_CustomCollectible*)&actor->local; if (!actor->initialized) { @@ -32,18 +52,18 @@ void CustomCollectible_Update(Actor* actor) { if (customLocal->randoItemId >= RI_MUSIC_NOTE_BUBBLEGLOOP_SWAMP && customLocal->randoItemId <= RI_MUSIC_NOTE_TREASURE_TROVE_COVE) { - actor->scale = 0.42857143f; + actor->scale = 0.4f; + } else if (customLocal->randoItemId >= RI_STOP_N_SWOP_EGG_BLUE && + customLocal->randoItemId <= RI_STOP_N_SWOP_EGG_YELLOW) { + actor->scale = 0.4f; } } actor->yaw += 5.0f; } -Actor* CustomCollectible_DrawCustom(ActorMarker* marker, Gfx** gdl, Mtx** mptr, Vtx** vtx) { - Actor* actor = marker_getActor(marker); - actor = actor_draw(actor->marker, gdl, mptr, vtx); - - return actor; +void CustomCollectible_Update(Actor* actor) { + Update(actor); } Actor* CustomCollectible::AttachCustomVariables(int32_t randoItemId, Actor* customCollectible) { @@ -58,118 +78,67 @@ Actor* CustomCollectible::Spawn(int32_t position[3], RandoItemId randoItemId) { int32_t flags = ACTOR_FLAG_UNKNOWN_6 | ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_21; + // Custom models exported for OoT are centered instead of offset to the marker, so they appear underground otherwise + actor_e actorId = (actor_e)Rando::StaticData::Items.find(randoItemId)->second.actorId; + auto drawInfo = customCollectibleDrawInfo.find(actorId); + if (drawInfo->second.drawType == CCT_CUSTOM_MODEL) { + position[1] += 50; + } + ActorInfo collectibleInfo = CustomCollectible::GetActorAndDrawInfo(randoItemId); Actor* customCollectible = actor_new(position, 0, &collectibleInfo, flags); + if (Rando::StaticData::Items.find(randoItemId)->second.randoItemType == RITYPE_SNS_EGG) { + customCollectible->actorTypeSpecificField = CustomCollectible::GetSNSEggColor(randoItemId); + } customCollectible->marker->collisionFunc = CustomCollectible::OnCollect; customCollectible = CustomCollectible::AttachCustomVariables(randoItemId, customCollectible); return customCollectible; } -ActorInfo CustomCollectible::GetActorAndDrawInfo(RandoItemId randoItemId) { - ActorInfo collectibleInfo = customActorInfo; - - // Empty Honeycomb - if (randoItemId >= RI_EMPTY_HONEYCOMB_BUBBLEGLOOP_SWAMP && randoItemId <= RI_EMPTY_HONEYCOMB_TREASURE_TROVE_COVE) { - collectibleInfo.modelId = ASSET_363_MODEL_HONEYCOMB; - collectibleInfo.draw_func = actor_draw; - } - - // Jiggy - else if (randoItemId >= RI_JIGGY_BUBBLEGLOOP_SWAMP && randoItemId <= RI_JIGGY_TREASURE_TROVE_COVE) { - collectibleInfo.modelId = ASSET_35F_MODEL_JIGGY; - collectibleInfo.draw_func = actor_draw; - } - - // Jinjo (Blue) - else if (randoItemId >= RI_JINJO_BLUE_BUBBLEGLOOP_SWAMP && randoItemId <= RI_JINJO_BLUE_TREASURE_TROVE_COVE) { - collectibleInfo.modelId = ASSET_3C0_MODEL_JINJO_BLUE; - collectibleInfo.draw_func = actor_draw; - } - - // Jinjo (Green) - else if (randoItemId >= RI_JINJO_GREEN_BUBBLEGLOOP_SWAMP && randoItemId <= RI_JINJO_GREEN_TREASURE_TROVE_COVE) { - collectibleInfo.modelId = ASSET_3C2_MODEL_JINJO_GREEN; - collectibleInfo.draw_func = actor_draw; - } - - // Jinjo (Orange) - else if (randoItemId >= RI_JINJO_ORANGE_BUBBLEGLOOP_SWAMP && randoItemId <= RI_JINJO_ORANGE_TREASURE_TROVE_COVE) { - collectibleInfo.modelId = ASSET_3BC_MODEL_JINJO_ORANGE; - collectibleInfo.draw_func = actor_draw; - } - - // Jinjo (Pink) - else if (randoItemId >= RI_JINJO_PINK_BUBBLEGLOOP_SWAMP && randoItemId <= RI_JINJO_PINK_TREASURE_TROVE_COVE) { - collectibleInfo.modelId = ASSET_3C1_MODEL_JINJO_PINK; - collectibleInfo.draw_func = actor_draw; - } - - // Jinjo (Yellow) - else if (randoItemId >= RI_JINJO_YELLOW_BUBBLEGLOOP_SWAMP && randoItemId <= RI_JINJO_YELLOW_TREASURE_TROVE_COVE) { - collectibleInfo.modelId = ASSET_3BB_MODEL_JINJO_YELLOW; - collectibleInfo.draw_func = actor_draw; - } - - // Molehill - else if (randoItemId >= RI_MOLEHILL_BARGE && randoItemId <= RI_MOLEHILL_WONDERWING) { - collectibleInfo.modelId = ASSET_388_MODEL_MOLEHILL; - collectibleInfo.draw_func = actor_draw; - } - - // Mumbo Token - else if (randoItemId >= RI_MUMBO_TOKEN_BUBBLEGLOOP_SWAMP && randoItemId <= RI_MUMBO_TOKEN_TREASURE_TROVE_COVE) { - collectibleInfo.modelId = ASSET_41A_SPRITE_MUMBO_TOKEN; - collectibleInfo.draw_func = fxTouchSparkle_draw; - } - - // Music Note - else if (randoItemId >= RI_MUSIC_NOTE_BUBBLEGLOOP_SWAMP && randoItemId <= RI_MUSIC_NOTE_TREASURE_TROVE_COVE) { - collectibleInfo.modelId = ASSET_6D6_SPRITE_MUSIC_NOTE; - collectibleInfo.draw_func = fxTouchSparkle_draw; - } - - // StopNSwop Egg (Blue) - else if (randoItemId == RI_STOP_N_SWOP_EGG_BLUE) { - collectibleInfo.modelId = ASSET_36D_SPRITE_BLUE_EGG; - collectibleInfo.draw_func = fxTouchSparkle_draw; - } - - // StopNSwop Egg (Cyan) - else if (randoItemId == RI_STOP_N_SWOP_EGG_CYAN) { - collectibleInfo.modelId = ASSET_36D_SPRITE_BLUE_EGG; - collectibleInfo.draw_func = fxTouchSparkle_draw; - } - - // StopNSwop Egg (Green) - else if (randoItemId == RI_STOP_N_SWOP_EGG_GREEN) { - collectibleInfo.modelId = ASSET_36D_SPRITE_BLUE_EGG; - collectibleInfo.draw_func = fxTouchSparkle_draw; - } - - // StopNSwop Egg (Pink) - else if (randoItemId == RI_STOP_N_SWOP_EGG_PINK) { - collectibleInfo.modelId = ASSET_36D_SPRITE_BLUE_EGG; - collectibleInfo.draw_func = fxTouchSparkle_draw; - } - - // StopNSwop Egg (Red) - else if (randoItemId == RI_STOP_N_SWOP_EGG_RED) { - collectibleInfo.modelId = ASSET_36D_SPRITE_BLUE_EGG; - collectibleInfo.draw_func = fxTouchSparkle_draw; +uint32_t CustomCollectible::GetSNSEggColor(RandoItemId randoItemId) { + switch (randoItemId) { + case RI_STOP_N_SWOP_EGG_BLUE: + return (uint32_t)SNS_ITEM_EGG_BLUE; + case RI_STOP_N_SWOP_EGG_CYAN: + return (uint32_t)SNS_ITEM_EGG_CYAN; + case RI_STOP_N_SWOP_EGG_GREEN: + return (uint32_t)SNS_ITEM_EGG_GREEN; + case RI_STOP_N_SWOP_EGG_PINK: + return (uint32_t)SNS_ITEM_EGG_PINK; + case RI_STOP_N_SWOP_EGG_RED: + return (uint32_t)SNS_ITEM_EGG_RED; + case RI_STOP_N_SWOP_EGG_YELLOW: + return (uint32_t)SNS_ITEM_EGG_YELLOW; + default: + return (uint32_t)SNS_ITEM_EGG_CYAN; } +} - // StopNSwop Egg (Yellow) - else if (randoItemId == RI_STOP_N_SWOP_EGG_YELLOW) { - collectibleInfo.modelId = ASSET_36D_SPRITE_BLUE_EGG; - collectibleInfo.draw_func = fxTouchSparkle_draw; - } +ActorInfo CustomCollectible::GetActorAndDrawInfo(RandoItemId randoItemId) { + ActorInfo collectibleInfo = customActorInfo; - // StopNSwop Ice Key - else if (randoItemId == RI_STOP_N_SWOP_ICE_KEY) { - collectibleInfo.modelId = ASSET_36D_SPRITE_BLUE_EGG; - collectibleInfo.draw_func = fxTouchSparkle_draw; + actor_e actorId = (actor_e)Rando::StaticData::Items.find(randoItemId)->second.actorId; + auto drawInfo = customCollectibleDrawInfo.find(actorId); + + collectibleInfo.modelId = drawInfo->second.drawModel; + + switch (drawInfo->second.drawType) { + case CCT_VANILLA_MODEL: + collectibleInfo.draw_func = actor_draw; + break; + case CCT_VANILLA_SPRITE: + collectibleInfo.draw_func = fxTouchSparkle_draw; + break; + case CCT_VANILLA_SNS_EGG: + collectibleInfo.draw_func = func_802D41C4; + break; + case CCT_CUSTOM_MODEL: + collectibleInfo.draw_func = CustomCollectible_DrawCustomModel; + break; + default: + break; } return collectibleInfo; diff --git a/src/port/Rando/CustomCollectible/CustomCollectible.h b/src/port/Rando/CustomCollectible/CustomCollectible.h index eea79127e..7e1ed00c4 100644 --- a/src/port/Rando/CustomCollectible/CustomCollectible.h +++ b/src/port/Rando/CustomCollectible/CustomCollectible.h @@ -3,9 +3,16 @@ #include "port/Rando/Types.h" typedef struct { - uint32_t randoItemId; + uint16_t randoItemId; } ActorLocal_CustomCollectible; +enum CustomCollectibleDrawTypes { CCT_VANILLA_MODEL, CCT_VANILLA_SPRITE, CCT_VANILLA_SNS_EGG, CCT_CUSTOM_MODEL }; + +typedef struct { + asset_e drawModel; + CustomCollectibleDrawTypes drawType; +} CustomCollectibleDrawInfo; + void CustomCollectible_Update(Actor* actor); class CustomCollectible { @@ -13,6 +20,7 @@ class CustomCollectible { static Actor* AttachCustomVariables(int32_t randoItemId, Actor* customCollectible); static void OnCollect(struct actorMarker_s* self, struct actorMarker_s* other); static ActorInfo GetActorAndDrawInfo(RandoItemId randoItemId); + static uint32_t GetSNSEggColor(RandoItemId randoItemId); public: static Actor* Spawn(int32_t position[3], RandoItemId randoItemId); diff --git a/src/port/Rando/CustomCollectible/CustomCollectibleDrawCustom.cpp b/src/port/Rando/CustomCollectible/CustomCollectibleDrawCustom.cpp new file mode 100644 index 000000000..6a0aec25b --- /dev/null +++ b/src/port/Rando/CustomCollectible/CustomCollectibleDrawCustom.cpp @@ -0,0 +1,107 @@ +// Custom item model rendering. +// +// The models live in lighthouse.o2r as XML libultraship resources under +// objects/object_X_item. +// They are untextured prim-color geometry, so they draw with a single matrix +// push and no material setup beyond what the display lists carry. + +// Include order matters here. +// 1. ResourceHelpers.h (via ship/Context.h -> spdlog) parses the Windows headers, +// which must happen before any decomp header: Events.h drags in prop.h -> +// structs.h -> bool.h, whose function-like BOOL(x) macro corrupts the +// `typedef BOOL (CALLBACK* ...)` declarations in the Windows SDK. +// 2. bridge.h/Events.h bring in the events bridge/json templates, which must be +// seen with C++ linkage before functions.h re-includes them inside the +// extern "C" block below. +#include +#include "port/ResourceHelpers.h" +#include "port/enhancements/events/hooks/Events.h" +#include "port/interpolation/FrameInterpolation.h" + +#include "CustomCollectibleDrawCustom.h" +#include "CustomCollectible.h" + +extern "C" { +#include +#include "macros.h" +#include "prop.h" +#include "functions.h" +#include "variables.h" +#include "core1/viewport.h" +#include "core1/mlmtx.h" +} + +static const char* sCustomModelPaths[] = { + "objects/object_archipelago_item/gArchipelagoItemDL", + "objects/object_archipelago_item/gArchipelagoJunkDL", + "objects/object_archipelago_item/gArchipelagoProgressiveDL", +}; + +// The models are authored at OoT world scale, which is roughly 10x too large +// for BK. Baked into every draw so callers treat scale 1.0 as "natural size". +static const f32 sCustomModelBaseScale = 0.05f; + +// BK never uploads RSP lights (its models bake shading into vertex colors), but +// these materials enable G_LIGHTING, so without our own light setup the shade +// input is garbage and the model renders black. Neutral white key light from +// the upper-front-right plus a mid ambient. +static Lights1 sCustomModelLights = gdSPDefLights1(110, 110, 110, 255, 255, 255, 40, 40, 40); + +// Pin the resources so the cached Gfx pointers stay valid across frames. +static std::shared_ptr sModelResources[ARRAY_COUNT(sCustomModelPaths)]; +static Gfx* sModelDLs[ARRAY_COUNT(sCustomModelPaths)]; + +static Gfx* CustomCollectible_GetDL(CustomItemModel model) { + if (model < 0 || model >= (s32)ARRAY_COUNT(sCustomModelPaths)) { + return nullptr; + } + if (sModelDLs[model] == nullptr) { + sModelResources[model] = GetResourceByName(sCustomModelPaths[model]); + if (sModelResources[model] == nullptr) { + return nullptr; + } + sModelDLs[model] = ResourceMgr_LoadGfxByName(sCustomModelPaths[model]); + } + return sModelDLs[model]; +} + +Actor* CustomCollectible_DrawCustomModel(ActorMarker* marker, Gfx** gfx, Mtx** mtx, Vtx** vtx) { + Actor* actor = marker_getActor(marker); + ActorLocal_CustomCollectible* customLocal = (ActorLocal_CustomCollectible*)&actor->local; + CustomItemModel model; + + switch (customLocal->randoItemId) { + case RI_STOP_N_SWOP_ICE_KEY: + model = ARCHIPELAGO_MODEL_PROGRESSIVE; + break; + default: + break; + } + + Gfx* dl = CustomCollectible_GetDL(model); + if (dl == nullptr) { + return actor; + } + + f32 camera_position[3]; + viewport_getPosition_vec3f(camera_position); + + // The mlMtx calls below are recorded for frame interpolation; the scope key + // pairs this draw's matrix across ticks. Keyed by model, so two instances + // of the same model drawn in the same frame would need instance-keyed + // scopes instead. + FrameInterpolation_RecordOpenChild("custom_item", (uintptr_t)model); + f32 rotation[3] = { actor->pitch, actor->yaw, actor->roll }; + // The modelview translation is camera-relative, matching modelRender_draw. + mlMtxIdent(); + func_80252AF0(camera_position, actor->position, rotation, actor->scale * sCustomModelBaseScale, NULL); + mlMtxApply(*mtx); + gSPMatrix((*gfx)++, (*mtx)++, G_MTX_PUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + gSPSetLights1((*gfx)++, sCustomModelLights); + gSPDisplayList((*gfx)++, dl); + gSPPopMatrix((*gfx)++, G_MTX_MODELVIEW); + + FrameInterpolation_RecordCloseChild(); + + return actor; +} diff --git a/src/port/Rando/CustomCollectible/CustomCollectibleDrawCustom.h b/src/port/Rando/CustomCollectible/CustomCollectibleDrawCustom.h new file mode 100644 index 000000000..ce87b41bf --- /dev/null +++ b/src/port/Rando/CustomCollectible/CustomCollectibleDrawCustom.h @@ -0,0 +1,36 @@ +#ifndef PORT_ARCHIPELAGO_ITEM_H +#define PORT_ARCHIPELAGO_ITEM_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// Forward declarations (tag structs from prop.h) so this header stays free of +// the decomp includes — including prop.h here would drag in bool.h, whose +// function-like BOOL() macro corrupts the Windows SDK headers in C++ TUs. +struct actorMarker_s; +struct actor_s; + +typedef enum CustomItemModel { + ARCHIPELAGO_MODEL_NONE = -1, // resolver sentinel: keep the vanilla model + ARCHIPELAGO_MODEL_ITEM, + ARCHIPELAGO_MODEL_JUNK, + ARCHIPELAGO_MODEL_PROGRESSIVE, +} CustomItemModel; + +// Draws an Archipelago item model at a world position. Must be called from a +// draw context that owns the display list and matrix pools (an actor draw +// callback, a world/player draw event hook, cutscene draw code, etc.). +// rotation is pitch/yaw/roll in degrees and may be NULL; scale is a relative +// multiplier where 1.0 = natural in-world size (the OoT-scale source models are +// shrunk to BK proportions internally). +Actor* CustomCollectible_DrawCustomModel(ActorMarker* marker, Gfx** gfx, Mtx** mtx, Vtx** vtx); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/port/ResourceHelpers.h b/src/port/ResourceHelpers.h index 1fb9957a8..450e6cd14 100644 --- a/src/port/ResourceHelpers.h +++ b/src/port/ResourceHelpers.h @@ -6,6 +6,7 @@ #include //#include "ResourceManager.h" #include "ship/Context.h" +#include "ship/resource/ResourceManager.h" std::shared_ptr GetResourceByName(const char* path); From 5b85bd9bc2ab20dbec8541ac66d4db005a08bda3 Mon Sep 17 00:00:00 2001 From: aMannus Date: Thu, 9 Jul 2026 19:40:09 +0200 Subject: [PATCH 008/131] Fix broken actor info referencing and cleanup --- .../CustomCollectible/CustomCollectible.cpp | 31 +++++++++---------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/src/port/Rando/CustomCollectible/CustomCollectible.cpp b/src/port/Rando/CustomCollectible/CustomCollectible.cpp index 202baba6e..563aca093 100644 --- a/src/port/Rando/CustomCollectible/CustomCollectible.cpp +++ b/src/port/Rando/CustomCollectible/CustomCollectible.cpp @@ -43,7 +43,7 @@ ActorInfo customActorInfo = { MARKER_300_CUSTOM_COLLECTIBLE, 0.9f, 0 }; -void Update(Actor* actor) { +void CustomCollectible_Update(Actor* actor) { ActorLocal_CustomCollectible* customLocal = (ActorLocal_CustomCollectible*)&actor->local; if (!actor->initialized) { @@ -62,10 +62,6 @@ void Update(Actor* actor) { actor->yaw += 5.0f; } -void CustomCollectible_Update(Actor* actor) { - Update(actor); -} - Actor* CustomCollectible::AttachCustomVariables(int32_t randoItemId, Actor* customCollectible) { ActorLocal_CustomCollectible* customLocal = (ActorLocal_CustomCollectible*)&customCollectible->local; customLocal->randoItemId = randoItemId; @@ -79,16 +75,19 @@ Actor* CustomCollectible::Spawn(int32_t position[3], RandoItemId randoItemId) { int32_t flags = ACTOR_FLAG_UNKNOWN_6 | ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_21; // Custom models exported for OoT are centered instead of offset to the marker, so they appear underground otherwise - actor_e actorId = (actor_e)Rando::StaticData::Items.find(randoItemId)->second.actorId; - auto drawInfo = customCollectibleDrawInfo.find(actorId); - if (drawInfo->second.drawType == CCT_CUSTOM_MODEL) { - position[1] += 50; + actor_e actorId = (actor_e)Rando::StaticData::Items[randoItemId].actorId; + auto drawInfo = customCollectibleDrawInfo[actorId]; + if (drawInfo.drawType == CCT_CUSTOM_MODEL) { + spawnPosition[1] += 50; } - ActorInfo collectibleInfo = CustomCollectible::GetActorAndDrawInfo(randoItemId); + // actor_new stores the ActorInfo* permanently, so it must outlive Spawn() + static std::unordered_map sActorInfoCache; + ActorInfo& collectibleInfo = sActorInfoCache[randoItemId]; + collectibleInfo = CustomCollectible::GetActorAndDrawInfo(randoItemId); - Actor* customCollectible = actor_new(position, 0, &collectibleInfo, flags); - if (Rando::StaticData::Items.find(randoItemId)->second.randoItemType == RITYPE_SNS_EGG) { + Actor* customCollectible = actor_new(spawnPosition, 0, &collectibleInfo, flags); + if (Rando::StaticData::Items[randoItemId].randoItemType == RITYPE_SNS_EGG) { customCollectible->actorTypeSpecificField = CustomCollectible::GetSNSEggColor(randoItemId); } customCollectible->marker->collisionFunc = CustomCollectible::OnCollect; @@ -119,12 +118,12 @@ uint32_t CustomCollectible::GetSNSEggColor(RandoItemId randoItemId) { ActorInfo CustomCollectible::GetActorAndDrawInfo(RandoItemId randoItemId) { ActorInfo collectibleInfo = customActorInfo; - actor_e actorId = (actor_e)Rando::StaticData::Items.find(randoItemId)->second.actorId; - auto drawInfo = customCollectibleDrawInfo.find(actorId); + actor_e actorId = (actor_e)Rando::StaticData::Items[randoItemId].actorId; + auto drawInfo = customCollectibleDrawInfo[actorId]; - collectibleInfo.modelId = drawInfo->second.drawModel; + collectibleInfo.modelId = drawInfo.drawModel; - switch (drawInfo->second.drawType) { + switch (drawInfo.drawType) { case CCT_VANILLA_MODEL: collectibleInfo.draw_func = actor_draw; break; From eb30273417487a842d3f45e990b1b0de538cf9bd Mon Sep 17 00:00:00 2001 From: Jeod <47716344+JeodC@users.noreply.github.com> Date: Thu, 9 Jul 2026 21:23:24 -0400 Subject: [PATCH 009/131] Update README.md (#248) --- README.md | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 0597f77ba..c52561e5c 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ # Lighthouse Lead Developers: -TODO: fill in +* Malkierian ## Discord @@ -19,12 +19,12 @@ Lighthouse does not include any copyrighted assets. You are required to provide ### 1. Verify your ROM dump The supported ROMs are US 1.0 and US 1.1 Rev A versions. You can verify you have dumped a supported copy of the game by using the SHA-1 File Checksum Online at https://www.romhacking.net/hash/. -- `baserom.us.v10.z64`: `1fe1632098865f639e22c11b9a81ee8f29c75d7a` -- `baserom.us.v11.z64`: `ded6ee166e740ad1bc810fd678a84b48e245ab80` -- `baserom.jp.z64`: `90726d7e7cd5bf6cdfd38f45c9acbf4d45bd9fd8` -- `baserom.pal.z64`: `bb359a75941df74bf7290212c89fbc6e2c5601fe` +* `baserom.us.v10.z64`: `1fe1632098865f639e22c11b9a81ee8f29c75d7a` +* `baserom.us.v11.z64`: `ded6ee166e740ad1bc810fd678a84b48e245ab80` +* `baserom.jp.z64`: `90726d7e7cd5bf6cdfd38f45c9acbf4d45bd9fd8` +* `baserom.pal.z64`: `bb359a75941df74bf7290212c89fbc6e2c5601fe` -TODO: add info about languages +If you have multiple regions of the game and want to use them as language packs, see `# Language Packs` below. ### 2. Verify your ROM is in .z64 format Your ROM needs to be in .z64 format. If it's in .n64 format, use the following to convert it to a .z64: https://hack64.net/tools/swapper.php @@ -34,7 +34,7 @@ Your ROM needs to be in .z64 format. If it's in .n64 format, use the following t ### 3. Generating the OTR from the ROM and Play! #### Windows * Extract every file from the zip into a folder of your choosing. -* Run lighthouse.exe and select your US 1.0 or US 1.1 ROM. +* Run lighthouse.exe and select your compatible ROM. #### Linux * Extract every file from the zip into a folder of your choosing. @@ -42,10 +42,10 @@ Your ROM needs to be in .z64 format. If it's in .n64 format, use the following t #### MacOS * Extract every file from the zip into a folder of your choosing. -* Run lighthouse and select your US 1.0 or US 1.1 ROM. +* Run lighthouse and select your compatible ROM. #### Nintendo Switch -* Run one of the PC releases to generate an `sf64.o2r` file. After launching the game on PC, you will be able to find these files in the same directory as `lighthouse.exe` or `lighthouse.appimage`. +* Run one of the PC releases to generate an `lighthouse.o2r` file. After launching the game on PC, you will be able to find these files in the same directory as `lighthouse.exe` or `lighthouse.appimage`. * Copy the files to your sd card # Configuration @@ -58,7 +58,7 @@ Your ROM needs to be in .z64 format. If it's in .n64 format, use the following t ### Other shortcuts | Keys | Action | | - | - | -| F1 | Toggle menubar | +| ESC | Toggle menubar | | F4 | Reset | | F11 | Fullscreen | | Tab | Toggle Alternate assets | @@ -69,6 +69,12 @@ TODO: verify this info Currently, there are three rendering APIs supported: DirectX11 (Windows), OpenGL (all platforms), and Metal (macOS). You can change which API to use in the `Settings` menu of the menubar, which requires a restart. If you're having an issue with crashing, you can change the API in the `lighthouse.cfg.json` file by finding the line `"Backend":{`... and changing the `id` value to `3` and set the `Name` to `OpenGL`. `DirectX 11` with id `2` is the default on Windows. `Metal` with id `4` is the default on macOS. +# Language Packs + +Lighthouse supports using multiple regions of Banjo-Kazooie as language packs. Generate your base `bk.o2r` file and once Lighthouse has started, open the imgui menu. Under General -> Languages, you will be able to select another ROM to extract as a language pack. PAL supports UK, French, and German, and Japanese adds Japanese support. After the language pack is generated, the language it brings will be added to the dropdown menu. + +When using romhacks, only US v1.0 is supported, inherited from Banjo's Backpack. Therefore, it is recommended to use **US v1.0** as your base `bk.o2r` file. + # Custom Assets Custom assets are packed in `.o2r` or `.otr` files. To use custom assets, place them in the `mods` folder. @@ -102,4 +108,5 @@ TODO: replace these with lighthouse builds # Special Thanks: +* GiantJigglypuff3 for their extensive and continued Banjo Decomp documentation TODO: fill in From 7e6ae2a3ebe643bd638e4519b1fab0f6476f6d05 Mon Sep 17 00:00:00 2001 From: Jeod <47716344+JeodC@users.noreply.github.com> Date: Wed, 15 Jul 2026 15:43:41 -0400 Subject: [PATCH 010/131] Fix HD dialog-font crash on v1.1/PAL/JP bases (#251) --- src/core2/font/print.c | 2 + src/port/Localization/Localization.cpp | 3 + src/port/Resource/Alt/AltDialogFont.cpp | 129 ++++++++++++++++++++++++ 3 files changed, 134 insertions(+) create mode 100644 src/port/Resource/Alt/AltDialogFont.cpp diff --git a/src/core2/font/print.c b/src/core2/font/print.c index f551887a9..39da4a82b 100644 --- a/src/core2/font/print.c +++ b/src/core2/font/print.c @@ -5,6 +5,7 @@ extern int ResourceMgr_GetDialogLanguageCount(void); extern int ResourceMgr_IsJapanese(void); +extern void port_dialogFontHd_rebuild(void); // [port] PAL font has 75 glyphs (0x21-0x6B), overlapping NTSC control codes b,d,e,f,h,j. // When PAL, fmtStrings use shifted codes above the glyph range. #define PRINT_PAL (ResourceMgr_GetDialogLanguageCount() > 1) @@ -478,6 +479,7 @@ void print_init(void){ D_80380AB8[4] = assetcache_get(print_getCurrentMapBoldFontTexture()); print_sFonts[0] = print_getLettersFromFont(D_80380AB8[0], D_80380AB8[4]); print_sDialogFontGlyphCount = sprite_getFramePtr(D_80380AB8[0], 0)->chunkCnt; + port_dialogFontHd_rebuild(); print_sFonts[1] = print_getLettersFromFont(D_80380AB8[1], D_80380AB8[4]); if (PRINT_JP) { // [port] JP font index 2 = the Japanese dialog font (sprite 1770, 256 I4 glyphs). diff --git a/src/port/Localization/Localization.cpp b/src/port/Localization/Localization.cpp index d5a738d64..71f42fa1b 100644 --- a/src/port/Localization/Localization.cpp +++ b/src/port/Localization/Localization.cpp @@ -46,6 +46,7 @@ void* assetcache_get(int assetId); void assetcache_release(void* ptr); void bk_free(void* ptr); void port_refreshDialogFontGlyphCount(void); +void port_dialogFontHd_rebuild(void); } // Live language change reactions @@ -96,6 +97,8 @@ void ReloadDialogFontSlot() { assetcache_release(tex); // A pack may ship an extended dialog font; refresh the reachable glyph count to match. port_refreshDialogFontGlyphCount(); + // Build cross-revision-corrected HD glyph textures for the current base (no-op without a pack). + port_dialogFontHd_rebuild(); } // Per cached-model-slot generation diff --git a/src/port/Resource/Alt/AltDialogFont.cpp b/src/port/Resource/Alt/AltDialogFont.cpp new file mode 100644 index 000000000..53bcfbf87 --- /dev/null +++ b/src/port/Resource/Alt/AltDialogFont.cpp @@ -0,0 +1,129 @@ +// Cross-revision HD dialog font. +// +// The dialog font changed between ROM revisions: US v1.0 has 62 glyphs at native 8x12; v1.1/PAL/JP +// extended it to 75 glyphs at 8x13 (the extra 13 are the PAL accents; every glyph also grew one row). +// A LOAD_AS_RAW alt bakes its h/v scale factors against the native dims of the ROM the pack was built +// from, so a v1.0-built pack's glyph carries a scale computed for 12 rows. +// +// The pixels are fine; only the baked scale is wrong, and it is wrong purely because native dims +// differ between revisions. Calculate and re-scale port-side so hd packs don't need per-revision art. + +#include +#include +#include +#include + +#include "port/Enhancements/Events/Hooks/Events.h" +#include "port/ShipInit.hpp" + +#include +#include +#include +#include +#include + +extern "C" void port_dialogFontHd_rebuild(void); + +namespace { + +constexpr const char* kFontBase = "assets/sprite/ASSET_6EB_DIALOG_FONT_ALPHAMASK"; + +bool sBuilt = false; + +std::shared_ptr loadTex(const std::string& path, bool loadExact) { + return std::static_pointer_cast( + Ship::Context::GetRawInstance()->GetResourceManager()->LoadResourceProcess(path, loadExact)); +} + +// Build a corrected alt for one chunk and cache it under "alt/". Returns false when there +// is nothing to do: no alt shipped, the dims already reconcile, or the alt isn't an HD raw texture. +bool correctChunk(const std::string& basePath) { + auto base = loadTex(basePath, true); // live native cell + if (base == nullptr || base->Width <= 0 || base->Height <= 0) { + return false; + } + auto alt = loadTex(basePath, false); // HD art, or the base itself if the pack has no alt + if (alt == nullptr || alt->ImageData == nullptr || alt.get() == base.get()) { + return false; + } + if (alt->Type != Fast::TextureType::RGBA32bpp || (alt->Flags & TEX_FLAG_LOAD_AS_RAW) == 0) { + return false; + } + + const int nativeW = base->Width; + const int nativeH = base->Height; + + // Width is revision-stable (drift is height-only), so the integer scale comes cleanly off it. + // Bail if the alt isn't an integer multiple of the native width, or is degenerate. + if (nativeW <= 0 || alt->Width % nativeW != 0) { + return false; + } + const int k = alt->Width / nativeW; + if (k < 1) { + return false; + } + + const int dstW = nativeW * k; + const int dstH = nativeH * k; + if (dstH == (int)alt->Height) { + return false; // alt height already matches the live native cell -> no drift, nothing to fix + } + + // Top-align the HD rows into the k-scaled native cell; the zero-filled remainder stays transparent. + const int copyRows = (int)alt->Height < dstH ? (int)alt->Height : dstH; + const int rowBytes = dstW * 4; + + auto pixels = std::make_shared>((size_t)dstW * dstH * 4, 0); + for (int r = 0; r < copyRows; r++) { + std::memcpy(pixels->data() + (size_t)r * rowBytes, alt->ImageData + (size_t)r * rowBytes, (size_t)rowBytes); + } + + // Same HD pixels, but VPixelScale re-derived against the live native rows (native_rows * k == dstH). + // Cache under the alt path so the resource layer returns this in place of the raw archive alt. + const std::string altPath = std::string("alt/") + basePath; + auto initData = std::make_shared(); + initData->Path = altPath; + auto tex = std::make_shared(initData); + tex->Type = Fast::TextureType::RGBA32bpp; + tex->Width = (uint16_t)dstW; + tex->Height = (uint16_t)dstH; + tex->Flags = TEX_FLAG_LOAD_AS_RAW; + tex->HByteScale = alt->HByteScale; + tex->VPixelScale = (float)k; + tex->ImageDataSize = (uint32_t)pixels->size(); + tex->mImageBuffer = pixels; + tex->ImageData = (uint8_t*)pixels->data(); + + Ship::Context::GetRawInstance()->GetResourceManager()->CacheExternalResource(altPath, tex); + return true; +} + +} // namespace + +// Called when the dialog font is (re)loaded. Scans every font chunk once per boot and corrects each; +// idempotent, and a no-op when no alt pack is mounted (a later call may still succeed). +extern "C" void port_dialogFontHd_rebuild(void) { + if (sBuilt) { + return; + } + if (!Ship::Context::GetRawInstance()->GetResourceManager()->IsAltAssetsEnabled()) { + return; + } + sBuilt = true; + + for (int frame = 0; frame < 64; frame++) { + bool anyInFrame = false; + for (int chunk = 0; chunk < 256; chunk++) { + const std::string basePath = + std::string(kFontBase) + "_" + std::to_string(frame) + "_" + std::to_string(chunk); + if (loadTex(basePath, true) == nullptr) { + break; + } + anyInFrame = true; + correctChunk(basePath); + } + if (!anyInFrame) { + break; + } + } +} From 68fdcda19a762393c43be88fd298747a4fa1aeef Mon Sep 17 00:00:00 2001 From: Caladius Date: Thu, 16 Jul 2026 15:36:04 -0400 Subject: [PATCH 011/131] Fix SkipSM to account for Rando. (#253) --- .../Enhancements/Gameplay/SkipSMTutorial.cpp | 26 +++++++++++-------- src/port/Rando/CustomObject/CustomObject.cpp | 4 ++- src/port/Rando/Logic/GenerateSaveData.cpp | 4 +++ 3 files changed, 22 insertions(+), 12 deletions(-) diff --git a/src/port/Enhancements/Gameplay/SkipSMTutorial.cpp b/src/port/Enhancements/Gameplay/SkipSMTutorial.cpp index 749413da7..0273698dc 100644 --- a/src/port/Enhancements/Gameplay/SkipSMTutorial.cpp +++ b/src/port/Enhancements/Gameplay/SkipSMTutorial.cpp @@ -3,6 +3,7 @@ #include "port/Enhancements/Events/Hooks/Events.h" #include "port/ShipInit.hpp" #include "port/Romhack/RomhackConfig.h" +#include "port/Rando/Rando.h" extern "C" { #include "enums.h" @@ -36,20 +37,23 @@ void RegisterSkipSMTutorial_Init() { } auto* ev = reinterpret_cast(event); - for (ability_e ability : kSpiralMountainAbilities) { - ability_unlock(ability); - } + if (!IS_RANDO) { + for (ability_e ability : kSpiralMountainAbilities) { + ability_unlock(ability); + } - for (ability_used move : kSpiralMountainUsedMoves) { - ability_setHasUsed(static_cast(move)); - } + for (ability_used move : kSpiralMountainUsedMoves) { + ability_setHasUsed(static_cast(move)); + } - for (int honeycomb = HONEYCOMB_13_SM_STUMP; honeycomb <= HONEYCOMB_18_SM_QUARRIES; honeycomb++) { - honeycombscore_set((honeycomb_e)honeycomb, true); + for (int honeycomb = HONEYCOMB_13_SM_STUMP; honeycomb <= HONEYCOMB_18_SM_QUARRIES; honeycomb++) { + honeycombscore_set((honeycomb_e)honeycomb, true); + } + func_8034789C(); + item_adjustByDiffWithoutHud(ITEM_14_HEALTH, + item_getCount(ITEM_15_HEALTH_TOTAL) - item_getCount(ITEM_14_HEALTH)); } - func_8034789C(); - item_adjustByDiffWithoutHud(ITEM_14_HEALTH, - item_getCount(ITEM_15_HEALTH_TOTAL) - item_getCount(ITEM_14_HEALTH)); + fileProgressFlag_set(FILEPROG_BD_ENTER_LAIR_CUTSCENE, 1); D_80386000[LEVEL_B_SPIRAL_MOUNTAIN] = 122.0f; // Average speedrun time for SM completion (2:02) diff --git a/src/port/Rando/CustomObject/CustomObject.cpp b/src/port/Rando/CustomObject/CustomObject.cpp index ded35b1c3..c807e808c 100644 --- a/src/port/Rando/CustomObject/CustomObject.cpp +++ b/src/port/Rando/CustomObject/CustomObject.cpp @@ -340,7 +340,9 @@ void CustomObject::CheckObtainedEX(RandoCheckId randoCheckId, bool isInit) { shouldRemoveEX = true; RANDO_SAVE_CHECKS[pool.randoCheckId].obtained = true; CustomObject::RemoveSpawnedIdFromList(randoCheckId); - if (!isInit) { + if (isInit) { + CustomObject::ResolveCustomActorCollisionEX(randoCheckId); + } else { Rando::StaticData::SendCollisionNotification(pool.randoCheckId); } Rando::StaticData::ModifyRandoInfFlagState(randoCheckId); diff --git a/src/port/Rando/Logic/GenerateSaveData.cpp b/src/port/Rando/Logic/GenerateSaveData.cpp index 864ecb2ca..bce619fa1 100644 --- a/src/port/Rando/Logic/GenerateSaveData.cpp +++ b/src/port/Rando/Logic/GenerateSaveData.cpp @@ -187,6 +187,10 @@ void Rando::Logic::GrantStartingLoadout() { } CustomObject::CheckObtainedEX(smCheckId, true); + if (randoSaveCheck.randoItemId == RI_MOLEHILL) { + ability_setLearned((ability_e)randoSaveCheck.randoCollectionId, true); + ability_setHasUsed((ability_e)randoSaveCheck.randoCollectionId); + } } } } \ No newline at end of file From 75244871e2d2e1d06fe41d1b361dd33441d2e894 Mon Sep 17 00:00:00 2001 From: Malkierian Date: Tue, 21 Jul 2026 18:18:37 -0700 Subject: [PATCH 012/131] Add note door dance skip. (#255) --- src/core2/actor_motioncurve.c | 5 ++++- src/port/Enhancements/Cutscenes/CutsceneSkips.cpp | 14 ++++++++++++++ src/port/Enhancements/Events/Hooks/Events.h | 1 + src/port/UI/LighthouseMenuEnhancements.cpp | 5 +++++ 4 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/core2/actor_motioncurve.c b/src/core2/actor_motioncurve.c index a914ff3a3..128b91d04 100644 --- a/src/core2/actor_motioncurve.c +++ b/src/core2/actor_motioncurve.c @@ -427,7 +427,10 @@ void func_80296608(void){ break; case BS_INTR_35: //L80296984 baflag_set(BA_FLAG_1A_OPEN_NOTEDOOR); - next_state = func_8029B504(); + // The dance masks the fall/land this normally forces; when it's skipped + // (listener clears the flag here), leave the state unchanged so Banjo keeps moving. + if(EventSystem_Should(VB_PLAY_NOTEDOOR_DANCE, true)) + next_state = func_8029B504(); sp2C = 2; break; case BS_INTR_34: //L802969A4 diff --git a/src/port/Enhancements/Cutscenes/CutsceneSkips.cpp b/src/port/Enhancements/Cutscenes/CutsceneSkips.cpp index b22e94f9b..3d32eea8d 100644 --- a/src/port/Enhancements/Cutscenes/CutsceneSkips.cpp +++ b/src/port/Enhancements/Cutscenes/CutsceneSkips.cpp @@ -15,12 +15,15 @@ enum level_e level_get(void); int volatileFlag_get(enum volatile_flags_e index); int func_8028F070(void); void gcparade_beginFFParade(void); +void baflag_clear(enum misc_flag_e arg0); +void coMusicPlayer_playMusic(enum comusic_e track_id, s32 volume); } #define CVAR_SKIP_BOOT_LOGOS CVAR_ENHANCEMENT("Cutscenes.SkipBootLogos") #define CVAR_SKIP_INTRO CVAR_ENHANCEMENT("Cutscenes.StartSkipIntro") #define CVAR_SKIP_MISC_CUTSCENES CVAR_ENHANCEMENT("Cutscenes.SkipMiscCutscenes") #define CVAR_SKIP_CLUCKER_CUTSCENE CVAR_ENHANCEMENT("Cutscenes.SkipCluckerCutscene") +#define CVAR_SKIP_NOTEDOOR_DANCE CVAR_ENHANCEMENT("Cutscenes.SkipNoteDoorDance") #define CVAR_TRIGGER_FF_PARADE CVAR_DEVELOPER_TOOLS("TriggerFFParade") void RegisterSkipBootLogos_Init() { @@ -52,6 +55,16 @@ void RegisterSkipCluckerCutscene_Init() { }); } +void RegisterSkipNoteDoorDance_Init() { + COND_VB_SHOULD(VB_PLAY_NOTEDOOR_DANCE, EVENT_PRIORITY_NORMAL, CVarGetInteger(CVAR_SKIP_NOTEDOOR_DANCE, 0), { + // Clear the flag so the (per-frame) state check doesn't retrigger, and still play the + // opening fanfare so the door-opened cue is preserved, then skip the dance state. + baflag_clear(BA_FLAG_1A_OPEN_NOTEDOOR); + // coMusicPlayer_playMusic(COMUSIC_42_NOTEDOOR_OPENING_FANFARE, -1); + *should = false; + }); +} + void RegisterTriggerFFParade_Init() { COND_HOOK(GameFrameUpdate, EVENT_PRIORITY_NORMAL, CVarGetInteger(CVAR_TRIGGER_FF_PARADE, 0), [](IEvent* event) { if (getGameMode() != GAME_MODE_3_NORMAL || level_get() <= 0 || !func_8028F070()) { @@ -70,4 +83,5 @@ static RegisterShipInitFunc initSkipIntroFunc(RegisterSkipIntroCutscene_Init, { static RegisterShipInitFunc initSkipMiscCutscenesFunc(RegisterSkipMiscCutscenes_Init, { CVAR_SKIP_MISC_CUTSCENES }); static RegisterShipInitFunc initSkipCluckerCutsceneFunc(RegisterSkipCluckerCutscene_Init, { CVAR_SKIP_CLUCKER_CUTSCENE }); +static RegisterShipInitFunc initSkipNoteDoorDanceFunc(RegisterSkipNoteDoorDance_Init, { CVAR_SKIP_NOTEDOOR_DANCE }); static RegisterShipInitFunc initTriggerFFParadeFunc(RegisterTriggerFFParade_Init, { CVAR_TRIGGER_FF_PARADE }); diff --git a/src/port/Enhancements/Events/Hooks/Events.h b/src/port/Enhancements/Events/Hooks/Events.h index 2e6699ded..72311533b 100644 --- a/src/port/Enhancements/Events/Hooks/Events.h +++ b/src/port/Enhancements/Events/Hooks/Events.h @@ -16,6 +16,7 @@ typedef enum VBehaviorID { VB_CAMERA_FOLLOW, VB_GRUNTY_DEFEATED_FLAG_BOSS, VB_PLAY_JIGGY_DANCE, + VB_PLAY_NOTEDOOR_DANCE, VB_PLAY_BOOT_LOGOS, VB_PLAY_INTRO_CUTSCENE, VB_DISABLE_SNACKER, diff --git a/src/port/UI/LighthouseMenuEnhancements.cpp b/src/port/UI/LighthouseMenuEnhancements.cpp index a9be7a36c..f04666dc7 100644 --- a/src/port/UI/LighthouseMenuEnhancements.cpp +++ b/src/port/UI/LighthouseMenuEnhancements.cpp @@ -45,6 +45,11 @@ void LighthouseMenu::AddMenuEnhancements() { .RaceDisable(false) .Options(CheckboxOptions().Tooltip("Skips the cutscene that plays when first defeating a Clucker.")); + AddWidget(path, "Skip Note Door Dance", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("Cutscenes.SkipNoteDoorDance")) + .RaceDisable(false) + .Options(CheckboxOptions().Tooltip("Skips Banjo's dance when a note door opens, opening it immediately.")); + // Enhancements -> Graphics path = { "Enhancements", "Graphics", SECTION_COLUMN_1 }; AddSidebarEntry("Enhancements", path.sidebarName, 2); From 79fe237ca3b7bb3ca8fa691a2c7087e87540d043 Mon Sep 17 00:00:00 2001 From: Malkierian Date: Thu, 23 Jul 2026 18:58:39 -0700 Subject: [PATCH 013/131] Anchor game sync (#199) * Sync progress flags. * Sync jiggies, tokens, and honeycombs. * Fix item collection triggers (were triggering before actually collecting just from proximity). Add saved item (note totals, tokens, jiggies, honeycombs) collection/use updates. Add note and jinjo collection to realtime sync.] Add jiggy spawn syncing. Make note collection packets update totals outside levels. * Add level and map flag syncing, and re-enable volatile flags for witch switch reasons. * Apply jiggy pedestal authority. * Potentially fix retention off. * Fix include casing. * Move retention files to common folder, add Retention files for common inclusion. Add listener to jinjo retention for VB_OVERRIDE_BUNDLE_SPAWN to prevent jinjo bundle from crashing when already collected. * Exclude Sandcastle and Christmas Tree cutscenes from syncing to avoid infinite scene reload cutscene glitches. * Properly live-sync ability unlocks. * Make honeycomb packets trigger HUD animations. * Make note door clear sync play animation, sound, and sparkles. * Live sync destructibles, fix cobwebs state on state restore. * Sync already-spawned jiggies when player entering a map another player is in. * Live, persistent acorn and worm sync in CCW. * Sync RBB transients. * Live-sync Blubber's Gold, the FP presents, and Conga's orange like acorns/worms. * Clear jinjo retention if jiggy orphaned, and force 31 (all collected) for retention value if jinjo jiggy collected. * Sync CC. * Sync BGS. * PUZZLE_STEP on Clanker's teeth. * Sync GV and honeycomb switches. * FP transient syncs. * Sync MMM. * CCW sync. * Fix dynamic spawned jiggy sync. Add hut sync. * Sync orange pads, juju totem, fix chimpy jiggy spawn. * Fix multiple bundle jiggy spawns. * Initial rando hookup. * Sync Bottles Bonuses. Add checkboxes for bottles bonuses when unlocked or connected to Anchor. * Fix jiggy dual spawn, remote hut ordering. Rando improvement. * Fix spawn-in croctus look-at binding player movement. * Fix timed jiggy switch timer sync. * Purge pending jiggy spawns on close/restart. * Fix actor misplacement issue. * Fix more transient syncs and puzzle steps. * Fix honeycomb switch spawns, ancient one next-step spawns, and level-open cutscene camera resets. * Sync final Grunty fight. Fix jiggy HUD to display level counts when same-level jiggy is collected. * Fix file on disk deletion. More fix for actor misplacement. * Re-implement collision and shadows. * Implement the room window and teleport to player functionality. * Make teleport go directly to other player. * Change forced disconnect on romhack status mismatch to warning. Make "Reset All Team States" reset the romhack status of the room. * Add notifications for jiggies and level opens in vanilla and rando checks. * Live sync/update blubber's gold and bear cub presents steps, and temporarily persist gold steps. * Add carried item and throw sync. * More actor misplacement fixing. * Defer actor despawn during game frame update. * Clear vanilla retention on file delete. * Add remote collect simulation to test actor misplacement fixes. * Clear temporary persistence when no players are in a level. * Fix sub-area destructible persistence. * Prevent camera actions during level door openings. * Fix Blubber's gold and the bear cub's presents not showing in-world after being thrown. * Fix collectibles showing in world after being thrown. Fix count desync of worms/acorns. * Fix flower watering stages. * Semi-persist ignored controllers (only by list index for now). * Fix grunty fight: non-authority eggs not damaging, jinjos not despawning, remote freeze during first jinjo statue cutscene. * Make fireballs (spell 0) target local players. * Fix timed switch jiggy despawns. * Swap to HM Torch main, latest commit. * Re-enable global room. * Add team-state check syncing and despawn. Add isRando and seed to room state (cleared on Clear All Team States) and warning on seed mismatch. * Make levitate cheat a fixed upward value, cancel fall damage/animation if used during damage fall. * Fix same-map warp-to-player getting stuck on level geometry. * Some comment cleanup. * Sync Slushes and snowman buttons in FP, and prevent multiple players from playing the twinkly minigame at the same time. * Prevent remote-triggered door-open camera locks. * More comment cleanup. * Disable vanilla retention checkboxes when Anchor connected. * Bump LUS. Force wait for team state when loading save. Force reload when joining/requesting team state after loading file. Increase levitate speed to 500. More comment cleanup. * Remove extra first-load team state request. * Fix live sync of entered levels for Level Totals. * Fix Tanktup cutscene unfreeze. * Add new water level packet and fix water level snapping for offline and remote clients. * Engine room fan switch temp persistence. * Fix engine fan persistence and Grunty door live sync. * Fix final fight syncing. * More comments. * Final comment sweep. * Comment streamlining. * Restore moved enum with #if 0. --- .gitmodules | 2 +- Torch | 2 +- include/functions.h | 41 ++ libultraship | 2 +- src/BGS/ch/croctus.c | 46 +- src/BGS/ch/mudhut.c | 49 +- src/BGS/ch/pinkegg.c | 21 +- src/BGS/ch/tanktup.c | 52 +- src/BGS/ch/tanktup_legs.c | 7 + src/CC/ch/clanker.c | 14 +- src/CC/ch/clankertoothext.c | 18 + src/CC/ch/key.c | 4 + src/CC/ch/tooth.c | 3 + src/CC/minigame_rings.c | 12 + src/CC/platform_physics.c | 4 + src/CCW/actor_spawninit.c | 8 +- src/CCW/ch/acorn.c | 30 +- src/CCW/ch/caterpillar.c | 23 + src/CCW/ch/eyrie_baby.c | 21 +- src/CCW/ch/eyrie_egg.c | 19 +- src/CCW/ch/eyrie_winter.c | 2 +- src/CCW/ch/gnawtyboulder.c | 9 +- src/CCW/ch/nabnut_autumn.c | 40 +- src/CCW/flower.c | 26 +- src/CCW/seasonal_switch.c | 10 +- src/FINALE/ch/chbossjinjobase.c | 8 + src/FINALE/ch/chfinalboss.c | 32 + src/FINALE/ch/chjinjonatorbase.c | 50 +- src/FINALE/fight.h | 28 + src/FP/ch/bearcub.c | 52 ++ src/FP/ch/snowmanbutton.c | 14 + src/FP/ch/twinklybox.c | 10 +- src/FP/ch/xmastree.c | 12 + src/FP/ch/xmastreeice.c | 23 + src/GV/actor_spawninit.c | 26 +- src/GV/ch/ancientone.c | 45 +- src/GV/ch/buriedpyramid.c | 7 + src/GV/ch/carpet2.c | 6 +- src/GV/pyramid_raise.c | 5 + src/GV/water_pyramidrot.c | 20 +- src/LAIR/actor_spawninit.c | 154 ++++- src/LAIR/jigsawpicture.c | 31 +- src/MM/ch/chimpystump.c | 6 +- src/MM/ch/hut.c | 65 +- src/MM/ch/jujuhitbox.c | 19 + src/MM/ch/lmonkey.c | 9 +- src/MM/ch/orangepad.c | 10 + src/MMM/actor_spawninit.c | 20 +- src/MMM/ch/flowerpot.c | 12 + src/RBB/ch/eggtoll1.c | 42 ++ src/RBB/ch/enginefanswitch.c | 11 + src/RBB/crane_boombox.c | 7 + src/RBB/crane_jiggycage.c | 61 +- src/TTC/ch/blubber.c | 39 ++ src/TTC/ch/leaky.c | 14 +- src/TTC/ch/nipper.c | 44 +- src/TTC/ch/treasurehunt.c | 38 ++ src/core1/init.c | 4 +- src/core2/abilityprogress.c | 10 +- src/core2/actor_array.c | 81 ++- src/core2/ba/ba_anim.c | 63 +- src/core2/ba/ba_lookdir.c | 6 + src/core2/ba/ba_marker.c | 26 +- src/core2/ch/honeycomb.c | 33 ++ src/core2/ch/jiggy.c | 2 + src/core2/ch/jinjo.c | 2 + src/core2/ch/level_collectible.c | 313 ++++++++++ src/core2/ch/mumbotoken.c | 1 + src/core2/ch/snowman.c | 19 +- src/core2/fileselect.c | 1 + src/core2/flags_bitfield.c | 27 +- src/core2/fx/effect_jiggy_list.c | 18 +- src/core2/gamestate.c | 28 +- src/core2/level/specificflags.c | 16 +- src/core2/map/gsworld.c | 3 +- src/core2/map/specificflags.c | 12 +- src/core2/quiz/game.c | 140 ++++- src/core2/savedata.c | 4 +- src/core2/scorequeue/drawui_models.c | 3 + src/core2/spawn_queue.c | 2 +- src/port/DevTools/RemoteCollectSim.cpp | 100 ++++ src/port/Enhancements/Cheats/Cheats.cpp | 27 +- src/port/Enhancements/Events/Hooks/Events.h | 18 + .../Events/Hooks/List/GameEvent.h | 11 + .../Events/Hooks/List/RandoEvent.h | 2 + .../Enhancements/Events/PortEnhancements.cpp | 8 + .../JinjoRetention/JinjoRetention.cpp | 195 ------ .../JinjoRetention/JinjoRetention.h | 8 - .../NoteRetention/NoteRetention.h | 17 - .../Enhancements/Retention/JinjoRetention.cpp | 263 +++++++++ .../NoteRetention.cpp | 242 ++++---- src/port/Enhancements/Retention/Retention.cpp | 39 ++ src/port/Enhancements/Retention/Retention.h | 77 +++ src/port/Enhancements/Retention/WormSync.cpp | 178 ++++++ src/port/Network/Anchor/Anchor.cpp | 153 ++++- src/port/Network/Anchor/Anchor.h | 117 +++- src/port/Network/Anchor/AnchorRoomWindow.cpp | 13 +- src/port/Network/Anchor/Authority.cpp | 18 +- src/port/Network/Anchor/Authority.h | 5 +- src/port/Network/Anchor/DummyPlayer.cpp | 84 ++- src/port/Network/Anchor/DummyPlayer.h | 9 +- src/port/Network/Anchor/FightSync.c | 555 ++++++++++++++++++ src/port/Network/Anchor/FightSync.h | 103 ++++ src/port/Network/Anchor/HookHandlers.cpp | 351 ++++++++++- src/port/Network/Anchor/JigsawPedestal.cpp | 82 +++ src/port/Network/Anchor/JigsawPedestal.h | 23 + src/port/Network/Anchor/Menu.cpp | 75 ++- .../Network/Anchor/Packets/AllClientState.cpp | 3 +- .../Network/Anchor/Packets/BreakObject.cpp | 115 ++++ .../Network/Anchor/Packets/CarryThrow.cpp | 66 +++ .../Network/Anchor/Packets/CollectItem.cpp | 141 +++++ .../Network/Anchor/Packets/DamagePlayer.cpp | 34 +- .../Network/Anchor/Packets/DisableAnchor.cpp | 1 - src/port/Network/Anchor/Packets/EggToll.cpp | 110 ++++ .../Anchor/Packets/EntranceDiscovered.cpp | 6 +- .../Network/Anchor/Packets/FightEvent.cpp | 73 +++ .../Network/Anchor/Packets/FightState.cpp | 70 +++ .../Network/Anchor/Packets/FightUpdate.cpp | 76 +++ .../Network/Anchor/Packets/GameComplete.cpp | 7 +- src/port/Network/Anchor/Packets/GiveItem.cpp | 7 +- src/port/Network/Anchor/Packets/Handshake.cpp | 2 - src/port/Network/Anchor/Packets/HutSmash.cpp | 110 ++++ .../Network/Anchor/Packets/JiggyCrane.cpp | 37 ++ src/port/Network/Anchor/Packets/MapLoad.cpp | 1 + .../Network/Anchor/Packets/PedestalOwner.cpp | 27 + src/port/Network/Anchor/Packets/PlayerSfx.cpp | 19 +- .../Network/Anchor/Packets/PlayerUpdate.cpp | 46 ++ .../Network/Anchor/Packets/PuzzleStep.cpp | 248 ++++++++ .../Anchor/Packets/RequestTeamState.cpp | 7 +- .../Anchor/Packets/RequestTeleport.cpp | 32 +- .../Network/Anchor/Packets/ScopedFlag.cpp | 81 +++ .../Network/Anchor/Packets/ScopedState.cpp | 91 +++ .../Network/Anchor/Packets/ServerMessage.cpp | 1 - .../Network/Anchor/Packets/SetAbility.cpp | 42 ++ .../Network/Anchor/Packets/SetCheckStatus.cpp | 109 ++-- src/port/Network/Anchor/Packets/SetFlag.cpp | 86 +-- .../Network/Anchor/Packets/SetItemCount.cpp | 47 ++ .../Network/Anchor/Packets/SpawnJiggy.cpp | 173 ++++++ .../Network/Anchor/Packets/TeleportTo.cpp | 58 +- src/port/Network/Anchor/Packets/UnsetFlag.cpp | 84 +-- .../Anchor/Packets/UpdateClientState.cpp | 8 +- .../Anchor/Packets/UpdateRoomState.cpp | 107 +++- .../Anchor/Packets/UpdateTeamState.cpp | 492 ++++++++-------- .../Network/Anchor/Packets/VileEatRequest.cpp | 7 - .../Network/Anchor/Packets/VileEatResult.cpp | 10 +- .../Network/Anchor/Packets/VileGameState.cpp | 7 +- src/port/Network/Anchor/Packets/WaterRise.cpp | 117 ++++ src/port/Patches/Patches.h | 69 +++ src/port/Rando/CustomObject/CustomObject.cpp | 4 + .../Rando/ObjectBehavior/ObjectBehavior.cpp | 79 +-- src/port/Rando/Rando.h | 6 + src/port/Rando/StaticData/StaticData.h | 1 + src/port/Romhack/RomhackCompat.cpp | 8 +- src/port/Romhack/RomhackQuirks.cpp | 2 +- src/port/Save/SaveManager.cpp | 16 + src/port/UI/LighthouseGui.cpp | 6 + src/port/UI/LighthouseInputEditorWindow.cpp | 16 + src/port/UI/LighthouseMenu.cpp | 7 + src/port/UI/LighthouseMenuDevTools.cpp | 7 + src/port/UI/LighthouseMenuEnhancements.cpp | 84 +++ src/port/UI/MenuTypes.h | 1 + 161 files changed, 6703 insertions(+), 1333 deletions(-) create mode 100644 src/port/DevTools/RemoteCollectSim.cpp delete mode 100644 src/port/Enhancements/JinjoRetention/JinjoRetention.cpp delete mode 100644 src/port/Enhancements/JinjoRetention/JinjoRetention.h delete mode 100644 src/port/Enhancements/NoteRetention/NoteRetention.h create mode 100644 src/port/Enhancements/Retention/JinjoRetention.cpp rename src/port/Enhancements/{NoteRetention => Retention}/NoteRetention.cpp (58%) create mode 100644 src/port/Enhancements/Retention/Retention.cpp create mode 100644 src/port/Enhancements/Retention/Retention.h create mode 100644 src/port/Enhancements/Retention/WormSync.cpp create mode 100644 src/port/Network/Anchor/FightSync.c create mode 100644 src/port/Network/Anchor/FightSync.h create mode 100644 src/port/Network/Anchor/JigsawPedestal.cpp create mode 100644 src/port/Network/Anchor/JigsawPedestal.h create mode 100644 src/port/Network/Anchor/Packets/BreakObject.cpp create mode 100644 src/port/Network/Anchor/Packets/CarryThrow.cpp create mode 100644 src/port/Network/Anchor/Packets/CollectItem.cpp create mode 100644 src/port/Network/Anchor/Packets/EggToll.cpp create mode 100644 src/port/Network/Anchor/Packets/FightEvent.cpp create mode 100644 src/port/Network/Anchor/Packets/FightState.cpp create mode 100644 src/port/Network/Anchor/Packets/FightUpdate.cpp create mode 100644 src/port/Network/Anchor/Packets/HutSmash.cpp create mode 100644 src/port/Network/Anchor/Packets/JiggyCrane.cpp create mode 100644 src/port/Network/Anchor/Packets/PedestalOwner.cpp create mode 100644 src/port/Network/Anchor/Packets/PuzzleStep.cpp create mode 100644 src/port/Network/Anchor/Packets/ScopedFlag.cpp create mode 100644 src/port/Network/Anchor/Packets/ScopedState.cpp create mode 100644 src/port/Network/Anchor/Packets/SetAbility.cpp create mode 100644 src/port/Network/Anchor/Packets/SetItemCount.cpp create mode 100644 src/port/Network/Anchor/Packets/SpawnJiggy.cpp create mode 100644 src/port/Network/Anchor/Packets/WaterRise.cpp diff --git a/.gitmodules b/.gitmodules index 8f556ee49..5481e188f 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,4 +4,4 @@ branch = main [submodule "Torch"] path = Torch - url = https://github.com/Malkierian/Torch.git + url = https://github.com/HarbourMasters/Torch.git diff --git a/Torch b/Torch index 75956acb7..024b7877b 160000 --- a/Torch +++ b/Torch @@ -1 +1 @@ -Subproject commit 75956acb7c2210427d3ac4cc7213421f6e1c490c +Subproject commit 024b7877b4f26e08f48ef1e59d8d7f98d657c842 diff --git a/include/functions.h b/include/functions.h index b6b8d686b..6852845e6 100644 --- a/include/functions.h +++ b/include/functions.h @@ -154,6 +154,8 @@ Actor *marker_getActor(ActorMarker *); Actor *marker_getActorAndRotation(ActorMarker *marker, f32 rotation[3]); Actor *subaddie_getLinkedActor(Actor *); ActorMarker *func_8032B16C(enum jiggy_e jiggy_id); +ActorMarker *actorArray_findHoneycombMarkerById(enum honeycomb_e id); +ActorMarker *actorArray_findMumboTokenMarkerById(enum mumbotoken_e id); bool func_80329078(Actor *, s32, s32); bool func_80329480(Actor *); bool subaddie_maybe_set_state_position_direction(Actor *, s32, f32, s32, f32 ); @@ -323,10 +325,13 @@ bool honeycombscore_get(enum honeycomb_e indx); // --- core2/map/specificflags.c --- s32 mapSpecificFlags_get(s32 i); void mapSpecificFlags_set(s32, s32); +void mapSpecificFlags_setEx(s32 i, s32 val, s32 triggerEvent); // --- core2/level/specificflags.c --- s32 levelSpecificFlags_get(s32 i); void levelSpecificFlags_set(s32, s32); +void levelSpecificFlags_setEx(s32 index, s32 val, s32 triggerEvent); +void levelSpecificFlags_getSizeAndPtr(s32 *size, u8 **addr); // --- core2/gameloop.c --- s32 getGameMode(void); @@ -335,8 +340,30 @@ void transitionToMap(enum map_e map, s32 exit, s32 transition); // --- core2/gamestate.c (item system) --- s32 item_empty(enum item_e item); void item_set(s32 item, s32 val); +void item_setEx(s32 item, s32 val, s32 triggerEvent); // --- core2/game_complete.c --- +enum AnchorFlagSpace { + ANCHOR_FLAGSPACE_FILE_PROGRESS = 0, + ANCHOR_FLAGSPACE_VOLATILE = 1, + ANCHOR_FLAGSPACE_LEVEL_SPECIFIC = 2, + ANCHOR_FLAGSPACE_MAP_SPECIFIC = 3, + ANCHOR_FLAGSPACE_RANDO_INF = 4, +}; +enum AnchorCollectibleSpace { + ANCHOR_COLLECTIBLE_JIGGY = 0, + ANCHOR_COLLECTIBLE_HONEYCOMB = 1, + ANCHOR_COLLECTIBLE_MUMBO = 2, + ANCHOR_COLLECTIBLE_NOTE = 3, + ANCHOR_COLLECTIBLE_JINJO = 4, + ANCHOR_COLLECTIBLE_WORM = 5, + ANCHOR_COLLECTIBLE_ACORN = 6, + ANCHOR_COLLECTIBLE_PRESENT_BLUE = 7, + ANCHOR_COLLECTIBLE_PRESENT_GREEN = 8, + ANCHOR_COLLECTIBLE_PRESENT_RED = 9, + ANCHOR_COLLECTIBLE_GOLD = 10, + ANCHOR_COLLECTIBLE_ORANGE = 11, +}; bool fileProgressFlag_get(enum file_progress_e index); s32 fileProgressFlag_getN(enum file_progress_e offset, s32 numBits); s32 volatileFlag_get(enum volatile_flags_e index); @@ -345,6 +372,8 @@ s32 volatileFlag_getN(enum volatile_flags_e index, s32 numBits); void fileProgressFlag_setN(enum file_progress_e, s32, s32); void volatileFlag_set(enum volatile_flags_e index, s32 set); void volatileFlag_setN(enum volatile_flags_e startIndex, s32 set, s32 length); +void fileProgressFlag_setEx(enum file_progress_e index, s32 set, s32 triggerEvent); +void volatileFlag_setEx(enum volatile_flags_e index, s32 set, s32 triggerEvent); // --- core2/dialog/progress_dialogs.c --- void volatileFlag_setAndTriggerDialog_0(enum volatile_flags_e arg0); @@ -1067,6 +1096,7 @@ void ability_setAllLearned(s32 val); void ability_setAllUsed(s32 val); void ability_setHasUsed(enum ability_e move); void ability_setLearned(s32 move, s32 val); +void ability_setLearnedEx(s32 move, s32 val, s32 triggerEvent); void ability_use(s32 arg0); // --- core2/actor_array.c --- @@ -1100,6 +1130,8 @@ void func_803268B4(void); void func_80326C24(s32 arg0); void func_803283BC(void); void func_803283D4(void); +void port_actorDespawn_beginDefer(void); +void port_actorDespawn_endDefer(void); void func_80328CA8(Actor *self, s32 angle); void func_803297FC(Actor *arg0, f32 *o1, f32 *o2); s32 func_80329904(ActorMarker *arg0, s32 arg1, f32 *arg2); @@ -1299,6 +1331,8 @@ void baAnim_init(void); void baAnim_update(void); void baanim_80289F30(void); enum baanim_update_type_e baanim_getUpdateType(void); +void baanim_applyBottlesBonusMask(uintptr_t arg0, s32 mask); +s32 baanim_getActiveBottlesBonusMask(void); void baanim_setModifyMethod(void (*arg0)(uintptr_t, uintptr_t)); void baanim_setUpdateType(enum baanim_update_type_e arg0); @@ -1576,6 +1610,7 @@ void playerPosition_getOffset(f32 arg0[3]); void playerPosition_setOffset(f32 arg0[3]); void playerPosition_applyOffset(void); void player_setPosition(f32 arg0[3]); +void player_setWarpDestination(f32 position[3], f32 yaw, s32 exit_id); // --- core2/ba/ba_recoil.c --- enum asset_e func_80294974(void); @@ -1988,6 +2023,7 @@ void func_802D8BE4(bool gold_feather); // --- core2/ch/honeycomb.c --- enum honeycomb_e func_802CA1C4(Actor *self); +enum mumbotoken_e func_802E0CB0(Actor *self); void func_802CA1CC(enum honeycomb_e id); // --- core2/ch/jiggy.c --- @@ -2348,6 +2384,8 @@ void jiggyscore_setSpawned(s32, s32); // --- core2/fx/score_jiggylist.c --- void codeABC00_spawnJiggyAtLocation(enum jiggy_e, f32[3]); +void codeABC00_spawnJiggyAtLocationEx(enum jiggy_e, f32[3], s32 triggerEvent); +s32 jiggylist_hasSpawnedObject(enum jiggy_e jiggy_id); void func_80332E08(void); void func_8033301C(void); void func_80333270(enum jiggy_e jiggy_id, f32 position[3], void (*method)(Actor *, ActorMarker *), ActorMarker *other_marker); @@ -2397,6 +2435,7 @@ s32 func_80320708(void); void bitfield_set_bit(u8 *array, s32 index, s32 set); void bitfield_set_n_bits(u8 *array, s32 startIndex, s32 set, s32 length); void fileProgressFlag_getSizeAndPtr(s32 *size, u8 **addr); +void volatileFlag_getSizeAndPtr(s32 *size, u8 **addr); void fileProgressFlag_set(enum file_progress_e index, s32 set); void volatileFlag_backupAll(void); void volatileFlag_clear(void); @@ -2975,6 +3014,8 @@ void item_setMaxCount(s32 item); void itemscore_highNoteScores_fromSaveData(u8 *savedata); void itemscore_levelReset(enum level_e level); void notescore_getSizeAndPtr(s32 *size, void **ptr); +void itemscore_noteScores_getSizeAndPtr(s32 *size, u8 **addr); +void itemscore_noteScores_setLevel(enum level_e level, s32 score); void saveditem_getSizeAndPtr(s32 *size, u8 **buffer); void timeScores_getSizeAndPtr(s32 *size, void **ptr); diff --git a/libultraship b/libultraship index 2c63e7ede..e8a161877 160000 --- a/libultraship +++ b/libultraship @@ -1 +1 @@ -Subproject commit 2c63e7edef577cd2a3726ce24dfedd7f088f12ae +Subproject commit e8a161877862edfcf79d3b33280a333e07461d5c diff --git a/src/BGS/ch/croctus.c b/src/BGS/ch/croctus.c index b589e5a60..c7a0d520d 100644 --- a/src/BGS/ch/croctus.c +++ b/src/BGS/ch/croctus.c @@ -3,6 +3,11 @@ #include "functions.h" #include "variables.h" +#include "port/Patches/Patches.h" + +// Anchor: set while replaying a teammate's feed; suppresses camera/dialog + rebroadcast. +static s32 sCroctusRemote = 0; + extern s32 func_80328748(AnimCtrl *, f32, f32); extern void func_8028F94C(s32, f32[3]); extern void func_80324CFC(f32, enum comusic_e, s32); @@ -97,8 +102,10 @@ void func_80387E68(ActorMarker *caller, enum asset_e text_id, s32 arg2){ func_80326310(this); //did not disappear when moved, after cutscene still there with collision but broken bgs_D_803907B8[this->actorTypeSpecificField]->propPtr->isNotFeatherEggOrNote = true; timedFunc_set_1(1.1f, (GenFunction_1)func_80387E00, (uintptr_t)bgs_D_803907B8[this->actorTypeSpecificField]); - timed_setStaticCameraToNode(0.8f, 9); - func_80324DBC(3.4f, 0xC87, 0xE, NULL, NULL, func_80387E68, NULL); + if(!sCroctusRemote){ + timed_setStaticCameraToNode(0.8f, 9); + func_80324DBC(3.4f, 0xC87, 0xE, NULL, NULL, func_80387E68, NULL); + } __spawnQueue_add_2((void (*)(void))func_80387D18, (uintptr_t)this->marker, 0x46); } else{ @@ -139,16 +146,40 @@ void chCroctus_updat(Actor *this){ return; }//L80388160 + // Anchor: teammate finished the chain — despawn our heads unless mid-cutscene (state 5/6). + if(jiggyscore_isSpawned(JIGGY_22_CROCTUS) && this->state != 5 && this->state != 6){ + marker_despawn(this->marker); + return; + } + + // Anchor: replay a teammate's feed of the active head (field 5 handled by the despawn above). + if (this->actorTypeSpecificField < 5 && this->state != 5 && this->state != 6 && !this->unk38_31 + && this->marker->propPtr->isNotFeatherEggOrNote + && (port_puzzleStep_get(ANCHOR_PUZZLE_BGS_CROCTUS) & (1 << (this->actorTypeSpecificField - 1)))) { + sCroctusRemote = 1; + this->unk38_31 = 1; + } + if(this->unk38_31){ if ((this->state != 5) && (this->state != 6)) { + if (!sCroctusRemote) { + port_puzzleStep_orBits(ANCHOR_PUZZLE_BGS_CROCTUS, 1 << (this->actorTypeSpecificField - 1)); + } coMusicPlayer_playMusic(COMUSIC_2B_DING_B, 28000); //TODO ISSUE HERE if (this->actorTypeSpecificField == 1) { - func_8028F94C(2, this->position); - gcdialog_showDialog(ASSET_C86_DIALOG_CROCTUS_FIRST_SUCCESS, 0xE, this->position, this->marker, func_80387E68, NULL); + // Anchor: func_8028F94C = look-at, released only by the dialog we skip; don't push when replaying. + if (!sCroctusRemote) { + func_8028F94C(2, this->position); + } + if (sCroctusRemote) { + func_80387E68(this->marker, ASSET_C86_DIALOG_CROCTUS_FIRST_SUCCESS, 0); + } else { + gcdialog_showDialog(ASSET_C86_DIALOG_CROCTUS_FIRST_SUCCESS, 0xE, this->position, this->marker, func_80387E68, NULL); + } subaddie_set_state_with_direction(this, 6, 0.79f, 1); } else { - timed_playSfx(0.4f, SFX_C9_PAUSEMENU_ENTER, 1.0f, 32000); //0.4f - timed_playSfx(1.4f, SFX_C9_PAUSEMENU_ENTER, 1.0f, 32000); //1.4f + timed_playSfx(0.4f, SFX_C9_PAUSEMENU_ENTER, 1.0f, 32000); + timed_playSfx(1.4f, SFX_C9_PAUSEMENU_ENTER, 1.0f, 32000); func_80324CFC(0.4f, COMUSIC_43_ENTER_LEVEL_GLITTER, 22000); func_80324D2C(4.5f, COMUSIC_43_ENTER_LEVEL_GLITTER); subaddie_set_state_with_direction(this, 5, 0.79f, 1); @@ -160,7 +191,7 @@ void chCroctus_updat(Actor *this){ if (this->actorTypeSpecificField < 5) { bgs_D_803907B8[this->actorTypeSpecificField]->propPtr->isNotFeatherEggOrNote = true; timedFunc_set_1(1.1f, (GenFunction_1)func_80387E00, (uintptr_t)bgs_D_803907B8[this->actorTypeSpecificField]); - gcStaticCamera_activate(D_803907B0[this->actorTypeSpecificField-1]); + if (!sCroctusRemote) gcStaticCamera_activate(D_803907B0[this->actorTypeSpecificField-1]); } else { timedFunc_set_1(0.8f, (GenFunction_1)chCroctus_jiggySpawn, (uintptr_t)this->marker); } @@ -168,6 +199,7 @@ void chCroctus_updat(Actor *this){ } } }//L80388348 + sCroctusRemote = 0; switch(this->state){ case 1:// L80388370 diff --git a/src/BGS/ch/mudhut.c b/src/BGS/ch/mudhut.c index eccc0113c..8eda12cb7 100644 --- a/src/BGS/ch/mudhut.c +++ b/src/BGS/ch/mudhut.c @@ -6,6 +6,8 @@ #include +#include "port/Patches/Patches.h" + /* TODO move declarations to respective headers*/ extern void player_stateTimer_set(enum state_timer_e, f32); extern f32 player_stateTimer_get(enum state_timer_e); @@ -79,8 +81,34 @@ void chMudHut_spawnExplosion(ActorMarker *this){ if(this); } +static void chMudHut_dropRecordedBundle(Actor *this, s32 tmp, s32 fullBundle){ + f32 pos[3]; + if(tmp < 0 || tmp >= 5){ + return; // jiggy / out of range: handled by JIGGY_SPAWN, not the hut + } + if(!fullBundle && tmp == 2){ + return; // note: spawn live but skip on reload + } + pos[0] = this->position_x; + pos[1] = this->position_y + 130.0f; + pos[2] = this->position_z; + __spawnQueue_add_4((GenFunction_4) spawnQueue_bundle_f32, D_80390B50[tmp], reinterpret_cast(s32, pos[0]), reinterpret_cast(s32, pos[1]), reinterpret_cast(s32, pos[2])); +} + +static void chMudHut_replaySmash(Actor *this, s32 tmp){ + sfx_playFadeShorthandDefault(SFX_5B_HEAVY_STUFF_FALLING, 1.0f, 28000, this->position, 0x12C, 0xBB8); + subaddie_set_state(this, 2); + this->marker->propPtr->unk8_3 = 0; + actor_playAnimationOnce(this); + if(tmp == 5){ + coMusicPlayer_playMusic(COMUSIC_2D_PUZZLE_SOLVED_FANFARE, 28000); + } + __spawnQueue_add_1((GenFunction_1)chMudHut_spawnExplosion, (uintptr_t)this->marker); + chMudHut_dropRecordedBundle(this, tmp, 1); +} + void chMudHut_update(Actor *this){ - + f32 diffPos[3]; f32 plyrPos[3]; s32 tmp; @@ -89,6 +117,14 @@ void chMudHut_update(Actor *this){ if(!this->initialized){ this->marker->collidable = false; this->initialized = true; + // Anchor: already smashed this session — restore broken, re-drop non-tracked loot. + tmp = port_hutSmash_get((s32)this->position_x, (s32)this->position_y, (s32)this->position_z); + if(tmp >= 0){ + this->state = 3; + this->marker->propPtr->unk8_3 = 0; + chMudHut_dropRecordedBundle(this, tmp, 0); + return; + } } switch(this->state){ @@ -98,8 +134,8 @@ void chMudHut_update(Actor *this){ diffPos[0] = plyrPos[0] - this->position_x; diffPos[1] = plyrPos[1] - this->position_y; diffPos[2] = plyrPos[2] - this->position_z; - if( (150.0f < diffPos[1]) - && (player_getActiveHitbox(this->marker) == HITBOX_1_BEAK_BUSTER) + if( (150.0f < diffPos[1]) + && (player_getActiveHitbox(this->marker) == HITBOX_1_BEAK_BUSTER) && (func_8028F20C()) && (LENGTH_VEC3F(diffPos) < 350.f) ){ @@ -124,6 +160,13 @@ void chMudHut_update(Actor *this){ else { jiggy_spawn(JIGGY_23_BGS_HUTS, diffPos); } + port_hutSmash_record((s32)this->position_x, (s32)this->position_y, (s32)this->position_z, tmp); + } + else { + tmp = port_hutSmash_get((s32)this->position_x, (s32)this->position_y, (s32)this->position_z); + if(tmp >= 0){ + chMudHut_replaySmash(this, tmp); + } } break; case 2: diff --git a/src/BGS/ch/pinkegg.c b/src/BGS/ch/pinkegg.c index 7845ccfc6..9cb3fa1db 100644 --- a/src/BGS/ch/pinkegg.c +++ b/src/BGS/ch/pinkegg.c @@ -3,6 +3,8 @@ #include "functions.h" #include "variables.h" +#include "port/Patches/Patches.h" + typedef struct chpinkegg_s{ u32 unk0; u32 unk4; @@ -90,9 +92,11 @@ void chPinkEgg_collision(ActorMarker *this, ActorMarker *other_marker){ actor_playAnimationOnce(thisActor); this->collidable = false; thisActor->unk124_6 = 0; - if(D_803906C4[(tmp = (ActorLocal_PinkEgg *) &thisActor->local)->unk0] != 0){ + tmp = (ActorLocal_PinkEgg *) &thisActor->local; + port_puzzleStep_orBits(ANCHOR_PUZZLE_BGS_PINKEGG, 1 << tmp->unk0); + if(D_803906C4[tmp->unk0] != 0){ __spawnQueue_add_2((void (*)(void))chPinkEgg_spawnNext, (uintptr_t)thisActor->marker, tmp->unk0); - } else { + } else if(!jiggyscore_isSpawned(JIGGY_21_BGS_PINKEGG)){ jiggy_spawn(JIGGY_21_BGS_PINKEGG, thisActor->position); coMusicPlayer_playMusic(COMUSIC_2D_PUZZLE_SOLVED_FANFARE, 28000); } @@ -105,6 +109,19 @@ void chPinkEgg_update(Actor *this){ this->initialized = true; } + // Anchor: team finished the chain — despawn unless mid-break (state 3). + if(jiggyscore_isSpawned(JIGGY_21_BGS_PINKEGG) && this->state != 3){ + marker_despawn(this->marker); + return; + } + + // Anchor: replay teammates' layer breaks. + if((port_puzzleStep_get(ANCHOR_PUZZLE_BGS_PINKEGG) & (1 << ((ActorLocal_PinkEgg *)&this->local)->unk0)) + && this->state != 3){ + chPinkEgg_collision(this->marker, NULL); + return; + } + switch(this->state){ case 1: if(!((ActorLocal_PinkEgg *) &this->local)->unk4){ diff --git a/src/BGS/ch/tanktup.c b/src/BGS/ch/tanktup.c index 6dd23ca02..b731902f4 100644 --- a/src/BGS/ch/tanktup.c +++ b/src/BGS/ch/tanktup.c @@ -5,6 +5,8 @@ #include "prop.h" +#include "port/Patches/Patches.h" + void timed_exitStaticCamera(f32); #include "core2/timedfunc.h" @@ -93,6 +95,9 @@ void func_8038F610(Actor *this) { void func_8028F94C(s32, f32[3]); void func_8028F918(s32); +// Anchor: set when state 2 took the head-raise look-at/freeze push; state 3 releases it. +static s32 sTanktupCameraPushed = 0; + void chTanktup_update(Actor *this) { ActorLocal_TanktupBody *local = (ActorLocal_TanktupBody *) (&this->local); @@ -121,6 +126,18 @@ void chTanktup_update(Actor *this) this->marker->propPtr->unk8_3 = 1; actor_collisionOff(this); this->scale = 1.0f; + sTanktupCameraPushed = 0; + // Anchor: adopt the team's already-retracted legs. + { + s32 legBits = port_puzzleStep_get(ANCHOR_PUZZLE_BGS_TANKTUP); + for (sp44 = 0; sp44 < 4; sp44++) + { + if (legBits & (1 << sp44)) + { + local->unk0[sp44] = 1; + } + } + } for (sp44 = 0; sp44 < 4; sp44++) { if (local->unk0[sp44] == 0) @@ -134,6 +151,12 @@ void chTanktup_update(Actor *this) ; } } + // Anchor: team completed Tanktup but our body is still idle (state 1) — raise the head to match. + if (this->state == 1 && jiggyscore_isSpawned(JIGGY_26_BGS_TANKTUP)) + { + subaddie_set_state_with_direction(this, 3, 0.0f, -1); + actor_playAnimationOnce(this); + } switch (this->state) { case 1: @@ -178,6 +201,7 @@ void chTanktup_update(Actor *this) { coMusicPlayer_playMusic(COMUSIC_2D_PUZZLE_SOLVED_FANFARE, 28000); func_8028F94C(2, local->unk18); + sTanktupCameraPushed = 1; } if (actor_animationIsAt(this, 0.99f)) { @@ -194,7 +218,12 @@ void chTanktup_update(Actor *this) break; case 3: - if (actor_animationIsAt(this, 0.1f) != 0) + { + f32 pp[3]; + s32 near; + player_getPosition(pp); + near = ml_vec3f_distance(local->unk18, pp) < 700.0f; + if (actor_animationIsAt(this, 0.1f) != 0 && near) { timed_setStaticCameraToNode(0.0f, 0xD); } @@ -202,7 +231,7 @@ void chTanktup_update(Actor *this) { func_8030E624(0x797FF885U); } - if (actor_animationIsAt(this, 0.4f) != 0) + if (actor_animationIsAt(this, 0.4f) != 0 && jiggyscore_isSpawned(JIGGY_26_BGS_TANKTUP) == 0) { f32 sp34[3]; vec3fArray_get_vec3f(this->marker->unk44, 6, sp34); @@ -212,15 +241,24 @@ void chTanktup_update(Actor *this) } if (actor_animationIsAt(this, 0.9f) != 0) { - func_8028F918(0); - if (jiggyscore_isCollected(JIGGY_26_BGS_TANKTUP) == 0) + // Anchor: release the freeze/look-at if state 2 took it, independent of the proximity check below. + if (sTanktupCameraPushed) { - gcdialog_showDialog(ASSET_C7F_DIALOG_TANKTUP_COMPLETE, 0xF, this->position, this->marker, func_8038F5E4, 0); + func_8028F918(0); + sTanktupCameraPushed = 0; } - else + if (near) { - func_8038F5E4(this->marker, ASSET_C7F_DIALOG_TANKTUP_COMPLETE, -1); + if (jiggyscore_isCollected(JIGGY_26_BGS_TANKTUP) == 0) + { + gcdialog_showDialog(ASSET_C7F_DIALOG_TANKTUP_COMPLETE, 0xF, this->position, this->marker, func_8038F5E4, 0); + } + else + { + func_8038F5E4(this->marker, ASSET_C7F_DIALOG_TANKTUP_COMPLETE, -1); + } } + } } break; diff --git a/src/BGS/ch/tanktup_legs.c b/src/BGS/ch/tanktup_legs.c index b63be8fe1..e71430554 100644 --- a/src/BGS/ch/tanktup_legs.c +++ b/src/BGS/ch/tanktup_legs.c @@ -3,6 +3,7 @@ #include "functions.h" #include "variables.h" +#include "port/Patches/Patches.h" void timed_exitStaticCamera(f32); void func_8028E668(f32[3], f32, f32, f32); @@ -77,6 +78,7 @@ void BGS_func_8038FB84(ActorMarker *this, ActorMarker *other_marker){ timedFunc_set_2(0.65f, (GenFunction_2) func_8038FB40, (uintptr_t) this, (uintptr_t) other_marker); func_8038F51C(thisActor); this->collidable = false; + port_puzzleStep_orBits(ANCHOR_PUZZLE_BGS_TANKTUP, 1 << thisActor->unk10_12); } void chTanktupLeg_update(Actor *this){ @@ -85,6 +87,11 @@ void chTanktupLeg_update(Actor *this){ this->marker->propPtr->unk8_3 = 1; marker_setCollisionScripts(this->marker, NULL, NULL, BGS_func_8038FB84); } + // Anchor: teammate hit this leg remotely — replay the pull-in. + if(this->state == 1 && this->marker->collidable + && (port_puzzleStep_get(ANCHOR_PUZZLE_BGS_TANKTUP) & (1 << this->unk10_12))){ + BGS_func_8038FB84(this->marker, NULL); + } if(this->state == 2){ if(anctrl_isAt(this->anctrl, 0.65f)){ gcsfx_playAtSampleRate(SFX_7C_CHEBOOF); diff --git a/src/CC/ch/clanker.c b/src/CC/ch/clanker.c index b9043260e..3dd6a8017 100644 --- a/src/CC/ch/clanker.c +++ b/src/CC/ch/clanker.c @@ -3,6 +3,9 @@ #include "functions.h" #include "variables.h" +extern void port_breakable_recordBreak(s32 markerId, s32 x, s32 y, s32 z); +extern s32 port_breakable_isBroken(s32 map, s32 markerId, s32 x, s32 y, s32 z); + typedef struct { u8 *unk0; f32 unk4; @@ -65,6 +68,8 @@ void chCCGrate_die(ActorMarker *marker, ActorMarker *other_marker){ if(actor->state == 1){ chCCGrate_setNextState(actor, *local->unk0); + port_breakable_recordBreak((s32)actor->marker->id, (s32)actor->position[0], + (s32)actor->position[1], (s32)actor->position[2]); } } @@ -82,11 +87,18 @@ void chCCGrate_update(Actor * this){ if(this->modelCacheIndex == 0x28E && jiggyscore_isSpawned(JIGGY_18_CC_BOLT)){ marker_despawn(this->marker); } + else if(port_breakable_isBroken((s32)gsworld_getMap(), (s32)this->marker->id, + (s32)this->position[0], (s32)this->position[1], + (s32)this->position[2])){ + marker_despawn(this->marker); + } return; }//L803899D4 if(this->state == 1){ - if(local->unk8){ + if(local->unk8 || port_breakable_isBroken((s32)gsworld_getMap(), (s32)this->marker->id, + (s32)this->position[0], (s32)this->position[1], + (s32)this->position[2])){ chCCGrate_setNextState(this, *local->unk0); } }//L80389A10 diff --git a/src/CC/ch/clankertoothext.c b/src/CC/ch/clankertoothext.c index a4395f326..9de9672a6 100644 --- a/src/CC/ch/clankertoothext.c +++ b/src/CC/ch/clankertoothext.c @@ -5,6 +5,8 @@ #include +#include "port/Patches/Patches.h" + typedef struct{ s32 unk0; s32 egg_count; @@ -90,6 +92,19 @@ void chClankerTooth_update(Actor *this){ chClankerTooth_setNextState(this, 3); } }//L803871D8 + if(this->state == 1){ + s32 base = (local->unk0 - 1) * 3; + s32 bits = (port_puzzleStep_get(ANCHOR_PUZZLE_CC_CLANKER_TEETH) >> base) & 0x7; + s32 shared = (bits & 1) + ((bits >> 1) & 1) + ((bits >> 2) & 1); + while(this->state == 1 && local->egg_count < shared){ + local->egg_count++; + if(local->egg_count == 3){ + chClankerTooth_setNextState(this, 2); + }else{ + coMusicPlayer_playMusic(COMUSIC_2B_DING_B, 28000); + } + } + } player_getPosition(sp70); local->unk8 += sp68; if(this->state == 2){ @@ -121,6 +136,9 @@ void chClankerTooth_update(Actor *this){ if(this->state == 1 && D_80389F80 == local->unk0){ D_80389F80 = 0; local->egg_count++; + // Anchor: broadcast cumulative egg progress. + port_puzzleStep_orBits(ANCHOR_PUZZLE_CC_CLANKER_TEETH, + ((1 << local->egg_count) - 1) << ((local->unk0 - 1) * 3)); if(local->egg_count == 3){ chClankerTooth_setNextState(this, 2); }else{ diff --git a/src/CC/ch/key.c b/src/CC/ch/key.c index 8ab935b43..bb163b2ad 100644 --- a/src/CC/ch/key.c +++ b/src/CC/ch/key.c @@ -117,6 +117,10 @@ void chClankerKey_update(Actor *this){ } } else{//L80386C40 + // Anchor: teammate raised Clanker — snap the key to finished (state 5). + if(this->state == 1 && jiggyscore_isSpawned(JIGGY_17_CC_CLANKER_RAISED)){ + CC_func_80386920(this, 5); + } local->unk14 += tick; player_getPosition(sp58); if(local->unk1 && ! local->unk2){ diff --git a/src/CC/ch/tooth.c b/src/CC/ch/tooth.c index 654456e8c..073116e40 100644 --- a/src/CC/ch/tooth.c +++ b/src/CC/ch/tooth.c @@ -80,6 +80,9 @@ extern void chTooth_update(Actor * this){ __chTooth_setState(this, 1); } } + else if(this->state == 1 && levelSpecificFlags_get(local->unk0->level_flag)){ + __chTooth_setState(this, 2); + } else if(this->state == 2){//L803876B4 if(local->unk0->jiggy_id && !jiggyscore_isSpawned(local->unk0->jiggy_id)){ player_getPosition(sp24); diff --git a/src/CC/minigame_rings.c b/src/CC/minigame_rings.c index 3a243bedf..d5630968e 100644 --- a/src/CC/minigame_rings.c +++ b/src/CC/minigame_rings.c @@ -4,6 +4,8 @@ #include "variables.h" #include "CC.h" +extern void port_ccWater_broadcastRise(int32_t map, int32_t waterId, int32_t targetDy, f32 duration); + /* .data */ f32 D_80389BF0[3] = {0.0f, 1300.0f, -2800.0f}; @@ -82,6 +84,15 @@ void func_8038817C(void){ Struct70s *tmp_v0; if(D_80389F90.unk0 != 0){ + if(jiggyscore_isSpawned(JIGGY_1C_CC_RINGS) && D_80389F90.unk0 < 9){ + func_80387FE8(); + // func_80387F80 snaps water to risen height; VB listener suppresses it when connected (rise already animating). + if(EventSystem_Should(VB_CC_RINGS_SNAP_WATER, true)){ + func_80387F80(); + } + D_80389F90.unk0 = 0; + return; + } D_80389F90.unk4 += sp20; player_getPosition(sp24); if(ml_timer_update(&D_80389F90.unk8, sp20)){ @@ -95,6 +106,7 @@ void func_8038817C(void){ if(tmp_v0){ func_8034E78C((Struct73s *)tmp_v0, 0x190, 12.0f); } + port_ccWater_broadcastRise(MAP_22_CC_INSIDE_CLANKER, 0x131, 0x190, 12.0f); D_80389F90.unk4 = 0.0f; }//L80388264 if(!(D_80389F90.unk0 < 2) && D_80389F90.unk1 != 0){ diff --git a/src/CC/platform_physics.c b/src/CC/platform_physics.c index 1e20fd654..341992650 100644 --- a/src/CC/platform_physics.c +++ b/src/CC/platform_physics.c @@ -330,6 +330,10 @@ void CC_func_80388F4C(void){ CC_func_80387D4C(); if(D_80389FA0.unk21 != 0 && gsworld_getUnk0() == 2){ + // Anchor: teammate raised Clanker — play the physical raise (no cutscene). + if(D_80389FA0.unk21 == 1 && jiggyscore_isSpawned(JIGGY_17_CC_CLANKER_RAISED)){ + func_80388EA4(); + } player_getPosition(sp6C); D_80389FA0.unk20 = (ml_vec3f_distance(sp6C, D_80389FA0.unkC) < 200.0f); diff --git a/src/CCW/actor_spawninit.c b/src/CCW/actor_spawninit.c index 032d47abd..7ed064f3f 100644 --- a/src/CCW/actor_spawninit.c +++ b/src/CCW/actor_spawninit.c @@ -84,10 +84,10 @@ void func_8038DAB0(Actor *this){ if(!this->initialized){ func_802D3CE8(this); this->initialized = true; - - if (levelSpecificFlags_get(LEVEL_FLAG_38_CCW_UNKNOWN)) { - marker_despawn(this->marker); - } + } + // Anchor: checked live, not just at spawn. + if (levelSpecificFlags_get(LEVEL_FLAG_38_CCW_UNKNOWN)) { + marker_despawn(this->marker); } } diff --git a/src/CCW/ch/acorn.c b/src/CCW/ch/acorn.c index 7602302f5..be025b938 100644 --- a/src/CCW/ch/acorn.c +++ b/src/CCW/ch/acorn.c @@ -2,8 +2,11 @@ #include #include "functions.h" #include "variables.h" +#include "port/Enhancements/Retention/Retention.h" extern ActorMarker *func_8028E86C(void); +extern s32 port_remoteCarry_displayUpdate(Actor *this); +extern void port_anchor_onCarryThrow(s32 markerId, f32 start[3], f32 target[3]); typedef struct { f32 unk0[3]; @@ -62,6 +65,11 @@ void func_8038C7A8(Actor *this) { local = (ActorLocal_CCW_61E0 *)&this->local; sp44 = time_getDelta(); + + if (port_remoteCarry_displayUpdate(this)) { + return; + } + if (!this->volatile_initialized) { this->volatile_initialized = true; return; @@ -69,20 +77,40 @@ void func_8038C7A8(Actor *this) { sp4C = (func_8028E86C() == this->marker); if (this->state == 0) { - CCW_func_8038C6A0(this, sp4C ? 2 : 1); + if (sp4C) { + CCW_func_8038C6A0(this, 2); + } else { + s32 acornSuppress; + port_carriedSync_register(ANCHOR_COLLECTIBLE_ACORN, this->marker, (s32)this->position[0], + (s32)this->position[1], (s32)this->position[2], &acornSuppress); + if (acornSuppress) { + CCW_func_8038C6A0(this, 5); + return; + } + CCW_func_8038C6A0(this, 1); + } } if (this->state == 1) { + if (port_carriedSync_consumeRemoteDespawn(ANCHOR_COLLECTIBLE_ACORN, this->marker)) { + CCW_func_8038C6A0(this, 5); + return; + } player_getPosition(sp38); if (ml_vec3f_distance(this->position, sp38) < 50.0f) { func_8028F030(0x2A9); sfx_playFadeShorthandDefault(SFX_C5_TWINKLY_POP, 1.0f, 25000, this->position, 500, 2500); + port_carriedSync_onLocalCollect(ANCHOR_COLLECTIBLE_ACORN, this->marker); CCW_func_8038C6A0(this, 5); } } if (this->state == 2) { if (this->unk138_21) { + f32 throwTarget[3]; + func_8038BC50(throwTarget); + port_anchor_onCarryThrow(this->marker->id, this->position, throwTarget); func_8028F010(0x2A9); + port_carriedSync_onLocalSpend(ANCHOR_COLLECTIBLE_ACORN); CCW_func_8038C6A0(this, 3); } else if (!sp4C) { func_8028F050(0x2A9); diff --git a/src/CCW/ch/caterpillar.c b/src/CCW/ch/caterpillar.c index 90049e190..fa824e537 100644 --- a/src/CCW/ch/caterpillar.c +++ b/src/CCW/ch/caterpillar.c @@ -2,9 +2,12 @@ #include #include "functions.h" #include "variables.h" +#include "port/Enhancements/Retention/Retention.h" extern ActorMarker *func_8028E86C(void); extern void func_8028F7D4(f32, f32); +extern s32 port_remoteCarry_displayUpdate(Actor *this); +extern void port_anchor_onCarryThrow(s32 markerId, f32 start[3], f32 target[3]); typedef struct { f32 unk0[3]; @@ -86,6 +89,10 @@ void chcaterpillar_update(Actor *this){ f32 sp54[3]; int i; + if (port_remoteCarry_displayUpdate(this)) { + return; + } + sp8C = func_8028E86C() == this->marker; sp84 = time_getDelta(); @@ -104,12 +111,23 @@ void chcaterpillar_update(Actor *this){ ) { chcaterpillar_setState(this, 5); } else { + s32 wormSuppress; + port_carriedSync_register(ANCHOR_COLLECTIBLE_WORM, this->marker, (s32)this->position[0], + (s32)this->position[1], (s32)this->position[2], &wormSuppress); + if (wormSuppress) { + marker_despawn(this->marker); + return; + } chcaterpillar_setState(this, 1); }//L8038A45C } }//L8038A45C if(this->state == 1){ + if(port_carriedSync_consumeRemoteDespawn(ANCHOR_COLLECTIBLE_WORM, this->marker)){ + marker_despawn(this->marker); + return; + } skeletalAnim_getProgressRange(this->unk148, &sp64, &sp60); player_getPosition(sp74); if(ml_vec3f_distance(this->position, local->unk0) < 10.0f){ @@ -158,13 +176,18 @@ void chcaterpillar_update(Actor *this){ volatileFlag_set(VOLATILE_FLAG_B2_HAS_COLLECTED_CATERPILLAR, true); } sfx_playFadeShorthandDefault(SFX_C5_TWINKLY_POP, 1.0f, 25000, this->position, 0x1f4, 0x9c4); + port_carriedSync_onLocalCollect(ANCHOR_COLLECTIBLE_WORM, this->marker); marker_despawn(this->marker); } }//L8038A794 if(this->state == 2){ if(this->unk138_21){ + f32 throwTarget[3]; + func_80389BD8(throwTarget); + port_anchor_onCarryThrow(this->marker->id, this->position, throwTarget); func_8028F010(ACTOR_2A2_CATERPILLAR); + port_carriedSync_onLocalSpend(ANCHOR_COLLECTIBLE_WORM); chcaterpillar_setState(this, 3); } else if(!sp8C){ diff --git a/src/CCW/ch/eyrie_baby.c b/src/CCW/ch/eyrie_baby.c index 1edf612dd..721433321 100644 --- a/src/CCW/ch/eyrie_baby.c +++ b/src/CCW/ch/eyrie_baby.c @@ -2,6 +2,7 @@ #include #include "functions.h" #include "variables.h" +#include "port/Patches/Patches.h" typedef struct { f32 unk0; @@ -223,7 +224,7 @@ void CCW_func_80389BFC(Actor *this) { D_8038FDE0[1] = this->position[1]; D_8038FDE0[2] = this->position[2]; if (this->state == 0) { - local->unk4 = 0U; + local->unk4 = (u32)port_puzzleCount_get(ANCHOR_COUNT_CCW_EYRIE_FED); } local->unk0 = &D_8038F080[0]; while(local->unk0->map_id != 0 && gsworld_getMap() != local->unk0->map_id){ @@ -277,7 +278,8 @@ void CCW_func_80389BFC(Actor *this) { if ((local->unk0->map_id == MAP_44_CCW_SUMMER) && (local->unk4 == 0)) { gcdialog_showDialog(0xCD8, 4, NULL, NULL, NULL, NULL); } - local->unk4++; + port_puzzleCount_add(ANCHOR_COUNT_CCW_EYRIE_FED, 1); + local->unk4 = (u32)port_puzzleCount_get(ANCHOR_COUNT_CCW_EYRIE_FED); if (local->unk4 < local->unk0->unk25) { func_803897B8(this, 5); } else { @@ -285,8 +287,19 @@ void CCW_func_80389BFC(Actor *this) { } } } - if (fileProgressFlag_get(local->unk0->unk4)) { - func_803897B8(this, local->unk0->unkC); + // Anchor: teammate fed a worm — play the interim eat animation; final feed handled below. + if (this->state == 1) { + s32 sharedFed = port_puzzleCount_get(ANCHOR_COUNT_CCW_EYRIE_FED); + if (sharedFed > (s32)local->unk4) { + local->unk4 = (u32)sharedFed; + if ((s32)local->unk4 < (s32)local->unk0->unk25) { + func_803897B8(this, 5); + } + } + } + if (this->state == 1 && fileProgressFlag_get(local->unk0->unk4)) { + // Anchor: fed flag synced from a teammate — skip to sleep state (spring keeps its hatch cutscene). + func_803897B8(this, (local->unk0->map_id == MAP_43_CCW_SPRING) ? local->unk0->unkC : 4); } } if ((this->state == 2) && (skeletalAnim_getLoopCount(this->unk148) > 0)) { diff --git a/src/CCW/ch/eyrie_egg.c b/src/CCW/ch/eyrie_egg.c index 615630179..451c466a0 100644 --- a/src/CCW/ch/eyrie_egg.c +++ b/src/CCW/ch/eyrie_egg.c @@ -9,6 +9,9 @@ void func_803895F4(Actor *this); /* .data */ ActorInfo D_8038EE70 = { 0x1B3, 0x2A0, 0x483, 0x0, NULL, func_803895F4, NULL, CCW_func_8038954C, 0, 0, 0.0f, 0}; +// Anchor: set while replaying a teammate's hatch; skips the camera pan. +static s32 sChEyrieEggRemote = 0; + /* .code */ void func_80389440(Actor *this, s32 next_state) { void *temp_v0; @@ -19,10 +22,12 @@ void func_80389440(Actor *this, s32 next_state) { fileProgressFlag_set(FILEPROG_E6_SPRING_EYRIE_HATCHED, true); skeletalAnim_set(this->unk148, 0x187, 0.0f, 2.0f); skeletalAnim_setBehavior(this->unk148, SKELETAL_ANIM_2_ONCE); - func_80324E38(0.0f, 3); - timed_setStaticCameraToNode(0.0f, 2); - timed_exitStaticCamera(8.0f); - func_80324E38(8.0f, 0); + if (!sChEyrieEggRemote) { + func_80324E38(0.0f, 3); + timed_setStaticCameraToNode(0.0f, 2); + timed_exitStaticCamera(8.0f); + func_80324E38(8.0f, 0); + } } this->state = next_state; } @@ -61,6 +66,12 @@ void func_803895F4(Actor *this) { return; } + if (this->state == 1 && fileProgressFlag_get(FILEPROG_E6_SPRING_EYRIE_HATCHED)) { + sChEyrieEggRemote = 1; + func_80389440(this, 2); + sChEyrieEggRemote = 0; + } + if (this->state == 2) { skeletalAnim_getProgressRange(this->unk148, &sp2C, &sp28); if ((sp2C < 0.5) && (sp28 >= 0.5)) { diff --git a/src/CCW/ch/eyrie_winter.c b/src/CCW/ch/eyrie_winter.c index 92b8bcbf4..13f9c2868 100644 --- a/src/CCW/ch/eyrie_winter.c +++ b/src/CCW/ch/eyrie_winter.c @@ -95,7 +95,7 @@ void func_8038AEBC(Actor *this) { if (this->state == 3) { actor_update_func_80326224(this); skeletalAnim_getProgressRange(this->unk148, &sp30, &sp2C); - if ((sp30 <= 0.5) && (sp2C >= 0.5)) { + if ((sp30 <= 0.5) && (sp2C >= 0.5) && !jiggyscore_isCollected(JIGGY_49_CCW_EYRIE)) { jiggy_spawn(JIGGY_49_CCW_EYRIE, this->position); } if (skeletalAnim_getLoopCount(this->unk148) > 0) { diff --git a/src/CCW/ch/gnawtyboulder.c b/src/CCW/ch/gnawtyboulder.c index 344e657b9..995a659f0 100644 --- a/src/CCW/ch/gnawtyboulder.c +++ b/src/CCW/ch/gnawtyboulder.c @@ -120,7 +120,14 @@ void chGnawtyBoulder_update(Actor *this) { marker_despawn(this->marker); } return; - } + } + // Anchor: teammate broke the boulder — despawn live (no break cutscene). + if (this->state == 1 + && levelSpecificFlags_get(LEVEL_FLAG_25_CCW_UNKNOWN) + && gsworld_getMap() != MAP_43_CCW_SPRING) { + marker_despawn(this->marker); + return; + } if(this->state == 2){ if (ml_timer_update(&local->unk0, tick) ) { chGnawtyBoulder_setNextState(this, 3); diff --git a/src/CCW/ch/nabnut_autumn.c b/src/CCW/ch/nabnut_autumn.c index 11c4c56ed..3bf0931f8 100644 --- a/src/CCW/ch/nabnut_autumn.c +++ b/src/CCW/ch/nabnut_autumn.c @@ -2,6 +2,10 @@ #include #include "functions.h" #include "variables.h" +#include "port/Patches/Patches.h" + +// Anchor: set during a remote completion replay; skips the finisher's camera/dialog. +static s32 sNabnutRemote = 0; typedef struct { s32 returned_acorn_count; @@ -48,16 +52,20 @@ void chnabnut_setState(Actor *this, s32 next_state) { this->marker->propPtr->unk8_3 = false; skeletalAnim_set(this->unk148, ASSET_22D_ANIM_NABNUT_BACKFLIP, 0.2f, 3.13f); skeletalAnim_setBehavior(this->unk148, SKELETAL_ANIM_2_ONCE); - func_80324E38(0.0f, 3); - timed_setStaticCameraToNode(0.0f, 0xB); - gcdialog_showDialog(0xCCC, 0x20, this->position, NULL, NULL, NULL); + if (!sNabnutRemote) { + func_80324E38(0.0f, 3); + timed_setStaticCameraToNode(0.0f, 0xB); + gcdialog_showDialog(0xCCC, 0x20, this->position, NULL, NULL, NULL); + } } if (next_state == NABNUT_STATE_4_THANK_PLAYER) { skeletalAnim_set(this->unk148, ASSET_22E_ANIM_NABNUT_STAND, 0.2f, 3.53f); skeletalAnim_setBehavior(this->unk148, SKELETAL_ANIM_1_LOOP); bundle_setYaw(this->yaw - 40.0f); - jiggy_spawn(JIGGY_4A_CCW_NABNUT, this->position); + if (!jiggyscore_isSpawned(JIGGY_4A_CCW_NABNUT)) { + jiggy_spawn(JIGGY_4A_CCW_NABNUT, this->position); + } } if (next_state == NABNUT_STATE_5_EXIT) { @@ -65,8 +73,10 @@ void chnabnut_setState(Actor *this, s32 next_state) { } if (next_state == NABNUT_STATE_6_DESPAWN) { - func_80324E38(0.0f, 0); - timed_exitStaticCamera(0.0f); + if (!sNabnutRemote) { + func_80324E38(0.0f, 0); + timed_exitStaticCamera(0.0f); + } marker_despawn(this->marker); } @@ -123,7 +133,8 @@ void chnabnut_update(Actor *this) { D_8038F350[2] = this->position[2]; if (this->state == 0) { this->has_met_before = false; - local->returned_acorn_count = 0; + local->returned_acorn_count = port_puzzleCount_get(ANCHOR_COUNT_CCW_NABNUT_ACORNS); + sNabnutRemote = 0; } chnabnut_setState(this, 1); if(jiggyscore_isSpawned(JIGGY_4A_CCW_NABNUT)) { @@ -146,14 +157,25 @@ void chnabnut_update(Actor *this) { player_setCarryObjectPoseInCylinder(this->position, 500.0f, 200.0f, ACTOR_2A9_ACORN, &this); if ((carriedObj_getActorId() == ACTOR_2A9_ACORN) && (ml_vec3f_distance(this->position, sp30) < 300.0f) && player_throwCarriedObject()) { player_setThrowTargetPosition(D_8038F350); - local->returned_acorn_count++; - if (local->returned_acorn_count == 6) { + port_puzzleCount_add(ANCHOR_COUNT_CCW_NABNUT_ACORNS, 1); + local->returned_acorn_count = port_puzzleCount_get(ANCHOR_COUNT_CCW_NABNUT_ACORNS); + if (local->returned_acorn_count >= 6) { chnabnut_setState(this, NABNUT_STATE_2_WAIT); } else if (item_getCount(ITEM_23_ACORNS) == 1) { gcdialog_showDialog(0xCCB, 0x20, this->position, NULL, NULL, NULL); } } } + if (this->state == NABNUT_STATE_1_SAD) { + s32 sharedReturned = port_puzzleCount_get(ANCHOR_COUNT_CCW_NABNUT_ACORNS); + if (sharedReturned > local->returned_acorn_count) { + local->returned_acorn_count = sharedReturned; + if (sharedReturned >= 6) { + sNabnutRemote = 1; + chnabnut_setState(this, NABNUT_STATE_2_WAIT); + } + } + } } if ((this->state == NABNUT_STATE_3_BACKFLIP) && (skeletalAnim_getLoopCount(this->unk148) > 0)) { chnabnut_setState(this, NABNUT_STATE_4_THANK_PLAYER); diff --git a/src/CCW/flower.c b/src/CCW/flower.c index 376fdf2be..15c8c394e 100644 --- a/src/CCW/flower.c +++ b/src/CCW/flower.c @@ -29,6 +29,9 @@ Struct_CCW_1B20_0 D_8038EC40[4] ={ {0x183, 1, 1, 0x000, 0x000, 0x00, 0} }; +// Anchor: set during a remote-water replay; skips camera/fanfare/jiggy spawn. +static s32 sFlowerRemoteGrow = 0; + ActorInfo D_8038EC70 = { 0x1B0, 0x29D, 0x447, 0x0, NULL, func_80388478, NULL, CCW_func_803882F4, 0, 0, 1.0f, 0}; f32 D_8038EC94[3] = {200.0f, 2120.0f, -5570.0f}; @@ -53,25 +56,29 @@ void func_80387F64(Actor *this, s32 next_state){ skeletalAnim_setBehavior(this->unk148, local->unk0->unk2); } if (next_state == 2) { - if (gsworld_getMap() == MAP_43_CCW_SPRING) { + if (gsworld_getMap() == MAP_43_CCW_SPRING && !sFlowerRemoteGrow) { coMusicPlayer_playMusic(COMUSIC_2D_PUZZLE_SOLVED_FANFARE, 28000); } fileProgressFlag_set(local->unk0->unk8, true); skeletalAnim_set(this->unk148, local->unk0->unk4, 0.0f, 6.0f); skeletalAnim_setBehavior(this->unk148, SKELETAL_ANIM_2_ONCE); - if (gsworld_getMap() == MAP_43_CCW_SPRING) { + if (gsworld_getMap() == MAP_43_CCW_SPRING && !sFlowerRemoteGrow) { func_80324E38(0.0f, 3); } - timed_setStaticCameraToNode(0.0f, 0); + if (!sFlowerRemoteGrow) { + timed_setStaticCameraToNode(0.0f, 0); + } for( phi_f22 = 0.0f; phi_f22 <= 1.0f; phi_f22 += 0.1) { timed_playSfx(phi_f22 * 5.7, 0x2C, phi_f22 * 0.3 + 0.7, (s32) (32000.0f - phi_f22 * 5000.0f)); } if (local->unk0->unkA != 0) { - timed_setStaticCameraToNode(6.0f, 1); - timedFunc_set_0(6.1f, (GenFunction_0)func_80387F10); + if (!sFlowerRemoteGrow) { + timed_setStaticCameraToNode(6.0f, 1); + timedFunc_set_0(6.1f, (GenFunction_0)func_80387F10); + } timedFunc_set_2(8.0f, (GenFunction_2)func_80387F38, (uintptr_t)this->marker, 3); } else { - if (gsworld_getMap() == MAP_43_CCW_SPRING) { + if (gsworld_getMap() == MAP_43_CCW_SPRING && !sFlowerRemoteGrow) { timed_exitStaticCamera(7.0f); func_80324E38(7.0f, 0); } @@ -166,5 +173,12 @@ void func_80388478(Actor *this) { else{ func_80387F64(this, 1); } + return; + } + + if ((this->state == 1) && EventSystem_Should(VB_CCW_FLOWER_REMOTE_GROW, false, (s32)local->unk0->unk8)) { + sFlowerRemoteGrow = 1; + func_80387F64(this, 2); + sFlowerRemoteGrow = 0; } } diff --git a/src/CCW/seasonal_switch.c b/src/CCW/seasonal_switch.c index e5a397dba..18b7b48d5 100644 --- a/src/CCW/seasonal_switch.c +++ b/src/CCW/seasonal_switch.c @@ -96,8 +96,16 @@ void func_80388FD4(Actor *this) { this->unk38_0 = false; this->volatile_initialized = true; } + // Anchor: teammate pressed this switch (flag synced) — drop it to match; unk38_0 stays false. + if( this->state != 4 + && fileProgressFlag_get(this->unk10_12 + FILEPROG_8B_CCW_SPRING_OPEN) + ){ + actor_playAnimationOnce(this); + subaddie_set_state_with_direction(this, 4, 0.999f, 1); + actor_collisionOff(this); + } if( (this->state == 4) - && this->unk38_0 + && this->unk38_0 && actor_animationIsAt(this, 0.999f) ){ func_802D6264(1.1f, 0x40, this->unk10_12 + 0x3C, 0x2B, D_8038ED10[this->unk10_12].unk3, this->unk10_12 + 0x8B); diff --git a/src/FINALE/ch/chbossjinjobase.c b/src/FINALE/ch/chbossjinjobase.c index f73718b4c..efb45d3b4 100644 --- a/src/FINALE/ch/chbossjinjobase.c +++ b/src/FINALE/ch/chbossjinjobase.c @@ -6,6 +6,8 @@ #include +#include "port/Network/Anchor/FightSync.h" + typedef struct { u8 sfxsourceIdx; } ActorLocal_BossJinjoBase; @@ -47,9 +49,15 @@ void chBossJinjoBase_func_8038D3DC(Actor *this, s32 arg1, f32 arg2, f32 arg3, f3 void chBossJinjoBase_getHitByEgg(ActorMarker *this, ActorMarker *other) { Actor *actor_bossjinjobase = marker_getActor(this); + // Anchor: follower forwards to authority; accepted egg replays here via EGG_FED (other == NULL). + if (other != NULL && FightSync_ForwardEgg(actor_bossjinjobase->actorTypeSpecificField, 0)) { + return; + } + if (actor_bossjinjobase->state != CHBOSSJINJOBASE_STATE_3_SPAWNED_BOSS_JINJO) { comusic_playTrack(COMUSIC_2B_DING_B); actor_bossjinjobase->unk38_31++; + FightSync_ReplicateEgg(actor_bossjinjobase->actorTypeSpecificField, 0); if (actor_bossjinjobase->unk38_31 >= 3) { subaddie_set_state(actor_bossjinjobase, CHBOSSJINJOBASE_STATE_3_SPAWNED_BOSS_JINJO); diff --git a/src/FINALE/ch/chfinalboss.c b/src/FINALE/ch/chfinalboss.c index 90aad6680..90e3d733d 100644 --- a/src/FINALE/ch/chfinalboss.c +++ b/src/FINALE/ch/chfinalboss.c @@ -6,6 +6,8 @@ #include +#include "port/Network/Anchor/FightSync.h" + extern bool func_8028F4B8(f32[3], f32, f32); extern int func_80320ED8(ActorMarker *, f32, s32); s32 subaddie_getYawToPosition(Actor*, f32*); @@ -20,6 +22,8 @@ extern void player_setIdealRotation(f32[3]); extern f32 func_8033229C(ActorMarker *); void func_8034DF30(Struct6Ds *, f32[3], f32[3], f32); +// ActorLocal_FinalBoss moved to fight.h for the Anchor fight-sync layer. +#if 0 typedef struct chfinalboss_s { u8 phase; u8 hits; @@ -46,6 +50,7 @@ typedef struct chfinalboss_s { f32 unk28; f32 unk2C; } ActorLocal_FinalBoss; +#endif f32 fight_D_80391380[4] = { 1.0f, 1.0f, 1.0f, 1.0f }; f32 fight_D_80391390[4] = { 0.33f, 0.33f, 0.33f, 1.0f }; @@ -140,6 +145,8 @@ f32 D_80392750; f32 D_80392758[3]; f32 D_80392768[3]; f32 D_80392778[3]; +// Anchor: lead time from the last local aim; followers reuse it to re-aim at their own player. +f32 __chFinalBossFireballFlightTime; f32 chFinalBossPlayerPosition[3]; f32 chFinalBossPosition[3]; ActorMarker *__chFinalBossShadowMarker; @@ -360,8 +367,13 @@ void __chfinalboss_dropHealth(ActorMarker *marker) { } void chfinalboss_despawnFlightPad(void) { + // Anchor: a follower that joined late never spawned one. + if (__chFinalBossFlightPadMarker == NULL) { + return; + } marker_despawn(__chFinalBossFlightPadMarker); __chFinalBossFlightPadMarker = NULL; + FightSync_OnFlightPadDespawned(); } void chfinalboss_spawnFlightPad(s32 arg0) { @@ -372,6 +384,7 @@ void chfinalboss_spawnFlightPad(s32 arg0) { flight_pad->alpha_124_19 = 0; flight_pad->unk38_31 = 6; __chFinalBossFlightPadMarker = flight_pad->marker; + FightSync_OnFlightPadSpawned(); } void chfinalboss_func_80386EC0(s32 arg0) { @@ -380,6 +393,8 @@ void chfinalboss_func_80386EC0(s32 arg0) { marker = actor_spawnWithYaw_f32(0x38A, D_80392758, 0)->marker; func_8030E878(SFX_147_GRUNTY_SPELL_ATTACK_2, randf2(0.95f, 1.05f), 32000, D_80392758, 5000.0f, 12000.0f); chGreenBlast_func_803900DC(marker, D_80392758, D_80392768[1], D_80392768[2]); + // Anchor: replay this green blast on followers with the exact same vectors. + FightSync_OnSpellSpawned(2); } void chfinalboss_func_80386F5C(ActorMarker * arg0, f32 arg1[3], f32 arg2, f32 arg3) { @@ -398,6 +413,8 @@ void chfinalboss_func_80386FD8(s32 arg0) { marker = actor_spawnWithYaw_f32(0x389, D_80392758, 0)->marker; func_8030E878(SFX_146_GRUNTY_SPELL_ATTACK_1, randf2(0.95f, 1.05f), 32000, D_80392758, 5000.0f, 12000.0f); chSpellFireball_func_8038FB84(marker, D_80392758, D_80392768, D_80392778); + // Anchor: replay this fireball on followers with the exact same vectors. + FightSync_OnSpellSpawned(0); } void chfinalboss_func_80387074(s32 arg0) { @@ -406,6 +423,8 @@ void chfinalboss_func_80387074(s32 arg0) { marker = actor_spawnWithYaw_f32(0x3AA, D_80392758, 0)->marker; func_8030E878(SFX_146_GRUNTY_SPELL_ATTACK_1, randf2(0.95f, 1.05f), 32000, D_80392758, 5000.0f, 12000.0f); chSpellFireball_func_8038FB84(marker, D_80392758, D_80392768, D_80392778); + // Anchor: replay this final-spell fireball on followers with the exact same vectors. + FightSync_OnSpellSpawned(1); } void chfinalboss_func_80387110(ActorMarker *marker, f32 arg1[3], f32 arg2, s32 arg3) { @@ -441,6 +460,7 @@ void chfinalboss_func_80387110(ActorMarker *marker, f32 arg1[3], f32 arg2, s32 a D_80392768[i] = (sp2C[i] - arg1[i]) / arg2 - (D_80392778[i] * arg2 / 2); } if (arg3 == 0) { + __chFinalBossFireballFlightTime = arg2; SPAWNQUEUE_ADD_1(chfinalboss_func_80386FD8, marker); } else{ @@ -1220,6 +1240,7 @@ void __chfinalboss_spawnStatue(enum ch_bossjinjo_e statue_id) { } sp1C->lifetime_value = (statue_id == BOSSJINJO_5_JINJONATOR) ? 5.25f : 1.54f; sp1C->actorTypeSpecificField = statue_id; + FightSync_OnStatueSpawned(statue_id); } void chfinalboss_spawnStatue(s32 statue_id) { @@ -1232,6 +1253,7 @@ void __chfinalboss_spawnSpellBarrier(ActorMarker *marker) { actor = marker_getActor(marker); actor->partnerActor = spawn_child_actor(ACTOR_3AB_GRUNTY_SPELL_BARRIER, &actor)->marker; __chFinalBossSpellBarrierActive = true; + FightSync_OnBarrierSpawned(); } void chfinalboss_spawnSpellBarrier(ActorMarker *arg0) { @@ -1546,6 +1568,8 @@ void chfinalboss_phase4_update(ActorMarker *marker) { sp70 = local->hits; sp6C = chfinalboss_findCollidingJinjo(this, func_8033229C(this->marker)); if (sp6C != NULL) { + // Anchor: only the authority detects the slam; despawn followers' copy of this jinjo too. + FightSync_OnJinjoSlam(marker_getActor(sp6C)->actorTypeSpecificField); chbossjinjo_attack(sp6C); if (!fileProgressFlag_get(FILEPROG_D1_HAS_ACTIVATED_A_JINJO_STATUE_IN_FINAL_FIGHT)) { fileProgressFlag_set(FILEPROG_D1_HAS_ACTIVATED_A_JINJO_STATUE_IN_FINAL_FIGHT, true); @@ -2020,6 +2044,10 @@ void chfinalboss_collisionPassive(ActorMarker *marker, ActorMarker *other_marker this = marker_getActor(marker); local = (ActorLocal_FinalBoss *)&this->local; + // Anchor: follower's hit is forwarded to the authority (with phase). + if (other_marker != NULL && FightSync_ForwardBossHit(local->phase)) { + return; + } switch (local->phase) { case 1: if (local->hits == 0) { @@ -2123,6 +2151,7 @@ void chfinalboss_update(Actor *this){ local->unk8 = 0; local->unk9 = 0; local->unkB = 0; + FightSync_OnBossSpawned(); for(i = 0; i < 4; i++){ __chFinalBossJinjoStatueMarker[i] = NULL; @@ -2148,6 +2177,8 @@ void chfinalboss_update(Actor *this){ timed_playSfx(2.0f, SFX_7F_HEAVYDOOR_SLAM, 1.0f, 32000); }//L8038BF0C + // Anchor: followers skip the boss brain - state rides FIGHT_UPDATE/FIGHT_EVENT instead. + if (!FightSync_BossFollowerTick(this)) switch(local->phase) { case FINALBOSS_PHASE_0_INTRO: chfinalboss_phase0_update(this->marker); @@ -2241,6 +2272,7 @@ void chfinalboss_setBossDefeated(void) { sp4C = actorArray_findActorFromActorId(ACTOR_38B_GRUNTILDA_FINAL_BOSS); sp48 = (ActorLocal_FinalBoss *)&sp4C->local; + FightSync_OnBossDefeated(); sp34 = chstonejinjo_getBreakUpTime(); temp_f20 = sp34 + chjinjonator_80391234(); sp40 = chjinjonator_80391240(); diff --git a/src/FINALE/ch/chjinjonatorbase.c b/src/FINALE/ch/chjinjonatorbase.c index e2d52a7e4..19b68b56c 100644 --- a/src/FINALE/ch/chjinjonatorbase.c +++ b/src/FINALE/ch/chjinjonatorbase.c @@ -4,6 +4,8 @@ #include "variables.h" #include "../fight.h" +#include "port/Network/Anchor/FightSync.h" + typedef struct { u8 egg_hits[4]; } ActorLocal_BossJinjonatorBase; @@ -42,18 +44,16 @@ void chjinjonatorbase_func_8038E0D4(Actor *arg0, s32 arg1, f32 arg2, f32 arg3, f } } -void chjinjonatorbase_getHitByEgg(ActorMarker *this, ActorMarker *other) { - Actor *actor_jinjonatorbase = marker_getActor(this); +static void __chjinjonatorbase_applyEgg(Actor *actor_jinjonatorbase, s32 indx) { ActorLocal_BossJinjonatorBase *local = (ActorLocal_BossJinjonatorBase *) &actor_jinjonatorbase->local; - int indx = this->unk40_31 - 1; s32 remaining_hits; - f32 pad; if (actor_jinjonatorbase->state != CHBOSSJINJOBASE_STATE_3_SPAWNED_BOSS_JINJO) { if (local->egg_hits[indx]) { local->egg_hits[indx]--; comusic_playTrack(COMUSIC_2B_DING_B); - + FightSync_ReplicateEgg(BOSSJINJO_5_JINJONATOR, indx); + if (local->egg_hits[indx] <= 0) { chjinjonatorbase_func_8038E0D4(actor_jinjonatorbase, indx + 0x19a, -100.0f, 0.0f, 1.2f); func_80324D54(1.2f, SFX_90_SWITCH_PRESS, 1.0f, 32000, actor_jinjonatorbase->position, 1000.0f, 2000.0f); @@ -70,6 +70,46 @@ void chjinjonatorbase_getHitByEgg(ActorMarker *this, ActorMarker *other) { } } +void chjinjonatorbase_getHitByEgg(ActorMarker *this, ActorMarker *other) { + Actor *actor_jinjonatorbase = marker_getActor(this); + int indx = this->unk40_31 - 1; + + // Anchor: follower forwards to authority; accepted egg replays via EGG_FED. + if (other != NULL && FightSync_ForwardEgg(BOSSJINJO_5_JINJONATOR, indx)) { + return; + } + + __chjinjonatorbase_applyEgg(actor_jinjonatorbase, indx); +} + +// Anchor: remaining-egg count per pad for the latecomer snapshot; false if pedestal isn't up. +bool chjinjonatorbase_netGetPads(u8 pads[4]) { + Actor *actor_jinjonatorbase = actorArray_findActorFromActorId(ACTOR_3A9_JINJONATOR_STATUE_BASE); + ActorLocal_BossJinjonatorBase *local; + s32 i; + + if (actor_jinjonatorbase == NULL || actor_jinjonatorbase->despawn_flag) { + for (i = 0; i < 4; i++) { + pads[i] = 5; + } + return false; + } + local = (ActorLocal_BossJinjonatorBase *) &actor_jinjonatorbase->local; + for (i = 0; i < 4; i++) { + pads[i] = local->egg_hits[i]; + } + return true; +} + +void chjinjonatorbase_netApplyEgg(s32 pad_index) { + Actor *actor_jinjonatorbase = actorArray_findActorFromActorId(ACTOR_3A9_JINJONATOR_STATUE_BASE); + + if (actor_jinjonatorbase == NULL || pad_index < 0 || pad_index >= 4) { + return; + } + __chjinjonatorbase_applyEgg(actor_jinjonatorbase, pad_index); +} + void chjinjonatorbase_spawnActivator(ActorMarker *marker) { Actor *sp24 = marker_getActor(marker); diff --git a/src/FINALE/fight.h b/src/FINALE/fight.h index d0bcd7bda..63a1e6794 100644 --- a/src/FINALE/fight.h +++ b/src/FINALE/fight.h @@ -84,6 +84,34 @@ extern ActorInfo chGreenBlast; extern ActorInfo chJinjonator; extern ActorInfo chBossShadow; +// Moved from chfinalboss.c for the Anchor fight-sync layer. +typedef struct chfinalboss_s { + u8 phase; + u8 hits; + u8 unk2; + u8 unk3; + u8 unk4; + u8 unk5; + u8 player_hit_in_phase3; + u8 mirror_phase5; + u8 unk8; + u8 unk9; + u8 unkA; + u8 unkB; + u8 unkC; + u8 unkD; + u8 unkE; + u8 unkF; + s32 player_hit_in_phase1; + f32 unk14; + f32 unk18; + f32 unk1C; + f32 unk20; + u8 pad24[4]; + f32 unk28; + f32 unk2C; +} ActorLocal_FinalBoss; + // fight.c extern void fight_addSpawnableActors(void); diff --git a/src/FP/ch/bearcub.c b/src/FP/ch/bearcub.c index d6ebfc6b6..553c070e8 100644 --- a/src/FP/ch/bearcub.c +++ b/src/FP/ch/bearcub.c @@ -3,6 +3,9 @@ #include "functions.h" #include "variables.h" +#include "port/Patches/Patches.h" +#include "port/Enhancements/Retention/Retention.h" + extern void func_8028E668(f32[3], f32, f32, f32); extern bool player_setCarryObjectPoseInHorizontalRadius(f32[3], f32, s32, Actor **); @@ -47,6 +50,26 @@ Struct_FP_3E00 D_80391E80[] ={ {LEVEL_FLAG_13_FP_UNKNOWN, MARKER_1FF_RED_PRESENT_COLLECTIBLE, ACTOR_1F1_RED_PRESENT_COLLECTIBLE, 0x1F2} }; +static const struct { + s32 bit; + s32 kind; + s32 item; +} sCubPresentSync[3] = { + { 0x1, ANCHOR_COLLECTIBLE_PRESENT_BLUE, ITEM_20_BLUE_PRESENT }, + { 0x2, ANCHOR_COLLECTIBLE_PRESENT_GREEN, ITEM_1F_GREEN_PRESENT }, + { 0x4, ANCHOR_COLLECTIBLE_PRESENT_RED, ITEM_21_RED_PRESENT }, +}; + +// D_80391E80 row for this cub, or -1. Same mapping the state machine derives inline (sp3C). +static s32 __chBearcub_cubIndex(Actor *this) { + switch (this->marker->id) { + case MARKER_1FA_POLAR_BEAR_CUB_BLUE: return 0; + case MARKER_1FB_POLAR_BEAR_CUB_GREEN: return 1; + case MARKER_1FC_POLAR_BEAR_CUB_RED: return 2; + } + return -1; +} + /* .code */ void func_8038A1F0(Actor **this_ptr, enum marker_e carried_obj_marker_id, enum actor_e actor_id, enum actor_e arg3){ player_setCarryObjectPoseInHorizontalRadius((*this_ptr)->position, 600.0f, actor_id, this_ptr); @@ -122,8 +145,37 @@ void func_8038A384(Actor *this){ ){ subaddie_set_state_with_direction(this, 2, randf2(0.0f, 0.9f), 1); } + + // Anchor: reconcile the shared present pool — carried = collected minus delivered. + { + s32 cubIdx = __chBearcub_cubIndex(this); + if (cubIdx >= 0) { + s32 netBits = port_puzzleStep_get(ANCHOR_PUZZLE_FP_PRESENTS); + s32 have = item_getCount(sCubPresentSync[cubIdx].item); + s32 pool = port_carriedSync_collectedCount(sCubPresentSync[cubIdx].kind) - + ((netBits & sCubPresentSync[cubIdx].bit) ? 1 : 0); + if (pool > have) { + item_adjustByDiffWithoutHud(sCubPresentSync[cubIdx].item, pool - have); + } + } + } }//L8038A4E4 + { + s32 cubIdx = __chBearcub_cubIndex(this); + if (cubIdx >= 0) { + s32 netBits; + if (levelSpecificFlags_get(D_80391E80[cubIdx].unk0)) { + port_puzzleStep_orBits(ANCHOR_PUZZLE_FP_PRESENTS, sCubPresentSync[cubIdx].bit); + } + netBits = port_puzzleStep_get(ANCHOR_PUZZLE_FP_PRESENTS); + if ((netBits & sCubPresentSync[cubIdx].bit) && !levelSpecificFlags_get(D_80391E80[cubIdx].unk0)) { + levelSpecificFlags_setEx(D_80391E80[cubIdx].unk0, 1, 0); + subaddie_set_state_with_direction(this, 2, 0.001f, 1); + } + } + } + sp34 = levelSpecificFlags_get(LEVEL_FLAG_11_FP_UNKNOWN) + levelSpecificFlags_get(LEVEL_FLAG_12_FP_UNKNOWN) + levelSpecificFlags_get(LEVEL_FLAG_13_FP_UNKNOWN); sp38 = (sp34 == 1) ? ASSET_C17_DIALOG_BOGGY_KIDS_PRESENT_RECEIVED_1 : (sp34 == 2) ? ASSET_C18_DIALOG_BOGGY_KIDS_PRESENT_RECEIVED_2 diff --git a/src/FP/ch/snowmanbutton.c b/src/FP/ch/snowmanbutton.c index 08e55fab0..3e2f8612a 100644 --- a/src/FP/ch/snowmanbutton.c +++ b/src/FP/ch/snowmanbutton.c @@ -3,6 +3,8 @@ #include "functions.h" #include "variables.h" +#include "port/Patches/Patches.h" + Actor *func_80386B80(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx); void FP_func_80386CF8(Actor *this); @@ -89,6 +91,18 @@ void FP_func_80386CF8(Actor *this){ } } + { + s32 bit = 1 << (this->actorTypeSpecificField - 1); + if(this->state == 1 && (port_puzzleStep_get(ANCHOR_PUZZLE_FP_SNOWBUTTONS) & bit)){ + subaddie_set_state_with_direction(this, 2, 0.01f, 1); + actor_collisionOff(this); + maSnowButton_decRemaining(); + } + if(this->state != 1){ + port_puzzleStep_orBits(ANCHOR_PUZZLE_FP_SNOWBUTTONS, bit); + } + } + switch(this->state){ case 1: break; diff --git a/src/FP/ch/twinklybox.c b/src/FP/ch/twinklybox.c index 875777158..a63d7f123 100644 --- a/src/FP/ch/twinklybox.c +++ b/src/FP/ch/twinklybox.c @@ -3,6 +3,8 @@ #include "functions.h" #include "variables.h" +#include "port/Patches/Patches.h" + extern void func_80324CD8(f32); extern Actor *actor_spawnWithYaw_f32(enum actor_e, f32[3], s32); @@ -239,7 +241,8 @@ void chTwinklyBox_spawnTwinkly(ActorMarker *marker){ void chTwinklyBox_completeMinigame(ActorMarker *marker){ Actor *this = marker_getActor(marker); - + + port_fpTwinkly_release(); item_set(ITEM_6_HOURGLASS, false); fileProgressFlag_set(FILEPROG_13_COMPLETED_TWINKLIES_MINIGAME, true); FUNC_8030E624(SFX_416_ELECTRIC_ZAP, 0.8f, 32000); @@ -257,6 +260,10 @@ void chTwinklyBox_activateBox(ActorMarker *this_marker, ActorMarker *other_marke Actor *this = marker_getActor(this_marker); if(this->state == 1 || this->state == 2){ + // Anchor: only one client may run this minigame at a time — claim it or block if already held. + if(!EventSystem_Should(VB_FP_TWINKLY_START, true)){ + return; + } actor_collisionOff(this); timed_setStaticCameraToNode(0.0f, 0xa); func_80324CD8(0.1f); @@ -394,6 +401,7 @@ void chTwinklyBox_update(Actor *this){ } if(item_empty(ITEM_6_HOURGLASS)){ + port_fpTwinkly_release(); subaddie_set_state_with_direction(this, 1, 0.001f, 0); actor_playAnimationOnce(this); this->unk38_31 = 0; diff --git a/src/FP/ch/xmastree.c b/src/FP/ch/xmastree.c index ea658f78c..58c66189d 100644 --- a/src/FP/ch/xmastree.c +++ b/src/FP/ch/xmastree.c @@ -3,6 +3,8 @@ #include "functions.h" #include "variables.h" +#include "port/Patches/Patches.h" + Actor *chXmasTree_draw(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx); void chXmasTree_update(Actor *this); @@ -109,6 +111,16 @@ void chXmasTree_update(Actor *this){ this->depth_mode = 1; + // Anchor: teammate finished the star minigame — light the tree locally and stop our countdown if running. + if (!levelSpecificFlags_get(LEVEL_FLAG_29_FP_XMAS_TREE_COMPLETE) + && (port_puzzleStep_getForMap(MAP_53_FP_CHRISTMAS_TREE, ANCHOR_PUZZLE_FP_TREE_ICE) & 0x1)) { + levelSpecificFlags_set(LEVEL_FLAG_29_FP_XMAS_TREE_COMPLETE, true); + if (this->state == 4) { + item_set(ITEM_6_HOURGLASS, false); + mapSpecificFlags_set(2, false); + } + } + if (jiggyscore_isCollected(JIGGY_2F_FP_XMAS_TREE) || levelSpecificFlags_get(LEVEL_FLAG_29_FP_XMAS_TREE_COMPLETE)) { __chXmasTree_80386EF4(this, 1); return; diff --git a/src/FP/ch/xmastreeice.c b/src/FP/ch/xmastreeice.c index beaaae180..dc73e9674 100644 --- a/src/FP/ch/xmastreeice.c +++ b/src/FP/ch/xmastreeice.c @@ -3,6 +3,12 @@ #include "functions.h" #include "variables.h" +#include "port/Patches/Patches.h" + +typedef struct { + u8 initShatter; // took the warped-in cutscene path at init; suppresses the live shatter +} ActorLocal_XmasTreeIce; + Actor *chXmasTreeIce_draw(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx); void chXmasTreeIce_update(Actor *this); @@ -68,6 +74,8 @@ void chXmasTreeIce_shatterIce(ActorMarker *marker){ func_8030E6D4(SFX_B6_GLASS_BREAKING_1); coMusicPlayer_playMusic(COMUSIC_2D_PUZZLE_SOLVED_FANFARE, 28000); this->unk38_31 = 1; + // Anchor: broadcast the shatter; LEVEL_FLAG_29 stays local. + port_puzzleStep_orBits(ANCHOR_PUZZLE_FP_TREE_ICE, 0x1); } void chXmasTreeIce_returnCameraToBanjo(ActorMarker *marker){ @@ -85,6 +93,7 @@ void chXmasTreeIce_initiateShatter(Actor *this){ } void chXmasTreeIce_update(Actor *this) { + ActorLocal_XmasTreeIce *local = (ActorLocal_XmasTreeIce *)&this->local; this->marker->propPtr->unk8_3 = true; actor_collisionOff(this); @@ -94,8 +103,22 @@ void chXmasTreeIce_update(Actor *this) { if (jiggyscore_isCollected(JIGGY_2F_FP_XMAS_TREE)) { marker_despawn(this->marker); } + else if (port_puzzleStep_get(ANCHOR_PUZZLE_FP_TREE_ICE) & 0x1) { + if (!levelSpecificFlags_get(LEVEL_FLAG_29_FP_XMAS_TREE_COMPLETE)) { + levelSpecificFlags_set(LEVEL_FLAG_29_FP_XMAS_TREE_COMPLETE, true); + } + marker_despawn(this->marker); + } else if (levelSpecificFlags_get(LEVEL_FLAG_29_FP_XMAS_TREE_COMPLETE)) { + local->initShatter = 1; chXmasTreeIce_initiateShatter(this); } } + else if (!local->initShatter && this->unk38_31 == 0 + && (port_puzzleStep_get(ANCHOR_PUZZLE_FP_TREE_ICE) & 0x1)) { + if (!levelSpecificFlags_get(LEVEL_FLAG_29_FP_XMAS_TREE_COMPLETE)) { + levelSpecificFlags_set(LEVEL_FLAG_29_FP_XMAS_TREE_COMPLETE, true); + } + chXmasTreeIce_shatterIce(this->marker); + } } diff --git a/src/GV/actor_spawninit.c b/src/GV/actor_spawninit.c index f96c415f9..75cbb7665 100644 --- a/src/GV/actor_spawninit.c +++ b/src/GV/actor_spawninit.c @@ -7,6 +7,8 @@ #include +#include "port/Patches/Patches.h" + extern void core1_7090_initSfxSource(s32, s32, s32, f32); extern void func_802D3D54(Actor *this); extern void func_802D3D74(Actor *this); @@ -175,12 +177,23 @@ void func_8038E430(Actor *this){ void func_8038E460(Actor *this){//banjo_door func_802D3D74(this); + // Anchor: flag 0x10 is transient, doesn't survive reload. + if(mapSpecificFlags_get(0x10)){ + if(!(port_puzzleStep_get(ANCHOR_PUZZLE_GV_JINXY_DOOR) & 1)){ + port_puzzleStep_orBits(ANCHOR_PUZZLE_GV_JINXY_DOOR, 1); + } + } else if(port_puzzleStep_get(ANCHOR_PUZZLE_GV_JINXY_DOOR) & 1){ + mapSpecificFlags_set(0x10, true); + mapSpecificFlags_set(2, true); + } if(mapSpecificFlags_get(0x10)){ func_8038E430(this); if(!mapSpecificFlags_get(2)){ mapSpecificFlags_set(2, true); - func_8028F918(0); - func_80324DBC(4.0f, ASSET_A7D_DIALOG_JINXY_HELPED, 4, NULL, NULL, NULL, NULL); + if(EventSystem_Should(VB_DOOR_OPEN_CAMERA, true, GV_DOOR_CAM_JINXY)){ + func_8028F918(0); + func_80324DBC(4.0f, ASSET_A7D_DIALOG_JINXY_HELPED, 4, NULL, NULL, NULL, NULL); + } } } } @@ -218,7 +231,8 @@ void func_8038E4DC(Actor *this){ else{ if(!mapSpecificFlags_get(4)){ mapSpecificFlags_set(4, true); - gcStaticCamera_activate(1); + if(EventSystem_Should(VB_DOOR_OPEN_CAMERA, true, GV_DOOR_CAM_SUN)) + gcStaticCamera_activate(1); } } } @@ -231,7 +245,8 @@ void func_8038E648(Actor *this){ case 1: //L8038E690 this->pitch = 0.0f; if(mapSpecificFlags_get(5)){ - gcStaticCamera_activate(2); + if(EventSystem_Should(VB_DOOR_OPEN_CAMERA, true, GV_DOOR_CAM_STAR)) + gcStaticCamera_activate(2); subaddie_set_state(this, 6); core1_7090_initSfxSource(0, 0x6A, 0x7ff8, 0.3f); s32 pyramidTimer = 25; @@ -333,7 +348,8 @@ void chKazooieDoor_update(Actor *this){ case 1: //L8038EB98 if(mapSpecificFlags_get(6)){ coMusicPlayer_playMusic(COMUSIC_2B_DING_B, -1); - gcStaticCamera_activate(3); + if(EventSystem_Should(VB_DOOR_OPEN_CAMERA, true, GV_DOOR_CAM_KAZOOIE)) + gcStaticCamera_activate(3); subaddie_set_state(this, 6); core1_7090_initSfxSource(1, 0x6a, 0x7ff8, 0.3f); this->unk1C[1] = this->position_y + 210.0f; diff --git a/src/GV/ch/ancientone.c b/src/GV/ch/ancientone.c index 6301e28b7..96ada5f56 100644 --- a/src/GV/ch/ancientone.c +++ b/src/GV/ch/ancientone.c @@ -120,20 +120,43 @@ void chAncientOne_update(Actor *this){ } } if(!this->initialized){ - if(D_80390C28[this->actorTypeSpecificField - 1]) + if(D_80390C28[this->actorTypeSpecificField - 1] == NULL){ + LOCAL_CH_ANCIENT_ONE(this)->unk1C = this->position_y; + this->position_y -= 1100.0f; + D_80390C28[this->actorTypeSpecificField - 1] = this->marker; + if(this->actorTypeSpecificField != 1){ + this->marker->propPtr->isNotFeatherEggOrNote = false; + } + this->marker->propPtr->unk8_3 = true; + actor_collisionOff(this); + func_80386620(this); return; - - LOCAL_CH_ANCIENT_ONE(this)->unk1C = this->position_y; - this->position_y -= 1100.0f; - D_80390C28[this->actorTypeSpecificField - 1] = this->marker; - if(this->actorTypeSpecificField != 1){ - this->marker->propPtr->isNotFeatherEggOrNote = false; } - this->marker->propPtr->unk8_3 = true; - actor_collisionOff(this); - func_80386620(this); + { + s32 fc = 0, fi; + for(fi = 7; fi < 0xC && mapSpecificFlags_get(fi); fi++) fc++; + if(fc == 0){ + return; + } + } } - else{//L803869B4 + {//L803869B4 + if(jiggyscore_isSpawned(JIGGY_46_GV_ANCIENT_ONES)){ + marker_despawn(this->marker); + return; + } + // Anchor: ring order is randomized per-client; advance by synced-flag count. + { + s32 fc = 0, fi; + for(fi = 7; fi < 0xC && mapSpecificFlags_get(fi); fi++) fc++; + if(this->state == 1 && this->actorTypeSpecificField <= fc){ + subaddie_set_state_with_direction(this, 2, 0.0f, 1); + actor_playAnimationOnce(this); + if(this->actorTypeSpecificField < 5 && D_80390C28[this->actorTypeSpecificField]){ + D_80390C28[this->actorTypeSpecificField]->propPtr->isNotFeatherEggOrNote = true; + } + } + } switch(this->state){ case 1: //L803869E4 player_getPosition(sp44); diff --git a/src/GV/ch/buriedpyramid.c b/src/GV/ch/buriedpyramid.c index 42f705b88..d342ff3f5 100644 --- a/src/GV/ch/buriedpyramid.c +++ b/src/GV/ch/buriedpyramid.c @@ -67,6 +67,13 @@ void chBuriedPyramid_update(Actor *this){ __chBuriedPyramid_setState(this, 1); }//L8038FE48 + if(this->state == 1){ + s32 flagState = fileProgressFlag_getN(FILEPROG_F8_KING_SANDYBUTT_PYRAMID_STATE, 2); + if(flagState > local->raised_state){ + chBuriedPyramid_setRaisedAmount(this->marker, flagState); + } + } + if(this->state == 2){ local->transistion_timer += time_getDelta()/3.0f; if(1.0f < local->transistion_timer) diff --git a/src/GV/ch/carpet2.c b/src/GV/ch/carpet2.c index 0ddd062c0..fe8a39cb9 100644 --- a/src/GV/ch/carpet2.c +++ b/src/GV/ch/carpet2.c @@ -89,9 +89,11 @@ void func_8038D47C(Actor *this){ } else if(!mapSpecificFlags_get(0xF) && mapSpecificFlags_get(0) + mapSpecificFlags_get(1) == 2){ mapSpecificFlags_set(0xF, true); - func_8028F918(2); + if(EventSystem_Should(VB_DOOR_OPEN_CAMERA, true, GV_DOOR_CAM_JINXY)){ + func_8028F918(2); + gcStaticCamera_activate(0); + } subaddie_set_state_forward(this, 3); - gcStaticCamera_activate(0); } break; case 2: //L8038D78C diff --git a/src/GV/pyramid_raise.c b/src/GV/pyramid_raise.c index 355f171b7..cc644b3c8 100644 --- a/src/GV/pyramid_raise.c +++ b/src/GV/pyramid_raise.c @@ -185,6 +185,11 @@ void func_8038CC98(Actor *this){ local->unk14 = actorArray_findActorFromActorId(ACTOR_31D_SANDYBUTT_PYRAMID)->marker; } + if(this->state != 8 && fileProgressFlag_getN(FILEPROG_F8_KING_SANDYBUTT_PYRAMID_STATE, 2) > *local->unk8){ + func_8038C8A0(this, 8); + return; + } + if(this->state == 1){ if(fileProgressFlag_getN(FILEPROG_F8_KING_SANDYBUTT_PYRAMID_STATE, 2) == *local->unk8){ func_8038C8A0(this, 2); diff --git a/src/GV/water_pyramidrot.c b/src/GV/water_pyramidrot.c index 67dec578d..ec385dd8f 100644 --- a/src/GV/water_pyramidrot.c +++ b/src/GV/water_pyramidrot.c @@ -4,6 +4,8 @@ #include "variables.h" +static s32 sGvPyramidRaised = 0; + void func_8038FF60(void){} void func_8038FF68(void){ @@ -15,11 +17,27 @@ void func_8038FF68(void){ if(jiggyscore_isCollected(JIGGY_42_GV_WATER_PYRAMID)){ tmp_s70 = func_8034C528(0x190); if(tmp_s70) subaddie_positionMoveVertical(&tmp_s70->type_6D, 0.0f, 270.0f, 0.0f, 1); + sGvPyramidRaised = 1; } else{ tmp_s70 = func_8034C5AC(0x130); if(tmp_s70) func_8034E71C(&tmp_s70->type_73, -1500, 0.0f); + sGvPyramidRaised = 0; } } -void func_8038FFF4(void){} +void func_8038FFF4(void){ + Struct70s *tmp_s70; + + // LEVEL_FLAG_6 = local rise cutscene in progress. + if(sGvPyramidRaised) return; + if(gsworld_getMap() != MAP_12_GV_GOBIS_VALLEY) return; + if(levelSpecificFlags_get(LEVEL_FLAG_6_GV_UNKNOWN)) return; + if(!jiggyscore_isCollected(JIGGY_42_GV_WATER_PYRAMID)) return; + + tmp_s70 = func_8034C5AC(0x130); + if(tmp_s70) func_8034E71C(&tmp_s70->type_73, 0, 2.5f); + tmp_s70 = func_8034C528(0x190); + if(tmp_s70) subaddie_positionMoveVertical(&tmp_s70->type_6D, 0.0f, 270.0f, 2.5f, 1); + sGvPyramidRaised = 1; +} diff --git a/src/LAIR/actor_spawninit.c b/src/LAIR/actor_spawninit.c index 5679de22d..2be3d8338 100644 --- a/src/LAIR/actor_spawninit.c +++ b/src/LAIR/actor_spawninit.c @@ -17,6 +17,7 @@ extern void func_80324CFC(f32, enum comusic_e, s32); extern int actor_animationIsAt(Actor *, f32); extern void subaddie_set_state_with_direction(Actor *, s32, f32, s32); extern void func_8033A45C(s32, s32); +extern ActorArray *suBaddieActorArray; @@ -216,11 +217,26 @@ s32 D_80393504[4] = {0x87, 0x87, 0x87, 0xB4}; //chcobweb void chFloorCobweb_update(Actor *this) { + enum file_progress_e brokenFlag = (this->actorTypeSpecificField == 1) + ? FILEPROG_CB_LAIR_COBWEB_OVER_FLIGHTPAD_BROKEN + : FILEPROG_CC_LAIR_COBWEB_OVER_GREEN_CAULDRON_BROKEN; + if(!this->initialized) { func_802D3CE8(this); - if (fileProgressFlag_get(this->actorTypeSpecificField == 1 ? FILEPROG_CB_LAIR_COBWEB_OVER_FLIGHTPAD_BROKEN : FILEPROG_CC_LAIR_COBWEB_OVER_GREEN_CAULDRON_BROKEN)) + if (fileProgressFlag_get(brokenFlag)) + { + marker_despawn(this->marker); + return; + } + } + + // Anchor: re-check on scene-return restore, which resets volatile_initialized but not initialized. + if (!this->volatile_initialized) + { + this->volatile_initialized = true; + if (fileProgressFlag_get(brokenFlag)) { marker_despawn(this->marker); return; @@ -251,6 +267,17 @@ void chWallCobweb_update(Actor *this) } } + // [port] Re-check on scene-return restore (see chFloorCobweb_update). + if (!this->volatile_initialized) + { + this->volatile_initialized = true; + if (fileProgressFlag_get(FILEPROG_CA_COBWEB_BLOCKING_PURPLE_CAULDRON_BROKEN)) + { + marker_despawn(this->marker); + return; + } + } + if (this->state == 0xF) { if (actor_animationIsAt(this, 0.9f)) @@ -263,11 +290,26 @@ void chWallCobweb_update(Actor *this) void lair_func_80386550(Actor *this) { + enum file_progress_e brokenFlag = (this->actorTypeSpecificField == 1) + ? FILEPROG_C8_LAIR_BRICKWALL_TO_WADINGBOOTS_BROKEN + : FILEPROG_C9_LAIR_BRICKWALL_TO_SHOCKJUMP_PAD_BROKEN; + if (!this->initialized) { func_802D3CE8(this); - if (fileProgressFlag_get(this->actorTypeSpecificField == 1 ? FILEPROG_C8_LAIR_BRICKWALL_TO_WADINGBOOTS_BROKEN : FILEPROG_C9_LAIR_BRICKWALL_TO_SHOCKJUMP_PAD_BROKEN)) + if (fileProgressFlag_get(brokenFlag)) + { + marker_despawn(this->marker); + return; + } + } + + // [port] Re-check on scene-return restore (see chFloorCobweb_update). + if (!this->volatile_initialized) + { + this->volatile_initialized = true; + if (fileProgressFlag_get(brokenFlag)) { marker_despawn(this->marker); return; @@ -658,6 +700,7 @@ void func_80387730(Actor *this) { s32 phi_s4; s32 sp6C[3]; f32 sp60[3]; + s32 forceOpen; func_802D3D74(this); if (!this->volatile_initialized) { @@ -684,15 +727,18 @@ void func_80387730(Actor *this) { this->unk1C[1] = 0.0f; this->unk1C[2] = 3.5f; } - if (!fileProgressFlag_get(this->actorTypeSpecificField + FILEPROG_39_CCW_OPEN) && ability_isUnlocked(ABILITY_13_1ST_NOTEDOOR)) { + // Anchor: unk1C[0] set by port_notedoor_remoteOpen = a teammate opened this door. + forceOpen = (this->unk1C[0] != 0.0f); + if (forceOpen || + (!fileProgressFlag_get(this->actorTypeSpecificField + FILEPROG_39_CCW_OPEN) && ability_isUnlocked(ABILITY_13_1ST_NOTEDOOR))) { player_getPosition(spAC); - if ((ml_vec3f_distance(spAC, this->position) < 500.0f) && (gcdialog_getCurrentTextId() != 0xF64)) { + if (!forceOpen && (ml_vec3f_distance(spAC, this->position) < 500.0f) && (gcdialog_getCurrentTextId() != 0xF64)) { code_73640_printItemCount(0xC); } doorIdx = this->actorTypeSpecificField - 1; noteThreshold = port_getRomhackNoteDoor(doorIdx); if (noteThreshold < 0) { noteThreshold = D_8039347C[doorIdx]; } - if (itemscore_noteScores_getTotal() >= noteThreshold) { + if (forceOpen || itemscore_noteScores_getTotal() >= noteThreshold) { if (this->marker->unk14_21) { func_8032BC60(this, 5, sp90); func_8032BC60(this, 6, sp84); @@ -705,11 +751,13 @@ void func_80387730(Actor *this) { phi_f20 = 290.0f; } sp9C[1] = this->position[1]; - if ((ml_vec3f_distance(spAC, sp9C) < phi_f20) || (this->alpha_124_19 != 0xFF)) { + if (forceOpen || (ml_vec3f_distance(spAC, sp9C) < phi_f20) || (this->alpha_124_19 != 0xFF)) { if (this->alpha_124_19 == 0xFF) { func_80324CFC(0.0f, COMUSIC_43_ENTER_LEVEL_GLITTER, 32700); func_80324D2C(2.4f, COMUSIC_43_ENTER_LEVEL_GLITTER); - func_8028F918(2); + if (!forceOpen) { + func_8028F918(2); + } } if (this->alpha_124_19 < 7U) { this->alpha_124_19 = 0; @@ -717,10 +765,14 @@ void func_80387730(Actor *this) { this->alpha_124_19 -= 7; } if (this->alpha_124_19 == 0) { - fileProgressFlag_set(this->actorTypeSpecificField + FILEPROG_39_CCW_OPEN, true); + if (!forceOpen) { + fileProgressFlag_set(this->actorTypeSpecificField + FILEPROG_39_CCW_OPEN, true); + } marker_despawn(this->marker); - func_8028F918(0); - func_8028F66C(BS_INTR_35); + if (!forceOpen) { + func_8028F918(0); + func_8028F66C(BS_INTR_35); + } return; } if (this->marker->unk14_21) { @@ -752,6 +804,27 @@ void func_80387730(Actor *this) { } } +void port_notedoor_remoteOpen(s32 progressFlag) { + s32 field; + s32 i; + + if (progressFlag < FILEPROG_3A_NOTE_DOOR_50_OPEN || progressFlag > FILEPROG_45_NOTE_DOOR_882_OPEN) { + return; + } + if (suBaddieActorArray == NULL) { + return; + } + field = progressFlag - FILEPROG_39_CCW_OPEN; + for (i = 0; i < suBaddieActorArray->cnt; i++) { + Actor *actor = &suBaddieActorArray->data[i]; + if (actor->marker != NULL && actor->modelCacheIndex == ACTOR_203_NOTE_DOOR && + actor->actorTypeSpecificField == field) { + actor->unk1C[0] = 1.0f; // picked up by func_80387730 next update + return; + } + } +} + //chnotedoor_draw @@ -950,7 +1023,10 @@ void func_803882B0(Actor *this) this->lifetime_value = 0; } - if (this->pitch == 90.f || !volatileFlag_get(VOLATILE_FLAG_BB_WITCH_SWITCH_PRESSED_FP)) + // Anchor: also honor persistent FILEPROG_47; VOLATILE_FLAG_BB is transient. + if (this->pitch == 90.f + || !(volatileFlag_get(VOLATILE_FLAG_BB_WITCH_SWITCH_PRESSED_FP) + || fileProgressFlag_get(FILEPROG_47_FP_WITCH_SWITCH_JIGGY_PRESSED))) return; if (this->pitch == 0) @@ -980,6 +1056,40 @@ void func_80388404(enum file_progress_e progress_flag, enum sfx_e sfx, f32 a2, s fileProgressFlag_set(progress_flag, true); } +static s32 sRemoteOpenDoorActor = 0; + +static enum file_progress_e __leveldoor_persistentFlag(s32 actorId) { + switch (actorId) { + case ACTOR_20E_MM_ENTRANCE_DOOR: return FILEPROG_31_MM_OPEN; + case ACTOR_211_TTC_ENTRANCE_CHEST_LID: return FILEPROG_32_TTC_OPEN; + case ACTOR_212_CC_ENTRANCE_BARS: return FILEPROG_33_CC_OPEN; + case ACTOR_210_BGS_ENTRANCE_DOOR: return FILEPROG_34_BGS_OPEN; + case ACTOR_235_FP_ENTRANCE_DOOR_LEFT: return FILEPROG_35_FP_OPEN; + case ACTOR_226_GV_ENTRANCE: return FILEPROG_36_GV_OPEN; + case ACTOR_228_MMM_ENTRANCE_DOOR: return FILEPROG_37_MMM_OPEN; + case ACTOR_20F_RBB_ENTRANCE_DOOR: return FILEPROG_38_RBB_OPEN; + case ACTOR_234_CCW_ENTRANCE_DOOR: return FILEPROG_39_CCW_OPEN; + case ACTOR_2E5_DOOR_OF_GRUNTY: return FILEPROG_E2_DOOR_OF_GRUNTY_OPEN; + default: return 0; + } +} + +void port_leveldoor_remoteOpen(s32 progressFlag) { + switch (progressFlag) { + case 0x28: sRemoteOpenDoorActor = ACTOR_20E_MM_ENTRANCE_DOOR; break; + case 0x29: sRemoteOpenDoorActor = ACTOR_211_TTC_ENTRANCE_CHEST_LID; break; + case 0x2A: sRemoteOpenDoorActor = ACTOR_212_CC_ENTRANCE_BARS; break; + case 0x2B: sRemoteOpenDoorActor = ACTOR_210_BGS_ENTRANCE_DOOR; break; + case 0x2C: sRemoteOpenDoorActor = ACTOR_235_FP_ENTRANCE_DOOR_LEFT; break; + case 0x2D: sRemoteOpenDoorActor = ACTOR_226_GV_ENTRANCE; break; + case 0x2E: sRemoteOpenDoorActor = ACTOR_228_MMM_ENTRANCE_DOOR; break; + case 0x2F: sRemoteOpenDoorActor = ACTOR_20F_RBB_ENTRANCE_DOOR; break; + case 0x30: sRemoteOpenDoorActor = ACTOR_234_CCW_ENTRANCE_DOOR; break; + case 0xE2: sRemoteOpenDoorActor = ACTOR_2E5_DOOR_OF_GRUNTY; break; + default: break; + } +} + void func_80388450(Actor *actor1, Actor *actor2) { f32 vec1[3]; @@ -1009,13 +1119,24 @@ void func_80388524(Actor *this) { ParticleEmitter *sp2C; Actor *sp28; - sp34 = func_802D677C(-1) + sp34 = func_802D677C(-1) && (func_802D677C(-1) == gsworld_getMap()) && (func_802D67AC(-1) >= 8) && (func_802D67AC(-1) < 0x12) && (func_802D67DC(-1) == this->modelCacheIndex) ; + if (!sp34 && this->modelCacheIndex == sRemoteOpenDoorActor) { + bool alreadyOpen = EventSystem_Should(VB_LEVELDOOR_REMOTE_OPEN_DONE, + fileProgressFlag_get(__leveldoor_persistentFlag(this->modelCacheIndex)) != 0, + this->modelCacheIndex, this->state); + if (alreadyOpen) { + sRemoteOpenDoorActor = 0; + } else { + sp34 = true; + } + } + func_802D3D74(this); if (!this->initialized) { if (!sp34) { @@ -1813,6 +1934,15 @@ void func_80389FA8(Actor *this, enum file_progress_e flag) if (fileProgressFlag_get(flag)) marker_despawn(this->marker); } + + // Anchor: re-check on scene-return restore (see chFloorCobweb_update). + if (!this->volatile_initialized) + { + this->volatile_initialized = true; + + if (fileProgressFlag_get(flag)) + marker_despawn(this->marker); + } } void func_80389FF4(Actor *this) diff --git a/src/LAIR/jigsawpicture.c b/src/LAIR/jigsawpicture.c index da648a147..02b65c090 100644 --- a/src/LAIR/jigsawpicture.c +++ b/src/LAIR/jigsawpicture.c @@ -3,6 +3,7 @@ #include "functions.h" #include "variables.h" #include "port/Romhack/RomhackConfig.h" +#include "port/Network/Anchor/JigsawPedestal.h" extern void player_walkToPosition(f32[3], f32, void(*)(ActorMarker *), ActorMarker *); extern void func_80324CFC(f32, enum comusic_e, s32); extern void rand_seed(s32); @@ -24,6 +25,8 @@ typedef struct { void jigsawPicture_setState(Actor *this, s32 next_state); void updateJigsawPictureActor(Actor *this); +static s32 sBuzzedPedestalField = 0; + /* .data */ ActorInfo JIGSAW_PICTURE_ACTOR = { 0x1EB, 0x3B7, 0x48B, 0x1, NULL, updateJigsawPictureActor, actor_update_func_80326224, actor_draw, 0, 0, 0.0f, 0}; ActorInfo JIGSAW_PICTURE_ACTOR_2 = { 0x1EB, 0x3BC, 0x538, 0x1, NULL, updateJigsawPictureActor, actor_update_func_80326224, actor_draw, 0, 0, 0.0f, 0}; @@ -302,6 +305,7 @@ void jigsawPicture_setState(Actor *this, s32 next_state){ vec3fArray_get_vec3f(func_803097A0(), getUnknownJigsawPictureIndex(this), sp50); switch (next_state) { case 1: //L8038F3BC + port_jigsawPedestal_release(this->actorTypeSpecificField); func_8028F918(0); break; @@ -447,10 +451,16 @@ void updateJigsawPictureActor(Actor *this) { this->volatile_initialized = true; if (this->actorTypeSpecificField == 9) { this->unk1C[0] = 8.0f; - if (!fileProgressFlag_get(FILEPROG_53_CCW_PUZZLE_PODIUM_SWITCH_PRESSED)) { - marker_despawn(this->marker); - return; - } + this->unk1C[1] = 0.0f; + } + } + + if (this->actorTypeSpecificField == 9) { + if (!fileProgressFlag_get(FILEPROG_53_CCW_PUZZLE_PODIUM_SWITCH_PRESSED)) { + return; + } + if (this->unk1C[1] == 0.0f) { + this->unk1C[1] = 1.0f; if (!fileProgressFlag_get(FILEPROG_54_CCW_PUZZLE_PODIUM_ACTIVE)) { __bundle_spawnFromFirstActor(BUNDLE_20__UNKNOWN, this); func_80324CFC(0.0f, COMUSIC_43_ENTER_LEVEL_GLITTER, 0x7FFF); @@ -486,6 +496,10 @@ void updateJigsawPictureActor(Actor *this) { controller_copyFaceButtons(0, sp7C); controller_copySideButtons(0, sp6C); func_8038EDBC(this); + if (this->state != 1 && !port_jigsawPedestal_isSelf(this->actorTypeSpecificField)) { + jigsawPicture_setState(this, 1); + return; + } switch(this->state){ case 1://L8038FCD0 if (!this->has_met_before && (!func_8028F20C() || !func_8028FB48(0x08000000))) { @@ -502,7 +516,14 @@ void updateJigsawPictureActor(Actor *this) { } } if (isBanjoOnPodium(this->marker) && this->has_met_before && !isPictureComplete(this) && (player_movementGroup() == BSGROUP_0_NONE || player_movementGroup() == BSGROUP_8_TROT)) { - jigsawPicture_setState(this, 2); + if (port_jigsawPedestal_tryClaim(this->actorTypeSpecificField)) { + jigsawPicture_setState(this, 2); + } else if (sBuzzedPedestalField != this->actorTypeSpecificField) { + comusic_playTrack(COMUSIC_2C_BUZZER); + sBuzzedPedestalField = this->actorTypeSpecificField; + } + } else if (sBuzzedPedestalField == this->actorTypeSpecificField) { + sBuzzedPedestalField = 0; } break; diff --git a/src/MM/ch/chimpystump.c b/src/MM/ch/chimpystump.c index da6df06c0..cd5aaf4fa 100644 --- a/src/MM/ch/chimpystump.c +++ b/src/MM/ch/chimpystump.c @@ -47,7 +47,11 @@ void chchimpystump_update(Actor *this) { actor_collisionOff(this); this->initialized = true; this->actor_specific_1_f = this->position_y; - this->position_y -= 134.0f; + if (mapSpecificFlags_get(MM_SPECIFIC_FLAG_0_CHIMPY_STUMP_RAISED)) { + subaddie_set_state(this, CHIMPY_STUMP_STATE_3_RAISED); + } else { + this->position_y -= 134.0f; + } this->marker->propPtr->unk8_3 = 1; } diff --git a/src/MM/ch/hut.c b/src/MM/ch/hut.c index 1a2ad24d5..f35116f5d 100644 --- a/src/MM/ch/hut.c +++ b/src/MM/ch/hut.c @@ -8,6 +8,8 @@ #include +#include "port/Patches/Patches.h" + /* extern function declarations */ void bundle_setYaw(f32); @@ -52,18 +54,43 @@ void __chhut_spawnExplosion(ActorMarker *this) { if (this); } -void chhut_update(Actor *this) { - static enum bundle_e D_803898D8[6] = { - BUNDLE_0_MM_HUT_MUSIC_NOTE, - BUNDLE_1_MM_HUT_BLUE_EGG, - BUNDLE_2_MM_HUT_GRUBLIN, - BUNDLE_3_MM_HUT_JINJO_GREEN, - BUNDLE_6_MM_HUT_EXTRA_LIFE, - BUNDLE_4_MM_HUT_JIGGY - }; +static enum bundle_e mm_hut_bundles[6] = { + BUNDLE_0_MM_HUT_MUSIC_NOTE, + BUNDLE_1_MM_HUT_BLUE_EGG, + BUNDLE_2_MM_HUT_GRUBLIN, + BUNDLE_3_MM_HUT_JINJO_GREEN, + BUNDLE_6_MM_HUT_EXTRA_LIFE, + BUNDLE_4_MM_HUT_JIGGY +}; + +static void chhut_dropRecordedBundle(Actor *this, s32 loot, s32 fullBundle) { + f32 pos[3]; + if (loot < 0 || loot >= 5) { + return; // jiggy / out of range + } + if (!fullBundle && (loot == 0 || loot == 3)) { + return; // note / jinjo: skip on reload + } + pos[0] = this->position_x; + pos[1] = this->position_y + 125.0f; + pos[2] = this->position_z; + __spawnQueue_add_4((GenFunction_4) spawnQueue_bundle_f32, mm_hut_bundles[loot], *(s32 *)(&pos[0]), *(s32 *)(&pos[1]), *(s32 *)(&pos[2])); +} + +static void chhut_replaySmash(Actor *this, s32 loot) { + sfxsource_playHighPriority(SFX_5B_HEAVY_STUFF_FALLING); + subaddie_set_state(this, HUT_STATE_1_DAMAGED); + actor_playAnimationOnce(this); + __spawnQueue_add_1((GenFunction_1) __chhut_spawnExplosion, (uintptr_t)this->marker); + bundle_setYaw(this->yaw); + chhut_dropRecordedBundle(this, loot, 1); +} +void chhut_update(Actor *this) { f32 diff_pos[3]; f32 plyr_pos[3]; + s32 loot; + s32 smashIndex; if (gsworld_getUnk0() != 2) { return; @@ -72,6 +99,13 @@ void chhut_update(Actor *this) { if (!this->initialized) { this->marker->collidable = false; this->initialized = true; + loot = port_hutSmash_get((s32)this->position_x, (s32)this->position_y, (s32)this->position_z); + if (loot >= 0) { + chhut_dropRecordedBundle(this, loot, 0); + subaddie_set_state(this, HUT_STATE_2_DESTROYED); + this->position_y -= 160.0f; + return; + } } switch (this->state) { @@ -97,14 +131,21 @@ void chhut_update(Actor *this) { __spawnQueue_add_1((GenFunction_1) __chhut_spawnExplosion, (uintptr_t)this->marker); bundle_setYaw(this->yaw); - if (mm_hut_smash_count < 5) { - __spawnQueue_add_4((GenFunction_4) spawnQueue_bundle_f32, D_803898D8[mm_hut_smash_count], *(s32 * )(&diff_pos[0]), *(s32 * )(&diff_pos[1]), *(s32 * )(&diff_pos[2])); + smashIndex = port_hutSmash_countForCurrentMap(); + if (smashIndex < 5) { + __spawnQueue_add_4((GenFunction_4) spawnQueue_bundle_f32, mm_hut_bundles[smashIndex], *(s32 * )(&diff_pos[0]), *(s32 * )(&diff_pos[1]), *(s32 * )(&diff_pos[2])); } else { jiggy_spawn(JIGGY_5_MM_HUTS, diff_pos); } - mm_hut_smash_count = (mm_hut_smash_count + 1) % 6; + port_hutSmash_record((s32)this->position_x, (s32)this->position_y, (s32)this->position_z, smashIndex); + } + else { + loot = port_hutSmash_get((s32)this->position_x, (s32)this->position_y, (s32)this->position_z); + if (loot >= 0) { + chhut_replaySmash(this, loot); + } } break; diff --git a/src/MM/ch/jujuhitbox.c b/src/MM/ch/jujuhitbox.c index 54fb88cc6..016fbc12c 100644 --- a/src/MM/ch/jujuhitbox.c +++ b/src/MM/ch/jujuhitbox.c @@ -4,11 +4,18 @@ #include "functions.h" #include "variables.h" +#include "port/Patches/Patches.h" + /* extern functions */ void __chjujuhitbox_initialize_all(ActorMarker *, s32); s32 subaddie_getYawToPlayer(Actor *); void func_80353580(ActorMarker *); +static s32 mm_juju_sharedKnocked(void) { + s32 bits = port_puzzleStep_get(ANCHOR_PUZZLE_MM_JUJU) & 0xF; + return (bits & 1) + ((bits >> 1) & 1) + ((bits >> 2) & 1) + ((bits >> 3) & 1); +} + typedef struct juju_hitbox_s { u8 pad0[0x4]; s32 unk4; @@ -75,6 +82,7 @@ void func_80388BEC(NodeProp *node, ActorMarker *marker) { if (func_80388B30(temp_v0, 90.0f)) { closest_actor->state = 1; ((ActorLocal_JujuHitbox *) &closest_actor->local)->unk4++; + port_puzzleStep_orBits(ANCHOR_PUZZLE_MM_JUJU, (1 << ((ActorLocal_JujuHitbox *) &closest_actor->local)->unk4) - 1); func_803892A8(((ActorLocal_JujuHitbox *) &closest_actor->local)->jujus); func_80353580(marker); __spawnQueue_add_4((GenFunction_4)spawnQueue_actor_f32, 0x58, *(s32 *)&position[0], *(s32 *)&position[1], *(s32 *)&position[2]); @@ -133,6 +141,11 @@ void chjujuhitbox_update(Actor *this) { if (!this->volatile_initialized) { this->volatile_initialized = true; + jujuCtlPtr->unk4 = mm_juju_sharedKnocked(); + if (jujuCtlPtr->unk4 >= 4) { + marker_despawn(this->marker); + return; + } __spawnQueue_add_2((void (*)(void)) __chjujuhitbox_initialize_all, (uintptr_t)this->marker, jujuCtlPtr->unk4); __chjujuhitbox_playRubbingSfx(this); return; @@ -161,6 +174,12 @@ void chjujuhitbox_update(Actor *this) { __chjuju_updateCount(jujuCtlPtr->jujus); } + if (this->state == 3 && jujuCtlPtr->unk4 < mm_juju_sharedKnocked()) { + this->state = 1; + jujuCtlPtr->unk4++; + func_803892A8(jujuCtlPtr->jujus); + } + if (mapSpecificFlags_get(MM_SPECIFIC_FLAG_9_JUJU_HAS_HALF_TURNED)) { __chjujuhitbox_playRubbingSfx(this); mapSpecificFlags_set(MM_SPECIFIC_FLAG_9_JUJU_HAS_HALF_TURNED, false); diff --git a/src/MM/ch/lmonkey.c b/src/MM/ch/lmonkey.c index a44f276df..329617b05 100644 --- a/src/MM/ch/lmonkey.c +++ b/src/MM/ch/lmonkey.c @@ -104,14 +104,15 @@ void chlmonkey_update(Actor *this) { switch (this->state) { case LMONKEY_STATE_1_IDLE://L80388690 - if (mapSpecificFlags_get(MM_SPECIFIC_FLAG_2_ORANGE_HAS_BEEN_RETURNED)) { + if (mapSpecificFlags_get(MM_SPECIFIC_FLAG_2_ORANGE_HAS_BEEN_RETURNED) || jiggyscore_isSpawned(JIGGY_9_MM_CHIMPY)) { subaddie_set_state(this, LMONKEY_STATE_4_LEAVING); - if (!jiggyscore_isCollected(JIGGY_9_MM_CHIMPY)) { - gcdialog_showDialog(ASSET_B40_DIALOG_CHIMPY_COMPLETE, 0xE, this->position, this->marker, __chlmonkey_complete, NULL); + if (jiggyscore_isSpawned(JIGGY_9_MM_CHIMPY)) { + mapSpecificFlags_set(MM_SPECIFIC_FLAG_4_SHAKE, true); + subaddie_set_state(this, LMONKEY_STATE_3_WALKING); } else {//L803886E8 - __chlmonkey_complete(this->marker, ASSET_B40_DIALOG_CHIMPY_COMPLETE, -1); + gcdialog_showDialog(ASSET_B40_DIALOG_CHIMPY_COMPLETE, 0xE, this->position, this->marker, __chlmonkey_complete, NULL); }//L80388898 } else { diff --git a/src/MM/ch/orangepad.c b/src/MM/ch/orangepad.c index cca3856a3..f5980ca62 100644 --- a/src/MM/ch/orangepad.c +++ b/src/MM/ch/orangepad.c @@ -9,6 +9,9 @@ void actor_update_func_80326224(Actor *); extern void particleEmitter_func_802EFA20(ParticleEmitter *, f32, f32); +extern void port_breakable_recordBreak(s32 markerId, s32 x, s32 y, s32 z); +extern s32 port_breakable_isBroken(s32 map, s32 markerId, s32 x, s32 y, s32 z); + /* public functions */ void chorangepad_update(Actor *); @@ -42,6 +45,7 @@ void handleOrangeCollision(ActorMarker *marker) { if (closest_orange_pad && !(500.0f < distance_to_orange_pad)) { closest_orange_pad->state = 1; + port_breakable_recordBreak((s32)closest_orange_pad->marker->id, (s32)closest_orange_pad->position[0], (s32)closest_orange_pad->position[1], (s32)closest_orange_pad->position[2]); if (actorArray_findClosestActorFromActorId(position, ACTOR_57_ORANGE_PAD, 1, &distance_to_orange_pad)) { coMusicPlayer_playMusic(COMUSIC_2B_DING_B, 22000); @@ -103,6 +107,12 @@ void chorangepad_update(Actor *this) { closest_actor = marker_getActor(this->partnerActor); } + if (this->state != 1 + && port_breakable_isBroken((s32)gsworld_getMap(), (s32)this->marker->id, + (s32)this->position[0], (s32)this->position[1], (s32)this->position[2])) { + this->state = 1; + } + if (subaddie_playerIsWithinSphereAndActive(this, 0x28) && !player_movementGroup() && !mapSpecificFlags_get(MM_SPECIFIC_FLAG_CONGA_WARNED_BLOCKS) && diff --git a/src/MMM/actor_spawninit.c b/src/MMM/actor_spawninit.c index a8944bb97..2e3f1e97d 100644 --- a/src/MMM/actor_spawninit.c +++ b/src/MMM/actor_spawninit.c @@ -305,7 +305,8 @@ void func_80388BDC(Actor *this) { case 1: this->yaw = 0.0f; if(mapSpecificFlags_get(MMM_SPECIFIC_FLAG_0_UNKNOWN)) { - gcStaticCamera_activate(0x21); + if(EventSystem_Should(VB_DOOR_OPEN_CAMERA, true, MMM_DOOR_CAM_CHURCH)) + gcStaticCamera_activate(0x21); subaddie_set_state(this, 6); core1_7090_initSfxSource(0, 0x6A, 0x7FF8, 0.3f); mapSpecificFlags_set(MMM_SPECIFIC_FLAG_2_UNKNOWN, false); @@ -335,10 +336,12 @@ void func_80388BDC(Actor *this) { if( (!this->unk38_31 && item_empty(ITEM_0_HOURGLASS_TIMER)) || ((this->unk38_31) && (this->lifetime_value == 0.0f)) ) { - if (!this->unk38_31) { - gcStaticCamera_activate(0x22); - } else { - gcStaticCamera_activate(0x23); + if(EventSystem_Should(VB_DOOR_OPEN_CAMERA, true, MMM_DOOR_CAM_CHURCH)){ + if (!this->unk38_31) { + gcStaticCamera_activate(0x22); + } else { + gcStaticCamera_activate(0x23); + } } subaddie_set_state(this, 8); core1_7090_initSfxSource(0, 0x6A, 0x7FF8, 0.3f); @@ -373,10 +376,9 @@ void func_80389004(Actor *this){ if (!this->volatile_initialized) { this->volatile_initialized = true; - - if (levelSpecificFlags_get(LEVEL_FLAG_2E_MMM_UNKNOWN)) { - marker_despawn(this->marker); - } + } + if (levelSpecificFlags_get(LEVEL_FLAG_2E_MMM_UNKNOWN)) { + marker_despawn(this->marker); } } diff --git a/src/MMM/ch/flowerpot.c b/src/MMM/ch/flowerpot.c index f1b13f9df..75452f162 100644 --- a/src/MMM/ch/flowerpot.c +++ b/src/MMM/ch/flowerpot.c @@ -6,6 +6,9 @@ /* public functions */ void chFlowerpot_update(Actor *this); +extern void port_breakable_recordBreak(s32 markerId, s32 x, s32 y, s32 z); +extern s32 port_breakable_isBroken(s32 map, s32 markerId, s32 x, s32 y, s32 z); + /* .data */ enum chFlowerpot_state_e { FLOWER_POT_STATE_1_IDLE = 1, @@ -60,6 +63,14 @@ void chFlowerpot_update(Actor *this) { this->unk130 = MMM_func_803871FC; } + // Anchor: teammate flowered this pot - match visually without decrementing the count. + if (this->state == FLOWER_POT_STATE_1_IDLE + && port_breakable_isBroken((s32)gsworld_getMap(), (s32)this->marker->id, + (s32)this->position[0], (s32)this->position[1], (s32)this->position[2])) { + subaddie_set_state(this, FLOWER_POT_STATE_2_FLOWERED); + anctrl_setPlaybackType(this->anctrl, ANIMCTRL_ONCE); + } + switch (this->state) { case FLOWER_POT_STATE_1_IDLE: anctrl_setPlaybackType(this->anctrl, ANIMCTRL_STOPPED); @@ -84,6 +95,7 @@ bool chFlowerpot_eggCollision(ActorMarker *marker) { subaddie_set_state(actor, FLOWER_POT_STATE_2_FLOWERED); anctrl_setPlaybackType(actor->anctrl, ANIMCTRL_ONCE); + port_breakable_recordBreak((s32)marker->id, (s32)actor->position[0], (s32)actor->position[1], (s32)actor->position[2]); remaining = chFlowerpot_getRemaining(); if (remaining != 0) { diff --git a/src/RBB/ch/eggtoll1.c b/src/RBB/ch/eggtoll1.c index d91f13410..ebe16eafe 100644 --- a/src/RBB/ch/eggtoll1.c +++ b/src/RBB/ch/eggtoll1.c @@ -5,6 +5,11 @@ extern void timed_exitStaticCamera(f32); +// Anchor: toll extension stage is actor-local (unk8), no flag; keyed by secondaryId. +extern void port_eggToll_onAdvance(s32 map, s32 secondaryId, s32 stage); +extern s32 port_eggToll_getStage(s32 map, s32 secondaryId); +extern ActorArray *suBaddieActorArray; + /* typedefs and declarations */ typedef struct { s32 unk0; @@ -44,6 +49,13 @@ Struct_RBB_0_1 D_80390074[4] = { }; /* .code */ +static s32 eggToll_countForStage(s32 tollIdx, s32 stage) { + s32 count = 0; + if (stage >= 1) count += D_80390074[tollIdx].unk1; + if (stage >= 2) count += D_80390074[tollIdx].unk2; + return count; +} + void RBB_func_803863F0(Actor *actor, s32 arg1){ ActorLocal_RBB_0 * local = (ActorLocal_RBB_0 *) &actor->local; void *temp_a0; @@ -112,6 +124,7 @@ void func_803866F4(Actor *this, s32 arg1){ } if(arg1 == 3){ local->unk8++; + port_eggToll_onAdvance((s32)gsworld_getMap(), this->secondaryId, local->unk8); coMusicPlayer_playMusic(COMUSIC_2B_DING_B, 28000); func_80324E38(0.0f, 3); timedFunc_set_2(0.5f, (GenFunction_2) coMusicPlayer_playMusic, COMUSIC_2D_PUZZLE_SOLVED_FANFARE, 28000); @@ -157,6 +170,8 @@ void func_803868F0(Actor *this){ local->unk4 = (this->secondaryId == 0x13)? 1: local->unk4; local->unk4 = (this->secondaryId == 0x14)? 2: local->unk4; local->unk4 = (this->secondaryId == 0xB)? 3: local->unk4; + local->unk8 = port_eggToll_getStage((s32)gsworld_getMap(), this->secondaryId); + local->unk0 = eggToll_countForStage(local->unk4, local->unk8); func_803866F4(this, 1); } RBB_func_803863F0(this, 0); @@ -168,3 +183,30 @@ void func_803868F0(Actor *this){ } } + +void port_eggToll_remoteApply(s32 map, s32 secondaryId, s32 stage) { + s32 i; + (void)map; + + if (suBaddieActorArray == NULL) { + return; + } + for (i = 0; i < suBaddieActorArray->cnt; i++) { + Actor *actor = &suBaddieActorArray->data[i]; + ActorLocal_RBB_0 *local; + if (actor->marker == NULL || actor->marker->id != MARKER_182_RBB_EGG_TOLL) { + continue; + } + if (actor->secondaryId != secondaryId) { + continue; + } + local = (ActorLocal_RBB_0 *) &actor->local; + if (stage > local->unk8) { + local->unk8 = stage; + local->unk0 = eggToll_countForStage(local->unk4, stage); + RBB_func_803863F0(actor, 1); + coMusicPlayer_playMusic(COMUSIC_2B_DING_B, 28000); + } + return; + } +} diff --git a/src/RBB/ch/enginefanswitch.c b/src/RBB/ch/enginefanswitch.c index 7238b2b36..e963814e2 100644 --- a/src/RBB/ch/enginefanswitch.c +++ b/src/RBB/ch/enginefanswitch.c @@ -3,6 +3,8 @@ #include "functions.h" #include "variables.h" +#include "port/Patches/Patches.h" + void chEngineFanSwitch_update(Actor *this); /* .data */ @@ -51,4 +53,13 @@ void chEngineFanSwitch_update(Actor *this){ chEngineFanSwitch_setState(this, 1); } } + // [port] Anchor temp-persist: the fan slowdown is transient map flag 0, set by pressing this + // switch (RBB_func_803898A0). It syncs live but resets on reload, so persist it + if(mapSpecificFlags_get(0)){ + port_puzzleStep_orBits(ANCHOR_PUZZLE_RBB_ENGINE_FANS, 1); + } else if((this->state == 1) && (port_puzzleStep_get(ANCHOR_PUZZLE_RBB_ENGINE_FANS) & 1)){ + this->position_y -= 35.0f; + this->state = 2; + mapSpecificFlags_set(0, 1); + } } diff --git a/src/RBB/crane_boombox.c b/src/RBB/crane_boombox.c index 326281704..4656215e7 100644 --- a/src/RBB/crane_boombox.c +++ b/src/RBB/crane_boombox.c @@ -243,4 +243,11 @@ void RBB_func_803882F4(Actor *this){ func_803881E8(this, 1); } } + // Anchor: teammate opened the entrance (LEVEL_FLAG_2D) - snap to opened state. + else if (this->state == 1 && levelSpecificFlags_get(LEVEL_FLAG_2D_RBB_UNKNOWN)) { + func_80387AC0(); + RBB_func_80387960(0.0f); + func_80387B24(); + func_803881E8(this, 3); + } } diff --git a/src/RBB/crane_jiggycage.c b/src/RBB/crane_jiggycage.c index a42412af0..87c71599d 100644 --- a/src/RBB/crane_jiggycage.c +++ b/src/RBB/crane_jiggycage.c @@ -9,6 +9,11 @@ void func_803878B0(Actor *this); void func_8038756C(Actor *this, s32 arg1); +// Anchor: set while replaying a teammate's crane action; suppresses camera pans and auto-raise. +static s32 sCraneRemote = 0; +extern void port_jiggyCrane_broadcast(s32 stage); +extern ActorArray *suBaddieActorArray; + /* .data */ ActorInfo D_80390200 = { 0x183, 0x173, 0x402, 0x0, NULL, @@ -59,16 +64,20 @@ void func_8038718C(ActorMarker *marker){ func_8034DDF0(sp44, sp38, sp2C, 4.0f, 1); func_8034E1A4(sp44, SFX_D8_CRANE, 1.0f, 1.0f); } - timed_setStaticCameraToNode(0.0f, 4); - timed_setStaticCameraToNode(2.5f, 5); + if (!sCraneRemote) { + timed_setStaticCameraToNode(0.0f, 4); + timed_setStaticCameraToNode(2.5f, 5); + } timed_playSfx(4.0f, SFX_7F_HEAVYDOOR_SLAM, 0.5f, 19000); timed_playSfx(4.0f, SFX_7F_HEAVYDOOR_SLAM, 0.6f, 19000); timed_playSfx(4.0f, SFX_7F_HEAVYDOOR_SLAM, 0.7f, 19000); timed_playSfx(4.0f, SFX_7F_HEAVYDOOR_SLAM, 0.8f, 19000); timed_playSfx(4.0f, SFX_7F_HEAVYDOOR_SLAM, 0.9f, 19000); timed_playSfx(4.0f, SFX_7F_HEAVYDOOR_SLAM, 1.0f, 19000);\ - timed_exitStaticCamera(5.0f); - func_80324E38(5.0f, 0); + if (!sCraneRemote) { + timed_exitStaticCamera(5.0f); + func_80324E38(5.0f, 0); + } timedFunc_set_2(5.0f, (GenFunction_2) func_80387090, (uintptr_t) marker, 3); } @@ -94,8 +103,10 @@ void func_80387308(ActorMarker *marker){ timedFunc_set_2(0.5f, (GenFunction_2) func_80387090, (uintptr_t)actor->marker, 1); timedFunc_set_2(1.5f, (GenFunction_2) func_803870BC, 0x19d, 0x1f4); - timed_exitStaticCamera(1.5f); - func_80324E38(1.5f, 0); + if (!sCraneRemote) { + timed_exitStaticCamera(1.5f); + func_80324E38(1.5f, 0); + } } @@ -111,8 +122,10 @@ void func_80387488(ActorMarker *marker){ return; } } - func_80324E38(0.0f, 3); - timed_setStaticCameraToNode(0.0f, 6); + if (!sCraneRemote) { + func_80324E38(0.0f, 3); + timed_setStaticCameraToNode(0.0f, 6); + } timedFunc_set_1(0.5f, (GenFunction_1) func_80387308, (uintptr_t)actor->marker); } @@ -128,6 +141,7 @@ void func_8038756C(Actor *this, s32 arg1){ f32 sp24[3]; if(arg1 == 1){ + sCraneRemote = 0; if(this->state != 0){ sp6C[0] = 0.0f; sp6C[1] = 0.0f; @@ -143,6 +157,9 @@ void func_8038756C(Actor *this, s32 arg1){ }//L80387610 if(arg1 == 2){ + if (!sCraneRemote) { + port_jiggyCrane_broadcast(2); + } sp50[0] = sp50[1] = sp50[2] = 0.0f; sp44[0] = 0.0f; sp44[1] = 0.0f; @@ -156,7 +173,9 @@ void func_8038756C(Actor *this, s32 arg1){ timedFunc_set_2(0.1f, (GenFunction_2)func_8038711C, 0x19d, 0x1f4); timedFunc_set_2(0.1f, (GenFunction_2)coMusicPlayer_playMusic, COMUSIC_2B_DING_B, 28000); - func_80324E38(0.2f, 3); + if (!sCraneRemote) { + func_80324E38(0.2f, 3); + } timedFunc_set_1(1.1f, (GenFunction_1)func_8038718C, (uintptr_t)this->marker); }//L80387704 @@ -170,6 +189,9 @@ void func_8038756C(Actor *this, s32 arg1){ } if(arg1 == 4){ + if (!sCraneRemote) { + port_jiggyCrane_broadcast(4); + } sp3C = func_8034C528(0x19a); if(sp3C){ sp30[0] = 0.0f; @@ -211,9 +233,28 @@ void func_803878B0(Actor *this){ func_8038756C(this, 1); } - if(this->state == 3){ + if(this->state == 3 && !sCraneRemote){ if(item_empty(ITEM_0_HOURGLASS_TIMER)){ func_8038756C(this, 4); } } } + +void port_jiggyCrane_remoteApply(s32 stage) { + s32 i; + + if (suBaddieActorArray == NULL) { + return; + } + for (i = 0; i < suBaddieActorArray->cnt; i++) { + Actor *actor = &suBaddieActorArray->data[i]; + if (actor->marker == NULL || actor->marker->id != 0x183) { + continue; + } + if ((stage == 2 && actor->state == 1) || (stage == 4 && actor->state == 3)) { + sCraneRemote = 1; + func_8038756C(actor, stage); + } + return; + } +} diff --git a/src/TTC/ch/blubber.c b/src/TTC/ch/blubber.c index 9f6fe29a3..91202f8d5 100644 --- a/src/TTC/ch/blubber.c +++ b/src/TTC/ch/blubber.c @@ -3,6 +3,9 @@ #include "functions.h" #include "variables.h" +#include "port/Patches/Patches.h" +#include "port/Enhancements/Retention/Retention.h" + extern void func_8028E668(f32 arg0[3], f32 arg1, f32 arg2, f32 arg3); extern s32 func_802E0970(s32, f32, f32, f32, s32, s32, f32[3]); @@ -140,13 +143,49 @@ static void __func_80387830(Actor *this , f32 arg1, f32 arg2){ static void __chBlubber_updateFunc(Actor *this){ ActorLocal_Blubber *local; + s32 netBits; this->marker->propPtr->unk8_3 = true; func_8028E668(this->position, 90.0f, -10.0f, 110.0f); + + netBits = port_puzzleStep_get(ANCHOR_PUZZLE_TTC_BLUBBER); + if (mapSpecificFlags_get(TTC_SPECIFIC_FLAG_0_BLUBBER_UNKNOWN)) { + port_puzzleStep_orBits(ANCHOR_PUZZLE_TTC_BLUBBER, 0x1); + } + if (mapSpecificFlags_get(TTC_SPECIFIC_FLAG_1_UNKNOWN)) { + port_puzzleStep_orBits(ANCHOR_PUZZLE_TTC_BLUBBER, 0x3); + } + if (!this->volatile_initialized && (netBits & 0x2) && !mapSpecificFlags_get(TTC_SPECIFIC_FLAG_1_UNKNOWN)) { + marker_despawn(this->marker); + return; + } + if ((netBits & 0x1) && !mapSpecificFlags_get(TTC_SPECIFIC_FLAG_0_BLUBBER_UNKNOWN)) { + mapSpecificFlags_set(TTC_SPECIFIC_FLAG_0_BLUBBER_UNKNOWN, true); + this->unk138_23 = true; // half-gold dialog belongs to the deliverer + this->has_met_before = true; + } + if (this->initialized && (netBits & 0x2) && !mapSpecificFlags_get(TTC_SPECIFIC_FLAG_1_UNKNOWN)) { + local = (ActorLocal_Blubber *)&this->local; + mapSpecificFlags_set(TTC_SPECIFIC_FLAG_1_UNKNOWN, true); + mapSpecificFlags_set(TTC_SPECIFIC_FLAG_2_BLUBBER_JIGGY_SPAWNED_TEXT_SHOWN, true); + mapSpecificFlags_set(TTC_SPECIFIC_FLAG_3_BLUBBER_SHOW_JIGGY_SPAWNED_TEXT_FLAG, true); + subaddie_set_state(this, CH_BLUBBER_STATE_4_UNKNOWN); + actor_loopAnimation(this); + this->actor_specific_1_f = 0.0f; + local->unk24 = 0; + } + if(!mapSpecificFlags_get(TTC_SPECIFIC_FLAG_1_UNKNOWN) && !subaddie_playerIsWithinSphereAndActive(this, 2500)) return; if(!this->volatile_initialized){ + // Anchor: rebuild local gold count as collected - delivered (carried gold is transient). + s32 goldBits = port_puzzleStep_get(ANCHOR_PUZZLE_TTC_BLUBBER); + s32 delivered = ((goldBits & 0x1) ? 1 : 0) + ((goldBits & 0x2) ? 1 : 0); + s32 pool = port_carriedSync_collectedCount(ANCHOR_COLLECTIBLE_GOLD) - delivered; + if (pool > item_getCount(ITEM_18_GOLD_BULLIONS)) { + item_adjustByDiffWithoutHud(ITEM_18_GOLD_BULLIONS, pool - item_getCount(ITEM_18_GOLD_BULLIONS)); + } if(this->state == CH_BLUBBER_STATE_3_UNKNOWN){ subaddie_set_state_with_direction(this, CH_BLUBBER_STATE_2_UNKNOWN, 0.0f, 1); } diff --git a/src/TTC/ch/leaky.c b/src/TTC/ch/leaky.c index 567414556..dddc8d7c6 100644 --- a/src/TTC/ch/leaky.c +++ b/src/TTC/ch/leaky.c @@ -57,10 +57,20 @@ static void __chLeaky_updateFunc(Actor *this) { } } - if( this->state == 1 + // Anchor: teammate finished feeding Leaky (LEVEL_FLAG_2) - lower water here too. + if (this->state == 1 && this->unk38_31 < 2 && levelSpecificFlags_get(LEVEL_FLAG_2_TTC_UNKNOWN)) { + Struct70s *water = func_8034C5AC(300); + if (water != NULL) { + func_8034E7B8(&water->type_73, -600, 4.0f, 2, 10.0f); + } + timedFunc_set_0(1.0f, __func_80388F88); + subaddie_set_state(this, 2); + } + + if( this->state == 1 && !this->has_met_before && subaddie_playerIsWithinSphereAndActive(this, 250) && !subaddie_playerIsWithinSphereAndActive(this, 160) - && !player_movementGroup() + && !player_movementGroup() && gcdialog_showDialog(ASSET_A1A_DIALOG_LEAKY_FIRST_MEET, 0, NULL, NULL, NULL, NULL) ){ this->has_met_before = true; diff --git a/src/TTC/ch/nipper.c b/src/TTC/ch/nipper.c index a214258db..4070958c6 100644 --- a/src/TTC/ch/nipper.c +++ b/src/TTC/ch/nipper.c @@ -3,6 +3,8 @@ #include "functions.h" #include "variables.h" +#include "port/Patches/Patches.h" + static void __chNipper_updateFunc(Actor *this); static Actor *__chNipper_animFunc(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx); @@ -16,6 +18,24 @@ enum ch_nipper_states_e { CH_NIPPER_STATE_7_UNKNOWN // already dead? L80388A20 }; +static s32 __chNipper_sharedHits(void) { + s32 bits = port_puzzleStep_get(ANCHOR_PUZZLE_TTC_NIPPER) & 0x7; + return (bits & 1) + ((bits >> 1) & 1) + ((bits >> 2) & 1); +} + +static s32 __chNipper_localHits(Actor *this) { + if (this->state == CH_NIPPER_STATE_6_DEAD || this->state == CH_NIPPER_STATE_7_UNKNOWN) { + return 3; + } + if (this->lifetime_value == 80.0f) { + return 1; + } + if (this->lifetime_value == 40.0f) { + return 2; + } + return 0; +} + /* .data */ ActorAnimationInfo gChNipperAnimations[8] = { {0, 0.0}, @@ -137,6 +157,7 @@ static void __chNipper_dieFunc(ActorMarker *this_marker, ActorMarker *other_mark func_8032B4DC(this, other_marker, 7); if (this->lifetime_value == 40.0f) { + port_puzzleStep_orBits(ANCHOR_PUZZLE_TTC_NIPPER, 0x7); subaddie_set_state_with_direction(this, CH_NIPPER_STATE_6_DEAD, 0.01f, 1); actor_playAnimationOnce(this); for(i = 0; i < 3; i++){ @@ -148,13 +169,15 @@ static void __chNipper_dieFunc(ActorMarker *this_marker, ActorMarker *other_mark gcStaticCamera_activate(0x1C); return; } - + if (this->lifetime_value == 80.0f) { + port_puzzleStep_orBits(ANCHOR_PUZZLE_TTC_NIPPER, 0x3); __chNipper_playDeathAnimation(this); this->lifetime_value = 40.0f; return; } + port_puzzleStep_orBits(ANCHOR_PUZZLE_TTC_NIPPER, 0x1); __chNipper_playDeathAnimation(this); this->lifetime_value = 80.0f; gcdialog_showDialog(ASSET_A10_DIALOG_NIPPER_HURT, 4, NULL, NULL, NULL, NULL); @@ -201,6 +224,7 @@ static void __chNipper_updateFunc(Actor *this){ s32 xVelocity; f32 playerPosition[3]; enum bsgroup_e player_movement_group; + s32 sharedHits; player_getPosition(playerPosition); xVelocity = func_80309D58(playerPosition, 1); @@ -225,6 +249,24 @@ static void __chNipper_updateFunc(Actor *this){ this->velocity_x = xVelocity; } + if (this->initialized && this->state != CH_NIPPER_STATE_4_DIEING && this->state != CH_NIPPER_STATE_6_DEAD && + this->state != CH_NIPPER_STATE_7_UNKNOWN) { + sharedHits = __chNipper_sharedHits(); + if (__chNipper_localHits(this) < sharedHits) { + if (sharedHits >= 3) { + this->lifetime_value = 40.0f; + subaddie_set_state_with_direction(this, CH_NIPPER_STATE_6_DEAD, 0.01f, 1); + actor_playAnimationOnce(this); + sfx_playFadeShorthandDefault(SFX_78_EAGLECRY, 0.7f, 20000, this->position, 1500, 3000); + comusic_8025AB44(COMUSIC_12_TTC_NIPPER, 0, 300); + func_8025AABC(COMUSIC_12_TTC_NIPPER); + func_8032BB88(this, -1, 300); + } else { + this->lifetime_value = (sharedHits == 1) ? 80.0f : 40.0f; + } + } + } + switch(this->state){ case CH_NIPPER_STATE_1_UNKNOWN: if(!this->initialized){ diff --git a/src/TTC/ch/treasurehunt.c b/src/TTC/ch/treasurehunt.c index d7379f5d3..2a0f97e10 100644 --- a/src/TTC/ch/treasurehunt.c +++ b/src/TTC/ch/treasurehunt.c @@ -3,6 +3,8 @@ #include "functions.h" #include "variables.h" +#include "port/Patches/Patches.h" + extern f32 mapModel_getFloorY(f32[3]); // func_8028F45C declared in port_prototypes.h (returns bool) @@ -124,6 +126,7 @@ static void __chTreasurehunt_checkStepProgress(s32 currentStep){ } CH_TREASUREHUNT_PUZZLE_CURRENT_STEP++; + port_puzzleStep_orBits(ANCHOR_PUZZLE_TTC_XHUNT, (1 << CH_TREASUREHUNT_PUZZLE_CURRENT_STEP) - 1); __spawnQueue_add_0(__chTreasurehunt_spawnActorForNextStep); __spawnQueue_add_0(__chTreasurehunt_spawnRedXForNextStep); } @@ -173,6 +176,7 @@ void chTreasurehunt_checkStepProgress5(NodeProp *this, ActorMarker *arg1){ timedFunc_set_1(0.1f, (GenFunction_1) gcpausemenu_80314AC8, 1); gcdialog_showDialog(ASSET_A17_DIALOG_BURIED_TREASURE_SPAWNED, 4, NULL, NULL, NULL, NULL); CH_TREASUREHUNT_PUZZLE_CURRENT_STEP++; + port_puzzleStep_orBits(ANCHOR_PUZZLE_TTC_XHUNT, 0x3F); } } @@ -180,6 +184,40 @@ void chTreasurehunt_resetProgress(void){ CH_TREASUREHUNT_PUZZLE_CURRENT_STEP = 0; } +// Anchor: replay teammates' hunt steps, one per frame; called each frame in TTC (PuzzleStep.cpp). +void chTreasurehunt_netTick(void){ + static f32 sNetTreasurePosition[3]; + s32 bits = port_puzzleStep_get(ANCHOR_PUZZLE_TTC_XHUNT) & 0x3F; + s32 sharedStep = 0; + + while(bits & 1){ + sharedStep++; + bits >>= 1; + } + if((s32)CH_TREASUREHUNT_PUZZLE_CURRENT_STEP >= sharedStep){ + return; + } + + if(CH_TREASUREHUNT_PUZZLE_CURRENT_STEP < 5){ + CH_TREASUREHUNT_PUZZLE_CURRENT_STEP++; + __spawnQueue_add_0(__chTreasurehunt_spawnActorForNextStep); + __spawnQueue_add_0(__chTreasurehunt_spawnRedXForNextStep); + } + else{ + CH_TREASUREHUNT_PUZZLE_CURRENT_STEP++; + if(!jiggyscore_isSpawned(JIGGY_11_TTC_RED_X) && !jiggyscore_isCollected(JIGGY_11_TTC_RED_X)){ + sNetTreasurePosition[0] = sChTreasurehunt_stepPositions[5][0]; + sNetTreasurePosition[1] = sChTreasurehunt_stepPositions[5][1]; + sNetTreasurePosition[2] = sChTreasurehunt_stepPositions[5][2]; + sNetTreasurePosition[1] = mapModel_getFloorY(sNetTreasurePosition); + __spawnQueue_add_4((GenFunction_4)spawnQueue_actor_f32, ACTOR_F4_BURIED_TREASURE, + reinterpret_cast(s32, sNetTreasurePosition[0]), + reinterpret_cast(s32, sNetTreasurePosition[1]), + reinterpret_cast(s32, sNetTreasurePosition[2])); + } + } +} + static void __chTreasurehunt_updateFunc(Actor *this){ f32 tick = time_getDelta(); ActorLocal_TreasureHunt *local = (ActorLocal_TreasureHunt*)&this->local; diff --git a/src/core1/init.c b/src/core1/init.c index 9686e2ad1..249b786d5 100644 --- a/src/core1/init.c +++ b/src/core1/init.c @@ -210,10 +210,12 @@ void mainLoop(void){ }//L8023DF70 #endif + port_actorDespawn_beginDefer(); CALL_EVENT(GameFrameUpdate); + port_actorDespawn_endDefer(); } -void mainThread_entry(void *arg) { +void mainThread_entry(void *arg) { core1_init(); sns_write_payload_over_heap(); diff --git a/src/core2/abilityprogress.c b/src/core2/abilityprogress.c index a79fc8c97..9a6fab42f 100644 --- a/src/core2/abilityprogress.c +++ b/src/core2/abilityprogress.c @@ -115,12 +115,20 @@ void ability_clearAll(void){ abilityprogress_usedAbilities = 0; } -void ability_setLearned(s32 move, s32 val){ +void ability_setLearnedEx(s32 move, s32 val, s32 triggerEvent){ + s32 prev = (abilityprogress_learnedAbilities >> move) & 1; if(val){ abilityprogress_learnedAbilities |= (1 << move); }else{ abilityprogress_learnedAbilities &= ~(1 << move); } + if(triggerEvent && prev != (val ? 1 : 0)){ + CALL_EVENT(OnAbilityLearned, move, val ? 1 : 0); + } +} + +void ability_setLearned(s32 move, s32 val){ + ability_setLearnedEx(move, val, 1); } void ability_setAllLearned(s32 val){ diff --git a/src/core2/actor_array.c b/src/core2/actor_array.c index e681a9dab..5fdf09026 100644 --- a/src/core2/actor_array.c +++ b/src/core2/actor_array.c @@ -5,7 +5,8 @@ #include "actor.h" #include "prop.h" -#include "port/Enhancements/NoteRetention/NoteRetention.h" +#include "port/Enhancements/Retention/Retention.h" +#include "port/Patches/Patches.h" extern s32 D_80370990; extern f32 GameEngine_GetAspectRatio(void); @@ -53,6 +54,10 @@ typedef struct { s16 unkE; }Actorlocal_Core2_9E370; +// [port] Sized ahead of demand so actor_new never bk_reallocs (relocates) the array mid-map. +#define ACTOR_ARRAY_INITIAL_CAP 512 +#define ACTOR_ARRAY_GROW_CHUNK 128 + /* .data */ ActorArray *suBaddieActorArray = NULL; //actorArrayPtr s32 D_8036E564 = 0; @@ -437,6 +442,8 @@ void actorArray_free(void) { // [port] Note retention: every note actor is about to be freed, so drop our // live-actor tracking (markers are being released here). port_noteRetention_onActorsFreed(); + port_remoteCarry_reset(); + port_anchorDummies_onActorsFreed(); if (suBaddieActorArray != NULL) { for(var_s0 = suBaddieActorArray->data; var_s0 < &suBaddieActorArray->data[suBaddieActorArray->cnt]; var_s0++){ @@ -568,12 +575,15 @@ void func_803268B4(void) { if (!actor->despawn_flag) { if (marker->unk2C_2) { marker->actorUpdate2Func(actor); + // [port] Update may have spawned actors, reallocating the array; re-fetch the slot. + actor = &suBaddieActorArray->data[temp_v1]; if (anim_ctrl != NULL) { actor->sound_timer = anctrl_getAnimTimer(anim_ctrl); } } else if (!temp_s1 || (temp_s1 && func_803296D8(actor, temp_s1))) { if ( marker->actorUpdateFunc != NULL) { marker->actorUpdateFunc(actor); + actor = &suBaddieActorArray->data[temp_v1]; // [port] re-fetch: see above if (anim_ctrl != NULL) { actor->sound_timer = anctrl_getAnimTimer(anim_ctrl); } @@ -801,13 +811,13 @@ Actor *actor_new(s32 position[3], s32 yaw, ActorInfo* actorInfo, u32 flags){ s32 pos_copy[3] = { pos_x, pos_y, pos_z }; if(suBaddieActorArray == NULL){ - suBaddieActorArray = (ActorArray *)bk_malloc(sizeof(ActorArray) + 20*sizeof(Actor)); + suBaddieActorArray = (ActorArray *)bk_malloc(sizeof(ActorArray) + ACTOR_ARRAY_INITIAL_CAP*sizeof(Actor)); suBaddieActorArray->cnt = 0; - suBaddieActorArray->max_cnt = 20; + suBaddieActorArray->max_cnt = ACTOR_ARRAY_INITIAL_CAP; } if(suBaddieActorArray->cnt + 1 > suBaddieActorArray->max_cnt){ - suBaddieActorArray->max_cnt = suBaddieActorArray->cnt + 5; + suBaddieActorArray->max_cnt = suBaddieActorArray->cnt + ACTOR_ARRAY_GROW_CHUNK; suBaddieActorArray = (ActorArray *)bk_realloc(suBaddieActorArray, sizeof(ActorArray) + suBaddieActorArray->max_cnt*sizeof(Actor)); } @@ -1084,11 +1094,7 @@ static void __actor_free(ActorMarker *arg0, Actor *arg1){ //remove last actor from actor array suBaddieActorArray->cnt--; - //shrink actor array capacity - if(suBaddieActorArray->cnt + 8 <= suBaddieActorArray->max_cnt){ - suBaddieActorArray->max_cnt = suBaddieActorArray->cnt + 4; - suBaddieActorArray = (ActorArray *)bk_realloc(suBaddieActorArray, suBaddieActorArray->max_cnt*sizeof(Actor) + sizeof(ActorArray)); - } + // [port] Never shrink the array; keeps the pre-sized headroom from actor_new so pointers stay stable. marker_free(arg0); } @@ -1158,13 +1164,38 @@ void marker_despawn(ActorMarker *marker){ } } else{ + // [port] Shadow-link cleanup for immediate-mode despawns. + if(actor->unk104){ + if(actor->modelCacheIndex != 0x108){ + // Freeing a shadow-owner: unlink and free its shadow too. + ActorMarker *shadowMarker = actor->unk104; + Actor *shadow = marker_getActor(shadowMarker); + shadow->unk104 = NULL; + actor->unk104 = NULL; + __actor_free(shadowMarker, shadow); + // Swap-remove may have relocated this actor; re-fetch through the marker. + actor = marker_getActor(marker); + } + else{ + // Freeing a shadow directly: sever the owner's link too. + marker_getActor(actor->unk104)->unk104 = NULL; + actor->unk104 = NULL; + } + } __actor_free(marker, actor); } } void func_803283BC(void){ D_8036E574 = 1; - D_8036E578 = 0; +} + +void port_actorDespawn_beginDefer(void){ + D_8036E574 = 1; +} + +void port_actorDespawn_endDefer(void){ + D_8036E574 = 0; } //actorArray_flushDespawns @@ -2218,6 +2249,36 @@ ActorMarker *func_8032B16C(enum jiggy_e jiggy_id) { } } +ActorMarker *actorArray_findHoneycombMarkerById(enum honeycomb_e id) { + Actor* base; + Actor* var_s0; + + if (suBaddieActorArray != NULL) { + base = &suBaddieActorArray->data[0]; + for (var_s0 = base; (var_s0 - base) < suBaddieActorArray->cnt; var_s0++) { + if ((var_s0->marker->id == MARKER_53_EMPTY_HONEYCOMB) && (func_802CA1C4(var_s0) == id)) { + return var_s0->marker; + } + } + } + return NULL; +} + +ActorMarker *actorArray_findMumboTokenMarkerById(enum mumbotoken_e id) { + Actor* base; + Actor* var_s0; + + if (suBaddieActorArray != NULL) { + base = &suBaddieActorArray->data[0]; + for (var_s0 = base; (var_s0 - base) < suBaddieActorArray->cnt; var_s0++) { + if ((var_s0->marker->id == MARKER_39_MUMBO_TOKEN) && (func_802E0CB0(var_s0) == id)) { + return var_s0->marker; + } + } + } + return NULL; +} + void func_8032B258(Actor *this, enum collision_e arg1) { f32 sp44; f32 sp38[3]; diff --git a/src/core2/ba/ba_anim.c b/src/core2/ba/ba_anim.c index a96e5912d..560822412 100644 --- a/src/core2/ba/ba_anim.c +++ b/src/core2/ba/ba_anim.c @@ -74,61 +74,68 @@ void __baanim_oscillateScale(f32 dst[3], f32 x, f32 min, f32 osc_size) { }; } -void __baanim_applyBottlesBonus(uintptr_t arg0, uintptr_t arg1) { +void baanim_applyBottlesBonusMask(uintptr_t arg0, s32 mask) { f32 scale[3]; - f32 sp28; - s32 phi_s0; - static s32 D_8037BF4C; - + f32 sp28 = func_802E4B38(); - sp28 = func_802E4B38(); - if (volatileFlag_get(VOLATILE_FLAG_78_SANDCASTLE_NO_BONUS) == 0) { - D_8037BF4C = 0; - } else { - for(phi_s0 = 0; phi_s0 < 7; phi_s0++){ - if (volatileFlag_get(phi_s0 + VOLATILE_FLAG_97_SANDCASTLE_BOTTLES_BONUS_1)) { - D_8037BF4C = D_803635EC[phi_s0]; - } - } - } - if ((D_8037BF4C & 1)) {//either big hands or big feet + if (mask & 1) {//either big hands or big feet __baanim_oscillateScale(scale, sp28, 2.0f, 1.0f); boneTransformList_setBoneScale((BoneTransformList *)arg0, 6, scale); boneTransformList_setBoneScale((BoneTransformList *)arg0, 0x14, scale); } - if (D_8037BF4C & 2) {//either big hands or big feet + if (mask & 2) {//either big hands or big feet __baanim_oscillateScale(scale, sp28, 2.0f, 1.0f); boneTransformList_setBoneScale((BoneTransformList *)arg0, 0x10, scale); boneTransformList_setBoneScale((BoneTransformList *)arg0, 0x1E, scale); } - if (D_8037BF4C & BAANIM_BIGHEAD) { + if (mask & BAANIM_BIGHEAD) { __baanim_oscillateScale(scale, sp28, 2.0f, 1.0f); boneTransformList_setBoneScale((BoneTransformList *)arg0, 0x12, scale); } - if (D_8037BF4C & BAANIM_SMALLHEAD) { + if (mask & BAANIM_SMALLHEAD) { __baanim_oscillateScale(scale, sp28, 0.2f, 0.5f); boneTransformList_setBoneScale((BoneTransformList *)arg0, 0x12, scale); } - if (D_8037BF4C & BAANIM_LONGBODY) { + if (mask & BAANIM_LONGBODY) { func_8033A968((BoneTransformList *)arg0, 1, D_803635E0); } - if (D_8037BF4C & BAANIM_BIGKAZOOIEHEAD) { + if (mask & BAANIM_BIGKAZOOIEHEAD) { __baanim_oscillateScale(scale, sp28, 2.0f, 1.0f); boneTransformList_setBoneScale((BoneTransformList *)arg0, 0x6C, scale); } - if (D_8037BF4C & BAANIM_BIGWINGS) { + if (mask & BAANIM_BIGWINGS) { __baanim_oscillateScale(scale, sp28, 2.0f, 1.0f); boneTransformList_setBoneScale((BoneTransformList *)arg0, 0x64, scale); boneTransformList_setBoneScale((BoneTransformList *)arg0, 0x67, scale); } - if (gsworld_getMap() == MAP_A_TTC_SANDCASTLE) { - if ((D_8037BF4C & BAANIM_WISHYWASHY) && (player_getTransformation() != TRANSFORM_7_WISHWASHY)) { - func_8028FB88(TRANSFORM_7_WISHWASHY); - } - if (!(D_8037BF4C & BAANIM_WISHYWASHY) && (player_getTransformation() == TRANSFORM_7_WISHWASHY)) { - func_8028FB88(TRANSFORM_1_BANJO); +} + +s32 baanim_getActiveBottlesBonusMask(void) { + s32 mask = 0; + s32 i; + + if (volatileFlag_get(VOLATILE_FLAG_78_SANDCASTLE_NO_BONUS) == 0) { + return 0; + } + for (i = 0; i < 7; i++) { + if (volatileFlag_get(i + VOLATILE_FLAG_97_SANDCASTLE_BOTTLES_BONUS_1)) { + mask = D_803635EC[i]; } } + return mask; +} + +void __baanim_applyBottlesBonus(uintptr_t arg0, uintptr_t arg1) { + s32 mask = baanim_getActiveBottlesBonusMask(); + + baanim_applyBottlesBonusMask(arg0, mask); + + if ((mask & BAANIM_WISHYWASHY) && (player_getTransformation() == TRANSFORM_1_BANJO)) { + func_8028FB88(TRANSFORM_7_WISHWASHY); + } + if (!(mask & BAANIM_WISHYWASHY) && (player_getTransformation() == TRANSFORM_7_WISHWASHY)) { + func_8028FB88(TRANSFORM_1_BANJO); + } if (baAnimModifyFunction != NULL) { baAnimModifyFunction(arg0, arg1); } diff --git a/src/core2/ba/ba_lookdir.c b/src/core2/ba/ba_lookdir.c index d78aea99a..9200a4068 100644 --- a/src/core2/ba/ba_lookdir.c +++ b/src/core2/ba/ba_lookdir.c @@ -964,3 +964,9 @@ void func_8028FCE8(void) { D_8037BFCC = yaw_get(); D_8037BFD0 = D_8037BFBC; } + +void player_setWarpDestination(f32 position[3], f32 yaw, s32 exit_id) { + ml_vec3f_copy(D_8037BFC0, position); + D_8037BFCC = yaw; + D_8037BFD0 = (f32) exit_id; +} diff --git a/src/core2/ba/ba_marker.c b/src/core2/ba/ba_marker.c index 843b4a6a8..8bacbfccd 100644 --- a/src/core2/ba/ba_marker.c +++ b/src/core2/ba/ba_marker.c @@ -3,6 +3,7 @@ #include "functions.h" #include "variables.h" #include "port/Romhack/RomhackConfig.h" +#include "port/Enhancements/Retention/Retention.h" #include "core2/ba/physics.h" #include "version.h" #include "prop.h" @@ -156,16 +157,36 @@ void __baMarker_8028B904(s32 arg0, s32 arg1, s32 arg2, s32 arg3){ } +extern ActorArray *suBaddieActorArray; +extern enum honeycomb_e D_8037DDC0; // honeycomb.c: pending uid for the next spawned honeycomb + +static bool __baMarker_honeycombPresent(s32 uid){ + s32 i; + s32 actorUid; + Actor *actor; + + if(suBaddieActorArray == NULL) return false; + for(i = 0; i < suBaddieActorArray->cnt; i++){ + actor = &suBaddieActorArray->data[i]; + if(actor->marker == NULL || actor->marker->id != MARKER_53_EMPTY_HONEYCOMB) continue; + actorUid = func_802CA1C4(actor); + if(actorUid == uid || (actorUid == 0 && D_8037DDC0 == uid)) return true; + } + return false; +} + void __baMarker_8028B9A8(uintptr_t arg0){ NodeProp *tmp_v0; s32 ideal_yaw[3]; + if(__baMarker_honeycombPresent(arg0)) return; + tmp_v0 = cubeList_findNodePropByActorIdAndPosition_s32(0x1F6, NULL); nodeprop_getPosition_s32(tmp_v0, ideal_yaw); func_802CA1CC(arg0); actor_spawnWithYaw_s32(ACTOR_47_EMPTY_HONEYCOMB, &ideal_yaw, 0); coMusicPlayer_playMusic(COMUSIC_2B_DING_B, 28000); - + } void __baMarker_8028BA00(s32 arg0){ @@ -555,6 +576,7 @@ void __baMarker_resolveCollision(Prop *other_prop){ || (player_isStable() && !(3600.0f < ml_distanceSquared_vec3f(actor->position, spA0))) ) { jiggyscore_setCollected(jiggy_id, true); + CALL_EVENT(OnCollectibleCollected, ANCHOR_COLLECTIBLE_JIGGY, jiggy_id); item_adjustByDiffWithoutHud(ITEM_26_JIGGY_TOTAL, 1); if (jiggy_id == JIGGY_20_BGS_ELEVATED_WALKWAY || jiggy_id == JIGGY_25_BGS_MAZE) { func_802D6924(); @@ -581,6 +603,7 @@ void __baMarker_resolveCollision(Prop *other_prop){ if (sp98 != HONEYCOMB_12_MMM_FLOORBOARD || player_getTransformation() == TRANSFORM_3_PUMPKIN) { honeycombscore_set(sp98, 1); + CALL_EVENT(OnCollectibleCollected, ANCHOR_COLLECTIBLE_HONEYCOMB, sp98); coMusicPlayer_playMusic(COMUSIC_17_EMPTY_HONEYCOMB_COLLECTED, 28000); timedFunc_set_1(2.0f, (GenFunction_1)progressDialog_showDialogMaskZero, FILEPROG_B_EMPTY_HONEYCOMB_TEXT); item_inc(ITEM_13_EMPTY_HONEYCOMB); @@ -698,6 +721,7 @@ void __baMarker_resolveCollision(Prop *other_prop){ return; __baMarker_resolveMusicNoteCollision(other_prop); + port_noteRetention_onLocalNoteCollected(marker); marker_despawn(marker); break; diff --git a/src/core2/ch/honeycomb.c b/src/core2/ch/honeycomb.c index fbdf64f24..e4725a3ad 100644 --- a/src/core2/ch/honeycomb.c +++ b/src/core2/ch/honeycomb.c @@ -133,6 +133,21 @@ void chHoneycomb_update(Actor *this){ } }//L802CA098 + { + s32 gateFlag = -1; + if(local->uid == HONEYCOMB_B_GV_CACTUS) gateFlag = 0xd; + else if(local->uid == HONEYCOMB_F_RBB_BOAT_HOUSE) gateFlag = 0; + if(gateFlag >= 0){ + if(!mapSpecificFlags_get(gateFlag)){ + this->unk58_0 = false; + actor_collisionOff(this); + return; + } + this->unk58_0 = true; + actor_collisionOn(this); + } + } + if(gsworld_getMap() == MAP_27_FP_FREEZEEZY_PEAK){ if(maSlalom_isActive()){ this->unk58_0 = false; @@ -157,6 +172,24 @@ void chHoneycomb_update(Actor *this){ } } +extern void __baMarker_8028BA00(s32); +void chHoneycomb_netRevealFromSwitch(void){ + s32 uid = -1; + + switch(gsworld_getMap()){ + case MAP_12_GV_GOBIS_VALLEY: + if(mapSpecificFlags_get(0xD)) uid = HONEYCOMB_B_GV_CACTUS; + break; + case MAP_31_RBB_RUSTY_BUCKET_BAY: + if(mapSpecificFlags_get(0)) uid = HONEYCOMB_F_RBB_BOAT_HOUSE; + break; + default: + break; + } + if(uid < 0 || honeycombscore_get(uid)) return; + __baMarker_8028BA00(uid); +} + enum honeycomb_e func_802CA1C4(Actor *this){ ActorLocal_EmptyHoneycomb *local = (ActorLocal_EmptyHoneycomb *)&this->local; return local->uid; diff --git a/src/core2/ch/jiggy.c b/src/core2/ch/jiggy.c index fed32dbd7..3e3165905 100644 --- a/src/core2/ch/jiggy.c +++ b/src/core2/ch/jiggy.c @@ -2,6 +2,7 @@ #include "functions.h" #include "variables.h" #include "enums.h" +#include "port/Enhancements/Events/Hooks/Events.h" extern void func_802BE720(void); extern f32 modelRender_func_8033A244(f32); @@ -76,6 +77,7 @@ void destroyJiggy(Actor *this, s32 arg1, s32 arg2, s32 arg3, s32 arg4, s32 arg5, && mapSpecificFlags_get(arg2) && item_getCount(ITEM_0_HOURGLASS_TIMER) == 0 ){ + CALL_EVENT(OnTimedJiggyExpired, (s32)chjiggy_getJiggyId(this)); player_setModelVisible(1); actor_collisionOff(this); gcStaticCamera_activate(arg3); diff --git a/src/core2/ch/jinjo.c b/src/core2/ch/jinjo.c index 45533fbff..f7190f36a 100644 --- a/src/core2/ch/jinjo.c +++ b/src/core2/ch/jinjo.c @@ -1,6 +1,7 @@ #include #include "functions.h" #include "variables.h" +#include "port/Enhancements/Retention/Retention.h" extern void subaddie_set_state_with_direction(Actor *, s32, f32 , s32); extern f32 func_80309B24(f32*); @@ -52,6 +53,7 @@ void __chJinjo_802CDBA8(ActorMarker *this, ActorMarker *other){ if (!EventSystem_Should(VB_UPDATE_JINJO_HUD, false, actorPtr->position)) { if (item_adjustByDiffWithHud(ITEM_12_JINJOS, 1 << ((this->id + 6) & 0x1F)) == 0x1f) // [port] MIPS SLL uses low 5 bits; mask to avoid UB localPtr->unk4 = 1; + port_jinjoRetention_onLocalJinjoCollected(this->id); } actor_loopAnimation(actorPtr); this->collidable = false; diff --git a/src/core2/ch/level_collectible.c b/src/core2/ch/level_collectible.c index 1d1fb4dcf..7cdb04f6f 100644 --- a/src/core2/ch/level_collectible.c +++ b/src/core2/ch/level_collectible.c @@ -1,10 +1,286 @@ #include #include "functions.h" #include "variables.h" +#include "port/Enhancements/Retention/Retention.h" extern void func_8028F7D4(f32, f32); void chLevelCollectible_update(Actor *this); extern ActorMarker *func_8028E86C(void); + +static s32 levelCollectible_syncKind(s32 markerId) { + switch (markerId) { + case MARKER_36_ORANGE_COLLECTIBLE: return ANCHOR_COLLECTIBLE_ORANGE; + case MARKER_37_GOLD_BULLION: return ANCHOR_COLLECTIBLE_GOLD; + case MARKER_1FD_BLUE_PRESENT_COLLECTIBLE: return ANCHOR_COLLECTIBLE_PRESENT_BLUE; + case MARKER_1FE_GREEN_PRESENT_COLLECTIBLE: return ANCHOR_COLLECTIBLE_PRESENT_GREEN; + case MARKER_1FF_RED_PRESENT_COLLECTIBLE: return ANCHOR_COLLECTIBLE_PRESENT_RED; + default: return -1; + } +} + +extern s32 port_anchor_getDummyTransform(u32 clientId, f32 pos[3], f32* yaw); +extern void port_anchor_onCarryThrow(s32 markerId, f32 start[3], f32 target[3]); + +void __chLevelCollectible_presentReturnEmitSparkles(f32 position[3], enum asset_e sprite_id); + +#define REMOTE_CARRY_MAX 16 +static struct { + u32 clientId; // 0 = free slot + ActorMarker *marker; // NULL while the spawn is still queued + s32 markerId; + u8 throwPending; + f32 throwStart[3]; + f32 throwTarget[3]; + f32 carryOff[3]; // held pose: object position relative to the owner + f32 carryYawOff; // held pose: object yaw relative to the owner's yaw +} sRemoteCarry[REMOTE_CARRY_MAX]; + +static s32 __remoteCarry_actorIdForMarker(s32 markerId) { + switch (markerId) { + case MARKER_36_ORANGE_COLLECTIBLE: return ACTOR_29_ORANGE_COLLECTIBLE; + case MARKER_37_GOLD_BULLION: return ACTOR_2A_GOLD_BULLION; + case MARKER_1FD_BLUE_PRESENT_COLLECTIBLE: return ACTOR_1ED_BLUE_PRESENT_COLLECTIBLE; + case MARKER_1FE_GREEN_PRESENT_COLLECTIBLE: return ACTOR_1EF_GREEN_PRESENT_COLLECTIBLE; + case MARKER_1FF_RED_PRESENT_COLLECTIBLE: return ACTOR_1F1_RED_PRESENT_COLLECTIBLE; + case MARKER_1B5_CATERPILLAR: return ACTOR_2A2_CATERPILLAR; + case 0x1BC /* acorn marker (unnamed) */: return ACTOR_2A9_ACORN; + default: return 0; + } +} + +static s32 __remoteCarry_findByClient(u32 clientId) { + s32 i; + for (i = 0; i < REMOTE_CARRY_MAX; i++) { + if (sRemoteCarry[i].clientId == clientId) { + return i; + } + } + return -1; +} + +static s32 __remoteCarry_findByMarker(ActorMarker *marker) { + s32 i; + for (i = 0; i < REMOTE_CARRY_MAX; i++) { + if (sRemoteCarry[i].clientId != 0 && sRemoteCarry[i].marker == marker) { + return i; + } + } + return -1; +} + +static void __remoteCarry_clearSlot(s32 slot) { + sRemoteCarry[slot].clientId = 0; + sRemoteCarry[slot].marker = NULL; + sRemoteCarry[slot].markerId = 0; + sRemoteCarry[slot].throwPending = 0; + sRemoteCarry[slot].carryOff[0] = sRemoteCarry[slot].carryOff[1] = sRemoteCarry[slot].carryOff[2] = 0.0f; + sRemoteCarry[slot].carryYawOff = 0.0f; +} + +static void __remoteCarry_setPose(s32 slot, f32 offset[3], f32 yawOffset) { + sRemoteCarry[slot].carryOff[0] = offset[0]; + sRemoteCarry[slot].carryOff[1] = offset[1]; + sRemoteCarry[slot].carryOff[2] = offset[2]; + sRemoteCarry[slot].carryYawOff = yawOffset; +} + +// Mirror of func_802D7DE8's arc math without its side effects. State 7 = remote flight. +static void __remoteCarry_launch(Actor *actor, f32 start[3], f32 target[3]) { + s32 tgt[3]; + f32 var_f12; + f32 var_f14; + f32 var_f18; + + actor->position[0] = start[0]; + actor->position[1] = start[1]; + actor->position[2] = start[2]; + ml_vec3f_to_vec3w(tgt, target); + actor->unk1C[0] = target[0]; + actor->unk1C[1] = target[1]; + actor->unk1C[2] = target[2]; + actor->velocity[0] = (f32)tgt[0] - actor->position[0]; + actor->velocity[1] = 28.0f; + actor->velocity[2] = (f32)tgt[2] - actor->position[2]; + var_f12 = actor->position[1]; + var_f14 = 28.0f; + var_f18 = 0.0f; + while (!(var_f12 < tgt[1]) || !(var_f14 < 0.0f)) { + var_f18 += 1.0f; + var_f12 += (var_f14 -= 5.0); + } + actor->velocity[0] /= var_f18; + actor->velocity[2] /= var_f18; + actor->unk38_31 = (u32)var_f18; + subaddie_set_state(actor, 7); +} + +static void __remoteCarry_spawnMethod(s32 markerId, s32 clientId) { + f32 pos[3]; + f32 yaw = 0.0f; + Actor *actor; + s32 slot = __remoteCarry_findByClient((u32)clientId); + s32 actorId = __remoteCarry_actorIdForMarker(markerId); + + if (slot < 0 || sRemoteCarry[slot].markerId != markerId || actorId == 0) { + return; // stale queue entry + } + if (!port_anchor_getDummyTransform((u32)clientId, pos, &yaw)) { + __remoteCarry_clearSlot(slot); + return; + } + actor = actor_spawnWithYaw_f32(actorId, pos, (s32)yaw); + // Display copy: skip init, no collision with the local player. + actor->volatile_initialized = true; + actor->marker->propPtr->unk8_3 = false; + if (sRemoteCarry[slot].throwPending) { + __remoteCarry_launch(actor, sRemoteCarry[slot].throwStart, sRemoteCarry[slot].throwTarget); + __remoteCarry_clearSlot(slot); + } else { + sRemoteCarry[slot].marker = actor->marker; + subaddie_set_state(actor, 6); + } +} + +void port_remoteCarry_setCarried(u32 clientId, s32 markerId, f32 offset[3], f32 yawOffset) { + s32 slot; + if (clientId == 0) { + return; + } + if (markerId != 0 && __remoteCarry_actorIdForMarker(markerId) == 0) { + markerId = 0; // not a synced carryable + } + slot = __remoteCarry_findByClient(clientId); + if (markerId == 0) { + if (slot >= 0 && !sRemoteCarry[slot].throwPending) { + if (sRemoteCarry[slot].marker != NULL) { + marker_despawn(sRemoteCarry[slot].marker); + } + __remoteCarry_clearSlot(slot); + } + return; + } + if (slot >= 0) { + if (sRemoteCarry[slot].markerId == markerId) { + __remoteCarry_setPose(slot, offset, yawOffset); + return; + } + if (sRemoteCarry[slot].marker != NULL) { + marker_despawn(sRemoteCarry[slot].marker); + } + __remoteCarry_clearSlot(slot); + } + slot = __remoteCarry_findByClient(0); + if (slot < 0) { + return; // registry full + } + sRemoteCarry[slot].clientId = clientId; + sRemoteCarry[slot].markerId = markerId; + sRemoteCarry[slot].marker = NULL; + sRemoteCarry[slot].throwPending = 0; + __remoteCarry_setPose(slot, offset, yawOffset); + __spawnQueue_add_2((void (*)(void))__remoteCarry_spawnMethod, markerId, clientId); +} + +void port_remoteCarry_throw(u32 clientId, s32 markerId, f32 start[3], f32 target[3]) { + s32 slot; + if (clientId == 0 || __remoteCarry_actorIdForMarker(markerId) == 0) { + return; + } + slot = __remoteCarry_findByClient(clientId); + if (slot >= 0 && sRemoteCarry[slot].marker != NULL) { + Actor *actor = marker_getActor(sRemoteCarry[slot].marker); + __remoteCarry_launch(actor, start, target); + __remoteCarry_clearSlot(slot); + return; + } + if (slot < 0) { + slot = __remoteCarry_findByClient(0); + if (slot < 0) { + return; + } + sRemoteCarry[slot].clientId = clientId; + __spawnQueue_add_2((void (*)(void))__remoteCarry_spawnMethod, markerId, clientId); + } + sRemoteCarry[slot].markerId = markerId; + sRemoteCarry[slot].throwPending = 1; + sRemoteCarry[slot].throwStart[0] = start[0]; + sRemoteCarry[slot].throwStart[1] = start[1]; + sRemoteCarry[slot].throwStart[2] = start[2]; + sRemoteCarry[slot].throwTarget[0] = target[0]; + sRemoteCarry[slot].throwTarget[1] = target[1]; + sRemoteCarry[slot].throwTarget[2] = target[2]; +} + +void port_remoteCarry_reset(void) { + s32 i; + for (i = 0; i < REMOTE_CARRY_MAX; i++) { + __remoteCarry_clearSlot(i); + } +} + +s32 port_remoteCarry_displayUpdate(Actor *this) { + s32 slot = __remoteCarry_findByMarker(this->marker); + + if (this->state == 6 || slot >= 0) { // carried: glued to the owner's dummy + f32 pos[3]; + f32 yaw = 0.0f; + if (slot < 0 || !port_anchor_getDummyTransform(sRemoteCarry[slot].clientId, pos, &yaw)) { + if (slot >= 0) { + __remoteCarry_clearSlot(slot); + } + marker_despawn(this->marker); + return 1; + } + this->position[0] = pos[0] + sRemoteCarry[slot].carryOff[0]; + this->position[1] = pos[1] + sRemoteCarry[slot].carryOff[1]; + this->position[2] = pos[2] + sRemoteCarry[slot].carryOff[2]; + this->yaw = mlNormalizeAngle(yaw + sRemoteCarry[slot].carryYawOff); + return 1; + } + + if (this->state == 7) { // thrown: replay the arc, land with feedback only + f32 landY; + this->position[0] += this->velocity[0]; + this->position[1] += (this->velocity[1] -= 5.0); + this->position[2] += this->velocity[2]; + landY = (--this->unk38_31 < 4) ? this->unk1C[1] : this->position[1]; + if (this->position[1] < landY) { + if (this->modelCacheIndex == ACTOR_2A2_CATERPILLAR || this->modelCacheIndex == ACTOR_2A9_ACORN) { + coMusicPlayer_playMusic(COMUSIC_2B_DING_B, 28000); + marker_despawn(this->marker); + return 1; + } + if (this->modelCacheIndex == ACTOR_2A_GOLD_BULLION) { + coMusicPlayer_playMusic(COMUSIC_2B_DING_B, 32000); + } + if (this->marker->id != MARKER_36_ORANGE_COLLECTIBLE) { + sfx_playFadeShorthandDefault(SFX_21_EGG_BOUNCE_1, 0.76f, 25000, this->position, 1000, 2000); + } else { + sfx_playFadeShorthandDefault(SFX_B3_ORANGE_TALKING, 1.0f, 25000, this->position, 1000, 2000); + } + // State 8: landed display copy. + this->position[1] = landY; + subaddie_set_state(this, 8); + return 1; + } + switch (this->marker->id) { + case MARKER_1FD_BLUE_PRESENT_COLLECTIBLE: + __chLevelCollectible_presentReturnEmitSparkles(this->position, ASSET_711_SPRITE_SPARKLE_DARK_BLUE); + break; + case MARKER_1FE_GREEN_PRESENT_COLLECTIBLE: + __chLevelCollectible_presentReturnEmitSparkles(this->position, 0x712); + break; + case MARKER_1FF_RED_PRESENT_COLLECTIBLE: + __chLevelCollectible_presentReturnEmitSparkles(this->position, ASSET_715_SPRITE_SPARKLE_RED); + break; + } + return 1; + } + + // State 8 (landed display copy) falls through to the vanilla lifecycle below. + + return 0; +} extern void timed_mapSpecificFlags_setTrue(f32, s32); extern void progressDialog_showDialogMaskFour(s32); @@ -149,6 +425,12 @@ void __chLevelCollectible_collide(ActorMarker *marker, ActorMarker *other_marker timedFunc_set_1(0.5f, (GenFunction_1)__chLevelCollectible_callDialog, dialog_id); } func_8028F030(this->modelCacheIndex); + { + s32 kind = levelCollectible_syncKind(marker->id); + if (kind >= 0) { + port_carriedSync_onLocalCollect(kind, marker); + } + } marker_despawn(marker); } } @@ -172,6 +454,12 @@ void func_802D7DE8(ActorMarker *marker, f32 arg1[3]) { } } func_8028F010(this->modelCacheIndex); + { + s32 kind = levelCollectible_syncKind(marker->id); + if (kind >= 0) { + port_carriedSync_onLocalSpend(kind); + } + } subaddie_set_state(this, 4); var_f12 = this->position[1]; var_f14 = 28.0f; @@ -283,6 +571,8 @@ void func_802D8374(Actor *this){ else{ if(this->unk138_21){ func_8028EF28(sp20); + // [port] Anchor: replay this throw on teammates; sent before func_802D7DE8 moves the actor. + port_anchor_onCarryThrow(this->marker->id, this->position, sp20); func_802D7DE8(this->marker, sp20); } } @@ -315,6 +605,10 @@ void chLevelCollectible_update(Actor *this){ s32 marker_id; if(this->despawn_flag) return; + if (port_remoteCarry_displayUpdate(this)) { + return; + } + if(!this->volatile_initialized){ this->volatile_initialized = true; if( this->marker->id == MARKER_1FD_BLUE_PRESENT_COLLECTIBLE @@ -329,9 +623,28 @@ void chLevelCollectible_update(Actor *this){ if(this->unk138_22){ func_8028F7D4(0.0f, 0.0f); subaddie_set_state(this, 3); + } else { + s32 kind = levelCollectible_syncKind(this->marker->id); + if (kind >= 0) { + s32 suppress; + port_carriedSync_register(kind, this->marker, (s32)this->position[0], + (s32)this->position[1], (s32)this->position[2], &suppress); + if (suppress) { + marker_despawn(this->marker); + return; + } + } } }//L802D85DC + if (!this->unk138_22) { + s32 kind = levelCollectible_syncKind(this->marker->id); + if (kind >= 0 && port_carriedSync_consumeRemoteDespawn(kind, this->marker)) { + marker_despawn(this->marker); + return; + } + } + switch(this->state){ case 5:// 802D8604 func_802D8030(this); diff --git a/src/core2/ch/mumbotoken.c b/src/core2/ch/mumbotoken.c index c3623b286..51242af9c 100644 --- a/src/core2/ch/mumbotoken.c +++ b/src/core2/ch/mumbotoken.c @@ -27,6 +27,7 @@ void chMumboToken_collect(ActorMarker *marker, ActorMarker *other_marker){ this = marker_getActor(marker); mumboscore_set(func_802E0CB0(this), true); + CALL_EVENT(OnCollectibleCollected, ANCHOR_COLLECTIBLE_MUMBO, func_802E0CB0(this)); func_8030E760(0x401, 1.0f, 0x7fff); timedFunc_set_1(0.75f, (GenFunction_1)progressDialog_showDialogMaskZero, FILEPROG_4_MUMBO_TOKEN_TEXT); fxSparkle_mumboToken(&marker->propPtr->x); diff --git a/src/core2/ch/snowman.c b/src/core2/ch/snowman.c index dba509c54..7bb4ce888 100644 --- a/src/core2/ch/snowman.c +++ b/src/core2/ch/snowman.c @@ -2,6 +2,8 @@ #include "functions.h" #include "variables.h" +#include "port/Patches/Patches.h" + extern void particleEmitter_func_802EFA20(ParticleEmitter *, f32, f32); extern void subaddie_set_state_with_direction(Actor *, s32, f32, s32); extern void subaddie_turnToYaw(Actor *, f32); @@ -185,8 +187,11 @@ void __chSnowman_deathCallback(ActorMarker *marker, ActorMarker *other_marker){ sfx_playFadeShorthandDefault(SFX_2F_ORANGE_SPLAT, 1.0f, 30000, actor->position, 1500, 4500); __spawnQueue_add_1((GenFunction_1)__chSnowman_spawnHat, (uintptr_t)actor->marker); - if(gsworld_getMap() == MAP_27_FP_FREEZEEZY_PEAK) + if(gsworld_getMap() == MAP_27_FP_FREEZEEZY_PEAK){ maSnowy_decRemaining(); + port_puzzlePos_mark(ANCHOR_PUZZLE_FP_SLUSHES, (s32)actor->position[0], (s32)actor->position[1], + (s32)actor->position[2]); + } __chSnowman_spawnSnowballParticles(actor->position, 0xC); marker_despawn(actor->marker); } @@ -224,8 +229,20 @@ void chSnowman_update(Actor *this){ if(gsworld_getMap() == MAP_27_FP_FREEZEEZY_PEAK){ local->unk0 = actorArray_findActorFromActorId(0x336)->marker; maSnowy_incTotal(); + if(port_puzzlePos_isMarked(ANCHOR_PUZZLE_FP_SLUSHES, (s32)this->position[0], + (s32)this->position[1], (s32)this->position[2])){ + maSnowy_decRemaining(); + marker_despawn(this->marker); + return; + } } }//L802E21D8 + if(gsworld_getMap() == MAP_27_FP_FREEZEEZY_PEAK && !this->despawn_flag + && port_puzzlePos_isMarked(ANCHOR_PUZZLE_FP_SLUSHES, (s32)this->position[0], + (s32)this->position[1], (s32)this->position[2])){ + __chSnowman_deathCallback(this->marker, NULL); + return; + } if(gsworld_getMap() == MAP_27_FP_FREEZEEZY_PEAK){ if(maSlalom_isActive() || func_8038DD14()){ actor_collisionOff(this); diff --git a/src/core2/fileselect.c b/src/core2/fileselect.c index 5f7b9e42a..837441c61 100644 --- a/src/core2/fileselect.c +++ b/src/core2/fileselect.c @@ -116,6 +116,7 @@ return 0; void gameFile_clear(s32 gamenum){ s32 filenum = gameFile_GameIdToFileIdMap[gamenum]; savedata_clear(&gameFile_saveData[filenum]); + CALL_EVENT(OnGameErase, gamenum); } void gameFile_load(s32 gamenum){ diff --git a/src/core2/flags_bitfield.c b/src/core2/flags_bitfield.c index 7e215e899..4a66d2da0 100644 --- a/src/core2/flags_bitfield.c +++ b/src/core2/flags_bitfield.c @@ -142,16 +142,25 @@ void func_8031FFAC(void) { func_8031FEC0(); } -void fileProgressFlag_set(enum file_progress_e index, s32 set) { +void fileProgressFlag_setEx(enum file_progress_e index, s32 set, s32 triggerEvent) { + s32 changed = bitfield_get_bit(gFileProgressFlags.unk8, index) != (set ? 1 : 0); bitfield_set_bit(gFileProgressFlags.unk8, index, set); func_8031FC40(); func_8031FEC0(); + if (triggerEvent && changed) { + CALL_EVENT(OnGameFlagSet, ANCHOR_FLAGSPACE_FILE_PROGRESS, index, set ? 1 : 0, 1); + } +} + +void fileProgressFlag_set(enum file_progress_e index, s32 set) { + fileProgressFlag_setEx(index, set, 1); } void fileProgressFlag_setN(enum file_progress_e startIndex, s32 set, s32 length) { bitfield_set_n_bits(gFileProgressFlags.unk8, startIndex, set, length); func_8031FC40(); func_8031FEC0(); + CALL_EVENT(OnGameFlagSet, ANCHOR_FLAGSPACE_FILE_PROGRESS, startIndex, set, length); } void fileProgressFlag_getSizeAndPtr(s32 *size, u8 **addr) { @@ -297,16 +306,30 @@ void volatileFlag_clear(void) { func_803203A0(); } -void volatileFlag_set(enum volatile_flags_e index, s32 set) { +void volatileFlag_setEx(enum volatile_flags_e index, s32 set, s32 triggerEvent) { + s32 changed = bitfield_get_bit(gVolatileFlags.unk8, index) != (set ? 1 : 0); bitfield_set_bit(gVolatileFlags.unk8, index, set); func_803202D0(); func_803203A0(); + if (triggerEvent && changed) { + CALL_EVENT(OnGameFlagSet, ANCHOR_FLAGSPACE_VOLATILE, index, set ? 1 : 0, 1); + } +} + +void volatileFlag_set(enum volatile_flags_e index, s32 set) { + volatileFlag_setEx(index, set, 1); } void volatileFlag_setN(enum volatile_flags_e startIndex, s32 set, s32 length) { bitfield_set_n_bits(gVolatileFlags.unk8, startIndex, set, length); func_803202D0(); func_803203A0(); + CALL_EVENT(OnGameFlagSet, ANCHOR_FLAGSPACE_VOLATILE, startIndex, set, length); +} + +void volatileFlag_getSizeAndPtr(s32 *size, u8 **addr) { + *size = 0x19; + *addr = gVolatileFlags.unk8; } s32 func_8032056C(void) { diff --git a/src/core2/fx/effect_jiggy_list.c b/src/core2/fx/effect_jiggy_list.c index efc1edcd6..2897b9748 100644 --- a/src/core2/fx/effect_jiggy_list.c +++ b/src/core2/fx/effect_jiggy_list.c @@ -253,6 +253,7 @@ void jiggy_spawn(enum jiggy_e jiggy_id, f32 pos[3]) { temp_v0->unk10.position[2] = pos[2]; temp_v0->init(&temp_v0->unk10); jiggyscore_setSpawned(jiggy_id, true); + CALL_EVENT(OnJiggySpawned, jiggy_id, pos[0], pos[1], pos[2]); if (!jiggyscore_isCollected(jiggy_id) && (jiggy_id != JIGGY_3E_GV_GRABBA) && (jiggy_id != JIGGY_0B_TTC_JINJO)) { core1_ce60_incOrDecCounter(false); func_8025A55C(0, 4000, 5); @@ -263,7 +264,15 @@ void jiggy_spawn(enum jiggy_e jiggy_id, f32 pos[3]) { } } -void codeABC00_spawnJiggyAtLocation(enum jiggy_e jiggy_id, f32 location[3]) { +// [port] Anchor: true once the jiggylist slot's marker is linked (covers bundle-pop, unlike jiggyscore_isSpawned). +s32 jiggylist_hasSpawnedObject(enum jiggy_e jiggy_id) { + if ((jiggy_id <= 0) || (jiggy_id >= (s_jiggyList_level_jiggy_count * 10))) { + return 0; + } + return jiggylist_list[jiggy_id - 1].unk10.marker != NULL; +} + +void codeABC00_spawnJiggyAtLocationEx(enum jiggy_e jiggy_id, f32 location[3], s32 triggerEvent) { jiggy_id = ((jiggy_id <= 0) || (jiggy_id >= (s_jiggyList_level_jiggy_count * 10))) ? JIGGY_A_MM_CONGA : jiggy_id; jiggylist_list[jiggy_id - 1].unk10.position[0] = location[0]; @@ -271,6 +280,13 @@ void codeABC00_spawnJiggyAtLocation(enum jiggy_e jiggy_id, f32 location[3]) { jiggylist_list[jiggy_id - 1].unk10.position[2] = location[2]; jiggylist_list[jiggy_id - 1].init(&jiggylist_list[jiggy_id - 1].unk10); jiggyscore_setSpawned(jiggy_id, true); + if (triggerEvent) { + CALL_EVENT(OnJiggySpawned, jiggy_id, location[0], location[1], location[2]); + } +} + +void codeABC00_spawnJiggyAtLocation(enum jiggy_e jiggy_id, f32 location[3]) { + codeABC00_spawnJiggyAtLocationEx(jiggy_id, location, 1); } void func_80333270(enum jiggy_e jiggy_id, f32 position[3], void (*method)(Actor *, ActorMarker *), ActorMarker *other_marker) { diff --git a/src/core2/gamestate.c b/src/core2/gamestate.c index 0ea5ed961..10cf40cbb 100644 --- a/src/core2/gamestate.c +++ b/src/core2/gamestate.c @@ -53,7 +53,7 @@ s32 item_getCount(enum item_e item){ } // func_80345FB4 -s32 item_adjustByDiff(enum item_e item, s32 diff, s32 no_hud){ +s32 item_adjustByDiff(enum item_e item, s32 diff, s32 no_hud, s32 triggerEvent){ // Modifies the count of an item by the diff // no_hud determines whether the HUD pops up during the adjustment s32 oldVal; @@ -175,6 +175,9 @@ s32 item_adjustByDiff(enum item_e item, s32 diff, s32 no_hud){ D_80385F30[ITEM_2B_UNKNOWN] += diff; break; } + if (triggerEvent) { + CALL_EVENT(OnItemCountChanged, item, D_80385F30[item]); + } return D_80385F30[item]; } @@ -182,18 +185,22 @@ s32 item_adjustByDiff(enum item_e item, s32 diff, s32 no_hud){ s32 item_adjustByDiffWithHud(enum item_e item, s32 diff){ // Modifies the count of an item by the diff // Displays the HUD during the adjustment - return item_adjustByDiff(item, diff, 0); + return item_adjustByDiff(item, diff, 0, 1); } // item_adjustByDiffWithoutHud void item_adjustByDiffWithoutHud(enum item_e item, s32 diff){ // Modifies the count of an item by the diff // Does not display the HUD during the adjustment - item_adjustByDiff(item, diff, 1); + item_adjustByDiff(item, diff, 1, 1); +} + +void item_setEx(s32 item, s32 val, s32 triggerEvent){ + item_adjustByDiff(item, val - item_getCount(item), 0, triggerEvent); } void item_set(s32 item, s32 val){ - item_adjustByDiffWithHud(item, val - item_getCount(item)); + item_setEx(item, val, 1); } // item_setMaxCount @@ -472,6 +479,19 @@ void notescore_getSizeAndPtr(s32 *size, void **ptr) { } } +// Raw per-level note-score array (vs. the packed u64 above). +void itemscore_noteScores_getSizeAndPtr(s32 *size, u8 **addr) { + *size = 0xE; + *addr = D_80385FF0; +} + +// Max-merge a level's note high score. +void itemscore_noteScores_setLevel(enum level_e level, s32 score) { + if (level >= 0 && level < 0xE && score > D_80385FF0[level]) { + D_80385FF0[level] = score; + } +} + void itemscore_noteScoress_maxAll(void) { s32 i; diff --git a/src/core2/level/specificflags.c b/src/core2/level/specificflags.c index f055d5c97..e31343008 100644 --- a/src/core2/level/specificflags.c +++ b/src/core2/level/specificflags.c @@ -101,16 +101,30 @@ void levelSpecificFlags_clear(void){ _levelSpecificFlags_updateCRC2(); } -void levelSpecificFlags_set(s32 index, s32 val){ +void levelSpecificFlags_setEx(s32 index, s32 val, s32 triggerEvent){ + s32 changed = bitfield_get_bit(D_80383320.unk8, index) != (val ? 1 : 0); bitfield_set_bit(D_80383320.unk8, index, val); _levelSpecificFlags_updateCRC1(); _levelSpecificFlags_updateCRC2(); + if (triggerEvent && changed) { + CALL_EVENT(OnGameFlagSet, ANCHOR_FLAGSPACE_LEVEL_SPECIFIC, index, val ? 1 : 0, 1); + } +} + +void levelSpecificFlags_set(s32 index, s32 val){ + levelSpecificFlags_setEx(index, val, 1); } void levelSpecificFlags_setN(s32 index, s32 val, s32 n){ bitfield_set_n_bits(D_80383320.unk8, index, val, n); _levelSpecificFlags_updateCRC1(); _levelSpecificFlags_updateCRC2(); + CALL_EVENT(OnGameFlagSet, ANCHOR_FLAGSPACE_LEVEL_SPECIFIC, index, val, n); +} + +void levelSpecificFlags_getSizeAndPtr(s32 *size, u8 **addr){ + *size = 8; + *addr = D_80383320.unk8; } s32 levelSpecificFlags_validateCRC1(void) { diff --git a/src/core2/map/gsworld.c b/src/core2/map/gsworld.c index 154af5ad4..137f7fdb4 100644 --- a/src/core2/map/gsworld.c +++ b/src/core2/map/gsworld.c @@ -7,7 +7,7 @@ #include #include "core2/particle.h" #include "port/Interpolation/FrameInterpolation.h" -#include "port/Enhancements/NoteRetention/NoteRetention.h" +#include "port/Enhancements/Retention/Retention.h" /* .data */ extern u8 D_80370250 = 0; @@ -432,6 +432,7 @@ void gsworld_load(enum map_e map_id) { File *fp; port_noteRetention_beginMapLoad((int32_t)map_id); + port_carriedSync_beginMapLoad((int32_t)map_id); core1_15B30_sendMesg3ToRenderThread(); fp = file_openMap(map_id); //LevelSetupFile_Open diff --git a/src/core2/map/specificflags.c b/src/core2/map/specificflags.c index dfaac4ad8..f371735de 100644 --- a/src/core2/map/specificflags.c +++ b/src/core2/map/specificflags.c @@ -43,16 +43,24 @@ u32 mapSpecificFlags_getN(s32 idx, s32 n){ u32 mapSpecificFlags_getClear(s32 i){ u32 ret_val = mapSpecificFlags_get(i); - mapSpecificFlags_set(i, 0); + mapSpecificFlags_setEx(i, 0, 0); return ret_val; } -void mapSpecificFlags_set(s32 i, s32 val){ +void mapSpecificFlags_setEx(s32 i, s32 val, s32 triggerEvent){ + s32 changed = ((D_80367000 >> i) & 1) != (val ? 1 : 0); if(val) D_80367000 |= 1 << i; else D_80367000 &= ~(1 << i); _mapSpecificFlags_updateCRCs(); + if (triggerEvent && changed) { + CALL_EVENT(OnGameFlagSet, ANCHOR_FLAGSPACE_MAP_SPECIFIC, i, val ? 1 : 0, 1); + } +} + +void mapSpecificFlags_set(s32 i, s32 val){ + mapSpecificFlags_setEx(i, val, 1); } void mapSpecificFlags_setN(s32 idx, s32 val, s32 n){ diff --git a/src/core2/quiz/game.c b/src/core2/quiz/game.c index fc740563c..bd961da9d 100644 --- a/src/core2/quiz/game.c +++ b/src/core2/quiz/game.c @@ -12,6 +12,9 @@ extern void func_802F9D38(s32); extern void func_802EE2E8(Actor *arg0, s32 arg1, s32 cnt, s32 arg3, f32 arg4, f32 arg5, f32 arg6); extern void gcquiz_func_80319EA4(void); +extern void port_lairWater_onRiseTrigger(int32_t waterMap, int32_t levelFlag); +extern int32_t port_lairWater_targetLevel(int32_t map, int32_t flagLevel); + void func_802D3D54(Actor *this); void func_802D3DA4(Actor *this); Actor *func_802D3F48(ActorMarker *this, Gfx **gdl, Mtx **mptr, Vtx **arg3); @@ -159,6 +162,9 @@ void func_802D317C(ActorMarker *marker, enum file_progress_e prog_flag_id) { marker_despawn(marker); } +extern void port_breakable_broadcastBreak(s32 markerId, s32 x, s32 y, s32 z); +extern s32 port_breakable_isBroken(s32 map, s32 markerId, s32 x, s32 y, s32 z); + // collision die function for several objects in Lair void func_802D31AC(ActorMarker *arg0, ActorMarker * arg1) { Actor *sp2C; @@ -171,6 +177,7 @@ void func_802D31AC(ActorMarker *arg0, ActorMarker * arg1) { case 0xFF: gcsfx_playAtSampleRate(SFX_82_METAL_BREAK); subaddie_set_state(sp2C, 4); + port_breakable_broadcastBreak(arg0->id, (s32)sp2C->position[0], (s32)sp2C->position[1], (s32)sp2C->position[2]); break; case 0x17D: @@ -191,6 +198,7 @@ void func_802D31AC(ActorMarker *arg0, ActorMarker * arg1) { case 0x107: gcsfx_playAtSampleRate(SFX_82_METAL_BREAK); func_802EE278(sp2C, 0xE, 0xF, 0x46, 0.8f, 0.7f); + port_breakable_broadcastBreak(arg0->id, (s32)sp2C->position[0], (s32)sp2C->position[1], (s32)sp2C->position[2]); marker_despawn(arg0); break; @@ -266,6 +274,7 @@ void func_802D31AC(ActorMarker *arg0, ActorMarker * arg1) { func_802EE278(sp2C, 7, 0x19, 0x82, 0.17f, 0.8f); break; } + port_breakable_broadcastBreak(arg0->id, (s32)sp2C->position[0], (s32)sp2C->position[1], (s32)sp2C->position[2]); marker_despawn(arg0); break; @@ -303,6 +312,7 @@ void func_802D31AC(ActorMarker *arg0, ActorMarker * arg1) { gcsfx_playAtSampleRate(SFX_82_METAL_BREAK); gcsfx_playAtSampleRate(SFX_B6_GLASS_BREAKING_1); func_802EE278(sp2C, 4, 0x23, 0x1E, 0.7f, 0.6f); + port_breakable_broadcastBreak(arg0->id, (s32)sp2C->position[0], (s32)sp2C->position[1], (s32)sp2C->position[2]); marker_despawn(arg0); break; @@ -319,6 +329,7 @@ void func_802D31AC(ActorMarker *arg0, ActorMarker * arg1) { if (arg0->id == 0x1F3) { func_802EE278(sp2C, 4, 0x2D, 0x104, 1.0f, 1.0f); } + port_breakable_broadcastBreak(arg0->id, (s32)sp2C->position[0], (s32)sp2C->position[1], (s32)sp2C->position[2]); marker_despawn(arg0); break; @@ -364,6 +375,101 @@ void func_802D3CE8(Actor *this){ marker_setCollisionScripts(this->marker, NULL, func_802D3138, func_802D31AC); this->marker->propPtr->unk8_3 = true; this->initialized = true; + if (port_breakable_isBroken((s32)gsworld_getMap(), this->marker->id, (s32)this->position[0], + (s32)this->position[1], (s32)this->position[2])) { + marker_despawn(this->marker); + } + } +} + +extern ActorArray *suBaddieActorArray; + +// fieldSel picks between two markers sharing an id: 0 = any, 1 = actorTypeSpecificField==1, 2 = !=1. +typedef struct { + s16 flag; + s16 markerId; + s8 fieldSel; +} LairBreakable; + +static const LairBreakable D_lairBreakables[] = { + { FILEPROG_A5_LAIR_CRYPT_GATE_OPEN, 0x17D, 0 }, + { FILEPROG_C2_GRATE_TO_RBB_PUZZLE_OPEN, 0x11A, 0 }, + { FILEPROG_C3_ICE_BALL_TO_CHEATO_BROKEN, 0x11E, 0 }, + { FILEPROG_C4_STATUE_EYE_BROKEN, MARKER_121_GLASS_EYE, 0 }, + { FILEPROG_C5_RAREWARE_BOX_BROKEN, 0x11F, 0 }, + { FILEPROG_C8_LAIR_BRICKWALL_TO_WADINGBOOTS_BROKEN, MARKER_109_BREAKABLE_BRICK_WALL, 1 }, + { FILEPROG_C9_LAIR_BRICKWALL_TO_SHOCKJUMP_PAD_BROKEN, MARKER_109_BREAKABLE_BRICK_WALL, 2 }, + { FILEPROG_CA_COBWEB_BLOCKING_PURPLE_CAULDRON_BROKEN, MARKER_225_BREAKABLE_WALL_COBWEB, 0 }, + { FILEPROG_CB_LAIR_COBWEB_OVER_FLIGHTPAD_BROKEN, MARKER_224_BREAKABLE_FLOOR_COBWEB, 1 }, + { FILEPROG_CC_LAIR_COBWEB_OVER_GREEN_CAULDRON_BROKEN, MARKER_224_BREAKABLE_FLOOR_COBWEB, 2 }, + { FILEPROG_CD_GRATE_TO_WATER_SWITCH_3_OPEN, 0x118, 0 }, + { FILEPROG_CE_GRATE_TO_MMM_PUZZLE_OPEN, 0x119, 0 }, +}; + +void port_breakable_remoteBreak(s32 progressFlag) { + s32 i; + s16 markerId = -1; + s8 fieldSel = 0; + + for (i = 0; i < (s32) (sizeof(D_lairBreakables) / sizeof(D_lairBreakables[0])); i++) { + if (D_lairBreakables[i].flag == progressFlag) { + markerId = D_lairBreakables[i].markerId; + fieldSel = D_lairBreakables[i].fieldSel; + break; + } + } + if (markerId < 0 || suBaddieActorArray == NULL) { + return; + } + for (i = 0; i < suBaddieActorArray->cnt; i++) { + Actor *actor = &suBaddieActorArray->data[i]; + if (actor->marker == NULL || actor->marker->id != markerId) { + continue; + } + if ((fieldSel == 1 && actor->actorTypeSpecificField != 1) || + (fieldSel == 2 && actor->actorTypeSpecificField == 1)) { + continue; + } + func_802D31AC(actor->marker, NULL); + return; + } +} + +void port_breakable_remoteBreakAt(s32 markerId, s32 x, s32 y, s32 z) { + s32 i; + + if (suBaddieActorArray == NULL) { + return; + } + for (i = 0; i < suBaddieActorArray->cnt; i++) { + Actor *actor = &suBaddieActorArray->data[i]; + if (actor->marker == NULL || actor->marker->id != markerId) { + continue; + } + if ((s32)actor->position[0] != x || (s32)actor->position[1] != y || (s32)actor->position[2] != z) { + continue; + } + func_802D31AC(actor->marker, NULL); + return; + } +} + +// [port] Iterates backward: despawn swap-removes from the end. +void port_breakable_despawnBrokenRestores(s32 map) { + s32 i; + + if (suBaddieActorArray == NULL) { + return; + } + for (i = suBaddieActorArray->cnt - 1; i >= 0; i--) { + Actor *actor = &suBaddieActorArray->data[i]; + if (actor->marker == NULL || actor->despawn_flag) { + continue; + } + if (port_breakable_isBroken(map, actor->marker->id, (s32)actor->position[0], (s32)actor->position[1], + (s32)actor->position[2])) { + marker_despawn(actor->marker); + } } } @@ -881,14 +987,28 @@ void func_802D5260(void) { if (levelSpecificFlags_get(LEVEL_FLAG_3C_LAIR_UNKNOWN) != false) { sp34 = D_803679C8[sp3C].unk6 + D_803676A4; } else { - sp34 = ((s16 *)&D_803679C8[sp3C])[(fileProgressFlag_get(FILEPROG_27_LAIR_WATER_LEVEL_3)) ? 3 - : (fileProgressFlag_get(FILEPROG_25_LAIR_WATER_LEVEL_2)) ? 2 - : (fileProgressFlag_get(FILEPROG_23_LAIR_WATER_LEVEL_1)) ? 1 - : 0]; + s32 lvl = (fileProgressFlag_get(FILEPROG_27_LAIR_WATER_LEVEL_3)) ? 3 + : (fileProgressFlag_get(FILEPROG_25_LAIR_WATER_LEVEL_2)) ? 2 + : (fileProgressFlag_get(FILEPROG_23_LAIR_WATER_LEVEL_1)) ? 1 + : 0; + lvl = port_lairWater_targetLevel(gsworld_getMap(), lvl); + sp34 = ((s16 *)&D_803679C8[sp3C])[lvl]; + } + static s32 sLairWaterMap = -1; + s32 curMap = gsworld_getMap(); + if (sLairWaterMap != curMap || levelSpecificFlags_get(LEVEL_FLAG_3C_LAIR_UNKNOWN)) { + sLairWaterMap = curMap; + } else { + f32 curY = sp38->type_6D.unk8; + f32 step = 240.0f * time_getDelta(); + f32 diff = sp34 - curY; + if (diff > step) sp34 = curY + step; + else if (diff < -step) sp34 = curY - step; + // within a step of the target: let sp34 stand. } func_8034DEB4(&sp38->type_6D, sp34); player_getPosition(sp28); - + fxRipple_802F363C(sp34 + ((sp3C != -1) ? (D_803679E0[sp3C] + ((sp3C == 2) ? (6600.0f < sp28[0]) ? -200 : 0 : 0)) : 0)); } } @@ -1121,11 +1241,13 @@ int func_802D60C4(void){ } void func_802D6114(void){ - s32 sp24; + s32 sp24; s32 sp20; + s32 camScript; sp24 = D_80367694;\ sp20 = D_80367698; + camScript = D_80367688; if(D_8036769C) fileProgressFlag_set(D_8036769C, true); func_802D6344(); @@ -1142,6 +1264,10 @@ void func_802D6114(void){ else{//L802D61DC func_80347A14(1); gcpausemenu_80314AC8(1); + // [port] Anchor: exit the camera manually; 0x30 (MM) and 0x40 (Door of Grunty) schedule their own exit. + if (camScript != 0x30 && camScript != 0x40) { + ncStaticCamera_exit(); + } } } @@ -1164,6 +1290,8 @@ void func_802D6264(f32 delay, enum map_e map_id, s32 arg2, s32 arg3, s32 arg4, e D_8036769C = arg5; D_803676A0 = 0; + port_lairWater_onRiseTrigger(map_id, arg5); + if(map_id != D_80367694){ timedFunc_set_1(delay, (GenFunction_1) func_802D61FC, map_id); } diff --git a/src/core2/savedata.c b/src/core2/savedata.c index e5c89ed91..39b9ec705 100644 --- a/src/core2/savedata.c +++ b/src/core2/savedata.c @@ -386,7 +386,7 @@ void saveData_load(void *savedata_){ func_8033C4E4((u8*)savedata); __savedata_load_abilities((u8*)savedata); for(i = 0; D_80370A20[i].unk0 != -1; i++){ - volatileFlag_set(D_80370A20[i].unk0, fileProgressFlag_get(D_80370A20[i].unk2)); + volatileFlag_setEx(D_80370A20[i].unk0, fileProgressFlag_get(D_80370A20[i].unk2), 0); } CALL_EVENT(OnSaveLoad, savedata); } @@ -395,7 +395,7 @@ void saveData_create(void *savedata_){ SaveData *savedata = (SaveData *)savedata_; int i; for(i = 0; D_80370A20[i].unk0 != -1; i++){ - fileProgressFlag_set(D_80370A20[i].unk2, volatileFlag_get(D_80370A20[i].unk0)); + fileProgressFlag_setEx(D_80370A20[i].unk2, volatileFlag_get(D_80370A20[i].unk0), 0); } savedata_clear((u8*)savedata); __savedata_save_magic((u8*)savedata); diff --git a/src/core2/scorequeue/drawui_models.c b/src/core2/scorequeue/drawui_models.c index df0f941ad..b2232f835 100644 --- a/src/core2/scorequeue/drawui_models.c +++ b/src/core2/scorequeue/drawui_models.c @@ -4,6 +4,7 @@ #include "port/Patches/Patches.h" #include "variables.h" #include "port/Engine.h" +#include "port/Interpolation/FrameInterpolation.h" extern f32 vtxList_getGlobalNorm(BKVertexList *); @@ -192,6 +193,7 @@ void fxcommon3score_draw(enum item_e item_id, void *arg1, Gfx **gfx, Mtx **mtx, sp40 = func_802FB0E4(arg1)*a1->unk54 + a1->unk34; if(a1->model != NULL && func_802FB0D4(arg1)){ + FrameInterpolation_RecordOpenChild("score_model", (uintptr_t)item_id); draw_x = a1->unk30 + port_hudOrthoShift(a1->unk30); a1->value_string[0] = '\0'; strIToA(a1->value_string, itemPrint_getValue(item_id)); @@ -216,6 +218,7 @@ void fxcommon3score_draw(enum item_e item_id, void *arg1, Gfx **gfx, Mtx **mtx, anctrl_drawSetup(a1->anim_ctrl, sp5C, 1); } modelRender_draw(gfx, mtx, sp5C, sp68, a1->unk3C*sp3C, sp44, a1->model); + FrameInterpolation_RecordCloseChild(); }//L80300BA4 } diff --git a/src/core2/spawn_queue.c b/src/core2/spawn_queue.c index d7a7aed28..44dcacee7 100644 --- a/src/core2/spawn_queue.c +++ b/src/core2/spawn_queue.c @@ -181,7 +181,7 @@ FunctionQueue *spawnQueue = NULL; /* .code */ // [port] N64 used 15 entries. If this overflows, find the root cause — // something is adding entries faster than they're being flushed. -#define SPAWN_QUEUE_DEFAULT_SIZE 15 +#define SPAWN_QUEUE_DEFAULT_SIZE 32 #define SPAWN_QUEUE_GL_SIZE 50 static u32 __spawnQueue_getMax(void) { diff --git a/src/port/DevTools/RemoteCollectSim.cpp b/src/port/DevTools/RemoteCollectSim.cpp new file mode 100644 index 000000000..5d6ef3c16 --- /dev/null +++ b/src/port/DevTools/RemoteCollectSim.cpp @@ -0,0 +1,100 @@ +// Dev tool: simulates a teammate's remote note/jinjo collects locally. Toggled by Dev Tools > +// General "Simulate Remote Collects". +// +// libultraship first: core2/timedfunc.h redefines `reinterpret_cast`, breaking MSVC's stdlib. +#include +#include "port/ShipInit.hpp" +#include "port/Enhancements/Events/PortEnhancements.h" +#include "port/Enhancements/Events/Hooks/Events.h" +#include "port/Enhancements/Retention/Retention.h" +#include "port/UI/cvar_prefixes.h" +#include "port/UI/Notification.h" + +#include +#include + +extern "C" { +#include "enums.h" +#include "functions.h" +} + +extern "C" void port_noteRetention_applyRemoteCollect(int32_t mapId, int32_t noteIndex, int32_t sameMap); +extern "C" int32_t port_noteRetention_debugPickLive(int32_t mapId); +extern "C" void port_jinjoRetention_applyRemoteCollect(int32_t map, int32_t bit, int32_t sameMap); +extern "C" int32_t port_jinjoRetention_debugPickLive(void); + +#define CVAR_SIM_REMOTE_COLLECT CVAR_DEVELOPER_TOOLS("SimRemoteCollect") + +namespace { + +using Clock = std::chrono::steady_clock; +constexpr std::chrono::seconds kInterval{ 30 }; + +bool sArmed = false; +int32_t sLastMap = -1; +Clock::time_point sNextFire; +bool sPreferNote = true; // alternate note/jinjo across successful ticks + +const char* jinjoColorName(int32_t bit) { + switch (bit) { + case 1 << 0: return "blue"; + case 1 << 1: return "green"; + case 1 << 2: return "orange"; + case 1 << 3: return "pink"; + case 1 << 4: return "yellow"; + default: return "?"; + } +} + +bool SimulateOne(bool note, int32_t map) { + if (note) { + int32_t idx = port_noteRetention_debugPickLive(map); + if (idx < 0) { + return false; + } + port_noteRetention_applyRemoteCollect(map, idx, 1); + Notification::Emit({ .message = "[Sim] remote note collect #" + std::to_string(idx) }); + return true; + } + int32_t bit = port_jinjoRetention_debugPickLive(); + if (bit == 0) { + return false; + } + port_jinjoRetention_applyRemoteCollect(map, bit, 1); + Notification::Emit({ .message = std::string("[Sim] remote jinjo collect (") + jinjoColorName(bit) + ")" }); + return true; +} + +void Tick() { + if (!retention::systemActive()) { + sArmed = false; + return; + } + int32_t map = (int32_t)gsworld_getMap(); + Clock::time_point now = Clock::now(); + if (!sArmed || map != sLastMap) { + sArmed = true; + sLastMap = map; + sNextFire = now + kInterval; + return; + } + if (now < sNextFire) { + return; + } + sNextFire = now + kInterval; + if (SimulateOne(sPreferNote, map)) { + sPreferNote = !sPreferNote; + } else { + SimulateOne(!sPreferNote, map); + } +} + +void RegisterRemoteCollectSim_Init() { + sArmed = false; + COND_HOOK(GameFrameUpdate, EVENT_PRIORITY_NORMAL, CVarGetInteger(CVAR_SIM_REMOTE_COLLECT, 0), + [](IEvent*) { Tick(); }); +} + +RegisterShipInitFunc initRemoteCollectSim(RegisterRemoteCollectSim_Init, { CVAR_SIM_REMOTE_COLLECT }); + +} // namespace diff --git a/src/port/Enhancements/Cheats/Cheats.cpp b/src/port/Enhancements/Cheats/Cheats.cpp index 2de8b7d81..d9d85a36e 100644 --- a/src/port/Enhancements/Cheats/Cheats.cpp +++ b/src/port/Enhancements/Cheats/Cheats.cpp @@ -11,6 +11,7 @@ extern "C" { #include "enums.h" #include "core2/statetimer.h" +#include "core2/ba/physics.h" #include "bs_funcs.h" #include "functions.h" @@ -184,23 +185,27 @@ void RegisterTalonTrotCycle_Init() { // MOVEMENT CHEATS // ============================================================================ -// Levitate — Hold L to float upward with gravity disabled +// Levitate — Hold L to float straight up; tapping L out of a damaging fall cancels the fall. void RegisterLevitate_Init() { + static const f32 LEVITATE_VELOCITY = 500.0f; static bool levitateActive = false; COND_HOOK(GameFrameUpdate, EVENT_PRIORITY_NORMAL, CVarGetInteger(CVAR_LEVITATE, 0), [](IEvent* event) { if (bakey_held(BUTTON_L)) { + // Cancel fall damage and the tumble/splat animation if pressed mid-fall. + if (bakey_pressed(BUTTON_L) && !player_isStable()) { + s32 fallDamage = 0; + if (bafalldamage_get_damage(&fallDamage) != 0) { + bafalldamage_start(); + bs_setState(BS_1_IDLE); + } + } baphysics_set_gravity(0.0f); - f32 pos[3]; - player_getPosition(pos); - pos[1] += 20.0f; - player_setPosition(pos); + baphysics_set_vertical_velocity(LEVITATE_VELOCITY); levitateActive = true; - } else { - // Only reset gravity once when L is released, not every frame - if (levitateActive) { - baphysics_reset_gravity(); - levitateActive = false; - } + } else if (levitateActive) { + // Only reset gravity once when L is released, not every frame. + baphysics_reset_gravity(); + levitateActive = false; } }); } diff --git a/src/port/Enhancements/Events/Hooks/Events.h b/src/port/Enhancements/Events/Hooks/Events.h index 72311533b..a1055d476 100644 --- a/src/port/Enhancements/Events/Hooks/Events.h +++ b/src/port/Enhancements/Events/Hooks/Events.h @@ -51,8 +51,26 @@ typedef enum VBehaviorID { VB_VILE_PLAYER_EAT_PIECE, VB_VILE_GAME_UPDATE, VB_VILE_CPU_AI, + // Anchor: lets a remotely-watered CCW flower grow without local camera/fanfare/jiggy. + VB_CCW_FLOWER_REMOTE_GROW, + // Anchor: gates FP twinkly minigame start so only one client owns a run at a time. + VB_FP_TWINKLY_START, + // Anchor: suppresses door-open camera lock when the flag came from a teammate, not us. + VB_DOOR_OPEN_CAMERA, + // CC rings water snap on run teardown (Anchor): suppressed when a teammate finished the rings. + VB_CC_RINGS_SNAP_WATER, + // Lair door remote-open "already handled" test (Anchor). Args: (s32 doorActorId, s32 doorState). + VB_LEVELDOOR_REMOTE_OPEN_DONE, } VBehaviorID; +typedef enum DoorCameraId { + GV_DOOR_CAM_SUN, // sun switch (flag 3) + GV_DOOR_CAM_STAR, // star switch / trapdoor (flag 5) + GV_DOOR_CAM_KAZOOIE, // beak-bomb door (flag 6) + GV_DOOR_CAM_JINXY, // Jinxy sneeze (flags 0, 1) + MMM_DOOR_CAM_CHURCH, // church door, Tumblar challenge (flag 0) +} DoorCameraId; + DEFINE_EVENT(VanillaBehavior, VBehaviorID id; bool* should; va_list * originalArgs;); #ifdef __cplusplus diff --git a/src/port/Enhancements/Events/Hooks/List/GameEvent.h b/src/port/Enhancements/Events/Hooks/List/GameEvent.h index e53254847..47f66605c 100644 --- a/src/port/Enhancements/Events/Hooks/List/GameEvent.h +++ b/src/port/Enhancements/Events/Hooks/List/GameEvent.h @@ -5,6 +5,17 @@ DEFINE_EVENT(OnActorDestroy, Actor* actor;) DEFINE_EVENT(OnGameSave, int32_t fileNum;) DEFINE_EVENT(OnGameLoad, int32_t fileNum;) +DEFINE_EVENT(OnGameErase, int32_t gameNum;) +// flagSpace = AnchorFlagSpace; length = 1 for single sets, bit count for setN. +DEFINE_EVENT(OnGameFlagSet, int32_t flagSpace; int32_t index; int32_t value; int32_t length;) +// count is the resulting absolute value. +DEFINE_EVENT(OnItemCountChanged, int32_t item; int32_t count;) +// kind = AnchorCollectibleSpace. +DEFINE_EVENT(OnCollectibleCollected, int32_t kind; int32_t id;) +// move = ability_e; value = 1 learned, 0 cleared. +DEFINE_EVENT(OnAbilityLearned, int32_t move; int32_t value;) +DEFINE_EVENT(OnJiggySpawned, int32_t jiggyId; float x; float y; float z;) +DEFINE_EVENT(OnTimedJiggyExpired, int32_t jiggyId;) DEFINE_EVENT(OnPropInit, Prop* propPtr;) DEFINE_EVENT(OnBottlesBonusComplete, int32_t index;) DEFINE_EVENT(OnSaveFileLoad, int32_t fileNum; void* saveBuffer; int32_t result;) diff --git a/src/port/Enhancements/Events/Hooks/List/RandoEvent.h b/src/port/Enhancements/Events/Hooks/List/RandoEvent.h index cdb556cd6..4b2da34a9 100644 --- a/src/port/Enhancements/Events/Hooks/List/RandoEvent.h +++ b/src/port/Enhancements/Events/Hooks/List/RandoEvent.h @@ -46,6 +46,8 @@ DEFINE_EVENT(OnIsJiggyScoreSpawned, int32_t jiggyId; int32_t result;) DEFINE_EVENT(SetRandoInfFlag, int32_t flagId; int32_t flagState;) +DEFINE_EVENT(OnRandoCheckObtained, int32_t randoCheckId; int32_t map;) + DEFINE_EVENT(OnIsHoneycombScoreCollected, int32_t honeycombId; int32_t result;) DEFINE_EVENT(ClearBundleDespawnQueue); diff --git a/src/port/Enhancements/Events/PortEnhancements.cpp b/src/port/Enhancements/Events/PortEnhancements.cpp index f369bb3be..dbca6c499 100644 --- a/src/port/Enhancements/Events/PortEnhancements.cpp +++ b/src/port/Enhancements/Events/PortEnhancements.cpp @@ -72,8 +72,15 @@ void PortEnhancements_Register() { REGISTER_EVENT(OnVileGameStateChange); // Register game events + REGISTER_EVENT(OnGameFlagSet); + REGISTER_EVENT(OnItemCountChanged); + REGISTER_EVENT(OnCollectibleCollected); + REGISTER_EVENT(OnAbilityLearned); + REGISTER_EVENT(OnJiggySpawned); + REGISTER_EVENT(OnTimedJiggyExpired); REGISTER_EVENT(OnGameLoad); REGISTER_EVENT(OnGameSave); + REGISTER_EVENT(OnGameErase); REGISTER_EVENT(OnBottlesBonusComplete); REGISTER_EVENT(OnSaveFileLoad); REGISTER_EVENT(OnSaveFileSave); @@ -104,6 +111,7 @@ void PortEnhancements_Register() { REGISTER_EVENT(OnIsJiggyScoreCollected); REGISTER_EVENT(OnIsJiggyScoreSpawned); REGISTER_EVENT(SetRandoInfFlag); + REGISTER_EVENT(OnRandoCheckObtained); REGISTER_EVENT(OnIsHoneycombScoreCollected); REGISTER_EVENT(ClearBundleDespawnQueue); REGISTER_EVENT(OnIsMumboTokenScoreCollected); diff --git a/src/port/Enhancements/JinjoRetention/JinjoRetention.cpp b/src/port/Enhancements/JinjoRetention/JinjoRetention.cpp deleted file mode 100644 index 4eb3ba567..000000000 --- a/src/port/Enhancements/JinjoRetention/JinjoRetention.cpp +++ /dev/null @@ -1,195 +0,0 @@ -// Jinjo Collection Retention -// -// Vanilla resets ITEM_12_JINJOS on every level entry (itemscore_levelReset), so jinjos -// respawn each visit and must all be collected in one go to earn the jiggy. This persists -// the per-level set of collected jinjo colors so individually collected jinjos stay -// collected across visits. -// -// How it works: -// - Saving is ALWAYS ON: collecting a jinjo records its color bit for the current -// level (same 5-bit layout as ITEM_12_JINJOS). -// - Application is behind an enhancement toggle (default off): when on, ITEM_12_JINJOS -// is seeded on level load from the saved bits, and already collected jinjos are not -// respawned. Collecting the remaining jinjos then completes the vanilla 0x1f mask and -// spawns the jiggy as usual. -// -// Stranded-jiggy guard: if all 5 of a level's jinjos are recorded but that level's jinjo -// jiggy has not been obtained (player got all 5 but skipped the jiggy), retention is not -// applied for that level -- the jinjos respawn so the jiggy can still be earned. -// -#include -#include - -#include "port/UI/cvar_prefixes.h" -#include "port/ShipInit.hpp" -#include "port/Enhancements/Events/PortEnhancements.h" -#include "port/Enhancements/Events/Hooks/Events.h" -#include "port/Enhancements/JinjoRetention/JinjoRetention.h" -#include "port/Rando/Rando.h" - -extern "C" { -#include "enums.h" -#include "actor.h" -#include "prop.h" -#include "functions.h" -} - -#define CVAR_JINJO_RETENTION CVAR_ENHANCEMENT("Gameplay.JinjoRetention") -#define CVAR_VALUE CVarGetInteger(CVAR_JINJO_RETENTION, 0) - -constexpr u8 kAllJinjos = 0x1F; // all five color bits collected - -// gameFile_saveData index of the live save slot for the current game, or -1. -int32_t activeSlot() { - if (selectedFileNum == DEFAULT_FILE_NUM || selectedFileNum < 0 || selectedFileNum >= 4) { - return -1; - } - return (int32_t)selectedFileNum; -} - -// Don't run during demos, Bottles bonus games, or rando files. -bool systemActive() { - int32_t slot = activeSlot(); - if (slot < 0 || gameFile_saveData[slot].shipSaveData.fileType == FILE_TYPE_SAVE_RANDO) { - return false; - } - switch (getGameMode()) { - case GAME_MODE_7_ATTRACT_DEMO: - case GAME_MODE_8_BOTTLES_BONUS: - case GAME_MODE_9_BANJO_AND_KAZOOIE: - case GAME_MODE_A_SNS_PICTURE: - return false; - default: - return true; - } -} - -bool applyEnabled() { - return CVarGetInteger(CVAR_JINJO_RETENTION, 0) != 0; -} - -JinjoRetentionSaveData* store() { - int32_t slot = activeSlot(); - return slot >= 0 ? &gameFile_saveData[slot].shipSaveData.jinjoRetention : nullptr; -} - -bool levelInRange(int32_t level) { - return level > 0 && level < JINJO_RETENTION_LEVEL_SLOTS; -} - -u8 collectedBits(int32_t level) { - JinjoRetentionSaveData* s = store(); - return (s != nullptr && levelInRange(level)) ? s->collected[level] : 0; -} - -u8 jinjoBitFromMarker(int32_t markerId) { - switch (markerId) { - case MARKER_5A_JINJO_BLUE: - case MARKER_5B_JINJO_GREEN: - case MARKER_5C_JINJO_ORANGE: - case MARKER_5D_JINJO_PINK: - case MARKER_5E_JINJO_YELLOW: - return (u8)(1 << ((markerId + 6) & 0x1F)); - default: - return 0; - } -} - -u8 jinjoBitFromActor(int32_t actorId) { - switch (actorId) { - case ACTOR_60_JINJO_BLUE: - return 1 << 0; - case ACTOR_62_JINJO_GREEN: - return 1 << 1; - case ACTOR_5F_JINJO_ORANGE: - return 1 << 2; - case ACTOR_61_JINJO_PINK: - return 1 << 3; - case ACTOR_5E_JINJO_YELLOW: - return 1 << 4; - default: - return 0; - } -} - -// Whether retention should seed/suppress jinjos for this level. False when retention is -// off, and false in the stranded-jiggy case so the jinjos respawn and the jiggy is still -// earnable. Seeding and suppression both gate on this so ITEM_12_JINJOS stays consistent. -bool retentionActiveForLevel(int32_t level) { - if (!applyEnabled() || !levelInRange(level)) { - return false; - } - if (collectedBits(level) == kAllJinjos && !jiggyscore_isCollected((enum jiggy_e)(10 * level - 9))) { - return false; - } - return true; -} - -void RegisterJinjoRetention_Init() { - // Record collection. Don't cancel: vanilla still updates ITEM_12_JINJOS / spawns the - // jiggy and despawns the jinjo. - COND_HOOK(OnActorCollision, EVENT_PRIORITY_NORMAL, CVAR_VALUE, [](IEvent* event) { - OnActorCollision* ev = (OnActorCollision*)event; - if (!systemActive() || !ev->propId->markerFlag) { - return; - } - ActorMarker* marker = ev->propId->actorProp.marker; - if (marker == nullptr) { - return; - } - u8 bit = jinjoBitFromMarker(marker->id); - if (bit == 0) { - return; - } - int32_t level = level_get(); - JinjoRetentionSaveData* s = store(); - if (s != nullptr && levelInRange(level)) { - s->collected[level] |= bit; - } - }); - - // Seed ITEM_12_JINJOS from the saved bits so prior progress carries across visits and - // the HUD reflects it. Mirrors note retention's OnSetJiggyList seeding. - COND_HOOK(OnSetJiggyList, EVENT_PRIORITY_NORMAL, CVAR_VALUE, [](IEvent* event) { - OnSetJiggyList* ev = (OnSetJiggyList*)event; - if (!systemActive() || !retentionActiveForLevel(ev->levelId)) { - return; - } - u8 bits = collectedBits(ev->levelId); - if (bits != 0) { - item_set(ITEM_12_JINJOS, bits); - } - }); - - // Suppress respawning already-collected jinjos. OnActorSpawn is cancellable; returning - // a null result with Cancelled means no actor spawns. - COND_HOOK(OnActorSpawn, EVENT_PRIORITY_NORMAL, CVAR_VALUE, [](IEvent* event) { - OnActorSpawn* ev = (OnActorSpawn*)event; - if (!systemActive()) { - return; - } - u8 bit = jinjoBitFromActor(ev->actorId); - if (bit == 0) { - return; - } - int32_t level = level_get(); - if (!retentionActiveForLevel(level) || !(collectedBits(level) & bit)) { - return; - } - ev->result = nullptr; - event->Cancelled = true; - }); - - // The engine's save double-buffers into a scratch slot via bcopy, which doesn't carry - // our bits. Sync the live slot's jinjoRetention into the buffer about to be serialized. - COND_HOOK(OnSaveFileSave, EVENT_PRIORITY_HIGH, CVAR_VALUE, [](IEvent* event) { - OnSaveFileSave* ev = (OnSaveFileSave*)event; - SaveData* buf = (SaveData*)ev->saveBuffer; - JinjoRetentionSaveData* live = store(); - if (buf != nullptr && live != nullptr && &buf->shipSaveData.jinjoRetention != live) { - buf->shipSaveData.jinjoRetention = *live; - } - }); -} - -static RegisterShipInitFunc initJinjoRetention(RegisterJinjoRetention_Init, { CVAR_JINJO_RETENTION }); diff --git a/src/port/Enhancements/JinjoRetention/JinjoRetention.h b/src/port/Enhancements/JinjoRetention/JinjoRetention.h deleted file mode 100644 index 91363c9d8..000000000 --- a/src/port/Enhancements/JinjoRetention/JinjoRetention.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef PORT_JINJO_RETENTION_H -#define PORT_JINJO_RETENTION_H - -// Jinjo Collection Retention is implemented entirely with port event listeners -// (collection, level-load seeding, spawn suppression) and needs no engine-side hooks, -// so this header only marks the module's presence for consistency with NoteRetention. - -#endif diff --git a/src/port/Enhancements/NoteRetention/NoteRetention.h b/src/port/Enhancements/NoteRetention/NoteRetention.h deleted file mode 100644 index 9022e9bef..000000000 --- a/src/port/Enhancements/NoteRetention/NoteRetention.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef PORT_NOTE_RETENTION_H -#define PORT_NOTE_RETENTION_H - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -void port_noteRetention_beginMapLoad(int32_t mapId); -void port_noteRetention_onActorsFreed(void); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/port/Enhancements/Retention/JinjoRetention.cpp b/src/port/Enhancements/Retention/JinjoRetention.cpp new file mode 100644 index 000000000..fc74bb170 --- /dev/null +++ b/src/port/Enhancements/Retention/JinjoRetention.cpp @@ -0,0 +1,263 @@ +// Jinjo Collection Retention +// +// Vanilla resets ITEM_12_JINJOS (per-level jinjo count) every level entry; this persists +// per-level collected colors across visits. +// +#include +#include + +#include "port/ShipInit.hpp" +#include "port/Enhancements/Events/PortEnhancements.h" +#include "port/Enhancements/Events/Hooks/Events.h" +#include "port/Enhancements/Retention/Retention.h" +#include "port/Rando/Rando.h" +#include "port/Rando/CustomObject/CustomObject.h" + +extern "C" { +#include "enums.h" +#include "actor.h" +#include "prop.h" +#include "functions.h" +} + +extern "C" int32_t port_jiggySpawn_isRecorded(int32_t jiggyId); + +static bool sForcedByAnchor = false; +#define CVAR_JINJO_RETENTION CVAR_ENHANCEMENT("Gameplay.JinjoRetention") +#define CVAR_VALUE (CVarGetInteger(CVAR_JINJO_RETENTION, 0) || sForcedByAnchor) + +constexpr u8 kAllJinjos = 0x1F; // all five color bits collected + +using retention::activeSlot; +using retention::systemActive; + +static bool applyEnabled() { + return CVAR_VALUE; +} + +extern "C" void port_jinjoRetention_setForced(int32_t forced) { + sForcedByAnchor = forced != 0; + ShipInit::Init(CVAR_JINJO_RETENTION); +} + +static JinjoRetentionSaveData* store() { + int32_t slot = activeSlot(); + return slot >= 0 ? &gameFile_saveData[slot].shipSaveData.jinjoRetention : nullptr; +} + +extern "C" void port_jinjoRetention_getSizeAndPtr(int32_t* size, uint8_t** addr) { + JinjoRetentionSaveData* s = store(); + if (s == nullptr) { + *size = 0; + *addr = nullptr; + return; + } + *size = (int32_t)sizeof(JinjoRetentionSaveData); + *addr = (uint8_t*)s; +} + +static bool levelInRange(int32_t level) { + return level > 0 && level < JINJO_RETENTION_LEVEL_SLOTS; +} + +static u8 collectedBits(int32_t level) { + JinjoRetentionSaveData* s = store(); + return (s != nullptr && levelInRange(level)) ? s->collected[level] : 0; +} + +static void setCollectedBits(int32_t level, u8 bits) { + JinjoRetentionSaveData* s = store(); + if (s != nullptr && levelInRange(level)) { + s->collected[level] = bits; + } +} + +static enum jiggy_e jinjoJiggy(int32_t level) { + return (enum jiggy_e)(10 * level - 9); +} + +static u8 jinjoBitFromMarker(int32_t markerId) { + switch (markerId) { + case MARKER_5A_JINJO_BLUE: + case MARKER_5B_JINJO_GREEN: + case MARKER_5C_JINJO_ORANGE: + case MARKER_5D_JINJO_PINK: + case MARKER_5E_JINJO_YELLOW: + return (u8)(1 << ((markerId + 6) & 0x1F)); + default: + return 0; + } +} + +static u8 jinjoBitFromActor(int32_t actorId) { + switch (actorId) { + case ACTOR_60_JINJO_BLUE: + return 1 << 0; + case ACTOR_62_JINJO_GREEN: + return 1 << 1; + case ACTOR_5F_JINJO_ORANGE: + return 1 << 2; + case ACTOR_61_JINJO_PINK: + return 1 << 3; + case ACTOR_5E_JINJO_YELLOW: + return 1 << 4; + default: + return 0; + } +} + +static int32_t jinjoActorFromBit(u8 bit) { + switch (bit) { + case 1 << 0: return ACTOR_60_JINJO_BLUE; + case 1 << 1: return ACTOR_62_JINJO_GREEN; + case 1 << 2: return ACTOR_5F_JINJO_ORANGE; + case 1 << 3: return ACTOR_61_JINJO_PINK; + case 1 << 4: return ACTOR_5E_JINJO_YELLOW; + default: return 0; + } +} + +extern "C" int32_t port_jinjoRetention_debugPickLive(void) { + static const enum actor_e kJinjoActors[] = { ACTOR_60_JINJO_BLUE, ACTOR_62_JINJO_GREEN, ACTOR_5F_JINJO_ORANGE, + ACTOR_61_JINJO_PINK, ACTOR_5E_JINJO_YELLOW }; + for (enum actor_e id : kJinjoActors) { + Actor* a = actorArray_findActorFromActorId(id); + if (a != nullptr && a->marker != nullptr) { + return jinjoBitFromActor(id); + } + } + return 0; +} + +extern "C" void port_jinjoRetention_applyRemoteCollect(int32_t map, int32_t bit, int32_t sameMap) { + int32_t level = map_getLevel((enum map_e)map); + JinjoRetentionSaveData* s = store(); + if (s != nullptr && levelInRange(level)) { + s->collected[level] |= (u8)bit; + } + // ITEM_12_JINJOS is per-level, not per-map; sub-areas are separate maps but share the count. + if (level == (int32_t)level_get()) { + item_set(ITEM_12_JINJOS, collectedBits(level)); + } + if (sameMap) { + int32_t actorId = jinjoActorFromBit((u8)bit); + if (actorId != 0) { + Actor* a = actorArray_findActorFromActorId((enum actor_e)actorId); + if (a != nullptr && a->marker != nullptr) { + marker_despawn(a->marker); + } + } + } +} + +// Called from the actual pickup (__chJinjo_802CDBA8), not broad-phase collision. +extern "C" void port_jinjoRetention_onLocalJinjoCollected(int32_t markerId) { + if (!applyEnabled() || !systemActive()) { + return; + } + u8 bit = jinjoBitFromMarker(markerId); + if (bit == 0) { + return; + } + int32_t level = level_get(); + JinjoRetentionSaveData* s = store(); + bool wasSet = (s != nullptr) && levelInRange(level) && ((s->collected[level] & bit) != 0); + if (s != nullptr && levelInRange(level)) { + s->collected[level] |= bit; + } + if (!wasSet) { + CALL_EVENT(OnCollectibleCollected, ANCHOR_COLLECTIBLE_JINJO, bit); + } +} + +// False when retention is off, or when the jiggy is stranded (all 5 recorded but not +// collected/spawned). +static bool retentionActiveForLevel(int32_t level) { + if (!applyEnabled() || !levelInRange(level)) { + return false; + } + if (collectedBits(level) == kAllJinjos && !jiggyscore_isCollected(jinjoJiggy(level)) && + !jiggyscore_isSpawned(jinjoJiggy(level)) && !port_jiggySpawn_isRecorded(jinjoJiggy(level))) { + return false; + } + return true; +} + +void RegisterJinjoRetention_Init() { + // Seed ITEM_12_JINJOS from saved bits on entry. + COND_HOOK(OnSetJiggyList, EVENT_PRIORITY_NORMAL, CVAR_VALUE, [](IEvent* event) { + OnSetJiggyList* ev = (OnSetJiggyList*)event; + if (!systemActive() || !applyEnabled() || !levelInRange(ev->levelId)) { + return; + } + int32_t level = ev->levelId; + if (jiggyscore_isCollected(jinjoJiggy(level))) { + // Jiggy earned but record out of sync — force all five. + if (collectedBits(level) != kAllJinjos) { + setCollectedBits(level, kAllJinjos); + } + } else if (collectedBits(level) == kAllJinjos && !jiggyscore_isSpawned(jinjoJiggy(level)) && + !port_jiggySpawn_isRecorded(jinjoJiggy(level))) { + // Orphaned: all recorded but jiggy neither collected nor spawned. + setCollectedBits(level, 0); + } + if (!retentionActiveForLevel(level)) { + return; + } + u8 bits = collectedBits(ev->levelId); + if (bits != 0) { + item_set(ITEM_12_JINJOS, bits); + } + }); + + // Suppress respawn of already-collected jinjos; null result + Cancelled = no spawn. + COND_HOOK(OnActorSpawn, EVENT_PRIORITY_NORMAL, CVAR_VALUE, [](IEvent* event) { + OnActorSpawn* ev = (OnActorSpawn*)event; + if (!systemActive()) { + return; + } + u8 bit = jinjoBitFromActor(ev->actorId); + if (bit == 0) { + return; + } + int32_t level = level_get(); + if (!retentionActiveForLevel(level) || !(collectedBits(level) & bit)) { + return; + } + ev->result = nullptr; + event->Cancelled = true; + }); + + // bcopy's scratch-slot save buffer doesn't carry our bits; sync them in. + COND_HOOK(OnSaveFileSave, EVENT_PRIORITY_HIGH, CVAR_VALUE, [](IEvent* event) { + OnSaveFileSave* ev = (OnSaveFileSave*)event; + SaveData* buf = (SaveData*)ev->saveBuffer; + JinjoRetentionSaveData* live = store(); + if (buf != nullptr && live != nullptr && &buf->shipSaveData.jinjoRetention != live) { + buf->shipSaveData.jinjoRetention = *live; + } + }); + + COND_VB_SHOULD(VB_OVERRIDE_BUNDLE_SPAWN, EVENT_PRIORITY_NORMAL, CVAR_VALUE, { + (void)va_arg(args, int); + BundleInfo* bundleInfo = va_arg(args, BundleInfo*); + (void)va_arg(args, s32); + (void)va_arg(args, f32*); + (void)va_arg(args, Actor**); + + if (!systemActive() || bundleInfo == nullptr) { + return; + } + u8 bit = jinjoBitFromActor(bundleInfo->actor_id); + if (bit == 0) { + return; + } + int32_t level = level_get(); + if (!retentionActiveForLevel(level) || !(collectedBits(level) & bit)) { + return; + } + *should = true; + }); +} + +static RegisterShipInitFunc initJinjoRetention(RegisterJinjoRetention_Init, { CVAR_JINJO_RETENTION }); diff --git a/src/port/Enhancements/NoteRetention/NoteRetention.cpp b/src/port/Enhancements/Retention/NoteRetention.cpp similarity index 58% rename from src/port/Enhancements/NoteRetention/NoteRetention.cpp rename to src/port/Enhancements/Retention/NoteRetention.cpp index 0f5651ff2..2f877fb77 100644 --- a/src/port/Enhancements/NoteRetention/NoteRetention.cpp +++ b/src/port/Enhancements/Retention/NoteRetention.cpp @@ -1,22 +1,8 @@ // Note Collection Retention // -// Persists which individual music notes the player has collected so they don't respawn -// on revisit. Works for vanilla and romhacks because each note is identified -// by (mapId, spawn-order index) within the map's deterministic cube-prop parse. -// -// How it works: -// - Static note sprite-props are replaced with ACTOR_51_MUSIC_NOTE actors so a -// stable spawn-order index can be attached to each via ObjectExtension. -// - Dynamically-spawned note bundles (hut/switch triggers) are also replaced with -// our own actors, given indices that continue AFTER the static notes for the map. -// Their identity resides in actor->local (not ObjectExtension) because bundle notes -// persist across sub-area save/restore, which copies the actor struct but assigns -// a fresh marker, so a marker-keyed extension wouldn't survive. -// - Saving is ALWAYS ON: collecting a note records (mapId, index) to the save. -// - Application is behind an enhancement toggle (default off): when on, already -// collected notes are not respawned, and ITEM_C_NOTE is seeded on level load -// from the collected count so totals stay reachable. Note-door logic is left -// to the vanilla per-level high score, unchanged. +// Notes are identified by (mapId, spawn-order index) from the map's deterministic cube parse. +// Bundle notes store identity in actor->local (survives sub-area save/restore, which copies +// the actor struct but assigns a new marker). // #include "port/ObjectExtension/ObjectExtension.h" #include @@ -26,7 +12,7 @@ #include "port/ShipInit.hpp" #include "port/Enhancements/Events/PortEnhancements.h" #include "port/Enhancements/Events/Hooks/Events.h" -#include "port/Enhancements/NoteRetention/NoteRetention.h" +#include "port/Enhancements/Retention/Retention.h" #include "port/Rando/Rando.h" #include "port/Rando/CustomObject/CustomObject.h" @@ -46,13 +32,12 @@ extern ActorInfo sumusicNote; namespace { #define CVAR_NOTE_RETENTION CVAR_ENHANCEMENT("Gameplay.NoteRetention") -#define CVAR_VALUE CVarGetInteger(CVAR_NOTE_RETENTION, 0) +static bool sForcedByAnchor = false; +#define CVAR_VALUE (CVarGetInteger(CVAR_NOTE_RETENTION, 0) || sForcedByAnchor) -// The note sprite asset id passed through VB_OVERRIDE_PROP_SPAWN identifies notes. constexpr s32 kNoteSpriteAsset = ASSET_6D6_SPRITE_MUSIC_NOTE; -// Per-actor note identity, attached via ObjectExtension. The constructor lets us -// build instances with parentheses, since brace-init commas break the event macros. +// Per-actor note identity. Parenthesized ctor avoids brace-init commas breaking event macros. struct NoteRetentionData { int32_t mapId; int32_t noteIndex; @@ -61,12 +46,8 @@ struct NoteRetentionData { }; ObjectExtension::Register NoteRetentionDataRegister; -// Identity for bundle notes, stored in the actor's local data block. Unlike static -// notes, bundle notes are restored across sub-area transitions by the engine's actor -// save-state, which memcpy's the whole Actor struct (so local survives) but assigns -// a new marker (so an extension wouldn't). -// magic distinguishes our data from the uninitialized garbage actor_new leaves -// in local, and from notes we didn't spawn. +// Identity for bundle notes, stored in actor->local (survives sub-area restore; a new marker +// is assigned, so an extension wouldn't). magic distinguishes our data from garbage. constexpr uint32_t kNoteLocalMagic = 0x4E4F5445u; // 'NOTE' struct NoteLocal { uint32_t magic; @@ -97,37 +78,11 @@ int64_t noteKey(int32_t mapId, int32_t noteIndex) { return ((int64_t)mapId << 32) | (uint32_t)noteIndex; } -// Active slot is wobbly -int32_t activeSlot() { - if (selectedFileNum == DEFAULT_FILE_NUM || selectedFileNum < 0 || selectedFileNum >= 4) { - return -1; - } - return (int32_t)selectedFileNum; -} - -bool fileValid() { - return activeSlot() >= 0; -} - -// Don't run during demos, Bottles bonus games, or rando files -bool systemActive() { - int32_t slot = activeSlot(); - if (slot < 0 || gameFile_saveData[slot].shipSaveData.fileType == FILE_TYPE_SAVE_RANDO) { - return false; - } - switch (getGameMode()) { - case GAME_MODE_7_ATTRACT_DEMO: - case GAME_MODE_8_BOTTLES_BONUS: - case GAME_MODE_9_BANJO_AND_KAZOOIE: - case GAME_MODE_A_SNS_PICTURE: - return false; - default: - return true; - } -} +using retention::activeSlot; +using retention::systemActive; bool applyEnabled() { - return CVarGetInteger(CVAR_NOTE_RETENTION, 0) != 0; + return CVAR_VALUE; } NoteRetentionSaveData* store() { @@ -162,9 +117,7 @@ int32_t countCollectedForLevel(int32_t levelId) { } int32_t total = 0; for (int32_t mapId = 0; mapId < NOTE_RETENTION_MAP_SLOTS; mapId++) { - // Count this map's collected bits first; only real maps that have been - // played ever get bits set. Skipping empties keeps us from calling - // map_getLevel on non-existent map ids (e.g. MAP_0_UNKNOWN), which crashes. + // Skip empty maps: map_getLevel crashes on non-existent ids (e.g. MAP_0_UNKNOWN). int32_t mapTotal = 0; for (int32_t b = 0; b < NOTE_RETENTION_BYTES_PER_MAP; b++) { uint8_t byte = s->collected[mapId][b]; @@ -185,21 +138,82 @@ int32_t countCollectedForLevel(int32_t levelId) { } // namespace -// Called from gsworld_load (the single entry that parses a map's cubes) before any -// cube is read. This is the reliable once-per-parse-pass signal -- it fires on every -// map load AND on intra-level warps/sub-area transitions that re-parse the cubes, -// even when OnMapLoad doesn't. Resetting the counter here keeps spawn-order indices -// stable across re-parses. The live-actor set is NOT cleared here: our note actors -// persist across map changes (they're only torn down by actorArray_free), so the set -// must persist too, or returning to a map would duplicate its still-live notes. +extern "C" void port_noteRetention_getSizeAndPtr(int32_t* size, uint8_t** addr) { + NoteRetentionSaveData* s = store(); + if (s == nullptr) { + *size = 0; + *addr = nullptr; + return; + } + *size = (int32_t)sizeof(NoteRetentionSaveData); + *addr = (uint8_t*)s; +} + +// Called from the actual pickup (MARKER_5F_MUSIC_NOTE), not broad-phase collision. +extern "C" void port_noteRetention_onLocalNoteCollected(void* markerPtr) { + if (!applyEnabled() || !systemActive()) { + return; + } + ActorMarker* marker = (ActorMarker*)markerPtr; + if (marker == nullptr || marker->id != MARKER_5F_MUSIC_NOTE) { + return; + } + int32_t mapId; + int32_t noteIndex; + NoteRetentionData* data = ObjectExtension::GetInstance().Get(marker); + if (data != nullptr) { + mapId = data->mapId; + noteIndex = data->noteIndex; + ObjectExtension::GetInstance().Remove(marker); + } else if (NoteLocal* nl = bundleNoteLocal(marker_getActor(marker))) { + mapId = nl->mapId; + noteIndex = nl->noteIndex; + nl->magic = 0; // consumed + } else { + return; // not one of ours + } + bool wasCollected = isCollected(mapId, noteIndex); + setCollected(mapId, noteIndex); + activeNoteSet.erase(noteKey(mapId, noteIndex)); + if (!wasCollected) { + CALL_EVENT(OnCollectibleCollected, ANCHOR_COLLECTIBLE_NOTE, noteIndex); + } +} + +extern "C" void port_noteRetention_applyRemoteCollect(int32_t mapId, int32_t noteIndex, int32_t sameMap) { + bool already = isCollected(mapId, noteIndex); + setCollected(mapId, noteIndex); + if (!already) { + // ITEM_C_NOTE is per-level; item_inc also bumps the high score and pause total. + int32_t level = map_getLevel((enum map_e)mapId); + if (level == (int32_t)level_get()) { + item_inc(ITEM_C_NOTE); + } else { + // Different level: can't touch live ITEM_C_NOTE, still bump its high score. + itemscore_noteScores_setLevel((enum level_e)level, countCollectedForLevel(level)); + } + } + if (sameMap) { + // Erase before despawn: OnActorDestroy's hook also erases this key. + auto it = activeNoteSet.find(noteKey(mapId, noteIndex)); + if (it != activeNoteSet.end()) { + ActorMarker* m = it->second; + activeNoteSet.erase(it); + if (m != nullptr) { + marker_despawn(m); + } + } + } +} + +// Called from gsworld_load before cube parsing; fires on every re-parse (map load, intra- +// level warps). Resets the index counter. extern "C" void port_noteRetention_beginMapLoad(int32_t mapId) { (void)mapId; noteCounter = 0; noteActorQueue.clear(); } -// Called from actorArray_free. At this point every note actor is gone, so drop the -// live-actor set and detach the ObjectExtension data. extern "C" void port_noteRetention_onActorsFreed(void) { for (auto& [key, marker] : activeNoteSet) { ObjectExtension::GetInstance().Remove(marker); @@ -208,8 +222,24 @@ extern "C" void port_noteRetention_onActorsFreed(void) { noteActorQueue.clear(); } +extern "C" void port_noteRetention_setForced(int32_t forced) { + sForcedByAnchor = forced != 0; + ShipInit::Init(CVAR_NOTE_RETENTION); +} + +extern "C" int32_t port_noteRetention_debugPickLive(int32_t mapId) { + for (auto& [key, marker] : activeNoteSet) { + int32_t keyMap = (int32_t)(key >> 32); + int32_t index = (int32_t)(uint32_t)(key & 0xFFFFFFFF); + if (keyMap == mapId && !isCollected(keyMap, index)) { + return index; + } + } + return -1; +} + void RegisterNoteRetention_Init() { - COND_VB_SHOULD(VB_OVERRIDE_PROP_SPAWN, EVENT_PRIORITY_NORMAL, true, { + COND_VB_SHOULD(VB_OVERRIDE_PROP_SPAWN, EVENT_PRIORITY_NORMAL, CVAR_VALUE, { s16* spawnPosition = va_arg(args, s16*); s32 spriteAsset = va_arg(args, s32); @@ -220,18 +250,18 @@ void RegisterNoteRetention_Init() { int32_t mapId = (int32_t)gsworld_getMap(); int32_t noteIndex = noteCounter++; if (!indexInRange(mapId, noteIndex)) { - return; // out of addressable range: leave as a vanilla sprite prop + return; // out of addressable range } - // From here we own this note: suppress the static sprite prop. + // We own this note: suppress the static sprite prop. *should = true; if (activeNoteSet.count(noteKey(mapId, noteIndex))) { - return; // a live actor already exists (re-parse): don't duplicate it + return; // a live actor already exists (re-parse) } if (applyEnabled() && isCollected(mapId, noteIndex)) { - return; // already collected and retention on: don't respawn it + return; // already collected and retention on } QueuedNote queued; @@ -244,7 +274,7 @@ void RegisterNoteRetention_Init() { noteActorQueue.push_back(queued); }); - // Flush queued notes into actors. actor_new does not re-fire OnActorSpawn, so no recursion. + // Flush queued notes into actors. actor_new does not re-fire OnActorSpawn. COND_HOOK(OnActorSpawn, EVENT_PRIORITY_NORMAL, CVAR_VALUE, [](IEvent* event) { if (!systemActive() || noteActorQueue.empty()) { return; @@ -260,7 +290,7 @@ void RegisterNoteRetention_Init() { Actor* note = actor_new(pos, 0, &sumusicNote, ACTOR_FLAG_UNKNOWN_21); ActorMarker* marker = (note != nullptr) ? note->marker : nullptr; if (marker != nullptr) { - // Key on the marker (stable across the actor's life and what the collision event hands us). + // Key on the marker (stable across the actor's life). ObjectExtension::GetInstance().Set(marker, NoteRetentionData(q.mapId, q.noteIndex)); activeNoteSet[noteKey(q.mapId, q.noteIndex)] = marker; } @@ -268,36 +298,33 @@ void RegisterNoteRetention_Init() { } }); - // Note bundles get spawn-order indices that continue after the map's static - // note count. We override the vanilla bundle spawn to substitute our own actor (carrying - // identity in local) and re-apply the vanilla fly-out physics. Detection is by the - // bundle's spawned actor type, so it stays romhack-agnostic. + // Bundle notes continue the map's index counter; identity stored in actor->local. COND_VB_SHOULD(VB_OVERRIDE_BUNDLE_SPAWN, EVENT_PRIORITY_NORMAL, true, { bundle_e bundleId = (bundle_e)va_arg(args, int); BundleInfo* bundleInfo = va_arg(args, BundleInfo*); - va_arg(args, s32); // index within the bundle (unused: we use our own counter) + va_arg(args, s32); // index within the bundle (unused) f32* position = va_arg(args, f32*); Actor** actorOut = va_arg(args, Actor**); if (!systemActive() || bundleInfo == nullptr || bundleInfo->actor_id != ACTOR_51_MUSIC_NOTE) { - return; // not our note bundle: leave it to vanilla (or rando) + return; // not our note bundle } int32_t mapId = (int32_t)gsworld_getMap(); int32_t noteIndex = noteCounter++; if (!indexInRange(mapId, noteIndex)) { - return; // out of addressable range: let vanilla spawn it normally + return; // out of addressable range } - // From here we own this note: suppress the vanilla bundle spawn. + // We own this note: suppress the vanilla bundle spawn. *should = true; int64_t key = noteKey(mapId, noteIndex); if (activeNoteSet.count(key)) { - return; // a live actor already exists (re-trigger this load): don't duplicate + return; // a live actor already exists (re-trigger this load) } if (applyEnabled() && isCollected(mapId, noteIndex)) { - return; // already collected and retention on: don't respawn it + return; // already collected and retention on } int32_t pos[3]; @@ -319,7 +346,6 @@ void RegisterNoteRetention_Init() { *actorOut = note; }); - // Prevent restoration from save states, as actors get re-added by the cubeprop parse. COND_HOOK(OnLoadActorSaveState, EVENT_PRIORITY_NORMAL, CVAR_VALUE, [](IEvent* event) { OnLoadActorSaveState* ev = (OnLoadActorSaveState*)event; if (!systemActive() || ev->actor == nullptr) { @@ -334,35 +360,7 @@ void RegisterNoteRetention_Init() { event->Cancelled = true; }); - // Record collection. Don't cancel: vanilla still increments ITEM_C_NOTE and despawns. - COND_HOOK(OnActorCollision, EVENT_PRIORITY_NORMAL, CVAR_VALUE, [](IEvent* event) { - OnActorCollision* ev = (OnActorCollision*)event; - if (!systemActive() || !ev->propId->markerFlag) { - return; - } - ActorMarker* marker = ev->propId->actorProp.marker; - if (marker == nullptr || marker->id != MARKER_5F_MUSIC_NOTE) { - return; - } - int32_t mapId; - int32_t noteIndex; - NoteRetentionData* data = ObjectExtension::GetInstance().Get(marker); - if (data != nullptr) { - mapId = data->mapId; - noteIndex = data->noteIndex; - ObjectExtension::GetInstance().Remove(marker); - } else if (NoteLocal* nl = bundleNoteLocal(marker_getActor(marker))) { - mapId = nl->mapId; - noteIndex = nl->noteIndex; - nl->magic = 0; // consumed - } else { - return; // not one of ours - } - setCollected(mapId, noteIndex); - activeNoteSet.erase(noteKey(mapId, noteIndex)); - }); - - // Seed the level's note counter from collected notes so totals stay reachable. + // Seed the level's note counter from collected notes. COND_HOOK(OnSetJiggyList, EVENT_PRIORITY_NORMAL, CVAR_VALUE, [](IEvent* event) { OnSetJiggyList* ev = (OnSetJiggyList*)event; if (!systemActive() || !applyEnabled()) { @@ -371,9 +369,7 @@ void RegisterNoteRetention_Init() { item_set(ITEM_C_NOTE, countCollectedForLevel(ev->levelId)); }); - // With retention applied, the vanilla note-score messages become misleading or fire - // spuriously (seeding ITEM_C_NOTE on load re-triggers the high-score milestones), so - // suppress them while the CVar is on. + // Seeding ITEM_C_NOTE re-triggers vanilla high-score dialogs; suppress them. COND_VB_SHOULD(VB_OVERRIDE_DIALOG_SHOW, EVENT_PRIORITY_NORMAL, true, { s32 textId = va_arg(args, s32); if (!applyEnabled()) { @@ -383,6 +379,7 @@ void RegisterNoteRetention_Init() { case 0xD9C: // Bottles' first-note text: "you can't take notes with you" case 0xF76: // "you just beat your high score" case 0xF74: // milestone: 50 notes (Mumbo's Mountain) + case 0xF78: // milestone: collected every note in the level *should = true; break; default: @@ -390,7 +387,6 @@ void RegisterNoteRetention_Init() { } }); - // Clean up per-marker data when actors are destroyed (marker pointers get reused). COND_HOOK(OnActorDestroy, EVENT_PRIORITY_NORMAL, CVAR_VALUE, [](IEvent* event) { OnActorDestroy* ev = (OnActorDestroy*)event; if (ev->actor == nullptr) { @@ -409,9 +405,7 @@ void RegisterNoteRetention_Init() { } }); - // The engine's save double-buffers into a scratch slot via bcopy, which doesn't - // reliably carry our note bits. Sync the live active slot's noteRetention into the - // buffer about to be serialized. + // bcopy's scratch-slot save buffer doesn't carry our bits; sync them in. COND_HOOK(OnSaveFileSave, EVENT_PRIORITY_HIGH, CVAR_VALUE, [](IEvent* event) { OnSaveFileSave* ev = (OnSaveFileSave*)event; SaveData* buf = (SaveData*)ev->saveBuffer; @@ -422,4 +416,4 @@ void RegisterNoteRetention_Init() { }); } -static RegisterShipInitFunc initNoteRetention(RegisterNoteRetention_Init); +static RegisterShipInitFunc initNoteRetention(RegisterNoteRetention_Init, { CVAR_NOTE_RETENTION }); diff --git a/src/port/Enhancements/Retention/Retention.cpp b/src/port/Enhancements/Retention/Retention.cpp new file mode 100644 index 000000000..a31153472 --- /dev/null +++ b/src/port/Enhancements/Retention/Retention.cpp @@ -0,0 +1,39 @@ +// Helpers shared by the note and jinjo retention systems. +// +// libultraship must precede the decomp headers: core2/timedfunc.h (via functions.h) defines a +// C-compat `reinterpret_cast` macro that breaks the MSVC C++ standard library. +#include +#include "port/Enhancements/Retention/Retention.h" +#include "port/Rando/Rando.h" // selectedFileNum, gameFile_saveData, DEFAULT_FILE_NUM, FILE_TYPE_SAVE_RANDO + +extern "C" { +#include "enums.h" +#include "functions.h" +} + +namespace retention { + +int32_t activeSlot() { + if (selectedFileNum == DEFAULT_FILE_NUM || selectedFileNum < 0 || selectedFileNum >= 4) { + return -1; + } + return (int32_t)selectedFileNum; +} + +bool systemActive() { + int32_t slot = activeSlot(); + if (slot < 0 || gameFile_saveData[slot].shipSaveData.fileType == FILE_TYPE_SAVE_RANDO) { + return false; + } + switch (getGameMode()) { + case GAME_MODE_7_ATTRACT_DEMO: + case GAME_MODE_8_BOTTLES_BONUS: + case GAME_MODE_9_BANJO_AND_KAZOOIE: + case GAME_MODE_A_SNS_PICTURE: + return false; + default: + return true; + } +} + +} // namespace retention diff --git a/src/port/Enhancements/Retention/Retention.h b/src/port/Enhancements/Retention/Retention.h new file mode 100644 index 000000000..67b045462 --- /dev/null +++ b/src/port/Enhancements/Retention/Retention.h @@ -0,0 +1,77 @@ +#ifndef PORT_RETENTION_H +#define PORT_RETENTION_H + +// Shared header for the vanilla collectible-retention systems (notes and jinjos). + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// --- Note retention --- + +void port_noteRetention_beginMapLoad(int32_t mapId); +void port_noteRetention_onActorsFreed(void); + +// Live slot's note-retention bytes for Anchor team-state sync (size 0 / null if no slot). +void port_noteRetention_getSizeAndPtr(int32_t* size, uint8_t** addr); + +void port_noteRetention_applyRemoteCollect(int32_t mapId, int32_t noteIndex, int32_t sameMap); + +// Record + broadcast a local note pickup (marker is ActorMarker*, void* to avoid engine types). +void port_noteRetention_onLocalNoteCollected(void* marker); + +// Force retention on/off regardless of the user CVar (Anchor uses this while connected). +void port_noteRetention_setForced(int32_t forced); + +// --- Jinjo retention --- + +// Live slot's jinjo-retention bytes for Anchor team-state sync (size 0 / null if no slot). +void port_jinjoRetention_getSizeAndPtr(int32_t* size, uint8_t** addr); + +void port_jinjoRetention_applyRemoteCollect(int32_t map, int32_t bit, int32_t sameMap); + +// Record + broadcast a local jinjo pickup. Call from the actual collection, not proximity. +void port_jinjoRetention_onLocalJinjoCollected(int32_t markerId); + +// Force retention on/off regardless of the user CVar (Anchor uses this while connected). +void port_jinjoRetention_setForced(int32_t forced); + +// --- CCW carried-collectible live-despawn sync (worms for Eyrie, acorns for Nabnut) --- +// +// Carried count is ITEM_22/23. Object identity is a hash of its fixed spawn position. `kind` = +// ANCHOR_COLLECTIBLE_WORM/_ACORN; marker is ActorMarker* (void* to avoid engine types). + +void port_carriedSync_beginMapLoad(int32_t mapId); + +// Registers a world object, attaching spawn-position identity to the marker. Sets *suppress +// non-zero if a teammate already collected it. +void port_carriedSync_register(int32_t kind, void* marker, int32_t x, int32_t y, int32_t z, + int32_t* suppress); + +void port_carriedSync_onLocalCollect(int32_t kind, void* marker); + +// Broadcast a local spend (feeding Eyrie/Nabnut): -1 to the shared pool. +void port_carriedSync_onLocalSpend(int32_t kind); + +// Apply a teammate's pickup (id = spawn-position hash): marks it collected. +void port_carriedSync_applyRemoteCollect(int32_t kind, int32_t mapId, int32_t id, int32_t sameMap); + +// True if a teammate collected this object (caller should despawn). +int32_t port_carriedSync_consumeRemoteDespawn(int32_t kind, void* marker); + +int32_t port_carriedSync_collectedCount(int32_t kind); + +#ifdef __cplusplus +} + +namespace retention { +// Active save slot index (0-3) for the current game, or -1 (default/demo file). +int32_t activeSlot(); +// False during demos, Bottles bonus games, and rando files. +bool systemActive(); +} // namespace retention +#endif + +#endif diff --git a/src/port/Enhancements/Retention/WormSync.cpp b/src/port/Enhancements/Retention/WormSync.cpp new file mode 100644 index 000000000..aa2e98928 --- /dev/null +++ b/src/port/Enhancements/Retention/WormSync.cpp @@ -0,0 +1,178 @@ +// CCW Carried-Collectible Live-Despawn Sync (worms for Eyrie, acorns for Nabnut). +// +// Carried count is ITEM_22/23. Object identity is a hash of its fixed spawn position, keyed +// with (kind, mapId, hash). +// +#include +#include "port/ObjectExtension/ObjectExtension.h" +#include "port/ShipInit.hpp" +#include "port/Enhancements/Events/PortEnhancements.h" +#include "port/Enhancements/Events/Hooks/Events.h" +#include "port/Enhancements/Retention/Retention.h" + +#include +#include + +extern "C" { +#include "enums.h" +#include "actor.h" +#include "functions.h" +} + +namespace { + +// Per-object identity. Parenthesized ctor avoids brace-init commas breaking event macros. +struct CarriedSpawnData { + int32_t mapId; + int32_t hash; + CarriedSpawnData(int32_t m = 0, int32_t h = 0) : mapId(m), hash(h) { + } +}; +ObjectExtension::Register CarriedSpawnDataRegister; + +// (slot, mapId, hash) of every carried collectible the team has picked up this session. +std::set> sCollected; + +int32_t slotForKind(int32_t kind) { + switch (kind) { + case ANCHOR_COLLECTIBLE_WORM: + return 0; + case ANCHOR_COLLECTIBLE_ACORN: + return 1; + case ANCHOR_COLLECTIBLE_PRESENT_BLUE: + return 2; + case ANCHOR_COLLECTIBLE_PRESENT_GREEN: + return 3; + case ANCHOR_COLLECTIBLE_PRESENT_RED: + return 4; + case ANCHOR_COLLECTIBLE_GOLD: + return 5; + case ANCHOR_COLLECTIBLE_ORANGE: + return 6; + default: + return -1; + } +} + +// Identity from spawn position; masked non-negative to avoid the -1 spend sentinel. +int32_t spawnHash(int32_t x, int32_t y, int32_t z) { + uint32_t h = (uint32_t)x * 73856093u ^ (uint32_t)y * 19349663u ^ (uint32_t)z * 83492791u; + return (int32_t)(h & 0x7FFFFFFFu); +} + +bool isCollected(int32_t slot, int32_t mapId, int32_t hash) { + return sCollected.count({ slot, mapId, hash }) != 0; +} + +} // namespace + +extern "C" void port_carriedSync_beginMapLoad(int32_t mapId) { + (void)mapId; +} + +extern "C" void port_carriedSync_register(int32_t kind, void* marker, int32_t x, int32_t y, int32_t z, + int32_t* suppress) { + *suppress = 0; + int32_t slot = slotForKind(kind); + if (slot < 0 || marker == nullptr) { + return; + } + int32_t mapId = (int32_t)gsworld_getMap(); + int32_t hash = spawnHash(x, y, z); + ObjectExtension::GetInstance().Set(marker, CarriedSpawnData(mapId, hash)); + if (isCollected(slot, mapId, hash)) { + *suppress = 1; + } +} + +extern "C" void port_carriedSync_onLocalCollect(int32_t kind, void* marker) { + int32_t slot = slotForKind(kind); + if (slot < 0) { + return; + } + CarriedSpawnData* d = ObjectExtension::GetInstance().Get(marker); + if (d == nullptr) { + return; + } + sCollected.insert({ slot, d->mapId, d->hash }); + CALL_EVENT(OnCollectibleCollected, kind, d->hash); +} + +extern "C" void port_carriedSync_onLocalSpend(int32_t kind) { + if (slotForKind(kind) < 0) { + return; + } + // A spend (feeding Eyrie/Nabnut) is -1 to the shared pool. + CALL_EVENT(OnCollectibleCollected, kind, -1); +} + +extern "C" void port_carriedSync_applyRemoteCollect(int32_t kind, int32_t mapId, int32_t id, int32_t sameMap) { + (void)sameMap; + int32_t slot = slotForKind(kind); + if (slot < 0 || id < 0) { + return; + } + sCollected.insert({ slot, mapId, id }); +} + +// Snapshot/restore as flat [slot, mapId, hash] tuples. +std::vector port_carriedSync_snapshotCollected() { + std::vector flat; + flat.reserve(sCollected.size() * 3); + for (const auto& e : sCollected) { + flat.insert(flat.end(), e.begin(), e.end()); + } + return flat; +} + +void port_carriedSync_restoreCollected(const std::vector& flat) { + sCollected.clear(); + for (size_t i = 0; i + 3 <= flat.size(); i += 3) { + sCollected.insert({ flat[i], flat[i + 1], flat[i + 2] }); + } +} + +extern "C" int32_t port_carriedSync_collectedCount(int32_t kind) { + int32_t slot = slotForKind(kind); + if (slot < 0) { + return 0; + } + int32_t count = 0; + for (const auto& e : sCollected) { + if (e[0] == slot) { + count++; + } + } + return count; +} + +void port_carriedSync_clearForLevel(int32_t levelId) { + std::erase_if(sCollected, [levelId](const std::array& e) { + return (int32_t)map_getLevel((enum map_e)e[1]) == levelId; + }); +} + +extern "C" int32_t port_carriedSync_consumeRemoteDespawn(int32_t kind, void* marker) { + int32_t slot = slotForKind(kind); + if (slot < 0) { + return 0; + } + CarriedSpawnData* d = ObjectExtension::GetInstance().Get(marker); + if (d == nullptr) { + return 0; + } + return isCollected(slot, d->mapId, d->hash) ? 1 : 0; +} + +void RegisterWormSync_Init() { + REGISTER_LISTENER(OnSaveLoad, EVENT_PRIORITY_NORMAL, [](IEvent* event) { sCollected.clear(); }); + + REGISTER_LISTENER(OnActorDestroy, EVENT_PRIORITY_NORMAL, [](IEvent* event) { + OnActorDestroy* ev = (OnActorDestroy*)event; + if (ev->actor != nullptr && ev->actor->marker != nullptr) { + ObjectExtension::GetInstance().Remove(ev->actor->marker); + } + }); +} + +static RegisterShipInitFunc initWormSync(RegisterWormSync_Init, {}); diff --git a/src/port/Network/Anchor/Anchor.cpp b/src/port/Network/Anchor/Anchor.cpp index f33f51ca1..9db72a587 100644 --- a/src/port/Network/Anchor/Anchor.cpp +++ b/src/port/Network/Anchor/Anchor.cpp @@ -6,11 +6,11 @@ #include "port/Nametag/Nametag.h" #include "port/Interpolation/FrameInterpolation.h" #include "port/ObjectExtension/ObjectExtension.h" +#include "port/Enhancements/Retention/Retention.h" extern "C" { #include "variables.h" #include "functions.h" -// extern PlayState* gPlayState; } // MARK: - Overrides @@ -30,7 +30,11 @@ void Anchor::Enable() { Network::Enable(CVarGetString(CVAR_REMOTE_ANCHOR("Host"), "anchor.hm64.org"), CVarGetInteger(CVAR_REMOTE_ANCHOR("Port"), 43383)); ownClientId = CVarGetInteger(CVAR_REMOTE_ANCHOR("LastClientId"), 0); - roomState.ownerClientId = 0; + roomState = RoomState{}; +} + +bool Anchor::IsGlobalRoom() { + return std::string("lh-global") == CVarGetString(CVAR_REMOTE_ANCHOR("RoomId"), ""); } void Anchor::Disable() { @@ -52,14 +56,22 @@ void Anchor::OnConnected() { SendPacket_Handshake(); RegisterHooks(); + port_noteRetention_setForced(1); + port_jinjoRetention_setForced(1); + if (IsSaveLoaded()) { SendPacket_RequestTeamState(); + hasRequestedTeamState = true; + reloadMapOnTeamState = true; } } void Anchor::OnDisconnected() { Authority_Reset(); RegisterHooks(); + + port_noteRetention_setForced(0); + port_jinjoRetention_setForced(0); } void Anchor::ProcessOutgoingPackets() { @@ -187,6 +199,38 @@ void Anchor::ProcessIncomingPacketQueue() { HandlePacket_SetCheckStatus(payload); else if (packetType == SET_FLAG) HandlePacket_SetFlag(payload); + else if (packetType == ITEM_COUNT) + HandlePacket_SetItemCount(payload); + else if (packetType == SET_ABILITY) + HandlePacket_SetAbility(payload); + else if (packetType == SCOPED_FLAG) + HandlePacket_ScopedFlag(payload); + else if (packetType == REQUEST_SCOPED_STATE) + HandlePacket_RequestScopedState(payload); + else if (packetType == SCOPED_STATE) + HandlePacket_ScopedState(payload); + else if (packetType == COLLECT_ITEM) + HandlePacket_CollectItem(payload); + else if (packetType == CARRY_THROW) + HandlePacket_CarryThrow(payload); + else if (packetType == BREAK_OBJECT) + HandlePacket_BreakObject(payload); + else if (packetType == EGG_TOLL) + HandlePacket_EggToll(payload); + else if (packetType == PUZZLE_STEP) + HandlePacket_PuzzleStep(payload); + else if (packetType == WATER_RISE) + HandlePacket_WaterRise(payload); + else if (packetType == PUZZLE_COUNT) + HandlePacket_PuzzleCount(payload); + else if (packetType == HUT_SMASH) + HandlePacket_HutSmash(payload); + else if (packetType == JIGGY_CRANE) + HandlePacket_JiggyCrane(payload); + else if (packetType == PEDESTAL_OWNER) + HandlePacket_PedestalOwner(payload); + else if (packetType == JIGGY_SPAWN) + HandlePacket_SpawnJiggy(payload); else if (packetType == TELEPORT_TO) HandlePacket_TeleportTo(payload); else if (packetType == UNSET_FLAG) @@ -207,6 +251,12 @@ void Anchor::ProcessIncomingPacketQueue() { HandlePacket_VileHoleState(payload); else if (packetType == VILE_UPDATE) HandlePacket_VileUpdate(payload); + else if (packetType == FIGHT_UPDATE) + HandlePacket_FightUpdate(payload); + else if (packetType == FIGHT_EVENT) + HandlePacket_FightEvent(payload); + else if (packetType == FIGHT_STATE) + HandlePacket_FightState(payload); } catch (const std::exception& e) { SPDLOG_ERROR("[Anchor] Exception while processing incoming packet {}", e.what()); SPDLOG_ERROR("[Anchor] Packet: {}", payload.dump()); @@ -246,14 +296,24 @@ void Anchor::DrawDummies(OnPlayerDraw* event) { void Anchor::ClearDummies() { for (auto& [id, dummy] : dummies) { - dummy->dummy_detachActor(); + dummy->dummy_despawnActor(); // skips if already detached by map teardown } dummies.clear(); } -// Takes the map explicitly rather than reading gsworld_getMap(): during the -// OnMapLoad event the new map hasn't been committed yet, so gsworld_getMap() -// still reports the map being left. +// actorArray_free tears down actors/markers without firing OnActorDestroy; forget them all. +extern "C" void port_anchorDummies_onActorsFreed(void) { + Anchor* anchor = Anchor::GetInstance(); + if (anchor == nullptr) { + return; + } + for (auto& [clientId, client] : anchor->clients) { + if (client.dummy != nullptr) { + client.dummy->dummy_detachActor(); + } + } +} + void Anchor::PopulateDummies(GameMap map) { for (const auto& [clientId, client] : clients) { if (client.map == map && !client.self && !dummies.contains(clientId) && client.online) { @@ -276,21 +336,59 @@ void Anchor::UpdateDummies() { } void Anchor::OnActorDestroyed(Actor* actor) { - // for (auto& [clientId, client] : clients) { - // if (client.dummy != nullptr && client.dummy->getDummyActor() == actor) { - // client.dummy->dummy_detachActor(); - // RemoveDummy(clientId); - // return; - // } - // } + // Stand-in was destroyed externally; forget its marker, dummy stays registered. + if (actor == nullptr || actor->marker == nullptr) { + return; + } + for (auto& [clientId, client] : clients) { + if (client.dummy != nullptr && client.dummy->dummy_getMarker() == actor->marker) { + client.dummy->dummy_detachActor(); + return; + } + } } void Anchor::RemoveDummy(uint32_t clientId) { if (dummies.contains(clientId)) { + dummies[clientId]->dummy_despawnActor(); dummies.erase(clientId); } } +extern void port_breakable_clearForLevel(int32_t levelId); +extern void port_hutSmash_clearForLevel(int32_t levelId); +extern void port_eggToll_clearForLevel(int32_t levelId); +extern void port_puzzleStep_clearForLevel(int32_t levelId); +extern void port_carriedSync_clearForLevel(int32_t levelId); + +void Anchor::SweepUnoccupiedLevelState(GameMap selfMap) { + bool occupied[0x20] = { false }; // level_e ids are small; matches jinjo retention slot count + auto markOccupied = [&occupied](s32 map) { + if (map <= 0 || map >= MAP_NUM_MAPS) { + return; + } + s32 level = (s32)map_getLevel((enum map_e)map); + if (level > 0 && level < 0x20) { + occupied[level] = true; + } + }; + markOccupied((s32)selfMap); + for (auto& [clientId, client] : clients) { + if (!client.self && client.online && client.isSaveLoaded) { + markOccupied((s32)client.map); + } + } + for (s32 level = 1; level < 0x20; level++) { + if (!occupied[level]) { + port_breakable_clearForLevel(level); + port_hutSmash_clearForLevel(level); + port_eggToll_clearForLevel(level); + port_puzzleStep_clearForLevel(level); + port_carriedSync_clearForLevel(level); + } + } +} + void Anchor::RegisterDummy(DummyPlayer* dummy, uint32_t clientID) { dummies.emplace(clientID, dummy); } @@ -323,23 +421,22 @@ void Anchor::RefreshClientActors() { } bool Anchor::IsSaveLoaded() { + s32 gameMode = getGameMode(); + if (gameMode == GAME_MODE_6_FILE_PLAYBACK || gameMode == GAME_MODE_7_ATTRACT_DEMO) { + return false; + } auto map = gsworld_getMap(); return map != MAP_1E_CS_START_NINTENDO && map != MAP_1F_CS_START_RAREWARE && map != MAP_91_FILE_SELECT; - /* if (gPlayState == nullptr) { - return false; - } - - if (GET_PLAYER(gPlayState) == nullptr) { - return false; - } - - if (gSaveContext.fileNum < 0 || gSaveContext.fileNum > 2) { - return false; - } +} - if (gSaveContext.gameMode != GAMEMODE_NORMAL) { - return false; - }*/ +bool Anchor::ShouldShowNotifications() { + return CVarGetInteger(CVAR_REMOTE_ANCHOR("Notifications"), 1) != 0; +} - // return true; +std::string Anchor::GetClientName(uint32_t clientId) { + auto it = clients.find(clientId); + if (it != clients.end() && !it->second.name.empty()) { + return it->second.name; + } + return "A teammate"; } diff --git a/src/port/Network/Anchor/Anchor.h b/src/port/Network/Anchor/Anchor.h index 5ffbdbcb7..1a547ae6a 100644 --- a/src/port/Network/Anchor/Anchor.h +++ b/src/port/Network/Anchor/Anchor.h @@ -4,6 +4,8 @@ #include #include #include +#include +#include #include #include "port/Enhancements/Events/Hooks/Events.h" #include "port/Network/Anchor/DummyPlayer.h" @@ -13,14 +15,8 @@ extern "C" { #include "prop.h" #include "variables.h" -//#include "z64.h" } -// void DummyPlayer_Init(Actor* actor, PlayState* play); -// void DummyPlayer_Update(Actor* actor, PlayState* play); -// void DummyPlayer_Draw(Actor* actor, PlayState* play); -// void DummyPlayer_Destroy(Actor* actor, PlayState* play); - typedef struct { uint32_t clientId; std::string name; @@ -38,15 +34,20 @@ typedef struct { DummyPlayer* dummy; } AnchorClient; -typedef struct { - uint32_t ownerClientId; - u8 pvpMode; // 0 = off, 1 = on, 2 = on with friendly fire - u8 showLocationsMode; // 0 = none, 1 = team, 2 = all - u8 teleportMode; // 0 = off, 1 = team, 2 = all - u8 syncItemsAndFlags; // 0 = off, 1 = on - bool isRomhack; +struct RoomState { + uint32_t ownerClientId = 0; + u8 pvpMode = 0; // 0 = off, 1 = on, 2 = on with friendly fire + u8 showLocationsMode = 0; // 0 = none, 1 = team, 2 = all + u8 teleportMode = 0; // 0 = off, 1 = team, 2 = all + u8 syncItemsAndFlags = 0; // 0 = off, 1 = on + u8 shareConsumables = 0; // 0 = off, 1 = on — share egg/feather counts in team state + bool isRomhack = false; std::string romhackName; -} RoomState; + bool isRando = false; + int32_t seed = 0; // rando seed id (0 when the room is vanilla) +}; + +bool Anchor_ScopedFlagExcluded(s32 space, s32 index); class Anchor : public Network { private: @@ -55,12 +56,15 @@ class Anchor : public Network { bool justLoadedSave = false; bool isHandlingUpdateTeamState = false; bool isProcessingIncomingPacket = false; + bool hasRequestedTeamState = false; std::queue incomingPacketQueue; std::mutex incomingPacketQueueMutex; std::queue outgoingPacketQueue; std::mutex outgoingPacketQueueMutex; std::unordered_map dummies; + void FlushPendingJiggySpawns(); + nlohmann::json PrepClientState(); nlohmann::json PrepRoomState(); void RegisterHooks(); @@ -94,6 +98,25 @@ class Anchor : public Network { void HandlePacket_ServerMessage(nlohmann::json& payload); void HandlePacket_SetCheckStatus(nlohmann::json& payload); void HandlePacket_SetFlag(nlohmann::json& payload); + void HandlePacket_SetItemCount(nlohmann::json& payload); + void HandlePacket_SetAbility(nlohmann::json& payload); + void HandlePacket_ScopedFlag(nlohmann::json& payload); + void HandlePacket_RequestScopedState(nlohmann::json& payload); + void HandlePacket_ScopedState(nlohmann::json& payload); + void HandlePacket_CollectItem(nlohmann::json& payload); + void HandlePacket_CarryThrow(nlohmann::json& payload); + void HandlePacket_BreakObject(nlohmann::json& payload); + void HandlePacket_EggToll(nlohmann::json& payload); + void HandlePacket_FightEvent(nlohmann::json& payload); + void HandlePacket_FightState(nlohmann::json& payload); + void HandlePacket_FightUpdate(nlohmann::json& payload); + void HandlePacket_PuzzleStep(nlohmann::json& payload); + void HandlePacket_PuzzleCount(nlohmann::json& payload); + void HandlePacket_WaterRise(nlohmann::json& payload); + void HandlePacket_HutSmash(nlohmann::json& payload); + void HandlePacket_JiggyCrane(nlohmann::json& payload); + void HandlePacket_PedestalOwner(nlohmann::json& payload); + void HandlePacket_SpawnJiggy(nlohmann::json& payload); void HandlePacket_TeleportTo(nlohmann::json& payload); void HandlePacket_UnsetFlag(nlohmann::json& payload); void HandlePacket_UpdateClientState(nlohmann::json& payload); @@ -107,6 +130,7 @@ class Anchor : public Network { public: uint32_t ownClientId; + bool reloadMapOnTeamState = false; inline static const std::string clientVersion = (char*)gGitCommitHash; // Packet types // @@ -130,6 +154,25 @@ class Anchor : public Network { inline static const std::string SERVER_MESSAGE = "SERVER_MESSAGE"; inline static const std::string SET_CHECK_STATUS = "SET_CHECK_STATUS"; inline static const std::string SET_FLAG = "SET_FLAG"; + inline static const std::string ITEM_COUNT = "ITEM_COUNT"; + inline static const std::string SET_ABILITY = "SET_ABILITY"; + inline static const std::string SCOPED_FLAG = "SCOPED_FLAG"; + inline static const std::string REQUEST_SCOPED_STATE = "REQUEST_SCOPED_STATE"; + inline static const std::string SCOPED_STATE = "SCOPED_STATE"; + inline static const std::string COLLECT_ITEM = "COLLECT_ITEM"; + inline static const std::string CARRY_THROW = "CARRY_THROW"; + inline static const std::string BREAK_OBJECT = "BREAK_OBJECT"; + inline static const std::string EGG_TOLL = "EGG_TOLL"; + inline static const std::string FIGHT_EVENT = "FIGHT_EVENT"; + inline static const std::string FIGHT_STATE = "FIGHT_STATE"; + inline static const std::string FIGHT_UPDATE = "FIGHT_UPDATE"; + inline static const std::string PUZZLE_STEP = "PUZZLE_STEP"; + inline static const std::string PUZZLE_COUNT = "PUZZLE_COUNT"; + inline static const std::string WATER_RISE = "WATER_RISE"; + inline static const std::string HUT_SMASH = "HUT_SMASH"; + inline static const std::string JIGGY_CRANE = "JIGGY_CRANE"; + inline static const std::string PEDESTAL_OWNER = "PEDESTAL_OWNER"; + inline static const std::string JIGGY_SPAWN = "JIGGY_SPAWN"; inline static const std::string TELEPORT_TO = "TELEPORT_TO"; inline static const std::string UNSET_FLAG = "UNSET_FLAG"; inline static const std::string UPDATE_CLIENT_STATE = "UPDATE_CLIENT_STATE"; @@ -143,6 +186,9 @@ class Anchor : public Network { std::map clients; RoomState roomState; + std::string lastWarnedRomhackLabel; + std::string lastWarnedRandoState; + bool hasCheckedRandoCompat = false; void Enable(); void Disable(); @@ -158,10 +204,13 @@ class Anchor : public Network { uint32_t GetDummyPlayerClientId(const Actor* actor); bool GetCurrentMapPlayers(); - void PrepDirectionPayload(nlohmann::json& payload); - void PrepTransformationPayload(nlohmann::json& payload); - void PrepAnimStatePayload(nlohmann::json& payload); - void PrepAnimSubRangePayload(nlohmann::json& payload); + bool IsGlobalRoom(); + + void AdoptRemoteCheck(s32 rc); + void CheckRandoRoomCompatibility(); + + bool ShouldShowNotifications(); + std::string GetClientName(uint32_t clientId); void SendPacket_AuthorityState(u8 activity, bool claimed); void SendPacket_ClearTeamState(std::string teamId); @@ -180,12 +229,30 @@ class Anchor : public Network { // client (used to hand a late arrival our current state directly). void SendPacket_PlayerTransformChange(Transformation tf_id, uint32_t targetClientId = 0); void SendPacket_PlayerUpdate(bool full = false, uint32_t targetClientId = 0); - void SendPacket_RequestTeamState(); - void SendPacket_RequestTeleport(u32 clientId); - void SendPacket_SetCheckStatus(/*RandomizerCheck rc*/); - void SendPacket_SetFlag(s16 sceneNum, s16 flagType, s16 flag); - void SendPacket_TeleportTo(u32 clientId); - void SendPacket_UnsetFlag(s16 sceneNum, s16 flagType, s16 flag); + void SendPacket_RequestTeamState(bool force = false); + void SendPacket_RequestTeleport(uint32_t clientId); + void SendPacket_SetCheckStatus(s32 rc, s32 map); + void SendPacket_SetFlag(u8 flagSpace, s16 flag); + void SendPacket_SetItemCount(s16 item, s32 count); + void SendPacket_SetAbility(s16 move, u8 value); + void SendPacket_ScopedFlag(u8 space, s16 index, u8 value); + void SendPacket_RequestScopedState(GameMap map); + void SendPacket_CollectItem(u8 kind, s32 id); + void SendPacket_CarryThrow(s32 markerId, f32 start[3], f32 target[3]); + void SendPacket_BreakObject(s16 markerId, s32 x, s32 y, s32 z, s32 map, bool replay = true); + void SendPacket_EggToll(s16 secondaryId, s32 stage, s32 map); + void SendPacket_FightEvent(s32 ev, s32 a, s32 b, const f32 v0[3], const f32 v1[3], const f32 v2[3]); + void SendPacket_FightState(u32 targetClientId); + void SendPacket_FightUpdate(const f32 pos[3], f32 yaw, s32 state, s32 phase, s32 mirror, s32 vuln); + void SendPacket_PuzzleStep(s32 puzzleId, s32 bits, s32 map, s32 phash = 0); + void SendPacket_PuzzleCount(s32 counterId, s32 delta, s32 map); + void SendPacket_WaterRise(s32 map, s32 kind, s32 p1, s32 p2, f32 duration); + void SendPacket_HutSmash(s32 x, s32 y, s32 z, s32 loot, s32 map); + void SendPacket_JiggyCrane(s32 stage); + void SendPacket_PedestalOwner(s32 id, bool claimed); + void SendPacket_SpawnJiggy(s16 jiggyId, f32 x, f32 y, f32 z); + void SendPacket_TeleportTo(uint32_t clientId); + void SendPacket_UnsetFlag(u8 flagSpace, s16 flag); void SendPacket_UpdateClientState(); void SendPacket_UpdateRoomState(); void SendPacket_UpdateTeamState(); @@ -196,6 +263,8 @@ class Anchor : public Network { void SendPacket_VileUpdate(const f32 position[3], f32 pitch, f32 yaw, f32 roll, u8 animMode); void OnActorDestroyed(Actor* actor); void SendToCurrentMapPlayers(nlohmann::json& payload); + void SendToCurrentLevelPlayers(nlohmann::json& payload); + void SweepUnoccupiedLevelState(GameMap selfMap); static Anchor* GetInstance(); static void Init(); diff --git a/src/port/Network/Anchor/AnchorRoomWindow.cpp b/src/port/Network/Anchor/AnchorRoomWindow.cpp index 589ccd760..62cd34c72 100644 --- a/src/port/Network/Anchor/AnchorRoomWindow.cpp +++ b/src/port/Network/Anchor/AnchorRoomWindow.cpp @@ -1,5 +1,7 @@ #include "Anchor.h" #include "port/Engine.h" +#include "port/Rando/Rando.h" +#include "port/GameStatus.h" extern "C" { #include "variables.h" @@ -34,9 +36,7 @@ void AnchorRoomWindow::Draw() { } void AnchorRoomWindow::DrawElement() { - bool isGlobalRoom = (std::string("soh-global") == CVarGetString(CVAR_REMOTE_ANCHOR("RoomId"), "")); - - if (isGlobalRoom) { + if (Anchor::GetInstance()->IsGlobalRoom()) { u32 activeClients = 0; for (auto& [clientId, client] : Anchor::GetInstance()->clients) { if (client.online) { @@ -84,9 +84,8 @@ void AnchorRoomWindow::DrawElement() { (Anchor::GetInstance()->roomState.showLocationsMode == 1 && isOwnTeam)) { if ((client.self ? Anchor::GetInstance()->IsSaveLoaded() : client.isSaveLoaded)) { ImGui::SameLine(); - ImGui::TextColored( - ImVec4(1, 1, 1, 0.5f), "- %s", - /*SohUtils::GetSceneName(client.self ? gPlayState->sceneNum : client.sceneNum).c_str()*/ ""); + ImGui::TextColored(ImVec4(1, 1, 1, 0.5f), "- %s", + port_getLevelName((int)(client.self ? gsworld_getMap() : client.map))); } } @@ -110,7 +109,7 @@ void AnchorRoomWindow::DrawElement() { ImGui::EndTooltip(); } } - uint32_t seed = /*IS_RANDO ? Rando::Context::GetRawInstance()->GetSeed() :*/ 0; + uint32_t seed = IS_RANDO ? (uint32_t)RANDO_SEED : 0; if (client.isSaveLoaded && Anchor::GetInstance()->IsSaveLoaded() && client.seed != seed && client.online && !client.self) { ImGui::SameLine(); diff --git a/src/port/Network/Anchor/Authority.cpp b/src/port/Network/Anchor/Authority.cpp index 0c88144e6..6d593ad30 100644 --- a/src/port/Network/Anchor/Authority.cpp +++ b/src/port/Network/Anchor/Authority.cpp @@ -1,6 +1,8 @@ #include "port/Network/Anchor/Authority.h" #include "port/Network/Anchor/Anchor.h" +#include "port/Network/Anchor/JigsawPedestal.h" #include "port/Network/Anchor/VileSync.h" +#include "port/Network/Anchor/FightSync.h" #include extern "C" { @@ -16,7 +18,9 @@ static ActivityState sActivities[NET_ACTIVITY_COUNT]; // The map each activity lives in. A claim is only valid while its owner is in this map. static const int32_t sActivityMap[NET_ACTIVITY_COUNT] = { - MAP_10_BGS_MR_VILE, // NET_ACTIVITY_VILE_MINIGAME + MAP_10_BGS_MR_VILE, // NET_ACTIVITY_VILE_MINIGAME + MAP_90_GL_BATTLEMENTS, // NET_ACTIVITY_FINAL_BOSS + MAP_27_FP_FREEZEEZY_PEAK, // NET_ACTIVITY_FP_TWINKLY }; static bool Authority_IsValidActivity(NetworkActivityId activity) { @@ -29,6 +33,9 @@ static void Authority_OnOwnerChanged(NetworkActivityId activity) { case NET_ACTIVITY_VILE_MINIGAME: VileSync_OnAuthorityChanged(); break; + case NET_ACTIVITY_FINAL_BOSS: + FightSync_OnAuthorityChanged(); + break; default: break; } @@ -116,6 +123,9 @@ void Authority_ApplyRemote(NetworkActivityId activity, uint32_t clientId, bool c } void Authority_OnClientStateChanged(uint32_t clientId, bool online, int32_t map) { + if (!online) { + JigsawPedestal_ClearClient(clientId); + } for (int32_t i = 0; i < NET_ACTIVITY_COUNT; i++) { ActivityState& state = sActivities[i]; if (state.claimed && state.owner == clientId && (!online || map != sActivityMap[i])) { @@ -125,6 +135,7 @@ void Authority_OnClientStateChanged(uint32_t clientId, bool online, int32_t map) } void Authority_OnPeerMapLoad(uint32_t clientId, int32_t map) { + JigsawPedestal_ClearClient(clientId); Anchor* anchor = Anchor::GetInstance(); for (int32_t i = 0; i < NET_ACTIVITY_COUNT; i++) { ActivityState& state = sActivities[i]; @@ -137,11 +148,15 @@ void Authority_OnPeerMapLoad(uint32_t clientId, int32_t map) { } else if (anchor != nullptr && state.owner == anchor->ownClientId && map == sActivityMap[i]) { // A peer just entered the map of an activity we own; make sure they know. anchor->SendPacket_AuthorityState((uint8_t)i, true); + if (i == NET_ACTIVITY_FINAL_BOSS) { + FightSync_SendSnapshot(clientId); + } } } } void Authority_OnSelfMapChanged(int32_t map) { + JigsawPedestal_ReleaseAllSelf(); Anchor* anchor = Anchor::GetInstance(); if (anchor == nullptr) { return; @@ -155,6 +170,7 @@ void Authority_OnSelfMapChanged(int32_t map) { } void Authority_Reset() { + JigsawPedestal_Reset(); for (int32_t i = 0; i < NET_ACTIVITY_COUNT; i++) { Authority_ClearClaim((NetworkActivityId)i); } diff --git a/src/port/Network/Anchor/Authority.h b/src/port/Network/Anchor/Authority.h index 8aa49d6d4..82effb7d7 100644 --- a/src/port/Network/Anchor/Authority.h +++ b/src/port/Network/Anchor/Authority.h @@ -25,6 +25,8 @@ typedef enum NetworkActivityId { NET_ACTIVITY_NONE = -1, NET_ACTIVITY_VILE_MINIGAME, + NET_ACTIVITY_FINAL_BOSS, + NET_ACTIVITY_FP_TWINKLY, NET_ACTIVITY_COUNT } NetworkActivityId; @@ -38,10 +40,7 @@ bool NetAuthority_IsSelf(NetworkActivityId activity); bool NetAuthority_IsClaimed(NetworkActivityId activity); // Owning clientId, or 0 when unclaimed. uint32_t NetAuthority_GetOwner(NetworkActivityId activity); -// Claim authority for the local client and broadcast it. No-op offline, or if another -// client already holds the claim. void NetAuthority_Claim(NetworkActivityId activity); -// Release our own claim and broadcast it. No-op unless we are the owner. void NetAuthority_Release(NetworkActivityId activity); #ifdef __cplusplus diff --git a/src/port/Network/Anchor/DummyPlayer.cpp b/src/port/Network/Anchor/DummyPlayer.cpp index 209a30316..03e4fd0b0 100644 --- a/src/port/Network/Anchor/DummyPlayer.cpp +++ b/src/port/Network/Anchor/DummyPlayer.cpp @@ -11,12 +11,22 @@ void func_802D729C(Actor* actor, f32 arg1); #include "bk_math.h" #include "port/Patches/Patches.h" +static s32 sActiveDummyBottlesBonus = 0; + +static void dummy_applyBottlesBonus(uintptr_t boneList, uintptr_t arg1) { + baanim_applyBottlesBonusMask(boneList, sActiveDummyBottlesBonus); +} + DummyPlayer::DummyPlayer(){}; void DummyPlayer::dummy_setTransformation(Transformation transform) { dummy_transformation = transform; } +void DummyPlayer::dummy_setBottlesBonus(s32 mask) { + dummyBottlesBonus = mask; +} + Transformation DummyPlayer::dummy_getTransformation() { return dummy_transformation; } @@ -179,7 +189,10 @@ void DummyPlayer::Draw(Gfx** gfx, Mtx** mtx, Vtx** vtx) { sp38[2] += dummyDisplacement[2]; if (dummyBin) { + // anctrl_drawSetup re-runs anim_update, which invokes the bonus-mask callback. + sActiveDummyBottlesBonus = dummyBottlesBonus; anctrl_drawSetup(dummyAnimCtrl, dummyPosition, 1); + sActiveDummyBottlesBonus = 0; func_8029DD6C(); modelRender_setEnvColor(env_color[0], env_color[1], env_color[2], dummyEnvAlpha); modelRender_func_8033A280(2.0f); @@ -227,9 +240,7 @@ void DummyPlayer::dummy_updateModel(void) { } void DummyPlayer::dummy_reset(void) { - // Clear stale actor reference — the game engine owns actor lifetime and may have - // already freed it (e.g. after a map transition). Don't dereference the old pointer. - // dummyActor = NULL; + dummy_despawnActor(); // skips if already detached if (dummyAnimCtrl) { dummyAnim_free(); dummyAnimCtrl = NULL; @@ -266,23 +277,31 @@ void DummyPlayer::dummy_reset(void) { dummyAnim_reset(); } +// Forget the stand-in without despawning it. void DummyPlayer::dummy_detachActor(void) { - // dummyActor = nullptr; + dummyMarker = nullptr; } -void DummyPlayer::dummy_free(void) { - /*if (dummyActor) { - if (dummyActor->unk104) { - Actor *shadow = marker_getActor(dummyActor->unk104); - shadow->unk104 = NULL; - shadow->despawn_flag = true; - dummyActor->unk104 = NULL; - } - if (dummyActor->marker) { - marker_despawn(dummyActor->marker); +void DummyPlayer::dummy_despawnActor(void) { + if (dummyMarker == nullptr) { + return; + } + Actor* actor = marker_getActor(dummyMarker); + if (actor != nullptr && actor->unk104 != nullptr) { + ActorMarker* shadowMarker = actor->unk104; + Actor* shadow = marker_getActor(shadowMarker); + if (shadow != nullptr) { + shadow->unk104 = nullptr; } - dummyActor = NULL; - }*/ + actor->unk104 = nullptr; + marker_despawn(shadowMarker); + } + marker_despawn(dummyMarker); + dummyMarker = nullptr; +} + +void DummyPlayer::dummy_free(void) { + dummy_despawnActor(); if (dummyBin) { assetcache_release(dummyBin); dummyBin = NULL; @@ -311,15 +330,31 @@ void DummyPlayer::dummyAnim_reset() { dummy_D_8037D23A = 0; } +// func_802D7124 (core2/fx/enemy_shadow.c): distance-gated drop-shadow attach + keep-alive. +extern "C" void func_802D7124(Actor* actor, f32 scale); + void DummyPlayer::dummy_update(void) { dummyAnim_update(); - // if (dummyActor && !dummyActor->despawn_flag) { - // dummyActor->position[0] = dummyPosition[0]; - // dummyActor->position[1] = dummyPosition[1]; - // dummyActor->position[2] = dummyPosition[2]; - // func_802D729C(dummyActor, 1.0f); - // } + if (dummyMarker == nullptr) { + Actor* spawned = actor_spawnWithYaw_f32(ACTOR_3CC_DUMMY_PLAYER_ANCHOR, dummyPosition, (s32)dummyYaw); + if (spawned == nullptr) { + return; + } + dummyMarker = spawned->marker; + } + + Actor* actor = marker_getActor(dummyMarker); + if (actor == nullptr || actor->despawn_flag) { + return; + } + actor->position[0] = dummyPosition[0]; + actor->position[1] = dummyPosition[1]; + actor->position[2] = dummyPosition[2]; + actor->yaw = dummyYaw; + if (dummyIsVisible) { + func_802D7124(actor, 1.0f); + } } BKModelBin* DummyPlayer::dummy_getModelBin(void) { @@ -459,8 +494,7 @@ void DummyPlayer::dummyAnim_init(void) { dummyAnimCtrl = anctrl_new(1); func_80287784(dummyAnimCtrl, 0); anctrl_setSmoothTransition(dummyAnimCtrl, false); - // func_8028746C(dummyAnimCtrl, __baanim_applyBottlesBonus); - // AnimModifyFunction = NULL; + func_8028746C(dummyAnimCtrl, dummy_applyBottlesBonus); anctrl_drawSetup(dummyAnimCtrl, dummyPosition, 1); dummyAnimUpdateType = BAANIM_UPDATE_0_NONE; //__baanim_setUpdateType(BAANIM_UPDATE_1_NORMAL); @@ -503,7 +537,9 @@ void DummyPlayer::dummyAnim_update(void) { default: break; } + sActiveDummyBottlesBonus = dummyBottlesBonus; anctrl_update(dummyAnimCtrl); + sActiveDummyBottlesBonus = 0; } void DummyPlayer::setModelSubStates(bool kazooie, bool squint, bool wink, bool mouth1, bool mouth2, f32 eyeBlendUpper, diff --git a/src/port/Network/Anchor/DummyPlayer.h b/src/port/Network/Anchor/DummyPlayer.h index 9eb364c84..a544f1d2b 100644 --- a/src/port/Network/Anchor/DummyPlayer.h +++ b/src/port/Network/Anchor/DummyPlayer.h @@ -49,6 +49,8 @@ class DummyPlayer { void dummy_setScale(f32 scale); void dummy_setTransformation(Transformation transform); Transformation dummy_getTransformation(); + // Bottles-bonus effect mask (D_803635EC bitfield). + void dummy_setBottlesBonus(s32 mask); void dummy_setVisible(s32 arg0); void dummy_setYDisplacement(f32 arg0); void dummy_setYaw(f32 yaw); @@ -77,7 +79,8 @@ class DummyPlayer { // eye/mouth void dummy_setEyeState(bool squint, bool wink, bool isHat); AnimCtrl* dummy_getAnimCtrl(); - // Actor* getDummyActor() const { return dummyActor; } + ActorMarker* dummy_getMarker() const { return dummyMarker; } + void dummy_despawnActor(void); private: uint32_t PlayerID; @@ -112,8 +115,7 @@ class DummyPlayer { } dummyAnimScale; AnimCtrl* dummyAnimCtrl = nullptr; f32 dummyVelocity[3]; - ActorMarker* dummyMarker; - Actor* dummyActor = nullptr; + ActorMarker* dummyMarker = nullptr; f32 dummy_D_8037C100[3]; f32 dummy_D_8037C110[3]; f32 dummyDisplacement[3]; @@ -135,4 +137,5 @@ class DummyPlayer { f32 dummy_modelEyeBlendUpper; f32 dummy_modelEyeBlendLower; Transformation dummy_transformation; + s32 dummyBottlesBonus = 0; }; \ No newline at end of file diff --git a/src/port/Network/Anchor/FightSync.c b/src/port/Network/Anchor/FightSync.c new file mode 100644 index 000000000..bdddf6fd5 --- /dev/null +++ b/src/port/Network/Anchor/FightSync.c @@ -0,0 +1,555 @@ +#include "FightSync.h" +#include "port/Network/Anchor/Authority.h" + +#include +#include "functions.h" +#include "variables.h" +#include "prop.h" +#include "FINALE/fight.h" + +// chfinalboss.c globals. D_803927xx = spell-spawn scratch vectors. +extern f32 D_80392758[3]; +extern f32 D_80392768[3]; +extern f32 D_80392778[3]; +extern f32 __chFinalBossFireballFlightTime; +extern ActorMarker *__chFinalBossFlightPadMarker; +extern u8 __chFinalBossSpellBarrierActive; +extern ActorArray *suBaddieActorArray; +extern u8 sFinalBossJinjoStatueActivated; +// Collision radius for the jinjo-into-Grunty test. +extern f32 func_8033229C(ActorMarker *marker); + +// Set once the ending script takes over (chfinalboss_setBossDefeated). +static u8 sFightNetCinematic = 0; +static u8 sFightNetWasFollower = 0; +// Bit per jinjo statue id (1-4): its jinjo already slammed Grunty. +static u8 sFightNetJinjoSlammed = 0; +static FightWorldSnapshot sFightNetSnap; +static u8 sFightNetCatchupActive = 0; +static u8 sFightNetCatchupSpawned[6]; // statue spawn already queued, indexed by statue id +static u8 sFightNetCatchupPadDone = 0; +static u8 sFightNetCatchupBarrierDone = 0; + +static bool FightSync_IsFollower(void) { + return NetAuthority_IsClaimed(NET_ACTIVITY_FINAL_BOSS) && !NetAuthority_IsSelf(NET_ACTIVITY_FINAL_BOSS); +} + +static bool FightSync_IsLiveAuthority(void) { + return NetAuthority_IsClaimed(NET_ACTIVITY_FINAL_BOSS) && NetAuthority_IsSelf(NET_ACTIVITY_FINAL_BOSS); +} + +static Actor *FightSync_FindBoss(void) { + Actor *boss = actorArray_findActorFromActorId(ACTOR_38B_GRUNTILDA_FINAL_BOSS); + + if (boss == NULL || !boss->volatile_initialized || boss->despawn_flag) { + return NULL; + } + return boss; +} + +// The jinjo statue bases share one actor id, so find by their statue id (1-4). +static Actor *FightSync_FindStatueBase(s32 statue_id) { + s32 i; + + if (suBaddieActorArray == NULL) { + return NULL; + } + for (i = 0; i < suBaddieActorArray->cnt; i++) { + Actor *actor = &suBaddieActorArray->data[i]; + if (actor->marker == NULL || actor->marker->id != MARKER_27A_JINJO_STATUE_BASE) { + continue; + } + if (actor->actorTypeSpecificField != statue_id || actor->despawn_flag) { + continue; + } + return actor; + } + return NULL; +} + +// Apply a networked egg via getHitByEgg(other == NULL), the counting path. +static void FightSync_ApplyJinjoStatueEgg(s32 statue_id) { + Actor *base = FightSync_FindStatueBase(statue_id); + + if (base != NULL) { + chBossJinjoBase_getHitByEgg(base->marker, NULL); + } +} + +static void FightSync_ReleaseFirstStatueCutscene(void) { + if (sFinalBossJinjoStatueActivated) { + sFinalBossJinjoStatueActivated = 0; + timed_exitStaticCamera(1.0f); + func_80324E38(1.0f, 0); + } +} + +// --- boss lifecycle hooks (called from chfinalboss.c) ----------------------------------------- + +void FightSync_OnBossSpawned(void) { + s32 i; + sFightNetCinematic = 0; + sFightNetWasFollower = 0; + sFightNetJinjoSlammed = 0; + sFightNetCatchupActive = 0; + // Cleared on a fresh boss spawn, not in ApplyWorld, so a repeat snapshot can't re-run catch-up. + sFightNetCatchupPadDone = 0; + sFightNetCatchupBarrierDone = 0; + for (i = 0; i < 6; i++) { + sFightNetCatchupSpawned[i] = 0; + } +} + +void FightSync_OnBossDefeated(void) { + sFightNetCinematic = 1; +} + +// --- authority replication hooks ------------------------------------------------------------- + +void FightSync_OnSpellSpawned(s32 kind) { + if (FightSync_IsLiveAuthority()) { + // Kind 0 (ballistic fireball) carries lead time; each follower re-aims at its own player. + s32 leadMs = (kind == 0) ? (s32)(__chFinalBossFireballFlightTime * 1000.0f) : 0; + FightSync_SendEvent(FIGHT_EV_SPELL, kind, leadMs, D_80392758, D_80392768, D_80392778); + } +} + +void FightSync_OnFlightPadSpawned(void) { + if (FightSync_IsLiveAuthority()) { + FightSync_SendEvent(FIGHT_EV_PAD_SPAWN, 0, 0, NULL, NULL, NULL); + } +} + +void FightSync_OnFlightPadDespawned(void) { + if (FightSync_IsLiveAuthority()) { + FightSync_SendEvent(FIGHT_EV_PAD_DESPAWN, 0, 0, NULL, NULL, NULL); + } +} + +void FightSync_OnBarrierSpawned(void) { + if (FightSync_IsLiveAuthority()) { + FightSync_SendEvent(FIGHT_EV_BARRIER, 0, 0, NULL, NULL, NULL); + } +} + +void FightSync_OnStatueSpawned(s32 statue_id) { + if (FightSync_IsLiveAuthority()) { + FightSync_SendEvent(FIGHT_EV_STATUE_SPAWN, statue_id, 0, NULL, NULL, NULL); + } +} + +void FightSync_OnJinjoSlam(s32 statue_id) { + sFightNetJinjoSlammed |= 1 << statue_id; + if (FightSync_IsLiveAuthority()) { + FightSync_SendEvent(FIGHT_EV_JINJO_ATTACK, statue_id, 0, NULL, NULL, NULL); + } +} + +void FightSync_ReplicateEgg(s32 statue_id, s32 pad_index) { + if (FightSync_IsLiveAuthority()) { + FightSync_SendEvent(FIGHT_EV_EGG_FED, statue_id, pad_index, NULL, NULL, NULL); + } +} + +// --- follower input forwarding ---------------------------------------------------------------- + +bool FightSync_ForwardBossHit(s32 phase) { + if (!FightSync_IsFollower()) { + return false; + } + FightSync_SendEvent(FIGHT_EV_BOSS_HIT, phase, 0, NULL, NULL, NULL); + return true; +} + +bool FightSync_ForwardEgg(s32 statue_id, s32 pad_index) { + if (!FightSync_IsFollower()) { + return false; + } + FightSync_SendEvent(FIGHT_EV_EGG, statue_id, pad_index, NULL, NULL, NULL); + return true; +} + +// --- stream: gather (authority) / apply (follower) --------------------------------------------- + +bool FightSync_GatherUpdate(f32 pos[3], f32 *yaw, s32 *state, s32 *phase, s32 *mirror, s32 *vuln) { + Actor *boss; + ActorLocal_FinalBoss *local; + + if (sFightNetCinematic) { + return false; + } + boss = FightSync_FindBoss(); + if (boss == NULL) { + return false; + } + local = (ActorLocal_FinalBoss *)&boss->local; + pos[0] = boss->position[0]; + pos[1] = boss->position[1]; + pos[2] = boss->position[2]; + *yaw = boss->yaw; + *state = boss->state; + *phase = local->phase; + *mirror = local->mirror_phase5; + // Phase-2 vulnerability toggle (unkA). + *vuln = local->unkA; + return true; +} + +static void FightSync_ApplyBossState(Actor *this, s32 phase, s32 state) { + ActorLocal_FinalBoss *local = (ActorLocal_FinalBoss *)&this->local; + + // unk44_31 = broomstick motor sfx source. + if (this->unk44_31 != 0 && phase != FINALBOSS_PHASE_1_BROOMSTICK) { + sfxsource_freeSfxsourceByIndex(this->unk44_31); + this->unk44_31 = 0; + } + local->phase = phase; + subaddie_set_state_with_direction(this, state, 0.0001f, 1); + if (state == 9 || state == 0x21 || state == 0x22 || state == 0x2B) { + actor_playAnimationOnce(this); + } else { + actor_loopAnimation(this); + } + chfinalboss_func_80386600(this->marker, (state == 6 || state == 7 || state == 8) ? 1 : 0); + if (phase == FINALBOSS_PHASE_5_JINJONATOR || state == 0x21 || state == 0x22) { + chfinalboss_func_80386628(this->marker, 0); + } else { + chfinalboss_func_80386628(this->marker, 1); + } + if (state == 0x21) { + // State 0x21 = broom shatters (end of phase 4); replay the burst. + chfinalboss_createBroomstickParticles(this->position, ASSET_552_MODEL_BROOMSTICK_PIECE_HEAD, 1); + chfinalboss_createBroomstickParticles(this->position, ASSET_553_MODEL_BROOMSTICK_PIECE_SHORT, 12); + chfinalboss_createBroomstickParticles(this->position, ASSET_554_MODEL_BROOMSTICK_PIECE_LONG, 20); + chfinalboss_createBroomstickParticles(this->position, ASSET_555_MODEL_BROOMSTICK_PIECE_EYE, 2); + } +} + +void FightSync_ApplyUpdate(const f32 pos[3], f32 yaw, s32 state, s32 phase, s32 mirror, s32 vuln) { + Actor *boss; + ActorLocal_FinalBoss *local; + + if (!FightSync_IsFollower() || sFightNetCinematic) { + return; + } + boss = FightSync_FindBoss(); + if (boss == NULL) { + return; + } + sFightNetWasFollower = 1; + local = (ActorLocal_FinalBoss *)&boss->local; + boss->position[0] = pos[0]; + boss->position[1] = pos[1]; + boss->position[2] = pos[2]; + boss->yaw = yaw; + boss->yaw_ideal = yaw; + local->mirror_phase5 = mirror; + // Applied every frame, not just on state change (see FightSync_GatherUpdate). + local->unkA = (u8)vuln; + if (local->phase != (u8)phase || boss->state != state) { + FightSync_ApplyBossState(boss, phase, state); + } +} + +// --- latecomer world snapshot ------------------------------------------------------------------- + +bool FightSync_GatherWorld(FightWorldSnapshot *snap) { + Actor *base; + s32 i; + + if (sFightNetCinematic || !FightSync_IsLiveAuthority() || FightSync_FindBoss() == NULL) { + return false; + } + snap->pad = (__chFinalBossFlightPadMarker != NULL) ? 1 : 0; + snap->barrier = __chFinalBossSpellBarrierActive ? 1 : 0; + for (i = 0; i < 4; i++) { + base = FightSync_FindStatueBase(i + 1); + if (base == NULL) { + snap->statue[i] = 0xFF; + snap->jinjoGone[i] = 0; + } else if (base->state == CHBOSSJINJOBASE_STATE_3_SPAWNED_BOSS_JINJO) { + snap->statue[i] = 3; + snap->jinjoGone[i] = (sFightNetJinjoSlammed & (1 << (i + 1))) ? 1 : 0; + } else { + snap->statue[i] = base->unk38_31; + snap->jinjoGone[i] = 0; + } + } + snap->jbase = chjinjonatorbase_netGetPads(snap->jpads) ? 1 : 0; + return true; +} + +void FightSync_ApplyWorld(const FightWorldSnapshot *snap) { + s32 i; + + if (!FightSync_IsFollower() || sFightNetCinematic) { + return; + } + sFightNetSnap = *snap; + sFightNetCatchupActive = 1; + // Seed the slammed set from the snapshot so a jinjo that reaches Grunty before catch-up + // rebuilds its statue is removed by the phase-4 guard rather than replaying the attack. + for (i = 0; i < 4; i++) { + if (snap->jinjoGone[i]) { + sFightNetJinjoSlammed |= 1 << (i + 1); + } + } +} + +static void FightSync_CatchupTick(Actor *boss) { + Actor *base; + Actor *jinjo; + u8 pads[4]; + s32 i; + s32 done = 1; + + if (!sFightNetCatchupActive) { + return; + } + + if (sFightNetSnap.pad && !sFightNetCatchupPadDone) { + sFightNetCatchupPadDone = 1; + __spawnQueue_add_1((GenFunction_1)chfinalboss_spawnFlightPad, 0); + } + if (sFightNetSnap.barrier && !sFightNetCatchupBarrierDone) { + sFightNetCatchupBarrierDone = 1; + chfinalboss_spawnSpellBarrier(boss->marker); + } + + for (i = 0; i < 4; i++) { + if (sFightNetSnap.statue[i] == 0xFF) { + continue; + } + base = FightSync_FindStatueBase(i + 1); + if (base == NULL) { + if (!sFightNetCatchupSpawned[i + 1]) { + sFightNetCatchupSpawned[i + 1] = 1; + chfinalboss_spawnStatue(i + 1); + } + done = 0; + continue; + } + if (base->state != CHBOSSJINJOBASE_STATE_3_SPAWNED_BOSS_JINJO && base->unk38_31 < sFightNetSnap.statue[i]) { + chBossJinjoBase_getHitByEgg(base->marker, NULL); + done = 0; + continue; + } + if (sFightNetSnap.jinjoGone[i]) { + jinjo = actorArray_findActorFromActorId(ACTOR_3A4_BOSS_JINJO_BASE_IDX + i + 1); + if (jinjo != NULL) { + sFightNetJinjoSlammed |= 1 << (i + 1); + marker_despawn(jinjo->marker); + sFightNetSnap.jinjoGone[i] = 0; + } else if (base->state == CHBOSSJINJOBASE_STATE_3_SPAWNED_BOSS_JINJO) { + done = 0; + } + } + } + + if (sFightNetSnap.jbase) { + if (!chjinjonatorbase_netGetPads(pads)) { + if (!sFightNetCatchupSpawned[5]) { + sFightNetCatchupSpawned[5] = 1; + chfinalboss_spawnStatue(BOSSJINJO_5_JINJONATOR); + } + done = 0; + } else { + for (i = 0; i < 4; i++) { + if (pads[i] > sFightNetSnap.jpads[i]) { + chjinjonatorbase_netApplyEgg(i); + done = 0; + break; + } + } + } + } + + if (done) { + sFightNetCatchupActive = 0; + } +} + +bool FightSync_BossFollowerTick(void *bossPtr) { + Actor *boss = (Actor *)bossPtr; + + if (!FightSync_IsFollower() || sFightNetCinematic) { + return false; + } + FightSync_CatchupTick(boss); + + // Detect a jinjo-into-Grunty collision locally (display-only) ahead of the authority's slam event. + if (((ActorLocal_FinalBoss *)&boss->local)->phase == FINALBOSS_PHASE_4_JINJOS) { + ActorMarker *jinjoMarker = chfinalboss_findCollidingJinjo(boss, func_8033229C(boss->marker)); + if (jinjoMarker != NULL) { + Actor *jinjo = marker_getActor(jinjoMarker); + s32 sid = (jinjo != NULL) ? jinjo->actorTypeSpecificField : 0; + if (sid >= BOSSJINJO_1_ORANGE && sid <= BOSSJINJO_4_YELLOW && + (sFightNetJinjoSlammed & (1 << sid))) { + marker_despawn(jinjoMarker); + } else { + if (sid >= BOSSJINJO_1_ORANGE && sid <= BOSSJINJO_4_YELLOW) { + sFightNetJinjoSlammed |= 1 << sid; + } + chbossjinjo_attack(jinjoMarker); + FightSync_ReleaseFirstStatueCutscene(); + } + } + } + + switch (boss->state) { + case 2: + case 3: + case 4: + case 6: + case 7: + case 8: + case 14: + case 21: + case 28: + chfinalboss_spawnBroomstickGlowParticles(boss); + break; + } + return true; +} + +// --- one-shot event dispatch -------------------------------------------------------------------- + +void FightSync_ApplyEvent(s32 ev, s32 a, s32 b, const f32 v0[3], const f32 v1[3], const f32 v2[3]) { + Actor *boss = FightSync_FindBoss(); + s32 i; + + switch (ev) { + case FIGHT_EV_SPELL: + if (!FightSync_IsFollower() || v0 == NULL) { + return; + } + // Kind 0 (ballistic fireball) is re-aimed at this client's own player. + if (a == 0) { + if (boss != NULL) { + f32 src[3]; + f32 leadTime = (b > 0) ? (b / 1000.0f) : 1.3f; + src[0] = boss->position[0]; + src[1] = boss->position[1]; + src[2] = boss->position[2]; + chfinalboss_func_80387110(boss->marker, src, leadTime, 0); + } + break; + } + // Spawn helpers read these globals; set them before queueing. + for (i = 0; i < 3; i++) { + D_80392758[i] = v0[i]; + D_80392768[i] = v1[i]; + D_80392778[i] = v2[i]; + } + if (a == 2) { + __spawnQueue_add_1((GenFunction_1)chfinalboss_func_80386EC0, 0); + } else if (a == 1) { + __spawnQueue_add_1((GenFunction_1)chfinalboss_func_80387074, 0); + } + break; + + case FIGHT_EV_PAD_SPAWN: + if (!FightSync_IsFollower()) { + return; + } + __spawnQueue_add_1((GenFunction_1)chfinalboss_spawnFlightPad, 0); + break; + + case FIGHT_EV_PAD_DESPAWN: + if (!FightSync_IsFollower()) { + return; + } + chfinalboss_despawnFlightPad(); + break; + + case FIGHT_EV_BARRIER: + if (!FightSync_IsFollower() || boss == NULL) { + return; + } + chfinalboss_spawnSpellBarrier(boss->marker); + break; + + case FIGHT_EV_STATUE_SPAWN: + if (!FightSync_IsFollower() || a < BOSSJINJO_1_ORANGE || a > BOSSJINJO_5_JINJONATOR) { + return; + } + chfinalboss_spawnStatue(a); + break; + + case FIGHT_EV_EGG_FED: + if (!FightSync_IsFollower()) { + return; + } + if (a == BOSSJINJO_5_JINJONATOR) { + chjinjonatorbase_netApplyEgg(b); + } else { + FightSync_ApplyJinjoStatueEgg(a); + } + break; + + case FIGHT_EV_JINJO_ATTACK: { + Actor *jinjo; + if (!FightSync_IsFollower() || a < BOSSJINJO_1_ORANGE || a > BOSSJINJO_4_YELLOW) { + return; + } + sFightNetJinjoSlammed |= 1 << a; + jinjo = actorArray_findActorFromActorId(ACTOR_3A4_BOSS_JINJO_BASE_IDX + a); + if (jinjo != NULL) { + chbossjinjo_attack(jinjo->marker); + } + FightSync_ReleaseFirstStatueCutscene(); + break; + } + + case FIGHT_EV_BOSS_HIT: + if (!FightSync_IsLiveAuthority() || boss == NULL) { + return; + } + if (getGameMode() == GAME_MODE_4_PAUSED) { + return; + } + if (((ActorLocal_FinalBoss *)&boss->local)->phase != (u8)a) { + return; + } + chfinalboss_collisionPassive(boss->marker, NULL); + break; + + case FIGHT_EV_EGG: + if (!FightSync_IsLiveAuthority()) { + return; + } + if (getGameMode() == GAME_MODE_4_PAUSED) { + return; + } + if (a == BOSSJINJO_5_JINJONATOR) { + chjinjonatorbase_netApplyEgg(b); + } else { + if (sFinalBossJinjoStatueActivated != 0) { + return; + } + FightSync_ApplyJinjoStatueEgg(a); + } + break; + } +} + +void FightSync_OnAuthorityChanged(void) { + Actor *boss; + ActorLocal_FinalBoss *local; + + FightSyncSeq_Reset(); + if (sFightNetCinematic) { + return; + } + boss = FightSync_FindBoss(); + if (boss == NULL) { + return; + } + if (sFightNetWasFollower && FightSync_IsLiveAuthority()) { + sFightNetWasFollower = 0; + local = (ActorLocal_FinalBoss *)&boss->local; + if (local->phase != FINALBOSS_PHASE_0_INTRO) { + chfinalboss_setPhase(boss->marker, local->phase); + } + } +} diff --git a/src/port/Network/Anchor/FightSync.h b/src/port/Network/Anchor/FightSync.h new file mode 100644 index 000000000..64081a31e --- /dev/null +++ b/src/port/Network/Anchor/FightSync.h @@ -0,0 +1,103 @@ +#pragma once +#include +#include + +// Final Grunty fight sync (Anchor). +// +// First client in the fight map with the boss spawned claims NET_ACTIVITY_FINAL_BOSS and runs +// the fight; everyone else mirrors it. +// +// FIGHT_UPDATE: authority -> map, per-frame transform/state stream, sequence-guarded. +// FIGHT_STATE: authority -> joining client, world catch-up snapshot. +// FIGHT_EVENT: one-shot; authority -> map for spells/pads/barrier/statues/eggs/jinjo +// attacks, follower -> authority for boss hits and statue eggs. + +// FIGHT_EVENT ids ('ev' field). +enum FightSyncEvent { + // authority -> followers + FIGHT_EV_SPELL = 0, // a = kind (0 fireball, 1 final fireball, 2 green blast); p/v/w = spawn vectors + FIGHT_EV_PAD_SPAWN, // flight pad appears (end of phase 2) + FIGHT_EV_PAD_DESPAWN, // flight pad removed (during phase 3 barrier cast) + FIGHT_EV_BARRIER, // spell barrier spawns on Grunty + FIGHT_EV_STATUE_SPAWN, // a = ch_bossjinjo_e statue id (1-4 jinjos, 5 jinjonator) + FIGHT_EV_EGG_FED, // a = statue id (1-4 jinjos, 5 jinjonator), b = jinjonator pad index + FIGHT_EV_JINJO_ATTACK, // a = jinjo statue id whose jinjo just slammed Grunty + // followers -> authority + FIGHT_EV_BOSS_HIT, // a = the phase the hitting client believed Grunty was in + FIGHT_EV_EGG, // a = statue id, b = jinjonator pad index +}; + +// FIGHT_STATE catch-up snapshot for a client joining mid-fight. +typedef struct FightWorldSnapshot { + uint8_t pad; // flight pad present + uint8_t barrier; // spell barrier up on Grunty + uint8_t statue[4]; // jinjo statue bases (ids 1-4): 0xFF absent, else eggs fed (3 = broken) + uint8_t jinjoGone[4]; // statue broken and its jinjo has already slammed into Grunty + uint8_t jbase; // jinjonator pedestal present + uint8_t jpads[4]; // remaining eggs per jinjonator pedestal pad +} FightWorldSnapshot; + +#ifdef __cplusplus +extern "C" { +#endif + +// --- hooks called by the FINALE actors (implemented in FightSync.c) -------------------- + +// Boss lifecycle: spawn resets sync state; defeat drops every client to local simulation. +void FightSync_OnBossSpawned(void); +void FightSync_OnBossDefeated(void); + +// True = a remote authority drives this boss; chfinalboss_update should skip its brain. +bool FightSync_BossFollowerTick(void* boss /* Actor* */); + +// Forward follower input to the authority; true = handled remotely, skip local apply. +bool FightSync_ForwardBossHit(int32_t phase); +bool FightSync_ForwardEgg(int32_t statue_id, int32_t pad_index); + +// Authority world replication (acts only as the live authority). +void FightSync_ReplicateEgg(int32_t statue_id, int32_t pad_index); +void FightSync_OnSpellSpawned(int32_t kind); +void FightSync_OnFlightPadSpawned(void); +void FightSync_OnFlightPadDespawned(void); +void FightSync_OnBarrierSpawned(void); +void FightSync_OnStatueSpawned(int32_t statue_id); +void FightSync_OnJinjoSlam(int32_t statue_id); + +// --- FINALE entry points used by FightSync.c (implemented in the decomp actors) -------- + +void chjinjonatorbase_netApplyEgg(int32_t pad_index); +bool chjinjonatorbase_netGetPads(uint8_t pads[4]); + +// --- C -> network (bridges implemented in the packet .cpp files) ----------------------- + +void FightSync_SendUpdate(const float pos[3], float yaw, int32_t state, int32_t phase, int32_t mirror, + int32_t vuln); +// v0/v1/v2 may be NULL for events that carry no vectors. +void FightSync_SendEvent(int32_t ev, int32_t a, int32_t b, const float v0[3], const float v1[3], + const float v2[3]); +void FightSync_SendSnapshot(uint32_t clientId); + +uint32_t FightSyncSeq_Next(void); +bool FightSyncSeq_Accept(uint32_t seq); +void FightSyncSeq_Reset(void); + +// --- network -> sync layer (implemented in FightSync.c) -------------------------------- + +void FightSync_OnAuthorityChanged(void); + +// Fill the stream fields from the live boss; false if there's no boss to stream. +bool FightSync_GatherUpdate(float pos[3], float* yaw, int32_t* state, int32_t* phase, int32_t* mirror, + int32_t* vuln); + +void FightSync_ApplyUpdate(const float pos[3], float yaw, int32_t state, int32_t phase, int32_t mirror, + int32_t vuln); +void FightSync_ApplyEvent(int32_t ev, int32_t a, int32_t b, const float v0[3], const float v1[3], + const float v2[3]); + +// Gather on the authority (false = nothing to send) / apply on a joining follower. +bool FightSync_GatherWorld(FightWorldSnapshot* snap); +void FightSync_ApplyWorld(const FightWorldSnapshot* snap); + +#ifdef __cplusplus +} +#endif diff --git a/src/port/Network/Anchor/HookHandlers.cpp b/src/port/Network/Anchor/HookHandlers.cpp index 884a69486..28f01d518 100644 --- a/src/port/Network/Anchor/HookHandlers.cpp +++ b/src/port/Network/Anchor/HookHandlers.cpp @@ -1,9 +1,12 @@ #include "Anchor.h" #include "Authority.h" #include "VileSync.h" +#include "FightSync.h" #include //#include "soh/frame_interpolation.h" #include "port/Engine.h" +#include "port/UI/Notification.h" +#include extern "C" { #include "variables.h" @@ -12,6 +15,12 @@ extern "C" { float OTRGetDimensionFromLeftEdge(float v); float OTRGetDimensionFromRightEdge(float v); s32 chvile_netGetAnimMode(Actor* actor); +void port_jiggySpawn_remove(int32_t jiggyId); +int32_t port_mapFlag_wasSetRemotely(int32_t index); +} + +extern "C" void port_fpTwinkly_release(void) { + NetAuthority_Release(NET_ACTIVITY_FP_TWINKLY); } // True when a remote client owns the Mr. Vile minigame (our local logic must follow). @@ -47,6 +56,106 @@ static void Anchor_UpdateVileSync() { } } +static void Anchor_UpdateFightSync() { + auto* anchor = Anchor::GetInstance(); + if (!anchor->isConnected || !anchor->IsSaveLoaded() || gsworld_getMap() != MAP_90_GL_BATTLEMENTS) { + return; + } + + f32 pos[3]; + f32 yaw; + s32 state, phase, mirror, vuln; + if (!FightSync_GatherUpdate(pos, &yaw, &state, &phase, &mirror, &vuln)) { + return; + } + + if (!NetAuthority_IsClaimed(NET_ACTIVITY_FINAL_BOSS)) { + NetAuthority_Claim(NET_ACTIVITY_FINAL_BOSS); + } + if (NetAuthority_IsClaimed(NET_ACTIVITY_FINAL_BOSS) && NetAuthority_IsSelf(NET_ACTIVITY_FINAL_BOSS)) { + anchor->SendPacket_FightUpdate(pos, yaw, state, phase, mirror, vuln); + } +} + +static bool Anchor_ShouldBroadcastVolatileFlag(s32 index) { + static const std::unordered_set syncList = { + VOLATILE_FLAG_B6_WITCH_SWITCH_PRESSED_MM, + VOLATILE_FLAG_B7_WITCH_SWITCH_PRESSED_MMM, + VOLATILE_FLAG_B8_WITCH_SWITCH_PRESSED_TTC, + VOLATILE_FLAG_B9_WITCH_SWITCH_PRESSED_RBB, + VOLATILE_FLAG_BA_WITCH_SWITCH_PRESSED_CCW, + VOLATILE_FLAG_BB_WITCH_SWITCH_PRESSED_FP, + VOLATILE_FLAG_BC_WITCH_SWITCH_PRESSED_CC, + VOLATILE_FLAG_BD_WITCH_SWITCH_PRESSED_BGS, + VOLATILE_FLAG_BE_WITCH_SWITCH_PRESSED_GV, + }; + return syncList.contains(index); +} + +bool Anchor_ScopedFlagExcluded(s32 space, s32 index) { + static const std::unordered_set excluded = { + (ANCHOR_FLAGSPACE_LEVEL_SPECIFIC << 16) | LEVEL_FLAG_5_TTC_UNKNOWN, // TTC sandcastle drain + (ANCHOR_FLAGSPACE_LEVEL_SPECIFIC << 16) | LEVEL_FLAG_29_FP_XMAS_TREE_COMPLETE, // FP xmas-tree ice shatter + (ANCHOR_FLAGSPACE_LEVEL_SPECIFIC << 16) | LEVEL_FLAG_30_RBB_UNKNOWN, // RBB anchor/Snorkel chain cutscene + // GV water-pyramid rise: reapplied live from JIGGY_42 in water_pyramidrot.c. + (ANCHOR_FLAGSPACE_LEVEL_SPECIFIC << 16) | LEVEL_FLAG_6_GV_UNKNOWN, + (ANCHOR_FLAGSPACE_MAP_SPECIFIC << 16) | MM_SPECIFIC_FLAG_2_ORANGE_HAS_BEEN_RETURNED, + (ANCHOR_FLAGSPACE_LEVEL_SPECIFIC << 16) | LEVEL_FLAG_1C_MM_OPEN, + (ANCHOR_FLAGSPACE_LEVEL_SPECIFIC << 16) | LEVEL_FLAG_1D_TTC_OPEN, + (ANCHOR_FLAGSPACE_LEVEL_SPECIFIC << 16) | LEVEL_FLAG_1E_CC_OPEN, + (ANCHOR_FLAGSPACE_LEVEL_SPECIFIC << 16) | LEVEL_FLAG_1F_BGS_OPEN, + (ANCHOR_FLAGSPACE_LEVEL_SPECIFIC << 16) | LEVEL_FLAG_20_FP_OPEN, + (ANCHOR_FLAGSPACE_LEVEL_SPECIFIC << 16) | LEVEL_FLAG_21_GV_OPEN, + (ANCHOR_FLAGSPACE_LEVEL_SPECIFIC << 16) | LEVEL_FLAG_22_MMM_OPEN, + (ANCHOR_FLAGSPACE_LEVEL_SPECIFIC << 16) | LEVEL_FLAG_23_RBB_OPEN, + (ANCHOR_FLAGSPACE_LEVEL_SPECIFIC << 16) | LEVEL_FLAG_24_CCW_OPEN, + (ANCHOR_FLAGSPACE_LEVEL_SPECIFIC << 16) | LEVEL_FLAG_3F_LAIR_GRUNTY_DOOR_OPEN, + }; + if (excluded.contains((space << 16) | index)) { + return true; + } + // BGS jiggy-switch timers (walkway=3, maze=0xC): kept local. + if (space == ANCHOR_FLAGSPACE_MAP_SPECIFIC && gsworld_getMap() == MAP_D_BGS_BUBBLEGLOOP_SWAMP && + (index == 3 || index == 0xC)) { + return true; + } + if (space == ANCHOR_FLAGSPACE_MAP_SPECIFIC && gsworld_getMap() == MAP_7_TTC_TREASURE_TROVE_COVE && + index <= TTC_SPECIFIC_FLAG_3_BLUBBER_SHOW_JIGGY_SPAWNED_TEXT_FLAG) { + return true; + } + // FP xmas tree star minigame (flags 2/3): per-player, kept local; result syncs via ANCHOR_PUZZLE_FP_TREE_ICE. + if (space == ANCHOR_FLAGSPACE_MAP_SPECIFIC && gsworld_getMap() == MAP_27_FP_FREEZEEZY_PEAK && + (index == 2 || index == 3)) { + return true; + } + // FP bear cubs' presents-received flags: kept local; ANCHOR_PUZZLE_FP_PRESENTS syncs the result. + if (space == ANCHOR_FLAGSPACE_LEVEL_SPECIFIC && + (s32)map_getLevel(gsworld_getMap()) == (s32)LEVEL_5_FREEZEEZY_PEAK && + (index == LEVEL_FLAG_11_FP_UNKNOWN || index == LEVEL_FLAG_12_FP_UNKNOWN || + index == LEVEL_FLAG_13_FP_UNKNOWN)) { + return true; + } + // SM_SPECIFIC_FLAG_10: Bottles-conversation position lock; kept local. + if (space == ANCHOR_FLAGSPACE_MAP_SPECIFIC && gsworld_getMap() == MAP_1_SM_SPIRAL_MOUNTAIN && + index == SM_SPECIFIC_FLAG_10) { + return true; + } + return false; +} + +static bool Anchor_ShouldSyncItemCount(s32 item, const RoomState& room) { + switch (item) { + case ITEM_1C_MUMBO_TOKEN: + case ITEM_26_JIGGY_TOTAL: + case ITEM_D_EGGS: + case ITEM_F_RED_FEATHER: + case ITEM_10_GOLD_FEATHER: + return room.shareConsumables != 0; + default: + return false; + } +} + void Anchor::RegisterHooks() { // #region Hooks that are required for basic Anchor functionality @@ -68,25 +177,67 @@ void Anchor::RegisterHooks() { Anchor::GetInstance()->ClearDummies(); Anchor::GetInstance()->PopulateDummies((GameMap)ev->nextMap); Authority_OnSelfMapChanged(ev->nextMap); + Anchor::GetInstance()->SweepUnoccupiedLevelState((GameMap)ev->nextMap); Anchor::GetInstance()->SendPacket_MapLoad((GameMap)ev->nextMap, ev->exit); // Anchor::GetInstance()->SendPacket_PlayerUpdate(true); + + auto* anchor = Anchor::GetInstance(); + if (anchor->isConnected && anchor->roomState.syncItemsAndFlags && + ev->nextMap != MAP_91_FILE_SELECT && ev->nextMap != MAP_1E_CS_START_NINTENDO && + ev->nextMap != MAP_1F_CS_START_RAREWARE) { + anchor->SendPacket_RequestScopedState((GameMap)ev->nextMap); + + s32 enteredFlag = -1; + switch (ev->nextMap) { + case MAP_2_MM_MUMBOS_MOUNTAIN: enteredFlag = FILEPROG_B0_HAS_ENTERED_MM; break; + case MAP_7_TTC_TREASURE_TROVE_COVE: enteredFlag = FILEPROG_B2_HAS_ENTERED_TTC; break; + case MAP_B_CC_CLANKERS_CAVERN: enteredFlag = FILEPROG_B8_HAS_ENTERED_CC; break; + case MAP_D_BGS_BUBBLEGLOOP_SWAMP: enteredFlag = FILEPROG_B1_HAS_ENTERED_BGS; break; + case MAP_12_GV_GOBIS_VALLEY: enteredFlag = FILEPROG_B3_HAS_ENTERED_GV; break; + case MAP_1B_MMM_MAD_MONSTER_MANSION:enteredFlag = FILEPROG_B7_HAS_ENTERED_MMM; break; + case MAP_27_FP_FREEZEEZY_PEAK: enteredFlag = FILEPROG_B6_HAS_ENTERED_FP; break; + case MAP_31_RBB_RUSTY_BUCKET_BAY: enteredFlag = FILEPROG_B4_HAS_ENTERED_RBB; break; + case MAP_40_CCW_HUB: enteredFlag = FILEPROG_B5_HAS_ENTERED_CCW; break; + default: break; + } + if (enteredFlag >= 0 && fileProgressFlag_get((enum file_progress_e)enteredFlag)) { + anchor->SendPacket_SetFlag((u8)ANCHOR_FLAGSPACE_FILE_PROGRESS, (s16)enteredFlag); + } + } }); COND_HOOK(OnReset, EVENT_PRIORITY_HIGH, true, [](IEvent* event) { Anchor::GetInstance()->SendPacket_MapLoad((GameMap)getDefaultBootMap(), gsworld_getExit()); }); + COND_HOOK(OnGameLoad, EVENT_PRIORITY_NORMAL, isConnected, [](IEvent* event) { + auto* anchor = Anchor::GetInstance(); + anchor->hasCheckedRandoCompat = false; + anchor->reloadMapOnTeamState = false; + anchor->SendPacket_RequestTeamState(true); + }); + COND_HOOK(OnPlayerDraw, EVENT_PRIORITY_HIGH, true, [](IEvent* event) { auto drawEv = reinterpret_cast(event); Anchor::GetInstance()->DrawDummies(reinterpret_cast(drawEv)); }); COND_HOOK(GameFrameUpdate, EVENT_PRIORITY_HIGH, isConnected, [](IEvent* event) { - Anchor::GetInstance()->SendPacket_PlayerUpdate(); - Anchor::GetInstance()->ProcessIncomingPacketQueue(); - Anchor::GetInstance()->RefreshClientActors(); - Anchor::GetInstance()->UpdateDummies(); + auto* anchor = Anchor::GetInstance(); + anchor->SendPacket_PlayerUpdate(); + anchor->ProcessIncomingPacketQueue(); + anchor->RefreshClientActors(); + anchor->UpdateDummies(); Anchor_UpdateVileSync(); + Anchor_UpdateFightSync(); + + if (anchor->isConnected && anchor->IsSaveLoaded()) { + anchor->FlushPendingJiggySpawns(); + if (!anchor->hasCheckedRandoCompat) { + anchor->CheckRandoRoomCompatibility(); + anchor->hasCheckedRandoCompat = true; + } + } }); COND_HOOK(OnPlayerTransformChange, EVENT_PRIORITY_NORMAL, isConnected, [](IEvent* event) { @@ -105,9 +256,7 @@ void Anchor::RegisterHooks() { } if (ev->state >= 2) { NetAuthority_Claim(NET_ACTIVITY_VILE_MINIGAME); - // Push the transition immediately (round start, round end with its result - // jingle) instead of waiting for the next periodic snapshot. Gather rejects - // the non-broadcast states, so this is a no-op for dialog transitions. + // Push round start/end immediately rather than waiting for the periodic snapshot. if (Anchor_IsVileAuthority()) { Anchor::GetInstance()->SendPacket_VileGameState(); } @@ -133,6 +282,54 @@ void Anchor::RegisterHooks() { }); // Followers: suppress local random logic; network state drives these instead. + COND_VB_SHOULD(VB_CCW_FLOWER_REMOTE_GROW, EVENT_PRIORITY_NORMAL, isConnected, { + s32 stageFlag = va_arg(args, s32); + *should = fileProgressFlag_get((enum file_progress_e)stageFlag) != 0; + }); + + COND_VB_SHOULD(VB_CC_RINGS_SNAP_WATER, EVENT_PRIORITY_NORMAL, isConnected, { *should = false; }); + + // Lair door remote-open: Door of Grunty's open flag (0xE2) is already set on arrival; key off + // visual state (fully open == 0x1B) instead. Other lair doors stay flag-based. + COND_VB_SHOULD(VB_LEVELDOOR_REMOTE_OPEN_DONE, EVENT_PRIORITY_NORMAL, isConnected, { + s32 doorActorId = va_arg(args, s32); + s32 doorState = va_arg(args, s32); + if (doorActorId == ACTOR_2E5_DOOR_OF_GRUNTY) { + *should = (doorState == 0x1B); + } + }); + + COND_VB_SHOULD(VB_FP_TWINKLY_START, EVENT_PRIORITY_NORMAL, isConnected, { + if (NetAuthority_IsClaimed(NET_ACTIVITY_FP_TWINKLY) && !NetAuthority_IsSelf(NET_ACTIVITY_FP_TWINKLY)) { + *should = false; + } else { + NetAuthority_Claim(NET_ACTIVITY_FP_TWINKLY); + } + }); + + COND_VB_SHOULD(VB_DOOR_OPEN_CAMERA, EVENT_PRIORITY_NORMAL, isConnected, { + s32 doorId = va_arg(args, s32); + switch (doorId) { + case GV_DOOR_CAM_SUN: + *should = !port_mapFlag_wasSetRemotely(3); + break; + case GV_DOOR_CAM_STAR: + *should = !port_mapFlag_wasSetRemotely(5); + break; + case GV_DOOR_CAM_KAZOOIE: + *should = !port_mapFlag_wasSetRemotely(6); + break; + case GV_DOOR_CAM_JINXY: + *should = !(port_mapFlag_wasSetRemotely(0) && port_mapFlag_wasSetRemotely(1)); + break; + case MMM_DOOR_CAM_CHURCH: + *should = !port_mapFlag_wasSetRemotely(0); // MMM_SPECIFIC_FLAG_0_UNKNOWN + break; + default: + break; + } + }); + COND_VB_SHOULD(VB_VILE_YUMBLIE_EMERGE, EVENT_PRIORITY_NORMAL, true, { if (Anchor_IsVileFollower()) { *should = false; @@ -188,29 +385,125 @@ void Anchor::RegisterHooks() { Anchor::GetInstance()->OnActorDestroyed(ev->actor); }); + // #region Flag sync + + COND_HOOK(OnGameFlagSet, EVENT_PRIORITY_NORMAL, isConnected, [](IEvent* event) { + auto* anchor = Anchor::GetInstance(); + if (!anchor->IsSaveLoaded() || !anchor->roomState.syncItemsAndFlags) { + return; + } + auto ev = reinterpret_cast(event); + for (s32 i = 0; i < ev->length; i++) { + s32 index = ev->index + i; + if (ev->flagSpace == ANCHOR_FLAGSPACE_LEVEL_SPECIFIC) { + if (Anchor_ScopedFlagExcluded(ev->flagSpace, index)) { + continue; + } + anchor->SendPacket_ScopedFlag((u8)ev->flagSpace, (s16)index, (u8)(levelSpecificFlags_get(index) ? 1 : 0)); + continue; + } + if (ev->flagSpace == ANCHOR_FLAGSPACE_MAP_SPECIFIC) { + if (Anchor_ScopedFlagExcluded(ev->flagSpace, index)) { + continue; + } + anchor->SendPacket_ScopedFlag((u8)ev->flagSpace, (s16)index, (u8)(mapSpecificFlags_get(index) ? 1 : 0)); + continue; + } + s32 bit; + if (ev->flagSpace == ANCHOR_FLAGSPACE_VOLATILE) { + if (!Anchor_ShouldBroadcastVolatileFlag(index)) { + continue; + } + bit = volatileFlag_get((enum volatile_flags_e)index); + } else { + bit = fileProgressFlag_get((enum file_progress_e)index); + } + SPDLOG_INFO("[Anchor][flagdiag] broadcast space={} index={:#x} bit={}", ev->flagSpace, index, bit); + if (bit) { + anchor->SendPacket_SetFlag((u8)ev->flagSpace, (s16)index); + } else { + anchor->SendPacket_UnsetFlag((u8)ev->flagSpace, (s16)index); + } + } + }); + + COND_HOOK(OnItemCountChanged, EVENT_PRIORITY_NORMAL, isConnected, [](IEvent* event) { + auto* anchor = Anchor::GetInstance(); + if (!anchor->IsSaveLoaded() || !anchor->roomState.syncItemsAndFlags) { + return; + } + auto ev = reinterpret_cast(event); + if (Anchor_ShouldSyncItemCount(ev->item, anchor->roomState)) { + anchor->SendPacket_SetItemCount((s16)ev->item, ev->count); + } + }); + + COND_HOOK(OnAbilityLearned, EVENT_PRIORITY_NORMAL, isConnected, [](IEvent* event) { + auto* anchor = Anchor::GetInstance(); + if (!anchor->IsSaveLoaded() || !anchor->roomState.syncItemsAndFlags) { + return; + } + auto ev = reinterpret_cast(event); + anchor->SendPacket_SetAbility((s16)ev->move, (u8)ev->value); + }); + + COND_HOOK(OnCollectibleCollected, EVENT_PRIORITY_NORMAL, isConnected, [](IEvent* event) { + auto* anchor = Anchor::GetInstance(); + if (!anchor->IsSaveLoaded() || !anchor->roomState.syncItemsAndFlags) { + return; + } + auto ev = reinterpret_cast(event); + anchor->SendPacket_CollectItem((u8)ev->kind, (s32)ev->id); + }); + + COND_HOOK(OnRandoCheckObtained, EVENT_PRIORITY_NORMAL, isConnected, [](IEvent* event) { + auto* anchor = Anchor::GetInstance(); + if (!anchor->IsSaveLoaded() || !anchor->roomState.syncItemsAndFlags) { + return; + } + auto ev = reinterpret_cast(event); + anchor->SendPacket_SetCheckStatus((s32)ev->randoCheckId, (s32)ev->map); + }); + + COND_HOOK(SetRandoInfFlag, EVENT_PRIORITY_NORMAL, isConnected, [](IEvent* event) { + auto* anchor = Anchor::GetInstance(); + if (!anchor->IsSaveLoaded() || !anchor->roomState.syncItemsAndFlags) { + return; + } + auto ev = reinterpret_cast(event); + if (!ev->flagState) { + return; + } + switch (ev->flagId) { + case RANDO_INF_BRIDGE_REPAIRED_DIALOG_COMPLETE: + anchor->SendPacket_SetFlag((u8)ANCHOR_FLAGSPACE_RANDO_INF, (s16)ev->flagId); + break; + default: + break; + } + }); + + COND_HOOK(OnJiggySpawned, EVENT_PRIORITY_NORMAL, isConnected, [](IEvent* event) { + auto* anchor = Anchor::GetInstance(); + if (!anchor->IsSaveLoaded() || !anchor->roomState.syncItemsAndFlags) { + return; + } + auto ev = reinterpret_cast(event); + anchor->SendPacket_SpawnJiggy((s16)ev->jiggyId, ev->x, ev->y, ev->z); + }); + + COND_HOOK(OnTimedJiggyExpired, EVENT_PRIORITY_NORMAL, isConnected, [](IEvent* event) { + auto ev = reinterpret_cast(event); + port_jiggySpawn_remove(ev->jiggyId); + }); + + COND_HOOK(OnSaveFileSave, EVENT_PRIORITY_NORMAL, isConnected, [](IEvent* event) { + Anchor::GetInstance()->SendPacket_UpdateTeamState(); + }); + + // #endregion + // COND_HOOK(OnPlayerSfx, isConnected, [&](u16 sfxId) { SendPacket_PlayerSfx(sfxId); }); - // COND_HOOK(OnOcarinaNote, isConnected, - // [&](uint8_t note, float modulator, int8_t bend) { SendPacket_OcarinaSfx(note, modulator, bend); }); - // - // COND_HOOK(OnLoadGame, isConnected, [&](s16 fileNum) { justLoadedSave = true; }); - // - // COND_HOOK(OnSaveFile, isConnected, [&](s16 fileNum, int sectionID) { - // if (sectionID == 0) { - // SendPacket_UpdateTeamState(); - // } - // }); - // - // COND_HOOK(OnFlagSet, isConnected, - // [&](s16 flagType, s16 flag) { SendPacket_SetFlag(SCENE_ID_MAX, flagType, flag); }); - // - // COND_HOOK(OnFlagUnset, isConnected, - // [&](s16 flagType, s16 flag) { SendPacket_UnsetFlag(SCENE_ID_MAX, flagType, flag); }); - // - // COND_HOOK(OnSceneFlagSet, isConnected, - // [&](s16 sceneNum, s16 flagType, s16 flag) { SendPacket_SetFlag(sceneNum, flagType, flag); }); - // - // COND_HOOK(OnSceneFlagUnset, isConnected, - // [&](s16 sceneNum, s16 flagType, s16 flag) { SendPacket_UnsetFlag(sceneNum, flagType, flag); }); // // COND_HOOK(OnRandoSetCheckStatus, isConnected, [&](RandomizerCheck rc, RandomizerCheckStatus status) { // if (!isHandlingUpdateTeamState) { diff --git a/src/port/Network/Anchor/JigsawPedestal.cpp b/src/port/Network/Anchor/JigsawPedestal.cpp new file mode 100644 index 000000000..b2cf51e72 --- /dev/null +++ b/src/port/Network/Anchor/JigsawPedestal.cpp @@ -0,0 +1,82 @@ +#include "port/Network/Anchor/JigsawPedestal.h" +#include "port/Network/Anchor/Anchor.h" +#include +#include + +static std::unordered_map sPedestalOwner; + +int32_t port_jigsawPedestal_tryClaim(int32_t id) { + Anchor* anchor = Anchor::GetInstance(); + if (anchor == nullptr || !anchor->isConnected) { + return 1; + } + auto it = sPedestalOwner.find(id); + if (it != sPedestalOwner.end() && it->second != anchor->ownClientId) { + return 0; + } + sPedestalOwner[id] = anchor->ownClientId; + anchor->SendPacket_PedestalOwner(id, true); + return 1; +} + +int32_t port_jigsawPedestal_isSelf(int32_t id) { + Anchor* anchor = Anchor::GetInstance(); + if (anchor == nullptr || !anchor->isConnected) { + return 1; + } + auto it = sPedestalOwner.find(id); + return (it == sPedestalOwner.end() || it->second == anchor->ownClientId) ? 1 : 0; +} + +void port_jigsawPedestal_release(int32_t id) { + Anchor* anchor = Anchor::GetInstance(); + if (anchor == nullptr || !anchor->isConnected) { + return; + } + auto it = sPedestalOwner.find(id); + if (it != sPedestalOwner.end() && it->second == anchor->ownClientId) { + sPedestalOwner.erase(it); + anchor->SendPacket_PedestalOwner(id, false); + } +} + +void JigsawPedestal_ApplyRemote(int32_t id, uint32_t clientId, bool claimed) { + auto it = sPedestalOwner.find(id); + if (claimed) { + // Simultaneous-claim tie-break: lowest clientId wins. + if (it == sPedestalOwner.end() || clientId < it->second) { + sPedestalOwner[id] = clientId; + } + } else if (it != sPedestalOwner.end() && it->second == clientId) { + sPedestalOwner.erase(it); + } +} + +void JigsawPedestal_ClearClient(uint32_t clientId) { + for (auto it = sPedestalOwner.begin(); it != sPedestalOwner.end();) { + it = (it->second == clientId) ? sPedestalOwner.erase(it) : std::next(it); + } +} + +void JigsawPedestal_ReleaseAllSelf() { + Anchor* anchor = Anchor::GetInstance(); + if (anchor == nullptr) { + return; + } + std::vector mine; + for (auto& [id, owner] : sPedestalOwner) { + if (owner == anchor->ownClientId) { + mine.push_back(id); + } + } + for (int32_t id : mine) { + sPedestalOwner.erase(id); + if (anchor->isConnected) { + anchor->SendPacket_PedestalOwner(id, false); + } + } +} + +void JigsawPedestal_Reset() { + sPedestalOwner.clear(); +} diff --git a/src/port/Network/Anchor/JigsawPedestal.h b/src/port/Network/Anchor/JigsawPedestal.h new file mode 100644 index 000000000..dbf37379e --- /dev/null +++ b/src/port/Network/Anchor/JigsawPedestal.h @@ -0,0 +1,23 @@ +#pragma once +#include + +// Per-pedestal interaction lock for the Lair jigsaw podiums (keyed by actorTypeSpecificField). + +#ifdef __cplusplus +extern "C" { +#endif + +int32_t port_jigsawPedestal_tryClaim(int32_t id); +// 1 if we may drive this podium (unowned/self/offline), 0 if another owns it. +int32_t port_jigsawPedestal_isSelf(int32_t id); +void port_jigsawPedestal_release(int32_t id); + +#ifdef __cplusplus +} + +// Network-internal entry points (Anchor packet handlers / lifecycle). +void JigsawPedestal_ApplyRemote(int32_t id, uint32_t clientId, bool claimed); +void JigsawPedestal_ClearClient(uint32_t clientId); +void JigsawPedestal_ReleaseAllSelf(); +void JigsawPedestal_Reset(); +#endif diff --git a/src/port/Network/Anchor/Menu.cpp b/src/port/Network/Anchor/Menu.cpp index afff951ed..f9219ef11 100644 --- a/src/port/Network/Anchor/Menu.cpp +++ b/src/port/Network/Anchor/Menu.cpp @@ -3,6 +3,9 @@ #include "port/UI/LighthouseGui.hpp" #include "port/UI/LighthouseMenu.h" #include "port/ShipUtils.h" +#include "port/Romhack/RomhackConfig.h" +#include "port/Romhack/RomhackCompat.h" +#include "port/Rando/Rando.h" namespace LighthouseGui { extern std::shared_ptr mLighthouseMenu; @@ -84,12 +87,13 @@ void AnchorMainMenu(WidgetInfo& info) { if (UIWidgets::Button("Global Room", UIWidgets::ButtonOptions() .Color(UIWidgets::Colors::Blue) - .Tooltip("Always-online public room so you don't have to experience " - "Hyrule alone. PVP and syncing are disabled."))) { + .Tooltip("Always-online public room so you don't have to explore alone. " + "You'll see other players' characters, but nothing is synced — " + "no items, flags, PvP, or teleporting."))) { CVarSetString(CVAR_REMOTE_ANCHOR("Host"), "anchor.hm64.org"); CVarSetInteger(CVAR_REMOTE_ANCHOR("Port"), 43383); CVarSetString(CVAR_REMOTE_ANCHOR("TeamId"), "default"); - CVarSetString(CVAR_REMOTE_ANCHOR("RoomId"), "soh-global"); + CVarSetString(CVAR_REMOTE_ANCHOR("RoomId"), "lh-global"); Ship::Context::GetRawInstance()->GetWindow()->GetGui()->SaveConsoleVariablesNextFrame(); } @@ -116,6 +120,17 @@ void AnchorMainMenu(WidgetInfo& info) { ImGui::EndDisabled(); ImGui::Spacing(); + UIWidgets::CVarCheckbox( + "Show Teammate Notifications", CVAR_REMOTE_ANCHOR("Notifications"), + UIWidgets::CheckboxOptions() + .DefaultValue(true) + .Color(THEME_COLOR) + .Tooltip("Show a notification when a teammate collects a jiggy, opens a level, or (in a " + "randomizer) obtains a shuffled check. Randomizer check notifications also require " + "\"Send Collection Notifications\" to be enabled in the Randomizer settings.")); + + ImGui::Spacing(); + if (!anchor->isEnabled) { return; } @@ -128,45 +143,32 @@ void AnchorMainMenu(WidgetInfo& info) { ImGui::SeparatorText("Current Room"); ImGui::Text("%s Connected", ICON_FA_CHECK); - UIWidgets::PushStyleButton(THEME_COLOR); - if (ImGui::Button("Request Team State")) { - anchor->SendPacket_RequestTeamState(); - } - UIWidgets::Tooltip("Try this if you are missing items or flags that your team members have collected"); - UIWidgets::PopStyleButton(); - - ImGui::SameLine(); - - // UIWidgets::WindowButton("Toggle Anchor Room Window", CVAR_WINDOW("AnchorRoom"), SohGui::mAnchorRoomWindow); + if (!anchor->IsGlobalRoom()) { + UIWidgets::PushStyleButton(THEME_COLOR); + if (ImGui::Button("Request Team State")) { + anchor->SendPacket_RequestTeamState(); + anchor->reloadMapOnTeamState = true; + } + UIWidgets::Tooltip("Try this if you are missing items or flags that your team members have collected"); + UIWidgets::PopStyleButton(); - ImGui::Spacing(); + ImGui::SameLine(); + } - bool hideLocations = Anchor::GetInstance()->roomState.showLocationsMode == 0; - ImGui::BeginDisabled(hideLocations); - UIWidgets::CVarCheckbox( - "Show Other Players on Minimap", CVAR_REMOTE_ANCHOR("ShowOtherPlayersOnMinimap"), - UIWidgets::CheckboxOptions() - .Color(THEME_COLOR) - .DefaultValue(true) - .Tooltip(!hideLocations - ? "Other players will appear on the minimap in areas where you have the compass. " - "Visibility is restricted according to the Show Locations mode for the room." - : "Cannot show other players because the room's Show Locations mode is set to None.")); - ImGui::EndDisabled(); + UIWidgets::WindowButton("Toggle Anchor Room Window", CVAR_WINDOW("AnchorRoom"), LighthouseGui::mAnchorRoomWindow); ImGui::Spacing(); - /*if (!SohGui::mAnchorRoomWindow->IsVisible()) { - SohGui::mAnchorRoomWindow->DrawElement(); - }*/ + if (!LighthouseGui::mAnchorRoomWindow->IsVisible()) { + LighthouseGui::mAnchorRoomWindow->DrawElement(); + } } void AnchorAdminMenu(WidgetInfo& info) { auto anchor = Anchor::GetInstance(); - bool isGlobalRoom = (std::string("soh-global") == CVarGetString(CVAR_REMOTE_ANCHOR("RoomId"), "")); if (!anchor->isEnabled || !anchor->isConnected || anchor->roomState.ownerClientId != anchor->ownClientId || - isGlobalRoom) { + anchor->IsGlobalRoom()) { return; } @@ -181,6 +183,13 @@ void AnchorAdminMenu(WidgetInfo& info) { for (auto& team : teams) { anchor->SendPacket_ClearTeamState(team); } + anchor->roomState.isRomhack = port_isRomhack(); + anchor->roomState.romhackName = Lighthouse::CurrentRomhackLabel(); + anchor->roomState.isRando = IS_RANDO; + anchor->roomState.seed = IS_RANDO ? (int32_t)RANDO_SEED : 0; + anchor->lastWarnedRomhackLabel.clear(); + anchor->lastWarnedRandoState.clear(); + anchor->SendPacket_UpdateRoomState(); } UIWidgets::PopStyleButton(); @@ -210,6 +219,10 @@ void AnchorAdminMenu(WidgetInfo& info) { UIWidgets::CheckboxOptions().DefaultValue(true).Color(THEME_COLOR))) { anchor->SendPacket_UpdateRoomState(); } + if (UIWidgets::CVarCheckbox("Share Consumables (Eggs/Feathers)", CVAR_REMOTE_ANCHOR("RoomSettings.ShareConsumables"), + UIWidgets::CheckboxOptions().DefaultValue(false).Color(THEME_COLOR))) { + anchor->SendPacket_UpdateRoomState(); + } } void AnchorInstructionsMenu(WidgetInfo& info) { diff --git a/src/port/Network/Anchor/Packets/AllClientState.cpp b/src/port/Network/Anchor/Packets/AllClientState.cpp index 0def295e9..afca8105a 100644 --- a/src/port/Network/Anchor/Packets/AllClientState.cpp +++ b/src/port/Network/Anchor/Packets/AllClientState.cpp @@ -20,7 +20,7 @@ extern "C" { void Anchor::HandlePacket_AllClientState(nlohmann::json& payload) { std::vector newClients = payload["state"].get>(); - bool isGlobalRoom = (std::string("lh-global") == CVarGetString(CVAR_REMOTE_ANCHOR("RoomId"), "")); + bool isGlobalRoom = IsGlobalRoom(); std::vector clientsToRemove; // add new clients @@ -88,5 +88,6 @@ void Anchor::HandlePacket_AllClientState(nlohmann::json& payload) { } PopulateDummies((GameMap)gsworld_getMap()); + SweepUnoccupiedLevelState((GameMap)gsworld_getMap()); SendPacket_PlayerUpdate(true); } diff --git a/src/port/Network/Anchor/Packets/BreakObject.cpp b/src/port/Network/Anchor/Packets/BreakObject.cpp new file mode 100644 index 000000000..947e77315 --- /dev/null +++ b/src/port/Network/Anchor/Packets/BreakObject.cpp @@ -0,0 +1,115 @@ +#include "port/Network/Anchor/Anchor.h" +#include +#include + +#include "port/ShipInit.hpp" +#include "port/Enhancements/Events/PortEnhancements.h" +#include "port/Enhancements/Events/Hooks/Events.h" + +#include +#include + +extern "C" { +#include "functions.h" +} + +#include "port/Patches/Patches.h" + +/** + * BREAK_OBJECT + */ + +std::set> sBrokenObjects; + +extern "C" int32_t port_breakable_isBroken(int32_t map, int32_t markerId, int32_t x, int32_t y, int32_t z) { + return sBrokenObjects.count({ map, markerId, x, y, z }) != 0 ? 1 : 0; +} + +std::vector port_breakable_snapshotBroken() { + std::vector flat; + flat.reserve(sBrokenObjects.size() * 5); + for (const auto& e : sBrokenObjects) { + flat.insert(flat.end(), e.begin(), e.end()); + } + return flat; +} + +void port_breakable_restoreBroken(const std::vector& flat) { + sBrokenObjects.clear(); + for (size_t i = 0; i + 5 <= flat.size(); i += 5) { + sBrokenObjects.insert({ flat[i], flat[i + 1], flat[i + 2], flat[i + 3], flat[i + 4] }); + } +} + +void port_breakable_clearForLevel(int32_t levelId) { + std::erase_if(sBrokenObjects, + [levelId](const std::array& e) { return (int32_t)map_getLevel((enum map_e)e[0]) == levelId; }); +} + +void Anchor::SendPacket_BreakObject(s16 markerId, s32 x, s32 y, s32 z, s32 map, bool replay) { + if (!IsSaveLoaded() || !roomState.syncItemsAndFlags) { + return; + } + + nlohmann::json payload; + payload["type"] = BREAK_OBJECT; + payload["targetTeamId"] = CVarGetString(CVAR_REMOTE_ANCHOR("TeamId"), "default"); + payload["addToQueue"] = true; + payload["marker"] = markerId; + payload["x"] = x; + payload["y"] = y; + payload["z"] = z; + payload["map"] = map; + payload["replay"] = replay; + + SendJsonToRemote(payload); +} + +void Anchor::HandlePacket_BreakObject(nlohmann::json& payload) { + if (!IsSaveLoaded() || !roomState.syncItemsAndFlags) { + return; + } + + s16 markerId = payload.at("marker").get(); + s32 x = payload.at("x").get(); + s32 y = payload.at("y").get(); + s32 z = payload.at("z").get(); + s32 map = payload.at("map").get(); + bool replay = payload.contains("replay") ? payload.at("replay").get() : true; + + sBrokenObjects.insert({ map, markerId, x, y, z }); + if (replay && (s32)gsworld_getMap() == map) { + port_breakable_remoteBreakAt(markerId, x, y, z); + } +} + +extern "C" void port_breakable_broadcastBreak(int32_t markerId, int32_t x, int32_t y, int32_t z) { + s32 map = (s32)gsworld_getMap(); + if (sBrokenObjects.count({ map, markerId, x, y, z }) != 0) { + return; + } + sBrokenObjects.insert({ map, markerId, x, y, z }); + Anchor::GetInstance()->SendPacket_BreakObject((s16)markerId, x, y, z, map); +} + +extern "C" void port_breakable_recordBreak(int32_t markerId, int32_t x, int32_t y, int32_t z) { + s32 map = (s32)gsworld_getMap(); + if (sBrokenObjects.count({ map, markerId, x, y, z }) != 0) { + return; + } + sBrokenObjects.insert({ map, markerId, x, y, z }); + Anchor::GetInstance()->SendPacket_BreakObject((s16)markerId, x, y, z, map, false); +} + +extern "C" void port_breakable_despawnBrokenRestores(s32 map); + +void RegisterBreakObject_Init() { + REGISTER_LISTENER(OnSaveLoad, EVENT_PRIORITY_NORMAL, [](IEvent* event) { sBrokenObjects.clear(); }); + + REGISTER_LISTENER(OnMapLoad, EVENT_PRIORITY_NORMAL, [](IEvent* event) { + OnMapLoad* ev = (OnMapLoad*)event; + port_breakable_despawnBrokenRestores((s32)ev->nextMap); + }); +} + +static RegisterShipInitFunc initBreakObject(RegisterBreakObject_Init, {}); diff --git a/src/port/Network/Anchor/Packets/CarryThrow.cpp b/src/port/Network/Anchor/Packets/CarryThrow.cpp new file mode 100644 index 000000000..77eef0242 --- /dev/null +++ b/src/port/Network/Anchor/Packets/CarryThrow.cpp @@ -0,0 +1,66 @@ +#include "port/Network/Anchor/Anchor.h" +#include +#include + +#include "port/Patches/Patches.h" + +extern "C" { +#include "functions.h" +} + +/** + * CARRY_THROW + */ + +void Anchor::SendPacket_CarryThrow(s32 markerId, f32 start[3], f32 target[3]) { + if (!IsSaveLoaded()) { + return; + } + + nlohmann::json payload; + payload["type"] = CARRY_THROW; + payload["marker"] = markerId; + payload["start"] = { start[0], start[1], start[2] }; + payload["target"] = { target[0], target[1], target[2] }; + + SendToCurrentMapPlayers(payload); +} + +void Anchor::HandlePacket_CarryThrow(nlohmann::json& payload) { + if (!IsSaveLoaded()) { + return; + } + + uint32_t clientId = payload.value("clientId", 0u); + s32 markerId = payload.value("marker", 0); + std::vector start = payload["start"].get>(); + std::vector target = payload["target"].get>(); + if (start.size() < 3 || target.size() < 3) { + return; + } + + port_remoteCarry_throw(clientId, markerId, start.data(), target.data()); +} + +extern "C" void port_anchor_onCarryThrow(s32 markerId, f32 start[3], f32 target[3]) { + Anchor* anchor = Anchor::GetInstance(); + if (anchor == nullptr || !anchor->isConnected) { + return; + } + anchor->SendPacket_CarryThrow(markerId, start, target); +} + +extern "C" s32 port_anchor_getDummyTransform(u32 clientId, f32 pos[3], f32* yaw) { + Anchor* anchor = Anchor::GetInstance(); + if (anchor == nullptr || !anchor->isConnected) { + return 0; + } + auto it = anchor->clients.find(clientId); + if (it == anchor->clients.end() || !it->second.online || it->second.dummy == nullptr || + (s32)it->second.map != (s32)gsworld_getMap()) { + return 0; + } + it->second.dummy->dummy_getPosition(pos); + *yaw = it->second.dummy->dummy_getYaw(); + return 1; +} diff --git a/src/port/Network/Anchor/Packets/CollectItem.cpp b/src/port/Network/Anchor/Packets/CollectItem.cpp new file mode 100644 index 000000000..7ae89ad4e --- /dev/null +++ b/src/port/Network/Anchor/Packets/CollectItem.cpp @@ -0,0 +1,141 @@ +#include "port/Network/Anchor/Anchor.h" +#include +#include +#include "port/Enhancements/Retention/Retention.h" +#include "port/Rando/Rando.h" +#include "port/UI/Notification.h" + +extern "C" { +#include "functions.h" +} + +static const char* const kJiggyLevelNames[10] = { + "Mumbo's Mountain", "Treasure Trove Cove", "Clanker's Cavern", "Bubblegloop Swamp", + "Freezeezy Peak", "Gruntilda's Lair", "Gobi's Valley", "Click Clock Wood", + "Rusty Bucket Bay", "Mad Monster Mansion", +}; + +/** + * COLLECT_ITEM + */ + +void Anchor::SendPacket_CollectItem(u8 kind, s32 id) { + if (!IsSaveLoaded() || !roomState.syncItemsAndFlags) { + return; + } + + nlohmann::json payload; + payload["type"] = COLLECT_ITEM; + payload["targetTeamId"] = CVarGetString(CVAR_REMOTE_ANCHOR("TeamId"), "default"); + payload["addToQueue"] = true; + payload["kind"] = kind; + payload["id"] = id; + payload["map"] = (s32)gsworld_getMap(); + + SendJsonToRemote(payload); +} + +void Anchor::HandlePacket_CollectItem(nlohmann::json& payload) { + if (!IsSaveLoaded() || !roomState.syncItemsAndFlags) { + return; + } + + u8 kind = payload.at("kind").get(); + s32 id = payload.at("id").get(); + s32 map = payload.at("map").get(); + bool sameMap = (s32)gsworld_getMap() == map; + + switch (kind) { + case ANCHOR_COLLECTIBLE_JIGGY: + if (!jiggyscore_isCollected((enum jiggy_e)id)) { + jiggyscore_setCollected(id, true); + func_8034798C(); // recompute the current-level jiggy HUD count + if ((s32)map_getLevel((enum map_e)map) == (s32)level_get()) { + code_73640_printItemCount(ITEM_E_JIGGY); + } else { + code_73640_printItemCount(ITEM_26_JIGGY_TOTAL); + } + if (!IS_RANDO && ShouldShowNotifications()) { + size_t levelIdx = (size_t)(id - 1) / 10; + const char* where = + levelIdx < (sizeof(kJiggyLevelNames) / sizeof(kJiggyLevelNames[0])) ? kJiggyLevelNames[levelIdx] + : "an unknown level"; + Notification::Emit({ + .prefix = GetClientName(payload.value("clientId", 0u)), + .message = "collected Jiggy #" + std::to_string(((id - 1) % 10) + 1) + " in " + where, + }); + } + } + if (sameMap) { + ActorMarker* m = func_8032B16C((enum jiggy_e)id); + if (m != nullptr) { + marker_despawn(m); + } + if (id == JIGGY_20_BGS_ELEVATED_WALKWAY || id == JIGGY_25_BGS_MAZE) { + func_802D6924(); + } + } + break; + case ANCHOR_COLLECTIBLE_HONEYCOMB: + if (!honeycombscore_get((enum honeycomb_e)id)) { + honeycombscore_set((enum honeycomb_e)id, 1); + item_inc(ITEM_13_EMPTY_HONEYCOMB); + if (!(item_getCount(ITEM_13_EMPTY_HONEYCOMB) < 6)) { + gcpausemenu_80314AC8(0); + } + } + if (sameMap) { + ActorMarker* m = actorArray_findHoneycombMarkerById((enum honeycomb_e)id); + if (m != nullptr) { + marker_despawn(m); + } + } + break; + case ANCHOR_COLLECTIBLE_MUMBO: + if (!mumboscore_get((enum mumbotoken_e)id)) { + mumboscore_set((enum mumbotoken_e)id, true); + } + if (sameMap) { + ActorMarker* m = actorArray_findMumboTokenMarkerById((enum mumbotoken_e)id); + if (m != nullptr) { + marker_despawn(m); + } + } + break; + case ANCHOR_COLLECTIBLE_NOTE: + port_noteRetention_applyRemoteCollect(map, id, sameMap ? 1 : 0); + break; + case ANCHOR_COLLECTIBLE_JINJO: + port_jinjoRetention_applyRemoteCollect(map, id, sameMap ? 1 : 0); + break; + case ANCHOR_COLLECTIBLE_WORM: + case ANCHOR_COLLECTIBLE_ACORN: + case ANCHOR_COLLECTIBLE_PRESENT_BLUE: + case ANCHOR_COLLECTIBLE_PRESENT_GREEN: + case ANCHOR_COLLECTIBLE_PRESENT_RED: + case ANCHOR_COLLECTIBLE_GOLD: + case ANCHOR_COLLECTIBLE_ORANGE: { + enum item_e item; + switch (kind) { + case ANCHOR_COLLECTIBLE_WORM: item = ITEM_22_CATERPILLAR; break; + case ANCHOR_COLLECTIBLE_ACORN: item = ITEM_23_ACORNS; break; + case ANCHOR_COLLECTIBLE_PRESENT_BLUE: item = ITEM_20_BLUE_PRESENT; break; + case ANCHOR_COLLECTIBLE_PRESENT_GREEN: item = ITEM_1F_GREEN_PRESENT; break; + case ANCHOR_COLLECTIBLE_PRESENT_RED: item = ITEM_21_RED_PRESENT; break; + case ANCHOR_COLLECTIBLE_ORANGE: item = ITEM_19_ORANGE; break; + default: item = ITEM_18_GOLD_BULLIONS; break; + } + bool noHud = (kind == ANCHOR_COLLECTIBLE_ORANGE) && !sameMap; + s32 delta = (id < 0) ? -1 : 1; + if (noHud) { + item_adjustByDiffWithoutHud(item, delta); + } else { + item_adjustByDiffWithHud(item, delta); + } + if (id >= 0) { + port_carriedSync_applyRemoteCollect(kind, map, id, sameMap ? 1 : 0); + } + break; + } + } +} diff --git a/src/port/Network/Anchor/Packets/DamagePlayer.cpp b/src/port/Network/Anchor/Packets/DamagePlayer.cpp index 09322c944..24002d43a 100644 --- a/src/port/Network/Anchor/Packets/DamagePlayer.cpp +++ b/src/port/Network/Anchor/Packets/DamagePlayer.cpp @@ -1,13 +1,10 @@ #include "port/Network/Anchor/Anchor.h" #include #include -//#include "soh/Enhancements/game-interactor/GameInteractor.h" extern "C" { #include "macros.h" #include "functions.h" -// extern PlayState* gPlayState; -// void func_80838280(Player* player); } /** @@ -29,37 +26,8 @@ void Anchor::SendPacket_DamagePlayer(u32 clientId, u8 damageEffect, u8 damage) { } void Anchor::HandlePacket_DamagePlayer(nlohmann::json& payload) { + return; // unimplemented uint32_t clientId = payload.at("clientId").get(); - // if (!clients.contains(clientId) || clients[clientId].player == nullptr) { - // return; - // } AnchorClient& anchorClient = clients[clientId]; - // Player* otherPlayer = anchorClient.player; - // Player* self = GET_PLAYER(gPlayState); - - //// Prevent incoming damage during cutscenes or item get sequences - // if (Player_InBlockingCsMode(gPlayState, self) || self->stateFlags1 & PLAYER_STATE1_IN_ITEM_CS || - // self->stateFlags1 & PLAYER_STATE1_GETTING_ITEM) { - // return; - // } - - // u8 damageEffect = payload.at("damageEffect").get(); - // u8 damage = payload.at("damage").get(); - - // self->actor.colChkInfo.damage = damage * 8; // Arbitrary number currently, need to fine tune - - // if (damageEffect == DUMMY_PLAYER_HIT_RESPONSE_FIRE) { - // for (int i = 0; i < ARRAY_COUNT(self->bodyFlameTimers); i++) { - // self->bodyFlameTimers[i] = Rand_S16Offset(0, 200); - // } - // self->bodyIsBurning = true; - // } else if (damageEffect == DUMMY_PLAYER_HIT_RESPONSE_STUN) { - // self->actor.freezeTimer = 20; - // Actor_SetColorFilter(&self->actor, 0, 0xFF, 0, 24); - // return; - // } - - // func_80837C0C(gPlayState, self, damageEffect, 4.0f, 5.0f, - // Actor_WorldYawTowardActor(&otherPlayer->actor, &self->actor), 20); } diff --git a/src/port/Network/Anchor/Packets/DisableAnchor.cpp b/src/port/Network/Anchor/Packets/DisableAnchor.cpp index ec047c3b5..9a4a322e6 100644 --- a/src/port/Network/Anchor/Packets/DisableAnchor.cpp +++ b/src/port/Network/Anchor/Packets/DisableAnchor.cpp @@ -1,7 +1,6 @@ #include "port/Network/Anchor/Anchor.h" #include #include -//#include "soh/Enhancements/game-interactor/GameInteractor.h" /** * DISABLE_ANCHOR diff --git a/src/port/Network/Anchor/Packets/EggToll.cpp b/src/port/Network/Anchor/Packets/EggToll.cpp new file mode 100644 index 000000000..8331d5d84 --- /dev/null +++ b/src/port/Network/Anchor/Packets/EggToll.cpp @@ -0,0 +1,110 @@ +#include "port/Network/Anchor/Anchor.h" +#include +#include + +#include "port/ShipInit.hpp" +#include "port/Enhancements/Events/PortEnhancements.h" +#include "port/Enhancements/Events/Hooks/Events.h" + +#include +#include +#include + +extern "C" { +#include "functions.h" +} + +#include "port/Patches/Patches.h" + +/** + * EGG_TOLL + */ + +std::map, int32_t> sStages; + +void recordStage(int32_t map, int32_t secondaryId, int32_t stage) { + std::array key = { map, secondaryId }; + auto it = sStages.find(key); + if (it == sStages.end() || stage > it->second) { + sStages[key] = stage; + } +} + +extern "C" int32_t port_eggToll_getStage(int32_t map, int32_t secondaryId) { + auto it = sStages.find({ map, secondaryId }); + return it != sStages.end() ? it->second : 0; +} + +extern "C" void port_eggToll_onAdvance(int32_t map, int32_t secondaryId, int32_t stage) { + recordStage(map, secondaryId, stage); + Anchor::GetInstance()->SendPacket_EggToll((s16)secondaryId, stage, map); +} + +void Anchor::SendPacket_EggToll(s16 secondaryId, s32 stage, s32 map) { + if (!IsSaveLoaded() || !roomState.syncItemsAndFlags) { + return; + } + + nlohmann::json payload; + payload["type"] = EGG_TOLL; + payload["targetTeamId"] = CVarGetString(CVAR_REMOTE_ANCHOR("TeamId"), "default"); + payload["addToQueue"] = true; + payload["sec"] = secondaryId; + payload["stage"] = stage; + payload["map"] = map; + + SendJsonToRemote(payload); +} + +void Anchor::HandlePacket_EggToll(nlohmann::json& payload) { + if (!IsSaveLoaded() || !roomState.syncItemsAndFlags) { + return; + } + + s16 secondaryId = payload.at("sec").get(); + s32 stage = payload.at("stage").get(); + s32 map = payload.at("map").get(); + + recordStage(map, secondaryId, stage); + if ((s32)gsworld_getMap() == map) { + port_eggToll_remoteApply(map, secondaryId, stage); + } +} + +std::vector port_eggToll_snapshot() { + std::vector flat; + flat.reserve(sStages.size() * 3); + for (const auto& [key, stage] : sStages) { + flat.push_back(key[0]); + flat.push_back(key[1]); + flat.push_back(stage); + } + return flat; +} + +void port_eggToll_restore(const std::vector& flat) { + sStages.clear(); + for (size_t i = 0; i + 3 <= flat.size(); i += 3) { + sStages[{ flat[i], flat[i + 1] }] = flat[i + 2]; + } +} + +void port_eggToll_clearForLevel(int32_t levelId) { + std::erase_if(sStages, + [levelId](const auto& kv) { return (int32_t)map_getLevel((enum map_e)kv.first[0]) == levelId; }); +} + +void RegisterEggToll_Init() { + REGISTER_LISTENER(OnSaveLoad, EVENT_PRIORITY_NORMAL, [](IEvent* event) { sStages.clear(); }); + + REGISTER_LISTENER(OnMapLoad, EVENT_PRIORITY_NORMAL, [](IEvent* event) { + OnMapLoad* ev = (OnMapLoad*)event; + for (const auto& [key, stage] : sStages) { + if (key[0] == (int32_t)ev->nextMap) { + port_eggToll_remoteApply(key[0], key[1], stage); + } + } + }); +} + +static RegisterShipInitFunc initEggToll(RegisterEggToll_Init, {}); diff --git a/src/port/Network/Anchor/Packets/EntranceDiscovered.cpp b/src/port/Network/Anchor/Packets/EntranceDiscovered.cpp index ab6192cdb..06e41b718 100644 --- a/src/port/Network/Anchor/Packets/EntranceDiscovered.cpp +++ b/src/port/Network/Anchor/Packets/EntranceDiscovered.cpp @@ -1,12 +1,11 @@ #include "port/Network/Anchor/Anchor.h" #include #include -//#include "soh/Enhancements/game-interactor/GameInteractor.h" -//#include "soh/Enhancements/randomizer/randomizer_entrance.h" -//#include "soh/OTRGlobals.h" /** * ENTRANCE_DISCOVERED + * + * currently unimplemented */ void Anchor::SendPacket_EntranceDiscovered(u16 entranceIndex) { @@ -29,5 +28,4 @@ void Anchor::HandlePacket_EntranceDiscovered(nlohmann::json& payload) { } u16 entranceIndex = payload.at("entranceIndex").get(); - // Entrance_SetEntranceDiscovered(entranceIndex, 1); } diff --git a/src/port/Network/Anchor/Packets/FightEvent.cpp b/src/port/Network/Anchor/Packets/FightEvent.cpp new file mode 100644 index 000000000..a5644bf10 --- /dev/null +++ b/src/port/Network/Anchor/Packets/FightEvent.cpp @@ -0,0 +1,73 @@ +#include "port/Network/Anchor/Anchor.h" +#include "port/Network/Anchor/Authority.h" +#include "port/Network/Anchor/FightSync.h" +#include +#include + +extern "C" { +#include "functions.h" +#include "variables.h" +} + +/** + * FIGHT_EVENT + */ + +void Anchor::SendPacket_FightEvent(s32 ev, s32 a, s32 b, const f32 v0[3], const f32 v1[3], const f32 v2[3]) { + if (!IsSaveLoaded() || gsworld_getMap() != MAP_90_GL_BATTLEMENTS || GetCurrentMapPlayers() == 0) { + return; + } + + nlohmann::json payload; + payload["type"] = FIGHT_EVENT; + payload["ev"] = ev; + payload["a"] = a; + payload["b"] = b; + if (v0 != nullptr && v1 != nullptr && v2 != nullptr) { + payload["p"] = { v0[0], v0[1], v0[2] }; + payload["v"] = { v1[0], v1[1], v1[2] }; + payload["w"] = { v2[0], v2[1], v2[2] }; + } + + SendToCurrentMapPlayers(payload); +} + +extern "C" void FightSync_SendEvent(int32_t ev, int32_t a, int32_t b, const float v0[3], const float v1[3], + const float v2[3]) { + Anchor* anchor = Anchor::GetInstance(); + if (anchor == nullptr || !anchor->isConnected) { + return; + } + anchor->SendPacket_FightEvent(ev, a, b, v0, v1, v2); +} + +void Anchor::HandlePacket_FightEvent(nlohmann::json& payload) { + if (gsworld_getMap() != MAP_90_GL_BATTLEMENTS) { + return; + } + + s32 ev = payload.value("ev", (s32)-1); + s32 a = payload.value("a", (s32)0); + s32 b = payload.value("b", (s32)0); + f32 p[3] = { 0.0f, 0.0f, 0.0f }; + f32 v[3] = { 0.0f, 0.0f, 0.0f }; + f32 w[3] = { 0.0f, 0.0f, 0.0f }; + bool hasVectors = payload.contains("p"); + + if (hasVectors) { + std::vector pv = payload["p"].get>(); + std::vector vv = payload["v"].get>(); + std::vector wv = payload["w"].get>(); + if (pv.size() < 3 || vv.size() < 3 || wv.size() < 3) { + return; + } + for (s32 i = 0; i < 3; i++) { + p[i] = pv[i]; + v[i] = vv[i]; + w[i] = wv[i]; + } + } + + FightSync_ApplyEvent(ev, a, b, hasVectors ? p : nullptr, hasVectors ? v : nullptr, + hasVectors ? w : nullptr); +} diff --git a/src/port/Network/Anchor/Packets/FightState.cpp b/src/port/Network/Anchor/Packets/FightState.cpp new file mode 100644 index 000000000..613157871 --- /dev/null +++ b/src/port/Network/Anchor/Packets/FightState.cpp @@ -0,0 +1,70 @@ +#include "port/Network/Anchor/Anchor.h" +#include "port/Network/Anchor/Authority.h" +#include "port/Network/Anchor/FightSync.h" +#include +#include + +extern "C" { +#include "functions.h" +#include "variables.h" +} + +/** + * FIGHT_STATE + */ + +void Anchor::SendPacket_FightState(u32 targetClientId) { + if (!IsSaveLoaded() || gsworld_getMap() != MAP_90_GL_BATTLEMENTS) { + return; + } + + FightWorldSnapshot snap; + if (!FightSync_GatherWorld(&snap)) { + return; + } + + nlohmann::json payload; + payload["type"] = FIGHT_STATE; + payload["targetClientId"] = targetClientId; + payload["pad"] = snap.pad; + payload["bar"] = snap.barrier; + payload["st"] = { snap.statue[0], snap.statue[1], snap.statue[2], snap.statue[3] }; + payload["jg"] = { snap.jinjoGone[0], snap.jinjoGone[1], snap.jinjoGone[2], snap.jinjoGone[3] }; + payload["jb"] = snap.jbase; + payload["jp"] = { snap.jpads[0], snap.jpads[1], snap.jpads[2], snap.jpads[3] }; + + SendJsonToRemote(payload); +} + +extern "C" void FightSync_SendSnapshot(uint32_t clientId) { + Anchor* anchor = Anchor::GetInstance(); + if (anchor == nullptr || !anchor->isConnected) { + return; + } + anchor->SendPacket_FightState(clientId); +} + +void Anchor::HandlePacket_FightState(nlohmann::json& payload) { + if (gsworld_getMap() != MAP_90_GL_BATTLEMENTS) { + return; + } + + FightWorldSnapshot snap; + std::vector st = payload["st"].get>(); + std::vector jg = payload["jg"].get>(); + std::vector jp = payload["jp"].get>(); + if (st.size() < 4 || jg.size() < 4 || jp.size() < 4) { + return; + } + + snap.pad = payload.value("pad", (u8)0); + snap.barrier = payload.value("bar", (u8)0); + snap.jbase = payload.value("jb", (u8)0); + for (s32 i = 0; i < 4; i++) { + snap.statue[i] = st[i]; + snap.jinjoGone[i] = jg[i]; + snap.jpads[i] = jp[i]; + } + + FightSync_ApplyWorld(&snap); +} diff --git a/src/port/Network/Anchor/Packets/FightUpdate.cpp b/src/port/Network/Anchor/Packets/FightUpdate.cpp new file mode 100644 index 000000000..18ab5d99a --- /dev/null +++ b/src/port/Network/Anchor/Packets/FightUpdate.cpp @@ -0,0 +1,76 @@ +#include "port/Network/Anchor/Anchor.h" +#include "port/Network/Anchor/Authority.h" +#include "port/Network/Anchor/FightSync.h" +#include +#include + +extern "C" { +#include "functions.h" +#include "variables.h" +} + +/** + * FIGHT_UPDATE + */ + +static uint32_t sOutgoingSeq = 0; +static uint32_t sLastAcceptedSeq = 0; + +extern "C" uint32_t FightSyncSeq_Next(void) { + return ++sOutgoingSeq; +} + +extern "C" bool FightSyncSeq_Accept(uint32_t seq) { + if (seq <= sLastAcceptedSeq) { + return false; + } + sLastAcceptedSeq = seq; + return true; +} + +extern "C" void FightSyncSeq_Reset(void) { + sOutgoingSeq = 0; + sLastAcceptedSeq = 0; +} + +void Anchor::SendPacket_FightUpdate(const f32 pos[3], f32 yaw, s32 state, s32 phase, s32 mirror, s32 vuln) { + if (!IsSaveLoaded() || gsworld_getMap() != MAP_90_GL_BATTLEMENTS || GetCurrentMapPlayers() == 0) { + return; + } + + nlohmann::json payload; + payload["type"] = FIGHT_UPDATE; + payload["seq"] = FightSyncSeq_Next(); + payload["pos"] = { pos[0], pos[1], pos[2] }; + payload["yaw"] = yaw; + payload["st"] = state; + payload["ph"] = phase; + payload["mir"] = mirror; + payload["vuln"] = vuln; + payload["quiet"] = true; + + SendToCurrentMapPlayers(payload); +} + +extern "C" void FightSync_SendUpdate(const float pos[3], float yaw, int32_t state, int32_t phase, int32_t mirror, + int32_t vuln) { + Anchor::GetInstance()->SendPacket_FightUpdate(pos, yaw, state, phase, mirror, vuln); +} + +void Anchor::HandlePacket_FightUpdate(nlohmann::json& payload) { + if (gsworld_getMap() != MAP_90_GL_BATTLEMENTS) { + return; + } + if (!FightSyncSeq_Accept(payload.value("seq", (u32)0))) { + return; + } + + std::vector pos = payload["pos"].get>(); + if (pos.size() < 3) { + return; + } + + FightSync_ApplyUpdate(pos.data(), payload.value("yaw", 0.0f), payload.value("st", (s32)1), + payload.value("ph", (s32)0), payload.value("mir", (s32)0), + payload.value("vuln", (s32)0)); +} diff --git a/src/port/Network/Anchor/Packets/GameComplete.cpp b/src/port/Network/Anchor/Packets/GameComplete.cpp index 44f314762..b502d8f31 100644 --- a/src/port/Network/Anchor/Packets/GameComplete.cpp +++ b/src/port/Network/Anchor/Packets/GameComplete.cpp @@ -1,9 +1,7 @@ #include "port/Network/Anchor/Anchor.h" #include #include -//#include "soh/Enhancements/game-interactor/GameInteractor.h" #include "port/UI/Notification.h" -//#include "soh/ShipUtils.h" const std::string gameCompleteMessages[] = { "killed Ganon", "saved Zelda", "proved their Courage", @@ -12,6 +10,8 @@ const std::string gameCompleteMessages[] = { /** * GAME_COMPLETE + * + * unimplemented */ void Anchor::SendPacket_GameComplete() { @@ -33,10 +33,9 @@ void Anchor::HandlePacket_GameComplete(nlohmann::json& payload) { AnchorClient& anchorClient = clients[clientId]; anchorClient.isGameComplete = true; - bool isGlobalRoom = (std::string("soh-global") == CVarGetString(CVAR_REMOTE_ANCHOR("RoomId"), "")); // Notification::Emit({ - // .prefix = isGlobalRoom ? "Someone" : anchorClient.name, + // .prefix = IsGlobalRoom() ? "Someone" : anchorClient.name, // .message = ShipUtils::RandomElement(gameCompleteMessages), // }); } diff --git a/src/port/Network/Anchor/Packets/GiveItem.cpp b/src/port/Network/Anchor/Packets/GiveItem.cpp index 3c4828fb1..11394429e 100644 --- a/src/port/Network/Anchor/Packets/GiveItem.cpp +++ b/src/port/Network/Anchor/Packets/GiveItem.cpp @@ -1,12 +1,7 @@ #include "port/Network/Anchor/Anchor.h" #include #include -//#include "soh/Enhancements/game-interactor/GameInteractor.h" #include "port/UI/Notification.h" -//#include "soh/Enhancements/randomizer/randomizer.h" -//#include "soh/SohGui/ImGuiUtils.h" -//#include "soh/Enhancements/item-tables/ItemTableManager.h" -//#include "soh/OTRGlobals.h" extern "C" { #include "functions.h" @@ -15,6 +10,8 @@ extern "C" { /** * GIVE_ITEM + * + * unimplemented */ uint8_t incomingIceTrapsFromAnchor = 0; diff --git a/src/port/Network/Anchor/Packets/Handshake.cpp b/src/port/Network/Anchor/Packets/Handshake.cpp index 0c80b0393..ce7d6dd78 100644 --- a/src/port/Network/Anchor/Packets/Handshake.cpp +++ b/src/port/Network/Anchor/Packets/Handshake.cpp @@ -1,8 +1,6 @@ #include "port/Network/Anchor/Anchor.h" #include #include -//#include "soh/Enhancements/game-interactor/GameInteractor.h" -//#include "soh/OTRGlobals.h" /** * HANDSHAKE diff --git a/src/port/Network/Anchor/Packets/HutSmash.cpp b/src/port/Network/Anchor/Packets/HutSmash.cpp new file mode 100644 index 000000000..d54ced085 --- /dev/null +++ b/src/port/Network/Anchor/Packets/HutSmash.cpp @@ -0,0 +1,110 @@ +#include "port/Network/Anchor/Anchor.h" +#include +#include + +#include "port/ShipInit.hpp" +#include "port/Enhancements/Events/PortEnhancements.h" +#include "port/Enhancements/Events/Hooks/Events.h" + +#include +#include +#include + +extern "C" { +#include "functions.h" +} + +/** + * HUT_SMASH + */ + +std::map, int32_t> sHuts; + +extern "C" int32_t port_hutSmash_get(int32_t x, int32_t y, int32_t z) { + auto it = sHuts.find({ (int32_t)gsworld_getMap(), x, y, z }); + return it != sHuts.end() ? it->second : -1; +} + +extern "C" int32_t port_hutSmash_countForCurrentMap(void) { + int32_t map = (int32_t)gsworld_getMap(); + int32_t count = 0; + for (const auto& [key, loot] : sHuts) { + if (key[0] == map) { + count++; + } + } + return count; +} + +extern "C" void port_hutSmash_record(int32_t x, int32_t y, int32_t z, int32_t loot) { + int32_t map = (int32_t)gsworld_getMap(); + std::array key = { map, x, y, z }; + if (sHuts.find(key) != sHuts.end()) { + return; + } + sHuts[key] = loot; + Anchor::GetInstance()->SendPacket_HutSmash(x, y, z, loot, map); +} + +void Anchor::SendPacket_HutSmash(s32 x, s32 y, s32 z, s32 loot, s32 map) { + if (!IsSaveLoaded() || !roomState.syncItemsAndFlags) { + return; + } + + nlohmann::json payload; + payload["type"] = HUT_SMASH; + payload["targetTeamId"] = CVarGetString(CVAR_REMOTE_ANCHOR("TeamId"), "default"); + payload["addToQueue"] = true; + payload["x"] = x; + payload["y"] = y; + payload["z"] = z; + payload["loot"] = loot; + payload["map"] = map; + + SendJsonToRemote(payload); +} + +void Anchor::HandlePacket_HutSmash(nlohmann::json& payload) { + if (!IsSaveLoaded() || !roomState.syncItemsAndFlags) { + return; + } + + s32 x = payload.at("x").get(); + s32 y = payload.at("y").get(); + s32 z = payload.at("z").get(); + s32 loot = payload.at("loot").get(); + s32 map = payload.at("map").get(); + + sHuts.emplace(std::array{ map, x, y, z }, loot); +} + +std::vector port_hutSmash_snapshot() { + std::vector flat; + flat.reserve(sHuts.size() * 5); + for (const auto& [key, loot] : sHuts) { + flat.push_back(key[0]); + flat.push_back(key[1]); + flat.push_back(key[2]); + flat.push_back(key[3]); + flat.push_back(loot); + } + return flat; +} + +void port_hutSmash_restore(const std::vector& flat) { + sHuts.clear(); + for (size_t i = 0; i + 5 <= flat.size(); i += 5) { + sHuts[{ flat[i], flat[i + 1], flat[i + 2], flat[i + 3] }] = flat[i + 4]; + } +} + +void port_hutSmash_clearForLevel(int32_t levelId) { + std::erase_if(sHuts, + [levelId](const auto& kv) { return (int32_t)map_getLevel((enum map_e)kv.first[0]) == levelId; }); +} + +void RegisterHutSmash_Init() { + REGISTER_LISTENER(OnSaveLoad, EVENT_PRIORITY_NORMAL, [](IEvent* event) { sHuts.clear(); }); +} + +static RegisterShipInitFunc initHutSmash(RegisterHutSmash_Init, {}); diff --git a/src/port/Network/Anchor/Packets/JiggyCrane.cpp b/src/port/Network/Anchor/Packets/JiggyCrane.cpp new file mode 100644 index 000000000..97369ffc8 --- /dev/null +++ b/src/port/Network/Anchor/Packets/JiggyCrane.cpp @@ -0,0 +1,37 @@ +#include "port/Network/Anchor/Anchor.h" +#include +#include + +extern "C" { +#include "functions.h" +} + +#include "port/Patches/Patches.h" + +/** + * JIGGY_CRANE + */ + +void Anchor::SendPacket_JiggyCrane(s32 stage) { + if (!IsSaveLoaded() || !roomState.syncItemsAndFlags || GetCurrentMapPlayers() == 0) { + return; + } + + nlohmann::json payload; + payload["type"] = JIGGY_CRANE; + payload["stage"] = stage; + + SendToCurrentMapPlayers(payload); +} + +void Anchor::HandlePacket_JiggyCrane(nlohmann::json& payload) { + if (!IsSaveLoaded() || !roomState.syncItemsAndFlags) { + return; + } + + port_jiggyCrane_remoteApply(payload.at("stage").get()); +} + +extern "C" void port_jiggyCrane_broadcast(int32_t stage) { + Anchor::GetInstance()->SendPacket_JiggyCrane(stage); +} diff --git a/src/port/Network/Anchor/Packets/MapLoad.cpp b/src/port/Network/Anchor/Packets/MapLoad.cpp index 6765b0aa1..8f48cead5 100644 --- a/src/port/Network/Anchor/Packets/MapLoad.cpp +++ b/src/port/Network/Anchor/Packets/MapLoad.cpp @@ -35,6 +35,7 @@ void Anchor::HandlePacket_MapLoad(nlohmann::json& payload) { clients[clientId].map != MAP_91_FILE_SELECT; EvaluateDummyForClient(clientId); Authority_OnPeerMapLoad(clientId, clients[clientId].map); + SweepUnoccupiedLevelState((GameMap)gsworld_getMap()); // Handle instances where map-specific updates aren't captured by other clients, causing transformations // and animation states to be desynced until updated again while the client is in the map. diff --git a/src/port/Network/Anchor/Packets/PedestalOwner.cpp b/src/port/Network/Anchor/Packets/PedestalOwner.cpp new file mode 100644 index 000000000..cd3ceca92 --- /dev/null +++ b/src/port/Network/Anchor/Packets/PedestalOwner.cpp @@ -0,0 +1,27 @@ +#include "port/Network/Anchor/Anchor.h" +#include "port/Network/Anchor/JigsawPedestal.h" +#include +#include + +/** + * PEDESTAL_OWNER + * + * Claim/release of a jigsaw podium lock; conflicts resolve by lowest clientId. + */ + +void Anchor::SendPacket_PedestalOwner(s32 id, bool claimed) { + nlohmann::json payload; + payload["type"] = PEDESTAL_OWNER; + payload["id"] = id; + payload["claimed"] = claimed; + + SendJsonToRemote(payload); +} + +void Anchor::HandlePacket_PedestalOwner(nlohmann::json& payload) { + uint32_t clientId = payload.at("clientId").get(); + s32 id = payload.at("id").get(); + bool claimed = payload.value("claimed", false); + + JigsawPedestal_ApplyRemote(id, clientId, claimed); +} diff --git a/src/port/Network/Anchor/Packets/PlayerSfx.cpp b/src/port/Network/Anchor/Packets/PlayerSfx.cpp index a3c2bdf5e..3ebe1e6c8 100644 --- a/src/port/Network/Anchor/Packets/PlayerSfx.cpp +++ b/src/port/Network/Anchor/Packets/PlayerSfx.cpp @@ -7,7 +7,6 @@ extern "C" { #include "macros.h" #include "functions.h" #include "variables.h" -// extern PlayState* gPlayState; } /** @@ -26,22 +25,6 @@ void Anchor::SendPacket_PlayerSfx(u16 sfxId) { payload["type"] = PLAYER_SFX; payload["sfxId"] = sfxId; payload["quiet"] = true; - - // for (auto& [clientId, client] : clients) { - // if (client.sceneNum == gPlayState->sceneNum && client.online && client.isSaveLoaded && !client.self) { - // payload["targetClientId"] = clientId; - // SendJsonToRemote(payload); - // } - // } } -void Anchor::HandlePacket_PlayerSfx(nlohmann::json& payload) { - // uint32_t clientId = payload.at("clientId").get(); - // u16 sfxId = payload.at("sfxId").get(); - - // if (!clients.contains(clientId) || !clients[clientId].player) { - // return; - // } - - // Player_PlaySfx((Actor*)clients[clientId].player, sfxId); -} +void Anchor::HandlePacket_PlayerSfx(nlohmann::json& payload) {} diff --git a/src/port/Network/Anchor/Packets/PlayerUpdate.cpp b/src/port/Network/Anchor/Packets/PlayerUpdate.cpp index 861451017..592ab1466 100644 --- a/src/port/Network/Anchor/Packets/PlayerUpdate.cpp +++ b/src/port/Network/Anchor/Packets/PlayerUpdate.cpp @@ -7,8 +7,11 @@ extern "C" { #include "functions.h" #include "macros.h" #include "variables.h" +ActorMarker* bacarry_get_marker(void); } +#include "port/Patches/Patches.h" + /** * PLAYER_UPDATE * @@ -28,6 +31,17 @@ void Anchor::SendToCurrentMapPlayers(nlohmann::json& payload) { } } +void Anchor::SendToCurrentLevelPlayers(nlohmann::json& payload) { + enum level_e myLevel = map_getLevel(gsworld_getMap()); + for (auto& [clientId, client] : clients) { + if (client.online && client.isSaveLoaded && !client.self && + map_getLevel((enum map_e)client.map) == myLevel) { + payload["targetClientId"] = clientId; + SendJsonToRemote(payload); + } + } +} + void Anchor::SendPacket_PlayerSubRangeChange(f32 duration, f32 end) { if (!IsSaveLoaded() || GetCurrentMapPlayers() == 0) { return; @@ -168,12 +182,29 @@ void Anchor::SendPacket_PlayerUpdate(bool full, uint32_t targetClientId) { payload["modelMouth2"] = func_8029DFEC(); // mouth 2 payload["modelEyeBlendUpper"] = func_8029DFC8(); // eye blend upper payload["modelEyeBlendLower"] = func_8029DFD4(); // eye blend lower + payload["bottlesBonus"] = baanim_getActiveBottlesBonusMask(); + { + // Carried-collectible marker id (0 = none); skipped once thrown (unk138_21 = in flight). + s32 carryId = 0; + ActorMarker* carryMarker = bacarry_get_marker(); + if (carryMarker != nullptr) { + Actor* carried = marker_getActor(carryMarker); + if (carried != nullptr && !carried->unk138_21) { + carryId = carryMarker->id; + payload["carryOff"] = { carried->position[0] - pos[0], carried->position[1] - pos[1], + carried->position[2] - pos[2] }; + payload["carryYaw"] = mlNormalizeAngle(carried->yaw - player_getYaw()); + } + } + payload["carry"] = carryId; + } if (full) { payload["anim_id"] = anctrl_getIndex(baanim_getAnimCtrlPtr()); payload["anim_control"] = anctrl_getPlaybackType(baanim_getAnimCtrlPtr()); } payload["type"] = full ? PLAYER_UPDATE_FULL : PLAYER_UPDATE; + payload["quiet"] = true; if (targetClientId != 0) { payload["targetClientId"] = targetClientId; @@ -238,5 +269,20 @@ void Anchor::HandlePacket_PlayerUpdate(nlohmann::json& payload) { payload.value("modelWink", false), payload.value("modelMouth1", false), payload.value("modelMouth2", false), payload.value("modelEyeBlendUpper", 0.0f), payload.value("modelEyeBlendLower", 0.0f)); + client.dummy->dummy_setBottlesBonus(payload.value("bottlesBonus", 0)); + { + f32 carryOff[3] = { 0.0f, 0.0f, 0.0f }; + f32 carryYaw = 0.0f; + if (payload.contains("carryOff")) { + std::vector off = payload["carryOff"].get>(); + if (off.size() >= 3) { + carryOff[0] = off[0]; + carryOff[1] = off[1]; + carryOff[2] = off[2]; + } + carryYaw = payload.value("carryYaw", 0.0f); + } + port_remoteCarry_setCarried(clientId, payload.value("carry", 0), carryOff, carryYaw); + } } } diff --git a/src/port/Network/Anchor/Packets/PuzzleStep.cpp b/src/port/Network/Anchor/Packets/PuzzleStep.cpp new file mode 100644 index 000000000..455ed4c4a --- /dev/null +++ b/src/port/Network/Anchor/Packets/PuzzleStep.cpp @@ -0,0 +1,248 @@ +#include "port/Network/Anchor/Anchor.h" +#include +#include + +#include "port/ShipInit.hpp" +#include "port/Enhancements/Events/PortEnhancements.h" +#include "port/Enhancements/Events/Hooks/Events.h" + +#include +#include +#include +#include + +extern "C" { +#include "functions.h" +void chTreasurehunt_netTick(void); +} + +#include "port/Patches/Patches.h" + +/** + * PUZZLE_STEP + * + * Syncs multi-step world puzzles with no flag of their own (Tanktup's legs, croctus feed, pink + * eggs). Progress is an OR-merged bitmask keyed by (map, puzzleId); never saved. + */ + +std::map, int32_t> sPuzzleBits; +std::map, int32_t> sPuzzleCounts; +// PUZZLE_POS: (map, puzzleId) -> set of spawn-position hashes for positional puzzles (see below). +std::map, std::set> sPuzzlePos; + +static int32_t puzzlePosHash(int32_t x, int32_t y, int32_t z) { + uint32_t h = (uint32_t)x * 73856093u ^ (uint32_t)y * 19349663u ^ (uint32_t)z * 83492791u; + return (int32_t)((h & 0x7FFFFFFFu) | 1u); // never 0 (the "no positional hash" sentinel) +} + +extern "C" int32_t port_puzzleStep_get(int32_t puzzleId) { + auto it = sPuzzleBits.find({ (int32_t)gsworld_getMap(), puzzleId }); + return it != sPuzzleBits.end() ? it->second : 0; +} + +extern "C" int32_t port_puzzleStep_getForMap(int32_t map, int32_t puzzleId) { + auto it = sPuzzleBits.find({ map, puzzleId }); + return it != sPuzzleBits.end() ? it->second : 0; +} + +extern "C" void port_puzzleStep_orBits(int32_t puzzleId, int32_t bits) { + int32_t map = (int32_t)gsworld_getMap(); + std::array key = { map, puzzleId }; + int32_t before = sPuzzleBits.count(key) ? sPuzzleBits[key] : 0; + int32_t after = before | bits; + if (after == before) { + return; + } + sPuzzleBits[key] = after; + Anchor::GetInstance()->SendPacket_PuzzleStep(puzzleId, after, map); +} + +void Anchor::SendPacket_PuzzleStep(s32 puzzleId, s32 bits, s32 map, s32 phash) { + if (!IsSaveLoaded() || !roomState.syncItemsAndFlags) { + return; + } + + nlohmann::json payload; + payload["type"] = PUZZLE_STEP; + payload["targetTeamId"] = CVarGetString(CVAR_REMOTE_ANCHOR("TeamId"), "default"); + payload["addToQueue"] = true; + payload["puzzle"] = puzzleId; + payload["bits"] = bits; + payload["map"] = map; + // A positional puzzle ships its member's hash instead of a bit; 0 = an ordinary bitmask step. + if (phash != 0) { + payload["phash"] = phash; + } + + SendJsonToRemote(payload); +} + +void Anchor::HandlePacket_PuzzleStep(nlohmann::json& payload) { + if (!IsSaveLoaded() || !roomState.syncItemsAndFlags) { + return; + } + + s32 puzzleId = payload.at("puzzle").get(); + s32 map = payload.at("map").get(); + s32 phash = payload.value("phash", (s32)0); + if (phash != 0) { + sPuzzlePos[{ map, puzzleId }].insert(phash); + return; + } + sPuzzleBits[{ map, puzzleId }] |= payload.at("bits").get(); +} + +std::vector port_puzzleStep_snapshot() { + std::vector flat; + flat.reserve(sPuzzleBits.size() * 3); + for (const auto& [key, bits] : sPuzzleBits) { + flat.push_back(key[0]); + flat.push_back(key[1]); + flat.push_back(bits); + } + return flat; +} + +void port_puzzleStep_restore(const std::vector& flat) { + sPuzzleBits.clear(); + for (size_t i = 0; i + 3 <= flat.size(); i += 3) { + sPuzzleBits[{ flat[i], flat[i + 1] }] = flat[i + 2]; + } +} + +void port_puzzleStep_clearForLevel(int32_t levelId) { + std::erase_if(sPuzzleBits, + [levelId](const auto& kv) { return (int32_t)map_getLevel((enum map_e)kv.first[0]) == levelId; }); + std::erase_if(sPuzzleCounts, + [levelId](const auto& kv) { return (int32_t)map_getLevel((enum map_e)kv.first[0]) == levelId; }); + std::erase_if(sPuzzlePos, + [levelId](const auto& kv) { return (int32_t)map_getLevel((enum map_e)kv.first[0]) == levelId; }); +} + +/** + * PUZZLE_POS + * + * Positional companion to PUZZLE_STEP for steps keyed by spawn position instead of a bit index + * (FP's Sir Slushes). Rides the same PUZZLE_STEP packet via the phash field. + */ + +extern "C" int32_t port_puzzlePos_isMarked(int32_t puzzleId, int32_t x, int32_t y, int32_t z) { + auto it = sPuzzlePos.find({ (int32_t)gsworld_getMap(), puzzleId }); + return (it != sPuzzlePos.end() && it->second.count(puzzlePosHash(x, y, z))) ? 1 : 0; +} + +extern "C" void port_puzzlePos_mark(int32_t puzzleId, int32_t x, int32_t y, int32_t z) { + int32_t map = (int32_t)gsworld_getMap(); + int32_t hash = puzzlePosHash(x, y, z); + auto& set = sPuzzlePos[{ map, puzzleId }]; + if (!set.insert(hash).second) { + return; + } + Anchor::GetInstance()->SendPacket_PuzzleStep(puzzleId, 0, map, hash); +} + +// Flat [map, puzzleId, count, hashes...] runs. +std::vector port_puzzlePos_snapshot() { + std::vector flat; + for (const auto& [key, set] : sPuzzlePos) { + flat.push_back(key[0]); + flat.push_back(key[1]); + flat.push_back((int32_t)set.size()); + for (int32_t h : set) { + flat.push_back(h); + } + } + return flat; +} + +void port_puzzlePos_restore(const std::vector& flat) { + sPuzzlePos.clear(); + size_t i = 0; + while (i + 3 <= flat.size()) { + int32_t map = flat[i], puzzleId = flat[i + 1], count = flat[i + 2]; + i += 3; + auto& set = sPuzzlePos[{ map, puzzleId }]; + for (int32_t j = 0; j < count && i < flat.size(); j++, i++) { + set.insert(flat[i]); + } + } +} + +/** + * PUZZLE_COUNT + * + * Companion to PUZZLE_STEP for count-based progress (Eyrie's fed worms, Nabnut's acorns). + */ + +extern "C" int32_t port_puzzleCount_get(int32_t counterId) { + auto it = sPuzzleCounts.find({ (int32_t)gsworld_getMap(), counterId }); + return it != sPuzzleCounts.end() ? it->second : 0; +} + +extern "C" void port_puzzleCount_add(int32_t counterId, int32_t delta) { + int32_t map = (int32_t)gsworld_getMap(); + sPuzzleCounts[{ map, counterId }] += delta; + Anchor::GetInstance()->SendPacket_PuzzleCount(counterId, delta, map); +} + +void Anchor::SendPacket_PuzzleCount(s32 counterId, s32 delta, s32 map) { + if (!IsSaveLoaded() || !roomState.syncItemsAndFlags) { + return; + } + + nlohmann::json payload; + payload["type"] = PUZZLE_COUNT; + payload["targetTeamId"] = CVarGetString(CVAR_REMOTE_ANCHOR("TeamId"), "default"); + payload["addToQueue"] = true; + payload["counter"] = counterId; + payload["delta"] = delta; + payload["map"] = map; + + SendJsonToRemote(payload); +} + +void Anchor::HandlePacket_PuzzleCount(nlohmann::json& payload) { + if (!IsSaveLoaded() || !roomState.syncItemsAndFlags) { + return; + } + + s32 counterId = payload.at("counter").get(); + s32 delta = payload.at("delta").get(); + s32 map = payload.at("map").get(); + + sPuzzleCounts[{ map, counterId }] += delta; +} + +std::vector port_puzzleCount_snapshot() { + std::vector flat; + flat.reserve(sPuzzleCounts.size() * 3); + for (const auto& [key, count] : sPuzzleCounts) { + flat.push_back(key[0]); + flat.push_back(key[1]); + flat.push_back(count); + } + return flat; +} + +void port_puzzleCount_restore(const std::vector& flat) { + sPuzzleCounts.clear(); + for (size_t i = 0; i + 3 <= flat.size(); i += 3) { + sPuzzleCounts[{ flat[i], flat[i + 1] }] = flat[i + 2]; + } +} + +void RegisterPuzzleStep_Init() { + REGISTER_LISTENER(OnSaveLoad, EVENT_PRIORITY_NORMAL, [](IEvent* event) { + sPuzzleBits.clear(); + sPuzzleCounts.clear(); + sPuzzlePos.clear(); + }); + // Treasure hunt has no actor to poll until the first X is busted. + REGISTER_LISTENER(GameFrameUpdate, EVENT_PRIORITY_NORMAL, [](IEvent* event) { + if (gsworld_getMap() == MAP_7_TTC_TREASURE_TROVE_COVE) { + chTreasurehunt_netTick(); + } + }); +} + +static RegisterShipInitFunc initPuzzleStep(RegisterPuzzleStep_Init, {}); diff --git a/src/port/Network/Anchor/Packets/RequestTeamState.cpp b/src/port/Network/Anchor/Packets/RequestTeamState.cpp index 220a16f80..7ebbfe2b0 100644 --- a/src/port/Network/Anchor/Packets/RequestTeamState.cpp +++ b/src/port/Network/Anchor/Packets/RequestTeamState.cpp @@ -1,7 +1,6 @@ #include "port/Network/Anchor/Anchor.h" #include #include -//#include "soh/OTRGlobals.h" /** * REQUEST_TEAM_STATE @@ -16,8 +15,10 @@ * state */ -void Anchor::SendPacket_RequestTeamState() { - if (!IsSaveLoaded() || !roomState.syncItemsAndFlags) { +void Anchor::SendPacket_RequestTeamState(bool force) { + // `force` bypasses the IsSaveLoaded check: OnGameLoad fires from gameFile_load while the map is + // still FILE_SELECT, so the save is loading but IsSaveLoaded() is still false. + if ((!force && !IsSaveLoaded()) || !roomState.syncItemsAndFlags) { return; } diff --git a/src/port/Network/Anchor/Packets/RequestTeleport.cpp b/src/port/Network/Anchor/Packets/RequestTeleport.cpp index ab02cedea..17a0e8926 100644 --- a/src/port/Network/Anchor/Packets/RequestTeleport.cpp +++ b/src/port/Network/Anchor/Packets/RequestTeleport.cpp @@ -1,13 +1,11 @@ #include "port/Network/Anchor/Anchor.h" #include #include -//#include "soh/Enhancements/game-interactor/GameInteractor.h" /** * REQUEST_TELEPORT * - * Because we don't have all the necessary information to directly teleport to a player, we emit a request, - * in which they will respond with a TELEPORT_TO packet, with the necessary information. + * Asks a client for their location; they reply with TELEPORT_TO (map, position, yaw). */ void Anchor::SendPacket_RequestTeleport(uint32_t clientId) { @@ -31,61 +29,33 @@ void Anchor::HandlePacket_RequestTeleport(nlohmann::json& payload) { SendPacket_TeleportTo(clientId); } -// Reusable function to check if teleporting to a client is allowed bool Anchor::CanTeleportTo(uint32_t clientId) { - // Teleporting is disabled if (roomState.teleportMode == 0) { return false; } - // You're not loaded into a save if (!IsSaveLoaded()) { return false; } - // The client doesn't exist if (clients.find(clientId) == clients.end()) { return false; } AnchorClient& client = clients[clientId]; - // The client is yourself if (client.self) { return false; } - // The client isn't online or loaded into a save if (!client.online || !client.isSaveLoaded) { return false; } - // Teleporting to team only, but the client is not on your team std::string ownTeamId = CVarGetString(CVAR_REMOTE_ANCHOR("TeamId"), "default"); if (roomState.teleportMode == 1 && client.teamId != ownTeamId) { return false; } - //// Problematic scenes for teleporting - // if (client.sceneNum == SCENE_ID_MAX || client.sceneNum == SCENE_GROTTOS || client.sceneNum == SCENE_MARKET_DAY || - // client.sceneNum == SCENE_MARKET_NIGHT || client.sceneNum == SCENE_MARKET_RUINS || - // client.sceneNum == SCENE_MARKET_ENTRANCE_DAY || client.sceneNum == SCENE_MARKET_ENTRANCE_NIGHT || - // client.sceneNum == SCENE_MARKET_ENTRANCE_RUINS || client.sceneNum == SCENE_TEMPLE_OF_TIME_EXTERIOR_DAY || - // client.sceneNum == SCENE_TEMPLE_OF_TIME_EXTERIOR_NIGHT || - // client.sceneNum == SCENE_TEMPLE_OF_TIME_EXTERIOR_RUINS || client.sceneNum == SCENE_BACK_ALLEY_DAY || - // client.sceneNum == SCENE_BACK_ALLEY_NIGHT) { - // return false; - // } - - //// Child can't teleport to Ganon's Castle exterior - // if (client.sceneNum == SCENE_OUTSIDE_GANONS_CASTLE && gSaveContext.linkAge == LINK_AGE_CHILD) { - // return false; - // } - - //// Adult can't teleport to Hyrule Castle exterior - // if (client.sceneNum == SCENE_HYRULE_CASTLE && gSaveContext.linkAge == LINK_AGE_ADULT) { - // return false; - // } - return true; } diff --git a/src/port/Network/Anchor/Packets/ScopedFlag.cpp b/src/port/Network/Anchor/Packets/ScopedFlag.cpp new file mode 100644 index 000000000..b947b75e2 --- /dev/null +++ b/src/port/Network/Anchor/Packets/ScopedFlag.cpp @@ -0,0 +1,81 @@ +#include "port/Network/Anchor/Anchor.h" +#include +#include + +#include "port/ShipInit.hpp" +#include "port/Enhancements/Events/PortEnhancements.h" +#include "port/Enhancements/Events/Hooks/Events.h" + +extern "C" { +#include "functions.h" +void chHoneycomb_netRevealFromSwitch(void); +} + +static uint32_t sMapFlagSetRemotely = 0; + +extern "C" int32_t port_mapFlag_wasSetRemotely(int32_t index) { + return (index >= 0 && index < 32 && (sMapFlagSetRemotely & (1u << index))) ? 1 : 0; +} + +/** + * SCOPED_FLAG + * + * Realtime sync of a transient level-/map flag; ctx = sender's level/map id. + */ + +void Anchor::SendPacket_ScopedFlag(u8 space, s16 index, u8 value) { + if (!IsSaveLoaded() || !roomState.syncItemsAndFlags) { + return; + } + + nlohmann::json payload; + payload["type"] = SCOPED_FLAG; + payload["space"] = space; + payload["index"] = index; + payload["value"] = value; + + if (space == ANCHOR_FLAGSPACE_LEVEL_SPECIFIC) { + payload["ctx"] = (s32)map_getLevel(gsworld_getMap()); + SendToCurrentLevelPlayers(payload); + } else { + payload["ctx"] = (s32)gsworld_getMap(); + SendToCurrentMapPlayers(payload); + } +} + +void Anchor::HandlePacket_ScopedFlag(nlohmann::json& payload) { + if (!IsSaveLoaded() || !roomState.syncItemsAndFlags) { + return; + } + + u8 space = payload.at("space").get(); + s16 index = payload.at("index").get(); + u8 value = payload.at("value").get(); + s32 ctx = payload.at("ctx").get(); + + if (space == ANCHOR_FLAGSPACE_LEVEL_SPECIFIC) { + if ((s32)map_getLevel(gsworld_getMap()) == ctx) { + levelSpecificFlags_setEx(index, value, 0); + } + } else if (space == ANCHOR_FLAGSPACE_MAP_SPECIFIC) { + if ((s32)gsworld_getMap() == ctx) { + mapSpecificFlags_setEx(index, value, 0); + if (value && index >= 0 && index < 32) { + sMapFlagSetRemotely |= (1u << index); + } + chHoneycomb_netRevealFromSwitch(); + } + } +} + +void RegisterScopedFlag_Init() { + REGISTER_LISTENER(OnGameFlagSet, EVENT_PRIORITY_NORMAL, [](IEvent* event) { + auto ev = reinterpret_cast(event); + if (ev->flagSpace == ANCHOR_FLAGSPACE_MAP_SPECIFIC && ev->index >= 0 && ev->index < 32) { + sMapFlagSetRemotely &= ~(1u << ev->index); + } + }); + REGISTER_LISTENER(OnMapLoad, EVENT_PRIORITY_NORMAL, [](IEvent* event) { sMapFlagSetRemotely = 0; }); +} + +static RegisterShipInitFunc initScopedFlag(RegisterScopedFlag_Init, {}); diff --git a/src/port/Network/Anchor/Packets/ScopedState.cpp b/src/port/Network/Anchor/Packets/ScopedState.cpp new file mode 100644 index 000000000..a7f35c3b9 --- /dev/null +++ b/src/port/Network/Anchor/Packets/ScopedState.cpp @@ -0,0 +1,91 @@ +#include "port/Network/Anchor/Anchor.h" +#include +#include +#include +#include + +extern "C" { +#include "functions.h" +void chHoneycomb_netRevealFromSwitch(void); +} + +/** + * REQUEST_SCOPED_STATE / SCOPED_STATE + * + * On map load, a client asks the team for current level/map flag state; same-scope teammates reply. + */ + +void Anchor::SendPacket_RequestScopedState(GameMap map) { + nlohmann::json payload; + payload["type"] = REQUEST_SCOPED_STATE; + payload["targetTeamId"] = CVarGetString(CVAR_REMOTE_ANCHOR("TeamId"), "default"); + payload["level"] = (s32)map_getLevel((enum map_e)map); + payload["map"] = (s32)map; + SendJsonToRemote(payload); +} + +void Anchor::HandlePacket_RequestScopedState(nlohmann::json& payload) { + if (!IsSaveLoaded() || !roomState.syncItemsAndFlags) { + return; + } + + s32 reqLevel = payload.at("level").get(); + s32 reqMap = payload.at("map").get(); + + nlohmann::json response; + response["type"] = SCOPED_STATE; + response["targetClientId"] = payload.at("clientId").get(); + bool any = false; + + if ((s32)map_getLevel(gsworld_getMap()) == reqLevel) { + s32 size; + u8* addr; + levelSpecificFlags_getSizeAndPtr(&size, &addr); + std::vector levelFlags(addr, addr + size); + for (s32 idx = 0; idx < size * 8; idx++) { + if (Anchor_ScopedFlagExcluded(ANCHOR_FLAGSPACE_LEVEL_SPECIFIC, idx)) { + levelFlags[idx >> 3] &= ~(1 << (idx & 7)); + } + } + response["level"] = reqLevel; + response["levelFlags"] = levelFlags; + any = true; + } + if ((s32)gsworld_getMap() == reqMap) { + u32 mapFlags = (u32)mapSpecificFlags_getAll(); + for (s32 idx = 0; idx < 32; idx++) { + if (Anchor_ScopedFlagExcluded(ANCHOR_FLAGSPACE_MAP_SPECIFIC, idx)) { + mapFlags &= ~(1u << idx); + } + } + response["map"] = reqMap; + response["mapFlags"] = mapFlags; + any = true; + } + + if (any) { + SendJsonToRemote(response); + } +} + +void Anchor::HandlePacket_ScopedState(nlohmann::json& payload) { + if (!IsSaveLoaded() || !roomState.syncItemsAndFlags) { + return; + } + + if (payload.contains("levelFlags") && (s32)map_getLevel(gsworld_getMap()) == payload.at("level").get()) { + auto bytes = payload["levelFlags"].get>(); + s32 size; + u8* addr; + levelSpecificFlags_getSizeAndPtr(&size, &addr); + s32 count = std::min(size, (s32)bytes.size()); + for (s32 i = 0; i < count; i++) { + addr[i] |= bytes[i]; + } + } + if (payload.contains("mapFlags") && (s32)gsworld_getMap() == payload.at("map").get()) { + u32 mapFlags = payload["mapFlags"].get(); + mapSpecificFlags_setAll(mapSpecificFlags_getAll() | mapFlags); + chHoneycomb_netRevealFromSwitch(); + } +} diff --git a/src/port/Network/Anchor/Packets/ServerMessage.cpp b/src/port/Network/Anchor/Packets/ServerMessage.cpp index dfa3ece6b..ed1dab04d 100644 --- a/src/port/Network/Anchor/Packets/ServerMessage.cpp +++ b/src/port/Network/Anchor/Packets/ServerMessage.cpp @@ -1,7 +1,6 @@ #include "port/Network/Anchor/Anchor.h" #include #include -//#include "soh/Enhancements/game-interactor/GameInteractor.h" #include "port/UI/Notification.h" /** diff --git a/src/port/Network/Anchor/Packets/SetAbility.cpp b/src/port/Network/Anchor/Packets/SetAbility.cpp new file mode 100644 index 000000000..49778a129 --- /dev/null +++ b/src/port/Network/Anchor/Packets/SetAbility.cpp @@ -0,0 +1,42 @@ +#include "port/Network/Anchor/Anchor.h" +#include +#include + +extern "C" { +#include "functions.h" +} + +/** + * SET_ABILITY + * + * Realtime sync of a learned move. Not queued. + */ + +void Anchor::SendPacket_SetAbility(s16 move, u8 value) { + if (!IsSaveLoaded() || !roomState.syncItemsAndFlags) { + return; + } + + nlohmann::json payload; + payload["type"] = SET_ABILITY; + payload["targetTeamId"] = CVarGetString(CVAR_REMOTE_ANCHOR("TeamId"), "default"); + payload["quiet"] = true; + payload["move"] = move; + payload["value"] = value; + + SendJsonToRemote(payload); +} + +void Anchor::HandlePacket_SetAbility(nlohmann::json& payload) { + if (!IsSaveLoaded() || !roomState.syncItemsAndFlags) { + return; + } + + s16 move = payload.at("move").get(); + u8 value = payload.at("value").get(); + + ability_setLearnedEx(move, value, 0); + if (value) { + ability_setHasUsed((enum ability_e)move); + } +} diff --git a/src/port/Network/Anchor/Packets/SetCheckStatus.cpp b/src/port/Network/Anchor/Packets/SetCheckStatus.cpp index a0a4334fc..99a78729d 100644 --- a/src/port/Network/Anchor/Packets/SetCheckStatus.cpp +++ b/src/port/Network/Anchor/Packets/SetCheckStatus.cpp @@ -1,57 +1,80 @@ #include "port/Network/Anchor/Anchor.h" #include #include -//#include "soh/Enhancements/game-interactor/GameInteractor.h" -//#include "soh/OTRGlobals.h" -static bool isResultOfHandling = false; +#include "port/UI/cvar_prefixes.h" +#include "port/Rando/Rando.h" +#include "port/Rando/CustomObject/CustomObject.h" +#include "port/Rando/StaticData/StaticData.h" + +extern "C" { +#include "functions.h" +void marker_despawn(ActorMarker* marker); +} + +Actor* FindActorByRandoCheckId(RandoCheckId randoCheckId); /** * SET_CHECK_STATUS * - * Fired when a check status is updated or skipped + * Fired when a shuffled rando check is first obtained; teammates mark it obtained and + * despawn their copy if in the same map. */ -void Anchor::SendPacket_SetCheckStatus(/*RandomizerCheck rc*/) { - // if (!IsSaveLoaded() || isResultOfHandling) { - // return; - // } - // - // auto randoContext = Rando::Context::GetRawInstance(); - // - // nlohmann::json payload; - // payload["type"] = SET_CHECK_STATUS; - // payload["targetTeamId"] = CVarGetString(CVAR_REMOTE_ANCHOR("TeamId"), "default"); - // payload["addToQueue"] = true; - // payload["rc"] = rc; - // payload["status"] = randoContext->GetItemLocation(rc)->GetCheckStatus(); - // payload["skipped"] = randoContext->GetItemLocation(rc)->GetIsSkipped(); - // payload["quiet"] = true; - // - // SendJsonToRemote(payload); +void Anchor::SendPacket_SetCheckStatus(s32 rc, s32 map) { + if (!IS_RANDO || !IsSaveLoaded() || !roomState.syncItemsAndFlags) { + return; + } + + nlohmann::json payload; + payload["type"] = SET_CHECK_STATUS; + payload["targetTeamId"] = CVarGetString(CVAR_REMOTE_ANCHOR("TeamId"), "default"); + payload["addToQueue"] = true; + payload["rc"] = rc; + payload["map"] = map; + + SendJsonToRemote(payload); +} + +// Adopt a check a teammate obtained: despawn our copy, mark obtained silently (no item grant, +// notification, or re-broadcast). +void Anchor::AdoptRemoteCheck(s32 rcRaw) { + RandoCheckId rc = (RandoCheckId)rcRaw; + if (rc <= RC_UNKNOWN || rc >= RC_MAX || RANDO_SAVE_CHECKS[rc].obtained) { + return; + } + if (CustomObject::CheckSpawnedIdList(rc)) { + Actor* actor = FindActorByRandoCheckId(rc); + if (actor != NULL && actor->marker != NULL) { + marker_despawn(actor->marker); + } + } + CustomObject::CheckObtainedEX(rc, true); } void Anchor::HandlePacket_SetCheckStatus(nlohmann::json& payload) { - // if (!IsSaveLoaded() || !roomState.syncItemsAndFlags) { - // return; - // } - // - // auto randoContext = Rando::Context::GetRawInstance(); - // - // RandomizerCheck rc = payload.at("rc").get(); - // RandomizerCheckStatus status = payload.at("status").get(); - // bool skipped = payload.at("skipped").get(); - // - // isResultOfHandling = true; - // - // if (randoContext->GetItemLocation(rc)->GetCheckStatus() != status) { - // randoContext->GetItemLocation(rc)->SetCheckStatus(status); - // } - // if (randoContext->GetItemLocation(rc)->GetIsSkipped() != skipped) { - // randoContext->GetItemLocation(rc)->SetIsSkipped(skipped); - // } - // - // CheckTracker::RecalculateAllAreaTotals(); - // CheckTracker::RecalculateAvailableChecks(); - // isResultOfHandling = false; + if (!IS_RANDO || !IsSaveLoaded() || !roomState.syncItemsAndFlags) { + return; + } + + RandoCheckId rc = (RandoCheckId)payload.at("rc").get(); + s32 map = payload.at("map").get(); + + if (rc <= RC_UNKNOWN || rc >= RC_MAX) { + return; + } + if (RANDO_SAVE_CHECKS[rc].obtained) { + return; + } + + // BGS timed-switch checks cleanup + if ((s32)gsworld_getMap() == map && (rc == RC_BGS_JIGGY_ELEVATED_WALKWAY || rc == RC_BGS_JIGGY_MAZE)) { + func_802D6924(); + } + + AdoptRemoteCheck(rc); + + if (CVarGetInteger(CVAR_RANDOMIZER_SETTING("RandoNotifications"), 0) && ShouldShowNotifications()) { + Rando::StaticData::SendRemoteCheckNotification(rc, GetClientName(payload.value("clientId", 0u))); + } } diff --git a/src/port/Network/Anchor/Packets/SetFlag.cpp b/src/port/Network/Anchor/Packets/SetFlag.cpp index 88e754f0f..37538f00e 100644 --- a/src/port/Network/Anchor/Packets/SetFlag.cpp +++ b/src/port/Network/Anchor/Packets/SetFlag.cpp @@ -1,22 +1,38 @@ #include "port/Network/Anchor/Anchor.h" #include #include -//#include "soh/Enhancements/game-interactor/GameInteractor.h" -//#include "soh/OTRGlobals.h" extern "C" { #include "functions.h" - -// extern PlayState* gPlayState; } +#include "port/Patches/Patches.h" +#include "port/Rando/Rando.h" +#include "port/UI/Notification.h" + /** * SET_FLAG * - * Fired when a flag is set in the save context + * Fired when a flag bit is set (raised) in either flag space. */ -void Anchor::SendPacket_SetFlag(s16 sceneNum, s16 flagType, s16 flag) { +static const char* LevelOpenSeenFlagName(s16 flag) { + switch (flag) { + case 0x28: return "Mumbo's Mountain"; + case 0x29: return "Treasure Trove Cove"; + case 0x2A: return "Clanker's Cavern"; + case 0x2B: return "Bubblegloop Swamp"; + case 0x2C: return "Freezeezy Peak"; + case 0x2D: return "Gobi's Valley"; + case 0x2E: return "Mad Monster Mansion"; + case 0x2F: return "Rusty Bucket Bay"; + case 0x30: return "Click Clock Wood"; + case FILEPROG_E2_DOOR_OF_GRUNTY_OPEN: return "the door to Gruntilda"; + default: return nullptr; + } +} + +void Anchor::SendPacket_SetFlag(u8 flagSpace, s16 flag) { if (!IsSaveLoaded() || !roomState.syncItemsAndFlags) { return; } @@ -25,8 +41,7 @@ void Anchor::SendPacket_SetFlag(s16 sceneNum, s16 flagType, s16 flag) { payload["type"] = SET_FLAG; payload["targetTeamId"] = CVarGetString(CVAR_REMOTE_ANCHOR("TeamId"), "default"); payload["addToQueue"] = true; - payload["sceneNum"] = sceneNum; - payload["flagType"] = flagType; + payload["flagSpace"] = flagSpace; payload["flag"] = flag; SendJsonToRemote(payload); @@ -37,37 +52,32 @@ void Anchor::HandlePacket_SetFlag(nlohmann::json& payload) { return; } - s16 sceneNum = payload.at("sceneNum").get(); - s16 flagType = payload.at("flagType").get(); + u8 flagSpace = payload.at("flagSpace").get(); s16 flag = payload.at("flag").get(); - // if (sceneNum == SCENE_ID_MAX) { - // auto effect = new GameInteractionEffect::SetFlag(); - // effect->parameters[0] = flagType; - // effect->parameters[1] = flag; - // effect->Apply(); - - // // Special case: If King Zora moved, and the player has Ruto's Letter, convert it to an empty bottle - // if (flagType == FLAG_EVENT_CHECK_INF && flag == EVENTCHKINF_KING_ZORA_MOVED && - // Inventory_HasSpecificBottle(ITEM_LETTER_RUTO)) { - // Inventory_ReplaceItem(gPlayState, ITEM_LETTER_RUTO, ITEM_BOTTLE); - // } - //} else { - // // Special case: Ignore water temple water level flags, stored at 0x1C, 0x1D, 0x1E. - // if (sceneNum == SCENE_WATER_TEMPLE && flagType == FLAG_SCENE_SWITCH && - // (flag == 0x1C || flag == 0x1D || flag == 0x1E)) { - // return; - // } + SPDLOG_INFO("[Anchor][flagdiag] received SetFlag space={} flag={:#x}", flagSpace, flag); - // // Special case: Ignore forest temple elevator flag, stored at 0x1B. - // if (sceneNum == SCENE_FOREST_TEMPLE && flagType == FLAG_SCENE_SWITCH && flag == 0x1B) { - // return; - // } - - // auto effect = new GameInteractionEffect::SetSceneFlag(); - // effect->parameters[0] = sceneNum; - // effect->parameters[1] = flagType; - // effect->parameters[2] = flag; - // effect->Apply(); - //} + if (flagSpace == ANCHOR_FLAGSPACE_RANDO_INF) { + // Non-derived rando flag; set directly. + if (IS_RANDO && flag > RANDO_INF_UNKNOWN && flag < RANDO_INF_MAX) { + RANDO_SAVE_FLAGS[flag].flagState = 1; + } + } else if (flagSpace == ANCHOR_FLAGSPACE_VOLATILE) { + volatileFlag_setEx((enum volatile_flags_e)flag, 1, 0); + } else { + bool wasSet = fileProgressFlag_get((enum file_progress_e)flag) != 0; + fileProgressFlag_setEx((enum file_progress_e)flag, 1, 0); + port_notedoor_remoteOpen(flag); + port_breakable_remoteBreak(flag); + port_leveldoor_remoteOpen(flag); + // Vanilla only; rando reports world access via SET_CHECK_STATUS instead. + if (!wasSet && !IS_RANDO && ShouldShowNotifications()) { + if (const char* opened = LevelOpenSeenFlagName(flag)) { + Notification::Emit({ + .prefix = GetClientName(payload.value("clientId", 0u)), + .message = std::string("opened ") + opened, + }); + } + } + } } diff --git a/src/port/Network/Anchor/Packets/SetItemCount.cpp b/src/port/Network/Anchor/Packets/SetItemCount.cpp new file mode 100644 index 000000000..6d1d41d76 --- /dev/null +++ b/src/port/Network/Anchor/Packets/SetItemCount.cpp @@ -0,0 +1,47 @@ +#include "port/Network/Anchor/Anchor.h" +#include +#include + +extern "C" { +#include "functions.h" +s32 item_adjustByDiff(enum item_e item, s32 diff, s32 no_hud, s32 triggerEvent); +} + +/** + * ITEM_COUNT + * + * Realtime sync of a spendable item count (absolute value). Not queued. + */ + +void Anchor::SendPacket_SetItemCount(s16 item, s32 count) { + if (!IsSaveLoaded() || !roomState.syncItemsAndFlags) { + return; + } + + nlohmann::json payload; + payload["type"] = ITEM_COUNT; + payload["targetTeamId"] = CVarGetString(CVAR_REMOTE_ANCHOR("TeamId"), "default"); + payload["quiet"] = true; + payload["item"] = item; + payload["count"] = count; + + SendJsonToRemote(payload); +} + +void Anchor::HandlePacket_SetItemCount(nlohmann::json& payload) { + if (!IsSaveLoaded() || !roomState.syncItemsAndFlags) { + return; + } + + s16 item = payload.at("item").get(); + s32 count = payload.at("count").get(); + + // Jiggy-total increase is a teammate's collect: apply silently (paired COLLECT_ITEM pops the + // HUD counter). Decreases (pedestal spends) keep the vanilla total pop. + if (item == ITEM_26_JIGGY_TOTAL && count > item_getCount(ITEM_26_JIGGY_TOTAL)) { + item_adjustByDiff((enum item_e)item, count - item_getCount(ITEM_26_JIGGY_TOTAL), 1, 0); + return; + } + + item_setEx(item, count, 0); +} diff --git a/src/port/Network/Anchor/Packets/SpawnJiggy.cpp b/src/port/Network/Anchor/Packets/SpawnJiggy.cpp new file mode 100644 index 000000000..96097c93a --- /dev/null +++ b/src/port/Network/Anchor/Packets/SpawnJiggy.cpp @@ -0,0 +1,173 @@ +#include "port/Network/Anchor/Anchor.h" +#include +#include + +#include "port/ShipInit.hpp" +#include "port/Enhancements/Events/PortEnhancements.h" +#include "port/Enhancements/Events/Hooks/Events.h" + +#include +#include + +extern "C" { +#include "functions.h" +} + +/** + * JIGGY_SPAWN + * + * Sync of dynamically spawned jiggies (witch-switch puzzle, minigame reward, jinjo fifth, etc). + * Team-wide record (map -> jiggyId -> position) re-applied every map visit. + */ + +struct SpawnedJiggy { + int16_t jiggyId; + float x; + float y; + float z; + bool inFlight = false; +}; +std::map> sSpawnedJiggies; + +SpawnedJiggy& recordJiggySpawn(int32_t map, int16_t jiggyId, float x, float y, float z) { + auto& list = sSpawnedJiggies[map]; + for (auto& pj : list) { + if (pj.jiggyId == jiggyId) { + pj.x = x; + pj.y = y; + pj.z = z; + return pj; + } + } + list.push_back({ jiggyId, x, y, z }); + return list.back(); +} + +void trySpawnRecordedJiggy(SpawnedJiggy& pj) { + if (jiggyscore_isCollected((enum jiggy_e)pj.jiggyId)) { + return; + } + if (jiggylist_hasSpawnedObject((enum jiggy_e)pj.jiggyId)) { + pj.inFlight = false; + return; + } + if (pj.inFlight) { + return; + } + f32 pos[3] = { pj.x, pj.y, pj.z }; + codeABC00_spawnJiggyAtLocationEx((enum jiggy_e)pj.jiggyId, pos, 0); // silent, no re-broadcast + pj.inFlight = true; +} + +void Anchor::SendPacket_SpawnJiggy(s16 jiggyId, f32 x, f32 y, f32 z) { + if (!IsSaveLoaded() || !roomState.syncItemsAndFlags) { + return; + } + + s32 map = (s32)gsworld_getMap(); + recordJiggySpawn(map, jiggyId, x, y, z); + + nlohmann::json payload; + payload["type"] = JIGGY_SPAWN; + payload["targetTeamId"] = CVarGetString(CVAR_REMOTE_ANCHOR("TeamId"), "default"); + payload["addToQueue"] = true; + payload["jiggyId"] = jiggyId; + payload["x"] = x; + payload["y"] = y; + payload["z"] = z; + payload["map"] = map; + + SendJsonToRemote(payload); +} + +void Anchor::HandlePacket_SpawnJiggy(nlohmann::json& payload) { + if (!IsSaveLoaded() || !roomState.syncItemsAndFlags) { + return; + } + + s16 jiggyId = payload.at("jiggyId").get(); + s32 map = payload.at("map").get(); + f32 x = payload.at("x").get(); + f32 y = payload.at("y").get(); + f32 z = payload.at("z").get(); + + SpawnedJiggy& pj = recordJiggySpawn(map, jiggyId, x, y, z); + + if ((s32)gsworld_getMap() == map) { + trySpawnRecordedJiggy(pj); + } +} + +void Anchor::FlushPendingJiggySpawns() { + auto it = sSpawnedJiggies.find((s32)gsworld_getMap()); + if (it == sSpawnedJiggies.end()) { + return; + } + auto& list = it->second; + for (size_t i = 0; i < list.size();) { + auto& pj = list[i]; + if (jiggyscore_isCollected((enum jiggy_e)pj.jiggyId)) { + list.erase(list.begin() + i); + continue; + } + trySpawnRecordedJiggy(pj); + i++; + } +} + +// Team-state snapshot/restore (UpdateTeamState.cpp). Flat [map, jiggyId, x, y, z] tuples. +std::vector port_jiggySpawn_snapshot() { + std::vector flat; + for (const auto& [map, list] : sSpawnedJiggies) { + for (const auto& pj : list) { + flat.push_back(map); + flat.push_back(pj.jiggyId); + flat.push_back((int32_t)pj.x); + flat.push_back((int32_t)pj.y); + flat.push_back((int32_t)pj.z); + } + } + return flat; +} + +void port_jiggySpawn_restore(const std::vector& flat) { + sSpawnedJiggies.clear(); + for (size_t i = 0; i + 5 <= flat.size(); i += 5) { + sSpawnedJiggies[flat[i]].push_back( + { (int16_t)flat[i + 1], (float)flat[i + 2], (float)flat[i + 3], (float)flat[i + 4] }); + } +} + +extern "C" void port_jiggySpawn_remove(int32_t jiggyId) { + for (auto& [map, list] : sSpawnedJiggies) { + std::erase_if(list, [jiggyId](const SpawnedJiggy& pj) { return pj.jiggyId == jiggyId; }); + } +} + +extern "C" int32_t port_jiggySpawn_isRecorded(int32_t jiggyId) { + if (jiggyscore_isCollected((enum jiggy_e)jiggyId)) { + return 0; + } + for (const auto& [map, list] : sSpawnedJiggies) { + for (const auto& pj : list) { + if (pj.jiggyId == jiggyId) { + return 1; + } + } + } + return 0; +} + +void RegisterSpawnJiggy_Init() { + REGISTER_LISTENER(OnSaveLoad, EVENT_PRIORITY_NORMAL, [](IEvent* event) { sSpawnedJiggies.clear(); }); + + REGISTER_LISTENER(OnMapLoad, EVENT_PRIORITY_NORMAL, [](IEvent* event) { + for (auto& [map, list] : sSpawnedJiggies) { + for (auto& pj : list) { + pj.inFlight = false; + } + } + }); +} + +static RegisterShipInitFunc initSpawnJiggy(RegisterSpawnJiggy_Init, {}); diff --git a/src/port/Network/Anchor/Packets/TeleportTo.cpp b/src/port/Network/Anchor/Packets/TeleportTo.cpp index 31140ff70..ad7fb4fab 100644 --- a/src/port/Network/Anchor/Packets/TeleportTo.cpp +++ b/src/port/Network/Anchor/Packets/TeleportTo.cpp @@ -1,18 +1,21 @@ #include "port/Network/Anchor/Anchor.h" #include #include -//#include "soh/Enhancements/game-interactor/GameInteractor.h" -#include "port/Network/Anchor/JsonConversions.hpp" extern "C" { -#include "macros.h" -// extern PlayState* gPlayState; +#include "functions.h" +void func_8031D04C(enum map_e arg0, s32 exit_id); +// Instant, sweep-free reposition within the current map (sets current + previous position). +void func_8028F85C(f32 arg0[3]); } +// Exit id the game reserves for "spawn at an explicit position" (see func_8028E4B0). +#define EXIT_WARP_DESTINATION 0x63 + /** * TELEPORT_TO * - * See REQUEST_TELEPORT for more information, this is the second part of the process. + * See REQUEST_TELEPORT; carries the sender's live map/position/yaw. */ void Anchor::SendPacket_TeleportTo(uint32_t clientId) { @@ -20,16 +23,18 @@ void Anchor::SendPacket_TeleportTo(uint32_t clientId) { return; } - /*Player* player = GET_PLAYER(gPlayState); + f32 pos[3]; + player_getPosition(pos); nlohmann::json payload; payload["type"] = TELEPORT_TO; payload["targetClientId"] = clientId; - payload["entranceIndex"] = gSaveContext.entranceIndex; - payload["roomIndex"] = gPlayState->roomCtx.curRoom.num; - payload["posRot"] = player->actor.world; + payload["map"] = gsworld_getMap(); + payload["exit"] = gsworld_getExit(); + payload["pos"] = pos; + payload["yaw"] = player_getYaw(); - SendJsonToRemote(payload);*/ + SendJsonToRemote(payload); } void Anchor::HandlePacket_TeleportTo(nlohmann::json& payload) { @@ -37,23 +42,18 @@ void Anchor::HandlePacket_TeleportTo(nlohmann::json& payload) { return; } - // s32 entranceIndex = payload.at("entranceIndex").get(); - // s8 roomIndex = payload.at("roomIndex").get(); - // PosRot posRot = payload.at("posRot").get(); - - // gPlayState->nextEntranceIndex = entranceIndex; - // gPlayState->transitionTrigger = TRANS_TRIGGER_START; - // gPlayState->transitionType = TRANS_TYPE_INSTANT; - // gSaveContext.respawn[RESPAWN_MODE_DOWN].entranceIndex = entranceIndex; - // gSaveContext.respawn[RESPAWN_MODE_DOWN].roomIndex = roomIndex; - // gSaveContext.respawn[RESPAWN_MODE_DOWN].pos = posRot.pos; - // gSaveContext.respawn[RESPAWN_MODE_DOWN].yaw = posRot.rot.y; - // gSaveContext.respawn[RESPAWN_MODE_DOWN].playerParams = 0xDFF; - // gSaveContext.nextTransitionType = TRANS_TYPE_FADE_BLACK_FAST; - // gSaveContext.respawnFlag = 1; - // static HOOK_ID hookId = 0; - // hookId = REGISTER_VB_SHOULD(VB_INFLICT_VOID_DAMAGE, { - // *should = false; - // GameInteractor::Instance->UnregisterGameHookForID(hookId); - // }); + GameMap map = payload.at("map").get(); + std::vector pos = payload.at("pos").get>(); + f32 yaw = payload.at("yaw").get(); + + if (map == (GameMap)gsworld_getMap()) { + yaw_set(yaw); + yaw_setIdeal(yaw); + yaw_applyIdeal(); + func_8028F85C(pos.data()); + return; + } + + player_setWarpDestination(pos.data(), yaw, payload.value("exit", 0)); + func_8031D04C(map, EXIT_WARP_DESTINATION); } diff --git a/src/port/Network/Anchor/Packets/UnsetFlag.cpp b/src/port/Network/Anchor/Packets/UnsetFlag.cpp index e1b88908c..01666819d 100644 --- a/src/port/Network/Anchor/Packets/UnsetFlag.cpp +++ b/src/port/Network/Anchor/Packets/UnsetFlag.cpp @@ -1,22 +1,18 @@ #include "port/Network/Anchor/Anchor.h" #include #include -//#include "soh/Enhancements/game-interactor/GameInteractor.h" -//#include "soh/OTRGlobals.h" extern "C" { #include "functions.h" -//#include "soh/Enhancements/randomizer/ShuffleTradeItems.h" -// extern PlayState* gPlayState; } /** * UNSET_FLAG * - * Fired when a flag is unset in the save context + * Fired when a flag bit is cleared (lowered) in either flag space. */ -void Anchor::SendPacket_UnsetFlag(s16 sceneNum, s16 flagType, s16 flag) { +void Anchor::SendPacket_UnsetFlag(u8 flagSpace, s16 flag) { if (!IsSaveLoaded() || !roomState.syncItemsAndFlags) { return; } @@ -25,8 +21,7 @@ void Anchor::SendPacket_UnsetFlag(s16 sceneNum, s16 flagType, s16 flag) { payload["type"] = UNSET_FLAG; payload["targetTeamId"] = CVarGetString(CVAR_REMOTE_ANCHOR("TeamId"), "default"); payload["addToQueue"] = true; - payload["sceneNum"] = sceneNum; - payload["flagType"] = flagType; + payload["flagSpace"] = flagSpace; payload["flag"] = flag; SendJsonToRemote(payload); @@ -37,73 +32,12 @@ void Anchor::HandlePacket_UnsetFlag(nlohmann::json& payload) { return; } - s16 sceneNum = payload.at("sceneNum").get(); - s16 flagType = payload.at("flagType").get(); + u8 flagSpace = payload.at("flagSpace").get(); s16 flag = payload.at("flag").get(); - // if (sceneNum == SCENE_ID_MAX) { - // auto effect = new GameInteractionEffect::UnsetFlag(); - // effect->parameters[0] = flagType; - // effect->parameters[1] = flag; - // effect->Apply(); - - // // Special case: If an adult trade item flag is unset, replace the item if the player has it equipped - // if (flagType == FLAG_RANDOMIZER_INF && - // (flag >= RAND_INF_ADULT_TRADES_HAS_POCKET_EGG && flag <= RAND_INF_ADULT_TRADES_HAS_CLAIM_CHECK)) { - // u16 itemToReplace = ITEM_POCKET_EGG; - // switch (flag) { - // case RAND_INF_ADULT_TRADES_HAS_POCKET_EGG: - // itemToReplace = ITEM_POCKET_EGG; - // break; - // case RAND_INF_ADULT_TRADES_HAS_POCKET_CUCCO: - // itemToReplace = ITEM_POCKET_CUCCO; - // break; - // case RAND_INF_ADULT_TRADES_HAS_COJIRO: - // itemToReplace = ITEM_COJIRO; - // break; - // case RAND_INF_ADULT_TRADES_HAS_ODD_MUSHROOM: - // itemToReplace = ITEM_ODD_MUSHROOM; - // break; - // case RAND_INF_ADULT_TRADES_HAS_ODD_POTION: - // itemToReplace = ITEM_ODD_POTION; - // break; - // case RAND_INF_ADULT_TRADES_HAS_SAW: - // itemToReplace = ITEM_SAW; - // break; - // case RAND_INF_ADULT_TRADES_HAS_SWORD_BROKEN: - // itemToReplace = ITEM_SWORD_BROKEN; - // break; - // case RAND_INF_ADULT_TRADES_HAS_PRESCRIPTION: - // itemToReplace = ITEM_PRESCRIPTION; - // break; - // case RAND_INF_ADULT_TRADES_HAS_FROG: - // itemToReplace = ITEM_FROG; - // break; - // case RAND_INF_ADULT_TRADES_HAS_EYEDROPS: - // itemToReplace = ITEM_EYEDROPS; - // break; - // case RAND_INF_ADULT_TRADES_HAS_CLAIM_CHECK: - // itemToReplace = ITEM_CLAIM_CHECK; - // break; - // } - // Inventory_ReplaceItem(gPlayState, itemToReplace, Randomizer_GetNextAdultTradeItem()); - // } - //} else { - // // Special case: Ignore water temple water level flags, stored at 0x1C, 0x1D, 0x1E. - // if (sceneNum == SCENE_WATER_TEMPLE && flagType == FLAG_SCENE_SWITCH && - // (flag == 0x1C || flag == 0x1D || flag == 0x1E)) { - // return; - // } - - // // Special case: Ignore forest temple elevator flag, stored at 0x1B. - // if (sceneNum == SCENE_FOREST_TEMPLE && flagType == FLAG_SCENE_SWITCH && flag == 0x1B) { - // return; - // } - - // auto effect = new GameInteractionEffect::UnsetSceneFlag(); - // effect->parameters[0] = sceneNum; - // effect->parameters[1] = flagType; - // effect->parameters[2] = flag; - // effect->Apply(); - //} + if (flagSpace == ANCHOR_FLAGSPACE_VOLATILE) { + volatileFlag_setEx((enum volatile_flags_e)flag, 0, 0); + } else { + fileProgressFlag_setEx((enum file_progress_e)flag, 0, 0); + } } diff --git a/src/port/Network/Anchor/Packets/UpdateClientState.cpp b/src/port/Network/Anchor/Packets/UpdateClientState.cpp index 9482d448f..a315a54dc 100644 --- a/src/port/Network/Anchor/Packets/UpdateClientState.cpp +++ b/src/port/Network/Anchor/Packets/UpdateClientState.cpp @@ -3,11 +3,11 @@ #include "port/Network/Anchor/JsonConversions.hpp" #include #include -//#include "soh/OTRGlobals.h" + +#include "port/Rando/Rando.h" extern "C" { #include "variables.h" -// extern PlayState* gPlayState; } /** @@ -29,7 +29,7 @@ nlohmann::json Anchor::PrepClientState() { payload["online"] = true; if (IsSaveLoaded()) { - payload["seed"] = /*IS_RANDO ? Rando::Context::GetRawInstance()->GetSeed() : */ 0; + payload["seed"] = (uint32_t)(IS_RANDO ? RANDO_SEED : 0); payload["isSaveLoaded"] = true; payload["isGameComplete"] = false; payload["map"] = gsworld_getMap(); @@ -60,7 +60,6 @@ void Anchor::HandlePacket_UpdateClientState(nlohmann::json& payload) { AnchorClient client = payload["state"].get(); clients[clientId].clientId = clientId; clients[clientId].name = client.name; - // clients[clientId].color = client.color; clients[clientId].clientVersion = client.clientVersion; clients[clientId].teamId = client.teamId; clients[clientId].online = client.online; @@ -71,6 +70,7 @@ void Anchor::HandlePacket_UpdateClientState(nlohmann::json& payload) { clients[clientId].exit = client.exit; EvaluateDummyForClient(clientId); Authority_OnClientStateChanged(clientId, client.online, client.map); + SweepUnoccupiedLevelState((GameMap)gsworld_getMap()); if (client.online) { // Covers clients (re)connecting while already in an activity's map: rebroadcast // any claim of ours so they don't briefly act as their own authority. diff --git a/src/port/Network/Anchor/Packets/UpdateRoomState.cpp b/src/port/Network/Anchor/Packets/UpdateRoomState.cpp index de1263a67..3b0395f5c 100644 --- a/src/port/Network/Anchor/Packets/UpdateRoomState.cpp +++ b/src/port/Network/Anchor/Packets/UpdateRoomState.cpp @@ -4,13 +4,12 @@ #include #include "port/Romhack/RomhackConfig.h" #include "port/Romhack/RomhackCompat.h" +#include "port/Rando/Rando.h" #include "port/UI/LighthouseGui.hpp" #include "port/UI/LighthouseModals.h" -//#include "soh/OTRGlobals.h" extern "C" { #include "variables.h" -// extern PlayState* gPlayState; } /** @@ -20,22 +19,29 @@ extern "C" { nlohmann::json Anchor::PrepRoomState() { nlohmann::json payload; payload["ownerClientId"] = ownClientId; - bool isGlobalRoom = (std::string("soh-global") == CVarGetString(CVAR_REMOTE_ANCHOR("RoomId"), "")); - - // if (isGlobalRoom) { - // // Global room uses hardcoded settings - // payload["pvpMode"] = 0; - // payload["showLocationsMode"] = 0; - // payload["teleportMode"] = 0; - // payload["syncItemsAndFlags"] = 0; - // } else { + + if (IsGlobalRoom()) { + payload["pvpMode"] = 0; + payload["showLocationsMode"] = 0; + payload["teleportMode"] = 0; + payload["syncItemsAndFlags"] = 0; + payload["shareConsumables"] = 0; + payload["isRomHack"] = false; + payload["romhackName"] = ""; + payload["isRando"] = false; + payload["seed"] = 0; + return payload; + } + payload["pvpMode"] = CVarGetInteger(CVAR_REMOTE_ANCHOR("RoomSettings.PvpMode"), 1); payload["showLocationsMode"] = CVarGetInteger(CVAR_REMOTE_ANCHOR("RoomSettings.ShowLocationsMode"), 1); payload["teleportMode"] = CVarGetInteger(CVAR_REMOTE_ANCHOR("RoomSettings.TeleportMode"), 1); payload["syncItemsAndFlags"] = CVarGetInteger(CVAR_REMOTE_ANCHOR("RoomSettings.SyncItemsAndFlags"), 1); + payload["shareConsumables"] = CVarGetInteger(CVAR_REMOTE_ANCHOR("RoomSettings.ShareConsumables"), 0); payload["isRomHack"] = port_isRomhack(); payload["romhackName"] = Lighthouse::CurrentRomhackLabel(); - //} + payload["isRando"] = (bool)IS_RANDO; + payload["seed"] = (int32_t)(IS_RANDO ? RANDO_SEED : 0); return payload; } @@ -52,17 +58,35 @@ void Anchor::HandlePacket_UpdateRoomState(nlohmann::json& payload) { if (!payload.contains("state")) { return; } + + if (IsGlobalRoom()) { + roomState.ownerClientId = payload["state"].value("ownerClientId", (uint32_t)0); + roomState.pvpMode = 0; + roomState.showLocationsMode = 0; + roomState.teleportMode = 0; + roomState.syncItemsAndFlags = 0; + roomState.shareConsumables = 0; + roomState.isRomhack = false; + roomState.romhackName.clear(); + return; + } + roomState.isRomhack = payload["state"]["isRomHack"].get(); roomState.romhackName = payload["state"]["romhackName"].get(); const std::string localLabel = Lighthouse::CurrentRomhackLabel(); if (roomState.romhackName != localLabel) { - Disable(); - std::string msg = "There's a romhack mismatch between your client and the server:\n\n"; - msg += Lighthouse::DescribeRomhackMismatch(port_isRomhack(), localLabel, roomState.isRomhack, - roomState.romhackName); - msg += "\n\nAnchor has been disabled. Please enable or disable the appropriate\n" - "mod(s) in the Mod Menu and reconnect, or enter a new room name."; - LighthouseGui::RegisterPopup("Incompatible Romhack State", msg); + if (roomState.romhackName != lastWarnedRomhackLabel) { + lastWarnedRomhackLabel = roomState.romhackName; + std::string msg = "There's a romhack mismatch between your client and the server:\n\n"; + msg += Lighthouse::DescribeRomhackMismatch(port_isRomhack(), localLabel, roomState.isRomhack, + roomState.romhackName); + msg += "\n\nYou can still play together, but items, flags, and custom content\n" + "may not sync correctly. To avoid desyncs, enable or disable the\n" + "appropriate mod(s) in the Mod Menu so both sides match, then reconnect."; + LighthouseGui::RegisterPopup("Romhack Mismatch Warning", msg); + } + } else { + lastWarnedRomhackLabel.clear(); } roomState.ownerClientId = payload["state"]["ownerClientId"].get(); @@ -70,4 +94,49 @@ void Anchor::HandlePacket_UpdateRoomState(nlohmann::json& payload) { roomState.showLocationsMode = payload["state"]["showLocationsMode"].get(); roomState.teleportMode = payload["state"]["teleportMode"].get(); roomState.syncItemsAndFlags = payload["state"]["syncItemsAndFlags"].get(); + roomState.shareConsumables = payload["state"].value("shareConsumables", (u8)0); + roomState.isRando = payload["state"].value("isRando", false); + roomState.seed = payload["state"].value("seed", (int32_t)0); + + CheckRandoRoomCompatibility(); +} + +void Anchor::CheckRandoRoomCompatibility() { + if (IsGlobalRoom() || !isConnected || !IsSaveLoaded()) { + return; + } + + const bool localRando = IS_RANDO; + const int32_t localSeed = localRando ? (int32_t)RANDO_SEED : 0; + + std::string msg; + if (roomState.isRando && !localRando) { + msg = "This is a randomizer room, but the save you loaded is not a randomizer file.\n\n" + "Items, flags, and checks will not line up — you'll receive progress you can't use\n" + "and may corrupt the shared session. Load the matching randomizer file, or\n" + "disconnect before continuing."; + } else if (!roomState.isRando && localRando) { + msg = "You loaded a randomizer file, but this room is running a vanilla game.\n\n" + "Shuffled checks won't match what teammates send, so progress will desync.\n" + "Reconnect to a randomizer room, or load a vanilla file to match this one."; + } else if (roomState.isRando && localRando && roomState.seed != localSeed) { + msg = "Seed mismatch: your randomizer seed differs from the room's.\n\n" + "Checks are shuffled differently per seed, so syncing will scatter items to the\n" + "wrong locations. Everyone on a team must generate/load from the same seed.\n"; + msg += "\n Your seed: " + std::to_string(localSeed); + msg += "\n Room seed: " + std::to_string(roomState.seed); + } + + if (msg.empty()) { + lastWarnedRandoState.clear(); + return; + } + + std::string sig = std::to_string(roomState.isRando) + ":" + std::to_string(roomState.seed) + "|" + + std::to_string(localRando) + ":" + std::to_string(localSeed); + if (sig == lastWarnedRandoState) { + return; + } + lastWarnedRandoState = sig; + LighthouseGui::RegisterPopup("Randomizer Mismatch Warning", msg); } diff --git a/src/port/Network/Anchor/Packets/UpdateTeamState.cpp b/src/port/Network/Anchor/Packets/UpdateTeamState.cpp index a51b0046d..ba68b9281 100644 --- a/src/port/Network/Anchor/Packets/UpdateTeamState.cpp +++ b/src/port/Network/Anchor/Packets/UpdateTeamState.cpp @@ -2,110 +2,99 @@ #include "port/Network/Anchor/JsonConversions.hpp" #include #include -//#include "soh/OTRGlobals.h" #include "port/UI/Notification.h" +#include "port/Enhancements/Retention/Retention.h" +#include "port/Rando/Rando.h" +#include +#include extern "C" { #include "variables.h" -// extern PlayState* gPlayState; +#include "functions.h" } +// In-memory session sets that aren't part of the save but still ride team state. Flat int +// tuples; defined in the respective port modules. +extern std::vector port_breakable_snapshotBroken(); +extern void port_breakable_restoreBroken(const std::vector& flat); +extern std::vector port_carriedSync_snapshotCollected(); +extern void port_carriedSync_restoreCollected(const std::vector& flat); +extern std::vector port_eggToll_snapshot(); +extern void port_eggToll_restore(const std::vector& flat); +extern std::vector port_puzzleStep_snapshot(); +extern void port_puzzleStep_restore(const std::vector& flat); +extern std::vector port_puzzleCount_snapshot(); +extern void port_puzzleCount_restore(const std::vector& flat); +extern std::vector port_puzzlePos_snapshot(); +extern void port_puzzlePos_restore(const std::vector& flat); +extern std::vector port_jiggySpawn_snapshot(); +extern void port_jiggySpawn_restore(const std::vector& flat); +extern std::vector port_hutSmash_snapshot(); +extern void port_hutSmash_restore(const std::vector& flat); + /** * UPDATE_TEAM_STATE * - * Pushes the current save state to the server for other teammates to use. - * - * Fires when the server passes on a REQUEST_TEAM_STATE packet, or when this client saves the game - * - * When sending this packet we will assume that the team queue has been emptied for this client, so the queue - * stored in the server will be cleared. - * - * When receiving this packet, if there is items in the team queue, we will play them back in order. + * Pushes our full flag state to teammates on REQUEST_TEAM_STATE or on save. Sending clears + * the team queue (assumed drained); receiving replays any queued packets after applying state. */ +// Snapshot a decomp byte-array score/flag section into a JSON byte array. +static std::vector ScoreBytes(void (*getSizeAndPtr)(s32*, u8**)) { + s32 size; + u8* addr; + getSizeAndPtr(&size, &addr); + return std::vector(addr, addr + size); +} + void Anchor::SendPacket_UpdateTeamState() { if (!IsSaveLoaded() || !roomState.syncItemsAndFlags) { return; } - // json payload; - // payload["type"] = UPDATE_TEAM_STATE; - // payload["targetTeamId"] = CVarGetString(CVAR_REMOTE_ANCHOR("TeamId"), "default"); - - //// Assume the team queue has been emptied, so clear it - // payload["queue"] = json::array(); - - // payload["state"] = gSaveContext; - //// manually update current scene flags - // payload["state"]["sceneFlags"][gPlayState->sceneNum * 4] = gPlayState->actorCtx.flags.chest; - // payload["state"]["sceneFlags"][gPlayState->sceneNum * 4 + 1] = gPlayState->actorCtx.flags.swch; - // payload["state"]["sceneFlags"][gPlayState->sceneNum * 4 + 2] = gPlayState->actorCtx.flags.clear; - // payload["state"]["sceneFlags"][gPlayState->sceneNum * 4 + 3] = gPlayState->actorCtx.flags.collect; - - //// The commented out code below is an attempt at sending the entire randomizer seed over, in hopes that a player - //// doesn't have to generate the seed themselves Currently it doesn't work :) - // if (IS_RANDO) { - // auto randoContext = Rando::Context::GetRawInstance(); - - // payload["state"]["rando"] = json::object(); - // payload["state"]["rando"]["itemLocations"] = json::array(); - // for (int i = 0; i < RC_MAX; i++) { - // payload["state"]["rando"]["itemLocations"][i] = json::array(); - // // payload["state"]["rando"]["itemLocations"][i]["rgID"] = - // // randoContext->GetItemLocation(i)->GetPlacedRandomizerGet(); - // payload["state"]["rando"]["itemLocations"][i][0] = randoContext->GetItemLocation(i)->GetCheckStatus(); - // payload["state"]["rando"]["itemLocations"][i][1] = (u8)randoContext->GetItemLocation(i)->GetIsSkipped(); - - // if (randoContext->GetItemLocation(i)->GetPlacedRandomizerGet() == RG_ICE_TRAP) { - // payload["state"]["rando"]["itemLocations"][i]["fakeRgID"] = - // randoContext->GetItemOverride(i).LooksLike(); - // payload["state"]["rando"]["itemLocations"][i]["trickName"] = json::object(); - // payload["state"]["rando"]["itemLocations"][i]["trickName"]["english"] = - // randoContext->GetItemOverride(i).GetTrickName().GetEnglish(); - // payload["state"]["rando"]["itemLocations"][i]["trickName"]["french"] = - // randoContext->GetItemOverride(i).GetTrickName().GetFrench(); - // } - // if (randoContext->GetItemLocation(i)->HasCustomPrice()) { - // payload["state"]["rando"]["itemLocations"][i]["price"] = - // randoContext->GetItemLocation(i)->GetPrice(); - // } - //} - - // auto entranceCtx = randoContext->GetEntranceShuffler(); - // for (int i = 0; i < ENTRANCE_OVERRIDES_MAX_COUNT; i++) { - // payload["state"]["rando"]["entrances"][i] = json::object(); - // payload["state"]["rando"]["entrances"][i]["type"] = entranceCtx->entranceOverrides[i].type; - // payload["state"]["rando"]["entrances"][i]["index"] = entranceCtx->entranceOverrides[i].index; - // payload["state"]["rando"]["entrances"][i]["destination"] = entranceCtx->entranceOverrides[i].destination; - // payload["state"]["rando"]["entrances"][i]["override"] = entranceCtx->entranceOverrides[i].override; - // payload["state"]["rando"]["entrances"][i]["overrideDestination"] = - // entranceCtx->entranceOverrides[i].overrideDestination; - // } - - // payload["state"]["rando"]["seed"] = json::array(); - // for (int i = 0; i < randoContext->hashIconIndexes.size(); i++) { - // payload["state"]["rando"]["seed"][i] = randoContext->hashIconIndexes[i]; - // } - // payload["state"]["rando"]["inputSeed"] = randoContext->GetSeedString(); - // payload["state"]["rando"]["finalSeed"] = randoContext->GetSeed(); - - // payload["state"]["rando"]["randoSettings"] = json::array(); - // for (int i = 0; i < RSK_MAX; i++) { - // payload["state"]["rando"]["randoSettings"][i] = - // randoContext->GetOption((RandomizerSettingKey(i))).GetSelectedOptionIndex(); - // } - - // payload["state"]["rando"]["masterQuestDungeonCount"] = randoContext->GetDungeons()->CountMQ(); - // payload["state"]["rando"]["masterQuestDungeons"] = json::array(); - // for (int i = 0; i < randoContext->GetDungeons()->GetDungeonListSize(); i++) { - // payload["state"]["rando"]["masterQuestDungeons"][i] = randoContext->GetDungeon(i)->IsMQ(); - // } - // for (int i = 0; i < randoContext->GetTrials()->GetTrialListSize(); i++) { - // payload["state"]["rando"]["requiredTrials"][i] = randoContext->GetTrial(i)->IsRequired(); - // } - /*} + json payload; + payload["type"] = UPDATE_TEAM_STATE; + payload["targetTeamId"] = CVarGetString(CVAR_REMOTE_ANCHOR("TeamId"), "default"); + payload["queue"] = json::array(); + payload["state"]["fileProgressFlags"] = ScoreBytes(fileProgressFlag_getSizeAndPtr); + payload["state"]["jiggies"] = ScoreBytes(jiggyscore_getSizeAndPtr); + payload["state"]["honeycombs"] = ScoreBytes(honeycombscore_getSizeAndPtr); + payload["state"]["mumboTokens"] = ScoreBytes(mumboscore_getSizeAndPtr); + payload["state"]["noteScores"] = ScoreBytes(itemscore_noteScores_getSizeAndPtr); + payload["state"]["savedItems"] = ScoreBytes(saveditem_getSizeAndPtr); + payload["state"]["abilities"] = ScoreBytes(ability_getSizeAndPtr); + // Time scores use a (s32*, void**) accessor, so packed inline. + s32 tsSize; + void* tsAddr; + timeScores_getSizeAndPtr(&tsSize, &tsAddr); + payload["state"]["timeScores"] = std::vector((u8*)tsAddr, (u8*)tsAddr + tsSize); + payload["state"]["volatileFlags"] = ScoreBytes(volatileFlag_getSizeAndPtr); + // In-memory session sets (never saved). + payload["state"]["brokenObjects"] = port_breakable_snapshotBroken(); + payload["state"]["carriedCollected"] = port_carriedSync_snapshotCollected(); + payload["state"]["eggTolls"] = port_eggToll_snapshot(); + payload["state"]["puzzleSteps"] = port_puzzleStep_snapshot(); + payload["state"]["puzzleCounts"] = port_puzzleCount_snapshot(); + payload["state"]["puzzlePos"] = port_puzzlePos_snapshot(); + payload["state"]["spawnedJiggies"] = port_jiggySpawn_snapshot(); + payload["state"]["huts"] = port_hutSmash_snapshot(); + + // Randomizer progress lives outside the vanilla score sections: obtained checks + RANDO_INF flags. + if (IS_RANDO) { + std::vector checks(RC_MAX, 0); + for (s32 rc = RC_UNKNOWN + 1; rc < RC_MAX; rc++) { + checks[rc] = RANDO_SAVE_CHECKS[rc].obtained ? 1 : 0; + } + payload["state"]["randoChecks"] = checks; + + std::vector randoFlags(RANDO_INF_MAX, 0); + for (s32 i = RANDO_INF_UNKNOWN + 1; i < RANDO_INF_MAX; i++) { + randoFlags[i] = RANDO_SAVE_FLAGS[i].flagState; + } + payload["state"]["randoFlags"] = randoFlags; + } - SendJsonToRemote(payload);*/ + SendJsonToRemote(payload); } void Anchor::SendPacket_ClearTeamState(std::string teamId) { @@ -117,188 +106,167 @@ void Anchor::SendPacket_ClearTeamState(std::string teamId) { SendJsonToRemote(payload); } +// Overwrites a local byte section with the authoritative team-state array (no additive merge). +static void ApplyTeamBytes(nlohmann::json& bytes, void (*getSizeAndPtr)(s32*, u8**)) { + s32 size; + u8* addr; + getSizeAndPtr(&size, &addr); + s32 count = std::min(size, (s32)bytes.size()); + for (s32 i = 0; i < count; i++) { + addr[i] = bytes[i].get(); + } +} + void Anchor::HandlePacket_UpdateTeamState(nlohmann::json& payload) { if (!roomState.syncItemsAndFlags) { return; } isHandlingUpdateTeamState = true; - // This can happen in between file select and the game starting, so we can't use this check, but we need to ensure - // we be careful to wrap PlayState usage in this check - // - // if (!IsSaveLoaded()) { - // return; - // } - - // if (payload.contains("state")) { - // SaveContext loadedData = payload["state"].get(); - // gSaveContext.healthCapacity = loadedData.healthCapacity; - // gSaveContext.magicLevel = loadedData.magicLevel; - // gSaveContext.magicCapacity = gSaveContext.magic = loadedData.magicCapacity; - // gSaveContext.isMagicAcquired = loadedData.isMagicAcquired; - // gSaveContext.isDoubleMagicAcquired = loadedData.isDoubleMagicAcquired; - // gSaveContext.isDoubleDefenseAcquired = loadedData.isDoubleDefenseAcquired; - // gSaveContext.bgsFlag = loadedData.bgsFlag; - // gSaveContext.swordHealth = loadedData.swordHealth; - // gSaveContext.ship.quest = loadedData.ship.quest; - - // for (int i = 0; i < 124; i++) { - // if (i == SCENE_WATER_TEMPLE) { - // // Keep water temple water level flags - // u32 mask = (1 << 0x1C) | (1 << 0x1D) | (1 << 0x1E); - // loadedData.sceneFlags[i].swch = - // (loadedData.sceneFlags[i].swch & ~mask) | (gSaveContext.sceneFlags[i].swch & mask); - // } - - // if (i == SCENE_FOREST_TEMPLE) { - // // Keep forest temple elevator flag - // u32 mask = (1 << 0x1B); - // loadedData.sceneFlags[i].swch = - // (loadedData.sceneFlags[i].swch & ~mask) | (gSaveContext.sceneFlags[i].swch & mask); - // } - - // gSaveContext.sceneFlags[i] = loadedData.sceneFlags[i]; - // if (IsSaveLoaded() && gPlayState->sceneNum == i) { - // gPlayState->actorCtx.flags.chest = loadedData.sceneFlags[i].chest; - // gPlayState->actorCtx.flags.swch = loadedData.sceneFlags[i].swch; - // gPlayState->actorCtx.flags.clear = loadedData.sceneFlags[i].clear; - // gPlayState->actorCtx.flags.collect = loadedData.sceneFlags[i].collect; - // } - // } - - // for (int i = 0; i < 14; i++) { - // gSaveContext.eventChkInf[i] = loadedData.eventChkInf[i]; - // } - - // for (int i = 0; i < 4; i++) { - // gSaveContext.itemGetInf[i] = loadedData.itemGetInf[i]; - // } - - // // Skip last row of infTable, don't want to sync swordless flag - // for (int i = 0; i < 29; i++) { - // gSaveContext.infTable[i] = loadedData.infTable[i]; - // } - - // for (int i = 0; i < ceil((RAND_INF_MAX + 15) / 16); i++) { - // gSaveContext.ship.randomizerInf[i] = loadedData.ship.randomizerInf[i]; - // } - - // for (int i = 0; i < 6; i++) { - // gSaveContext.gsFlags[i] = loadedData.gsFlags[i]; - // } - - // gSaveContext.ship.stats.firstInput = loadedData.ship.stats.firstInput; - // gSaveContext.ship.stats.fileCreatedAt = loadedData.ship.stats.fileCreatedAt; - - // // Restore master sword state - // // Disabling this for now, not really sure I understand why I did this in the past - // // u8 hasMasterSword = CHECK_OWNED_EQUIP(EQUIP_TYPE_SWORD, 1); - // // if (hasMasterSword) { - // // loadedData.inventory.equipment |= 0x2; - // // } else { - // // loadedData.inventory.equipment &= ~0x2; - // // } - - // // Restore bottle contents (unless it's ruto's letter) - // for (int i = 0; i < 4; i++) { - // if (gSaveContext.inventory.items[SLOT_BOTTLE_1 + i] != ITEM_NONE && - // gSaveContext.inventory.items[SLOT_BOTTLE_1 + i] != ITEM_LETTER_RUTO) { - // loadedData.inventory.items[SLOT_BOTTLE_1 + i] = gSaveContext.inventory.items[SLOT_BOTTLE_1 + i]; - // } - // } - - // // Restore ammo if it's non-zero, unless it's beans - // for (int i = 0; i < ARRAY_COUNT(gSaveContext.inventory.ammo); i++) { - // if (gSaveContext.inventory.ammo[i] != 0 && i != SLOT(ITEM_BEAN) && i != SLOT(ITEM_BEAN + 1)) { - // loadedData.inventory.ammo[i] = gSaveContext.inventory.ammo[i]; - // } - // } - - // gSaveContext.inventory = loadedData.inventory; - - // // The commented out code below is an attempt at sending the entire randomizer seed over, in hopes that a - // player - // // doesn't have to generate the seed themselves Currently it doesn't work :) - // if (IS_RANDO && payload["state"].contains("rando")) { - // auto randoContext = Rando::Context::GetRawInstance(); - - // for (int i = 0; i < RC_MAX; i++) { - // auto itemLocation = payload["state"]["rando"].at("itemLocations").at(i); - // // randoContext->GetItemLocation(i)->RefPlacedItem() = - // // itemLocation.at("rgID").get(); - // OTRGlobals::Instance->gRandoContext->GetItemLocation(i)->SetCheckStatus( - // itemLocation.at(0).get()); - // OTRGlobals::Instance->gRandoContext->GetItemLocation(i)->SetIsSkipped(itemLocation.at(1).get()); - - // // if (itemLocation.contains("fakeRgID")) { - // // randoContext->overrides.emplace(static_cast(i), - // // Rando::ItemOverride(static_cast(i), - // // itemLocation.at("fakeRgID").get())); - // // randoContext->GetItemOverride(i).GetTrickName().english = - // // itemLocation.at("trickName").at("english").get(); - // // randoContext->GetItemOverride(i).GetTrickName().french = - // // itemLocation.at("trickName").at("french").get(); - // // } - // // if (itemLocation.contains("price")) { - // // u16 price = itemLocation.at("price"].get(); - // // if (price > 0) { - // // randoContext->GetItemLocation(i)->SetCustomPrice(price); - // // } - // // } - // } - - // // auto entranceCtx = randoContext->GetEntranceShuffler(); - // // for (int i = 0; i < ENTRANCE_OVERRIDES_MAX_COUNT; i++) { - // // entranceCtx->entranceOverrides[i].type = - // // payload["state"]["rando"]["entrances"][i]["type"].get(); - // entranceCtx->entranceOverrides[i].index - // // = payload["state"]["rando"]["entrances"][i]["index"].get(); - // // entranceCtx->entranceOverrides[i].destination = - // // payload["state"]["rando"]["entrances"][i]["destination"].get(); - // // entranceCtx->entranceOverrides[i].override = - // // payload["state"]["rando"]["entrances"][i]["override"].get(); - // // entranceCtx->entranceOverrides[i].overrideDestination = - // // payload["state"]["rando"]["entrances"][i]["overrideDestination"].get(); - // // } - - // // for (int i = 0; i < randoContext->hashIconIndexes.size(); i++) { - // // randoContext->hashIconIndexes[i] = payload["state"]["rando"]["seed"][i].get(); - // // } - // // randoContext->GetSettings()->SetSeedString(payload["state"]["rando"]["inputSeed"].get()); - // // randoContext->GetSettings()->SetSeed(payload["state"]["rando"]["finalSeed"].get()); - - // // for (int i = 0; i < RSK_MAX; i++) { - // // - // randoContext->GetOption(RandomizerSettingKey(i)).SetSelectedIndex(payload["state"]["rando"]["randoSettings"][i].get()); - // // } - - // // randoContext->GetDungeons()->ClearAllMQ(); - // // for (int i = 0; i < randoContext->GetDungeons()->GetDungeonListSize(); i++) { - // // if (payload["state"]["rando"]["masterQuestDungeons"][i].get()) { - // // randoContext->GetDungeon(i)->SetMQ(); - // // } - // // } - - // // randoContext->GetTrials()->SkipAll(); - // // for (int i = 0; i < randoContext->GetTrials()->GetTrialListSize(); i++) { - // // if (payload["state"]["rando"]["requiredTrials"][i].get()) { - // // randoContext->GetTrial(i)->SetAsRequired(); - // // } - // // } - // } + if (payload.contains("state")) { + auto& state = payload["state"]; + // Direct byte copy bypasses the setters; no OnGameFlagSet / collectible events fire. + if (state.contains("fileProgressFlags")) { + ApplyTeamBytes(state["fileProgressFlags"], fileProgressFlag_getSizeAndPtr); + } + if (state.contains("volatileFlags")) { + ApplyTeamBytes(state["volatileFlags"], volatileFlag_getSizeAndPtr); + } + if (state.contains("jiggies")) { + ApplyTeamBytes(state["jiggies"], jiggyscore_getSizeAndPtr); + } + if (state.contains("honeycombs")) { + ApplyTeamBytes(state["honeycombs"], honeycombscore_getSizeAndPtr); + } + if (state.contains("mumboTokens")) { + ApplyTeamBytes(state["mumboTokens"], mumboscore_getSizeAndPtr); + } + if (state.contains("noteScores")) { + ApplyTeamBytes(state["noteScores"], itemscore_noteScores_getSizeAndPtr); + } + // Per-level retention sets; takes effect on next map load. + if (state.contains("noteRetention")) { + ApplyTeamBytes(state["noteRetention"], port_noteRetention_getSizeAndPtr); + } + if (state.contains("jinjoRetention")) { + ApplyTeamBytes(state["jinjoRetention"], port_jinjoRetention_getSizeAndPtr); + } + if (state.contains("abilities")) { + ApplyTeamBytes(state["abilities"], ability_getSizeAndPtr); + } + // In-memory session sets; takes effect on next map load. + if (state.contains("brokenObjects")) { + port_breakable_restoreBroken(state["brokenObjects"].get>()); + } + if (state.contains("carriedCollected")) { + port_carriedSync_restoreCollected(state["carriedCollected"].get>()); + } + if (state.contains("eggTolls")) { + port_eggToll_restore(state["eggTolls"].get>()); + } + if (state.contains("puzzleSteps")) { + port_puzzleStep_restore(state["puzzleSteps"].get>()); + } + if (state.contains("puzzlePos")) { + port_puzzlePos_restore(state["puzzlePos"].get>()); + } + if (state.contains("puzzleCounts")) { + port_puzzleCount_restore(state["puzzleCounts"].get>()); + } + if (state.contains("spawnedJiggies")) { + port_jiggySpawn_restore(state["spawnedJiggies"].get>()); + } + if (state.contains("huts")) { + port_hutSmash_restore(state["huts"].get>()); + } + + // Recompute cached HUD counts the overwrites above bypassed. + if (IsSaveLoaded()) { + if (state.contains("jiggies")) { + func_8034798C(); + } + if (state.contains("honeycombs")) { + func_80347958(); + } + if (state.contains("mumboTokens")) { + func_80347984(); + } + + // Saved item counts: mumbo tokens [0] and jiggy total [4] always sync; feathers + // [1-3] only when the room shares consumables. + if (state.contains("savedItems")) { + auto& incoming = state["savedItems"]; + s32 size; + u8* addr; + saveditem_getSizeAndPtr(&size, &addr); // rebuilds the array from live counts + u8 buf[5]; + for (s32 i = 0; i < 5; i++) { + buf[i] = (i < size) ? addr[i] : 0; + } + if (incoming.size() >= 5) { + buf[0] = incoming[0].get(); + buf[4] = incoming[4].get(); + if (roomState.shareConsumables) { + buf[1] = incoming[1].get(); + buf[2] = incoming[2].get(); + buf[3] = incoming[3].get(); + } + func_803479C0(buf); + } + } + + // Per-level best times (truncated u16 each). + if (state.contains("timeScores")) { + auto incoming = state["timeScores"].get>(); + u16 ts[0xB] = { 0 }; + size_t n = std::min(incoming.size(), sizeof(ts)); + for (size_t i = 0; i < n; i++) { + ((u8*)ts)[i] = incoming[i]; + } + itemscore_timeScores_fromSaveData(ts); + } + } + + // Randomizer catch-up: reconcile check records (obtain without re-granting, see + // AdoptRemoteCheck) and take RANDO_INF flags authoritatively. + if (IS_RANDO && IsSaveLoaded()) { + if (state.contains("randoChecks")) { + auto checks = state["randoChecks"].get>(); + s32 n = std::min((s32)checks.size(), (s32)RC_MAX); + for (s32 rc = RC_UNKNOWN + 1; rc < n; rc++) { + if (checks[rc]) { + AdoptRemoteCheck(rc); + } + } + } + if (state.contains("randoFlags")) { + auto flags = state["randoFlags"].get>(); + s32 n = std::min((s32)flags.size(), (s32)RANDO_INF_MAX); + for (s32 i = RANDO_INF_UNKNOWN + 1; i < n; i++) { + RANDO_SAVE_FLAGS[i].flagState = flags[i]; + } + } + } + + SweepUnoccupiedLevelState((GameMap)gsworld_getMap()); + + Notification::Emit({ + .message = "Save updated from team", + }); + + if (reloadMapOnTeamState && IsSaveLoaded()) { + reloadMapOnTeamState = false; + transitionToMap(gsworld_getMap(), gsworld_getExit(), 1); + } + } - // Notification::Emit({ - // .message = "Save updated from team", - // }); - //} + if (payload.contains("queue")) { + std::lock_guard lock(incomingPacketQueueMutex); + for (auto& item : payload["queue"]) { + incomingPacketQueue.push(nlohmann::json::parse(item.get())); + } + } - // if (payload.contains("queue")) { - // std::lock_guard lock(incomingPacketQueueMutex); - // for (auto& item : payload["queue"]) { - // nlohmann::json itemPayload = nlohmann::json::parse(item.get()); - // incomingPacketQueue.push(itemPayload); - // } - // } - // isHandlingUpdateTeamState = false; + isHandlingUpdateTeamState = false; } diff --git a/src/port/Network/Anchor/Packets/VileEatRequest.cpp b/src/port/Network/Anchor/Packets/VileEatRequest.cpp index 536b061f1..6d244a2e9 100644 --- a/src/port/Network/Anchor/Packets/VileEatRequest.cpp +++ b/src/port/Network/Anchor/Packets/VileEatRequest.cpp @@ -14,9 +14,6 @@ extern "C" { * Sent by a non-authority client when its local player chomps a piece. The minigame * authority validates the request against the live piece list and, on success, consumes * the piece and broadcasts the result as a VILE_HOLE_STATE (eaten) packet. - * - * No sequence number: this is a request toward the authority, not part of the - * authority's ordered state stream. */ void Anchor::SendPacket_VileEatRequest(u8 holeId) { @@ -41,14 +38,10 @@ void Anchor::HandlePacket_VileEatRequest(nlohmann::json& payload) { return; } - // Only the authority acts on eat requests; VileSync_HandleEatRequest returns false - // (touching nothing) on non-authority clients. uint32_t eaterClientId = payload.at("clientId").get(); s32 pieceType = 0; s32 correctType = 0; if (VileSync_HandleEatRequest(holeId, eaterClientId, &pieceType, &correctType)) { - // Confirm the successful eat back to the requester so it replays its croc's eat - // feedback (the piece removal already rides the eaten VILE_HOLE_STATE broadcast). SendPacket_VileEatResult(eaterClientId, (u8)pieceType, (u8)correctType); } } diff --git a/src/port/Network/Anchor/Packets/VileEatResult.cpp b/src/port/Network/Anchor/Packets/VileEatResult.cpp index 214943b6f..04032093e 100644 --- a/src/port/Network/Anchor/Packets/VileEatResult.cpp +++ b/src/port/Network/Anchor/Packets/VileEatResult.cpp @@ -11,14 +11,8 @@ extern "C" { /** * VILE_EAT_RESULT * - * Sent by the minigame authority to confirm a successful VILE_EAT_REQUEST. The - * requester suppressed its local consume (so its croc never played the chomp), so on - * receipt it replays the eat feedback: the chomp animation/SFX, plus the wrong-type - * reaction when the eaten piece didn't match the required type. Score and piece removal - * are authority-driven and arrive via the snapshot / eaten VILE_HOLE_STATE separately. - * - * Broadcast to the chamber with the eater's id; only the eater acts on it. No sequence - * number: this is one-shot cosmetic feedback, not part of the ordered state stream. + * Sent by the minigame authority to confirm a successful VILE_EAT_REQUEST. + * Catches up on animations and sounds as necessary */ void Anchor::SendPacket_VileEatResult(u32 eaterClientId, u8 pieceType, u8 correctType) { diff --git a/src/port/Network/Anchor/Packets/VileGameState.cpp b/src/port/Network/Anchor/Packets/VileGameState.cpp index fba3bc9cb..ebdbc0415 100644 --- a/src/port/Network/Anchor/Packets/VileGameState.cpp +++ b/src/port/Network/Anchor/Packets/VileGameState.cpp @@ -12,12 +12,7 @@ extern "C" { * VILE_GAME_STATE * * Periodic full snapshot of the Mr. Vile minigame, broadcast by the authority to other - * clients in the chamber every second or two while the game is running. Application is - * idempotent: it corrects any drift from lost packets and brings late joiners fully up - * to date (a late joiner is just a client whose drift is 100%). - * - * Events (VILE_HOLE_STATE / VILE_UPDATE) make the game feel synced; this packet makes - * it provably synced. + * clients in the chamber every second or two while the game is running. */ void Anchor::SendPacket_VileGameState() { diff --git a/src/port/Network/Anchor/Packets/WaterRise.cpp b/src/port/Network/Anchor/Packets/WaterRise.cpp new file mode 100644 index 000000000..85c0d62ef --- /dev/null +++ b/src/port/Network/Anchor/Packets/WaterRise.cpp @@ -0,0 +1,117 @@ +#include "port/Network/Anchor/Anchor.h" +#include +#include + +#include "port/ShipInit.hpp" +#include "port/Enhancements/Events/PortEnhancements.h" +#include "port/Enhancements/Events/Hooks/Events.h" + +#include + +extern "C" { +#include "functions.h" +#include "variables.h" +// func_8034C5AC: xform-3 water group. func_8034E78C: animate its dy. +} + +/** + * WATER_RISE + * + * A rising water level animates only on the client that triggered it (lair: switch cutscene in + * func_802D5628/func_802D5260; CC rings: func_8034E78C). Remotes otherwise only get the trailing + * fileprog flag / JIGGY_1C spawn at the end, snapping the water. This packet signals the rise start. + * + * kind 0 (lair): RBB-lobby water subaddie, driven every frame by func_802D5260. p1 = target level + * (1-3), stashed by a remote as a "pending level" until the real flag catches up. + * kind 1 (CC): rings water (xform-3 dy), no per-frame holder; remote replays func_8034E78C. + * p1 = mesh id, p2 = target dy, dur = seconds. + */ + +enum { WATERRISE_KIND_LAIR = 0, WATERRISE_KIND_CC = 1 }; + +// map -> pending target level for the lair water (remote only; cleared once the flag reaches it). +static std::map sLairPendingLevel; + +static int32_t lairLevelForFlag(int32_t levelFlag) { + switch (levelFlag) { + case FILEPROG_23_LAIR_WATER_LEVEL_1: return 1; + case FILEPROG_25_LAIR_WATER_LEVEL_2: return 2; + case FILEPROG_27_LAIR_WATER_LEVEL_3: return 3; + default: return 0; + } +} + +// Called from func_802D6264 (the lair switch/cutscene trigger). If the flag the cutscene will set is +// a water-level flag, broadcast the rise now. +extern "C" void port_lairWater_onRiseTrigger(int32_t waterMap, int32_t levelFlag) { + int32_t level = lairLevelForFlag(levelFlag); + if (level == 0) { + return; // not a water switch (doors, witch switches, etc. use this same trigger) + } + Anchor::GetInstance()->SendPacket_WaterRise(waterMap, WATERRISE_KIND_LAIR, level, 0, 0.0f); +} + +// func_802D5260 asks for the effective target level: max(flag-derived level, pending level from a +// teammate's in-flight rise). Clears the pending once the real flag catches up. +extern "C" int32_t port_lairWater_targetLevel(int32_t map, int32_t flagLevel) { + auto it = sLairPendingLevel.find(map); + if (it == sLairPendingLevel.end()) { + return flagLevel; + } + if (flagLevel >= it->second) { + sLairPendingLevel.erase(it); + return flagLevel; + } + return it->second; +} + +extern "C" void port_ccWater_broadcastRise(int32_t map, int32_t waterId, int32_t targetDy, f32 duration) { + Anchor::GetInstance()->SendPacket_WaterRise(map, WATERRISE_KIND_CC, waterId, targetDy, duration); +} + +void Anchor::SendPacket_WaterRise(s32 map, s32 kind, s32 p1, s32 p2, f32 duration) { + if (!IsSaveLoaded() || !roomState.syncItemsAndFlags) { + return; + } + nlohmann::json payload; + payload["type"] = WATER_RISE; + payload["targetTeamId"] = CVarGetString(CVAR_REMOTE_ANCHOR("TeamId"), "default"); + payload["map"] = map; + payload["kind"] = kind; + payload["p1"] = p1; + payload["p2"] = p2; + payload["dur"] = duration; + SendJsonToRemote(payload); +} + +void Anchor::HandlePacket_WaterRise(nlohmann::json& payload) { + if (!roomState.syncItemsAndFlags) { + return; + } + s32 map = payload.at("map").get(); + s32 kind = payload.at("kind").get(); + s32 p1 = payload.at("p1").get(); + s32 p2 = payload.value("p2", (s32)0); + f32 dur = payload.value("dur", 0.0f); + + if (kind == WATERRISE_KIND_LAIR) { + int32_t cur = sLairPendingLevel.count(map) ? sLairPendingLevel[map] : 0; + if (p1 > cur) { + sLairPendingLevel[map] = p1; + } + } else if (kind == WATERRISE_KIND_CC) { + // Only replay while in the water's map; on later entry func_80388104 snaps it on its own. + if ((s32)gsworld_getMap() == map) { + Struct70s* water = func_8034C5AC(p1); + if (water != nullptr) { + func_8034E78C((Struct73s*)water, p2, dur); + } + } + } +} + +void RegisterWaterRise_Init() { + REGISTER_LISTENER(OnSaveLoad, EVENT_PRIORITY_NORMAL, [](IEvent* event) { sLairPendingLevel.clear(); }); +} + +static RegisterShipInitFunc initWaterRise(RegisterWaterRise_Init, {}); diff --git a/src/port/Patches/Patches.h b/src/port/Patches/Patches.h index cf1c8a564..b9ab1784c 100644 --- a/src/port/Patches/Patches.h +++ b/src/port/Patches/Patches.h @@ -102,6 +102,75 @@ void port_audioIntMaskExit(void); void port_beginDemoAudioHold(void); +void port_notedoor_remoteOpen(int32_t progressFlag); + +void port_leveldoor_remoteOpen(int32_t progressFlag); + +void port_breakable_remoteBreak(int32_t progressFlag); + +void port_breakable_broadcastBreak(int32_t markerId, int32_t x, int32_t y, int32_t z); +void port_breakable_remoteBreakAt(int32_t markerId, int32_t x, int32_t y, int32_t z); + +void port_breakable_recordBreak(int32_t markerId, int32_t x, int32_t y, int32_t z); + +int32_t port_breakable_isBroken(int32_t map, int32_t markerId, int32_t x, int32_t y, int32_t z); + +void port_eggToll_onAdvance(int32_t map, int32_t secondaryId, int32_t stage); +int32_t port_eggToll_getStage(int32_t map, int32_t secondaryId); +void port_eggToll_remoteApply(int32_t map, int32_t secondaryId, int32_t stage); + +#define ANCHOR_PUZZLE_BGS_TANKTUP 1 +#define ANCHOR_PUZZLE_BGS_CROCTUS 2 +#define ANCHOR_PUZZLE_BGS_PINKEGG 3 +// CC clanker teeth: bits 0-2 = token tooth egg count, bits 3-5 = jiggy tooth. +#define ANCHOR_PUZZLE_CC_CLANKER_TEETH 4 +#define ANCHOR_PUZZLE_GV_JINXY_DOOR 5 +// MM Juju totem: bits 0-3, count of the 4 segments knocked off. +#define ANCHOR_PUZZLE_MM_JUJU 6 +// TTC Nipper: bits 0-2, count of hits taken (all 3 = dead, shell open). +#define ANCHOR_PUZZLE_TTC_NIPPER 7 +// TTC Blubber: bit 0 = first bullion delivered, bit 1 = second (jiggy spawned, Blubber leaves). +#define ANCHOR_PUZZLE_TTC_BLUBBER 8 +// TTC treasure hunt: bits 0-5, count of beak-busted X steps (bit 5 = treasure dug up). +#define ANCHOR_PUZZLE_TTC_XHUNT 9 +// FP xmas tree ice: 1 bit, set when the tree-top ice shatters. Recorded in the tree-interior +// map; the FP hub tree reads it via getForMap. +#define ANCHOR_PUZZLE_FP_TREE_ICE 10 +// FP bear cubs' presents: bit 0 = blue, bit 1 = green, bit 2 = red delivered. +#define ANCHOR_PUZZLE_FP_PRESENTS 11 +// FP snowman buttons: bit per button; all three spawns JIGGY_2D. +#define ANCHOR_PUZZLE_FP_SNOWBUTTONS 12 +#define ANCHOR_PUZZLE_FP_SLUSHES 13 +// RBB engine-room fans: 1 bit. Transient map flag 0 (enginefan.c reads it to slow the fans); persisted across reloads. +#define ANCHOR_PUZZLE_RBB_ENGINE_FANS 14 + +void port_remoteCarry_setCarried(uint32_t clientId, int32_t markerId, float offset[3], float yawOffset); +void port_remoteCarry_throw(uint32_t clientId, int32_t markerId, float start[3], float target[3]); +void port_remoteCarry_reset(void); +void port_anchorDummies_onActorsFreed(void); +void port_puzzleStep_orBits(int32_t puzzleId, int32_t bits); +int32_t port_puzzleStep_get(int32_t puzzleId); +int32_t port_puzzleStep_getForMap(int32_t map, int32_t puzzleId); + +void port_puzzlePos_mark(int32_t puzzleId, int32_t x, int32_t y, int32_t z); +int32_t port_puzzlePos_isMarked(int32_t puzzleId, int32_t x, int32_t y, int32_t z); + +void port_fpTwinkly_release(void); + +int32_t port_mapFlag_wasSetRemotely(int32_t index); + +#define ANCHOR_COUNT_CCW_EYRIE_FED 0 +#define ANCHOR_COUNT_CCW_NABNUT_ACORNS 1 +void port_puzzleCount_add(int32_t counterId, int32_t delta); +int32_t port_puzzleCount_get(int32_t counterId); + +void port_hutSmash_record(int32_t x, int32_t y, int32_t z, int32_t loot); +int32_t port_hutSmash_get(int32_t x, int32_t y, int32_t z); +int32_t port_hutSmash_countForCurrentMap(void); + +void port_jiggyCrane_broadcast(int32_t stage); +void port_jiggyCrane_remoteApply(int32_t stage); + #ifdef __cplusplus } #endif diff --git a/src/port/Rando/CustomObject/CustomObject.cpp b/src/port/Rando/CustomObject/CustomObject.cpp index c807e808c..2958bc2f1 100644 --- a/src/port/Rando/CustomObject/CustomObject.cpp +++ b/src/port/Rando/CustomObject/CustomObject.cpp @@ -347,6 +347,10 @@ void CustomObject::CheckObtainedEX(RandoCheckId randoCheckId, bool isInit) { } Rando::StaticData::ModifyRandoInfFlagState(randoCheckId); Rando::Logic::RefreshReachableRegions(); + // Broadcast real collects only (not save-load/remote apply, both isInit). + if (!isInit) { + CALL_EVENT(OnRandoCheckObtained, (int32_t)randoCheckId, (int32_t)gsworld_getMap()); + } break; } } diff --git a/src/port/Rando/ObjectBehavior/ObjectBehavior.cpp b/src/port/Rando/ObjectBehavior/ObjectBehavior.cpp index 6c84867c7..97e542402 100644 --- a/src/port/Rando/ObjectBehavior/ObjectBehavior.cpp +++ b/src/port/Rando/ObjectBehavior/ObjectBehavior.cpp @@ -162,46 +162,55 @@ Actor* FindActorByRandoCheckId(RandoCheckId randoCheckId) { return NULL; } +// subject is "You" or a teammate's name for Anchor remote collects. +static void EmitCheckNotification(RandoCheckId randoCheckId, const std::string& subject) { + RandoSaveCheck randoSaveCheck = RANDO_SAVE_CHECKS[randoCheckId]; + std::string prefix; + std::string message; + std::string suffix = ""; + ImVec4 itemColor = WIDGET_TEXT_COLOR(randoItemColors.at(randoSaveCheck.randoItemId)); + + if (randoSaveCheck.randoItemId == RI_MOLEHILL) { + prefix = subject + " learned"; + message = abilityNameList[randoSaveCheck.randoCollectionId].c_str(); + } else if (randoSaveCheck.randoItemId == RI_STOP_N_SWOP_EGG || + randoSaveCheck.randoItemId == RI_STOP_N_SWOP_KEY) { + int32_t totalsnsItems = Rando::Logic::GetTotalSnsItemsCollected(); + prefix = subject + " collected "; + prefix += Rando::StaticData::Items[randoSaveCheck.randoItemId].article; + + message = Rando::StaticData::Items[randoSaveCheck.randoItemId].name; + suffix = "("; + suffix += std::to_string(totalsnsItems); + suffix += " / 7)"; + + itemColor = WIDGET_TEXT_COLOR(snsItemColors.at(randoSaveCheck.randoCollectionId)); + } else { + prefix = subject + " collected "; + prefix += Rando::StaticData::Items[randoSaveCheck.randoItemId].article; + message = Rando::StaticData::Items[randoSaveCheck.randoItemId].name; + } + + Notification::Emit({ + .prefix = prefix, + .prefixColor = WIDGET_TEXT_COLOR(UIWidgets::Colors::White), + .message = message, + .messageColor = itemColor, + .suffix = suffix, + .suffixColor = WIDGET_TEXT_COLOR(UIWidgets::Colors::White), + }); +} + void Rando::StaticData::SendCollisionNotification(RandoCheckId randoCheckId) { if (CVAR_SHOW_COLLISION_NOTIFICATIONS) { - RandoSaveCheck randoSaveCheck = RANDO_SAVE_CHECKS[randoCheckId]; - std::string prefix; - std::string message; - std::string suffix = ""; - ImVec4 itemColor = WIDGET_TEXT_COLOR(randoItemColors.at(randoSaveCheck.randoItemId)); - - if (randoSaveCheck.randoItemId == RI_MOLEHILL) { - prefix = "You learned"; - message = abilityNameList[randoSaveCheck.randoCollectionId].c_str(); - } else if (randoSaveCheck.randoItemId == RI_STOP_N_SWOP_EGG || - randoSaveCheck.randoItemId == RI_STOP_N_SWOP_KEY) { - int32_t totalsnsItems = Rando::Logic::GetTotalSnsItemsCollected(); - prefix = "You collected "; - prefix += Rando::StaticData::Items[randoSaveCheck.randoItemId].article; - - message = Rando::StaticData::Items[randoSaveCheck.randoItemId].name; - suffix = "("; - suffix += std::to_string(totalsnsItems); - suffix += " / 7)"; - - itemColor = WIDGET_TEXT_COLOR(snsItemColors.at(randoSaveCheck.randoCollectionId)); - } else { - prefix = "You collected "; - prefix += Rando::StaticData::Items[randoSaveCheck.randoItemId].article; - message = Rando::StaticData::Items[randoSaveCheck.randoItemId].name; - } - - Notification::Emit({ - .prefix = prefix, - .prefixColor = WIDGET_TEXT_COLOR(UIWidgets::Colors::White), - .message = message, - .messageColor = itemColor, - .suffix = suffix, - .suffixColor = WIDGET_TEXT_COLOR(UIWidgets::Colors::White), - }); + EmitCheckNotification(randoCheckId, "You"); } }; +void Rando::StaticData::SendRemoteCheckNotification(RandoCheckId randoCheckId, const std::string& collectorName) { + EmitCheckNotification(randoCheckId, collectorName); +}; + bool ShouldOverrideSpawn(RandoCheckId randoCheckId) { if (Rando::Logic::IsCheckShuffled(randoCheckId)) { return true; diff --git a/src/port/Rando/Rando.h b/src/port/Rando/Rando.h index f2897cc38..faf0f56bc 100644 --- a/src/port/Rando/Rando.h +++ b/src/port/Rando/Rando.h @@ -22,6 +22,12 @@ extern int16_t selectedFileNum; #define RANDO_SAVE_OPTIONS gameFile_saveData[selectedFileNum].shipSaveData.randoSaveData.randoSaveOption #define RANDO_SAVE_FLAGS gameFile_saveData[selectedFileNum].shipSaveData.randoSaveData.randoSaveFlag +// Loaded rando file's seed id, or 0 if none. +#define RANDO_SEED \ + (selectedFileNum == DEFAULT_FILE_NUM \ + ? 0 \ + : gameFile_saveData[selectedFileNum].shipSaveData.randoSaveData.seedId) + // #define RANDO_SAVE_ENTRANCES(fileNum) gSaveBuffer.files[fileNum]->shipSaveData.randoSaveData.randoSaveEntrances // #define RANDO_EVENTS gSaveContext.save.shipSaveInfo.rando.randoEvents // #define RANDO_STARTING_ITEMS gSaveContext.save.shipSaveInfo.rando.randoStartingItems diff --git a/src/port/Rando/StaticData/StaticData.h b/src/port/Rando/StaticData/StaticData.h index 9c39b7063..0b6e807e3 100644 --- a/src/port/Rando/StaticData/StaticData.h +++ b/src/port/Rando/StaticData/StaticData.h @@ -12,6 +12,7 @@ namespace Rando { namespace StaticData { void SendCollisionNotification(RandoCheckId randoCheckId); +void SendRemoteCheckNotification(RandoCheckId randoCheckId, const std::string& collectorName); struct RandoLogicData { const char* name; diff --git a/src/port/Romhack/RomhackCompat.cpp b/src/port/Romhack/RomhackCompat.cpp index 0bd322e5f..904facd27 100644 --- a/src/port/Romhack/RomhackCompat.cpp +++ b/src/port/Romhack/RomhackCompat.cpp @@ -7,7 +7,13 @@ namespace Lighthouse { static constexpr const char* kVanillaLabel = "Vanilla"; std::string CurrentRomhackLabel() { - return port_isRomhack() ? port_getRomhackName() : kVanillaLabel; + if (!port_isRomhack()) { + return kVanillaLabel; + } + if (const char* id = port_getRomhackIdentifier()) { + return id; + } + return port_getRomhackName(); } std::string DescribeRomhackMismatch(bool localIsRomhack, const std::string& localLabel, bool remoteIsRomhack, diff --git a/src/port/Romhack/RomhackQuirks.cpp b/src/port/Romhack/RomhackQuirks.cpp index 7df269857..efc46609f 100644 --- a/src/port/Romhack/RomhackQuirks.cpp +++ b/src/port/Romhack/RomhackQuirks.cpp @@ -7,7 +7,7 @@ // To add a new quirk: // 1. Make sure the romhack has an entry in RomhackTable.h. // 2. Find the engine event the quirk should hook (or define a new one in -// src/port/enhancements/events/hooks/list/). +// src/port/Enhancements/Events/Hooks/List/). // 3. Add a REGISTER_LISTENER block below, gated on // port_getRomhackIdentifier() returning the matching name. // 4. Wire the registration into RegisterRomhackQuirks_Init(). diff --git a/src/port/Save/SaveManager.cpp b/src/port/Save/SaveManager.cpp index 4bd6cb7d9..9b7b5ffd0 100644 --- a/src/port/Save/SaveManager.cpp +++ b/src/port/Save/SaveManager.cpp @@ -21,6 +21,7 @@ extern "C" { #include "core1/sns.h" extern SaveData gameFile_saveData[4]; +extern s8 gameFile_GameIdToFileIdMap[4]; void savedata_update_crc(void* buffer, s32 size); s32 item_getCount(enum item_e item); extern u8 gCompletedBottlesBonusGames[7]; @@ -769,6 +770,21 @@ void SaveManager_Init() { event->Cancelled = true; }); + REGISTER_LISTENER(OnGameErase, EVENT_PRIORITY_NORMAL, [](IEvent* event) { + OnGameErase* ev = (OnGameErase*)event; + std::string fileName = createFileName(ev->gameNum); + std::error_code ec; + if (fs::remove(SaveManager_GetSavePath(fileName), ec)) { + SPDLOG_INFO("SaveManager: deleted erased save file \"{}\"", fileName); + } else if (ec) { + SPDLOG_ERROR("SaveManager: failed to delete erased save file \"{}\": {}", fileName, ec.message()); + } + // Drop retention data too. + if (ev->gameNum >= 0 && ev->gameNum < 4) { + gameFile_saveData[gameFile_GameIdToFileIdMap[ev->gameNum]].shipSaveData = {}; + } + }); + REGISTER_LISTENER(OnSaveClear, EVENT_PRIORITY_NORMAL, [](IEvent* event) { OnSaveClear* ev = (OnSaveClear*)event; SaveData* saveData = (SaveData*)ev->result; diff --git a/src/port/UI/LighthouseGui.cpp b/src/port/UI/LighthouseGui.cpp index 2e5d70095..ece79ef8c 100644 --- a/src/port/UI/LighthouseGui.cpp +++ b/src/port/UI/LighthouseGui.cpp @@ -23,6 +23,7 @@ #include "port/Rando/CheckTracker/CheckTracker.h" #include "Notification.h" +#include "port/Network/Anchor/Anchor.h" #include "port/Enhancements/Backports/EggAim.h" #include "LighthouseMenu.h" #include "LighthouseInputEditorWindow.h" @@ -72,6 +73,7 @@ std::shared_ptr mEggAimCrosshair; std::shared_ptr mModalWindow; std::shared_ptr mEventDebuggerWindow; std::shared_ptr mOcclusionDebugWindow; +std::shared_ptr mAnchorRoomWindow; UIWidgets::Colors GetMenuThemeColor() { return mLighthouseMenu->GetMenuThemeColor(); @@ -202,6 +204,9 @@ void SetupGuiElements() { mOcclusionDebugWindow = std::make_shared(CVAR_WINDOW("OcclusionDebug"), "Occlusion Debugger"); gui->AddGuiWindow(mOcclusionDebugWindow); + + mAnchorRoomWindow = std::make_shared(CVAR_WINDOW("AnchorRoom"), "Anchor Room"); + gui->AddGuiWindow(mAnchorRoomWindow); } void Destroy() { @@ -237,6 +242,7 @@ void Destroy() { mEggAimCrosshair = nullptr; mEventDebuggerWindow = nullptr; mOcclusionDebugWindow = nullptr; + mAnchorRoomWindow = nullptr; } void RegisterPopup(std::string title, std::string message, std::string button1, std::string button2, diff --git a/src/port/UI/LighthouseInputEditorWindow.cpp b/src/port/UI/LighthouseInputEditorWindow.cpp index e762f7be1..1bd9e1977 100644 --- a/src/port/UI/LighthouseInputEditorWindow.cpp +++ b/src/port/UI/LighthouseInputEditorWindow.cpp @@ -4,6 +4,7 @@ #include #include #include +#include "cvar_prefixes.h" #ifndef __WIIU__ #include #endif @@ -13,6 +14,13 @@ #define SCALE_IMGUI_SIZE(value) ((value / 13.0f) * ImGui::GetFontSize()) LighthouseInputEditorWindow::~LighthouseInputEditorWindow() { + auto ignored = Ship::Context::GetRawInstance()->GetControlDeck()->GetConnectedPhysicalDeviceManager()->GetIgnoredInstanceIdsForPort(0); + if (!ignored.empty()) { + Ship::Context::GetRawInstance()->GetConfig()->SetBlock("CVars.gSettings.IgnoredControllers", ignored); + } + else { + Ship::Context::GetRawInstance()->GetConfig()->EraseBlock("CVars.gSettings.IgnoredControllers"); + } } void LighthouseInputEditorWindow::InitElement() { @@ -40,6 +48,14 @@ void LighthouseInputEditorWindow::InitElement() { addButtonName(BTN_DLEFT, "D-pad left"); addButtonName(BTN_DRIGHT, "D-pad right"); addButtonName(0, "None"); + if (Ship::Context::GetRawInstance()->GetConfig()->GetNestedJson()["CVars"]["gSettings"].contains("IgnoredControllers")) { + std::vector ignored = Ship::Context::GetRawInstance()->GetConfig()->GetNestedJson()["CVars"]["gSettings"]["IgnoredControllers"]; + if (!ignored.empty()) { + for (int id : ignored) { + Ship::Context::GetRawInstance()->GetControlDeck()->GetConnectedPhysicalDeviceManager()->IgnoreInstanceIdForPort(0, id); + } + } + } } #define INPUT_EDITOR_WINDOW_GAME_INPUT_BLOCK_ID 95237929 diff --git a/src/port/UI/LighthouseMenu.cpp b/src/port/UI/LighthouseMenu.cpp index 63769245f..766470581 100644 --- a/src/port/UI/LighthouseMenu.cpp +++ b/src/port/UI/LighthouseMenu.cpp @@ -5,6 +5,7 @@ #include "port/Localization/Language.h" #include "port/Romhack/RomhackConfig.h" #include "port/Patches/Patches.h" +#include "port/Network/Anchor/Anchor.h" #include #include #include @@ -213,6 +214,12 @@ void LighthouseMenu::InitElement() { "Not available during the character parade." } }, { DISABLE_FOR_ROMHACK, { [](disabledInfo& info) -> bool { return port_isRomhack(); }, "Not available with romhacks" } }, + { FORCED_ON_FOR_ANCHOR_CONNECTED, + { [](disabledInfo& info) -> bool { + Anchor* anchor = Anchor::GetInstance(); + return anchor != nullptr && anchor->isConnected; + }, + "Forced on while connected to Anchor" } }, }; } diff --git a/src/port/UI/LighthouseMenuDevTools.cpp b/src/port/UI/LighthouseMenuDevTools.cpp index 38a337350..b0b171b8c 100644 --- a/src/port/UI/LighthouseMenuDevTools.cpp +++ b/src/port/UI/LighthouseMenuDevTools.cpp @@ -76,6 +76,13 @@ void LighthouseMenu::AddMenuDevTools() { AddWidget(path, "Nametag Distance", WIDGET_CVAR_SLIDER_FLOAT) .CVar(CVAR_DEVELOPER_TOOLS("NametagDist")) .Options(FloatSliderOptions().DefaultValue(3000.0f).Min(1000.0f).Max(10000.0f).Step(10.0f)); + AddWidget(path, "Simulate Remote Collects", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_DEVELOPER_TOOLS("SimRemoteCollect")) + .Options(CheckboxOptions().Tooltip( + "Every 30 seconds while in a map with live uncollected notes or jinjos, feeds one through the " + "remote-collect path (retention record + live despawn) as if a teammate collected it — for testing " + "the Anchor collection sync without a second machine. Requires note/jinjo retention to be active " + "(enhancement on, or connected to Anchor).")); /*AddWidget(path, "Debug Mode", WIDGET_CVAR_CHECKBOX) .CVar(CVAR_DEVELOPER_TOOLS("DebugMode")) .Options(CheckboxOptions().Tooltip("Various debug features, including a level selector from the main menu."));*/ diff --git a/src/port/UI/LighthouseMenuEnhancements.cpp b/src/port/UI/LighthouseMenuEnhancements.cpp index f04666dc7..a672a930b 100644 --- a/src/port/UI/LighthouseMenuEnhancements.cpp +++ b/src/port/UI/LighthouseMenuEnhancements.cpp @@ -1,5 +1,12 @@ #include "LighthouseMenu.h" #include "port/Enhancements/Trackers/DisplayOverlay.h" +#include "port/Network/Anchor/Anchor.h" + +extern "C" { +#include "functions.h" +#include "variables.h" +extern u8 gCompletedBottlesBonusGames[7]; +} #define CVAR_INT_SHIP_INIT(cvar, val) \ CVarSetInteger(cvar, val); \ @@ -7,6 +14,54 @@ namespace LighthouseGui { +// Live toggle state for the Bottles' Bonus gags (non-cvar checkboxes). Order matches +// D_803635EC in ba_anim.c and gCompletedBottlesBonusGames. +static bool sBottlesBonusState[7] = { false }; + +static const char* kBottlesBonusNames[7] = { + "Big Head", + "Big Hands & Feet", + "Big Kazooie", + "Tall Body & Small Head", + "Tall Body, Small Head, Big Hands & Feet", + "Big Everything", + "Wishy-Washy Banjo", +}; + +static const char* kBottlesBonusTooltips[7] = { + "Bottles' Bonus: enlarges Banjo's head.", + "Bottles' Bonus: enlarges Banjo's hands and feet.", + "Bottles' Bonus: enlarges Kazooie's head and wings.", + "Bottles' Bonus: stretches Banjo's body and shrinks his head.", + "Bottles' Bonus: stretched body, shrunken head, and big hands and feet.", + "The 'Big Bottles Bonus': big head, big hands and feet, and big Kazooie.", + "Bottles' Bonus: turns Banjo into Wishy-Washy.", +}; + +static const char* kBottlesBonusLockedTooltip = + "Complete this Bottles' Bonus puzzle to unlock it. (Always available while connected to Anchor.)"; + +static bool IsBottlesBonusUnlocked(int i) { + Anchor* anchor = Anchor::GetInstance(); + if (anchor != nullptr && anchor->isConnected) { + return true; + } + return gCompletedBottlesBonusGames[i] != 0; +} + +static void ApplyBottlesBonusState() { + bool any = false; + for (int i = 0; i < 7; i++) { + volatileFlag_setEx((enum volatile_flags_e)(VOLATILE_FLAG_97_SANDCASTLE_BOTTLES_BONUS_1 + i), + sBottlesBonusState[i] ? 1 : 0, 0); + if (sBottlesBonusState[i]) { + any = true; + } + } + // Master gate read by __baanim_applyBottlesBonus / baanim_getActiveBottlesBonusMask. + volatileFlag_setEx(VOLATILE_FLAG_78_SANDCASTLE_NO_BONUS, any ? 1 : 0, 0); +} + extern std::shared_ptr mLighthouseMenu; using namespace UIWidgets; @@ -65,6 +120,25 @@ void LighthouseMenu::AddMenuEnhancements() { .Options(CheckboxOptions().Tooltip("Forces game to show original aspect ratio during cutscenes to avoid seeing " "unfinished edges of scene geometry.")); + path.column = SECTION_COLUMN_2; + + AddWidget(path, "Bottles' Bonuses", WIDGET_SEPARATOR_TEXT); + + for (int i = 0; i < 7; i++) { + AddWidget(path, kBottlesBonusNames[i], WIDGET_CHECKBOX) + .ValuePointer(&sBottlesBonusState[i]) + .Callback([](WidgetInfo& info) { ApplyBottlesBonusState(); }) + .PreFunc([i](WidgetInfo& info) { + if (!IsBottlesBonusUnlocked(i)) { + info.options->disabled = true; + info.options->disabledTooltip = kBottlesBonusLockedTooltip; + } + }) + .Options(CheckboxOptions().Tooltip(kBottlesBonusTooltips[i])); + } + + path.column = SECTION_COLUMN_1; + AddWidget(path, "Extended Draw Distance: %dx", WIDGET_CVAR_SLIDER_INT) .CVar(CVAR_ENHANCEMENT("Graphics.DrawDistance")) .RaceDisable(false) @@ -427,6 +501,11 @@ void LighthouseMenu::AddMenuEnhancements() { AddWidget(path, "Note Collection Retention", WIDGET_CVAR_CHECKBOX) .CVar(CVAR_ENHANCEMENT("Gameplay.NoteRetention")) .RaceDisable(false) + .PreFunc([](WidgetInfo& info) { + if (mLighthouseMenu->disabledMap.at(FORCED_ON_FOR_ANCHOR_CONNECTED).active) { + info.activeDisables.push_back(FORCED_ON_FOR_ANCHOR_CONNECTED); + } + }) .Options(CheckboxOptions().Tooltip( "Notes you've already collected stay collected and don't respawn when you revisit a level. " "Collection is always tracked; this toggle controls whether collected notes are skipped on " @@ -435,6 +514,11 @@ void LighthouseMenu::AddMenuEnhancements() { AddWidget(path, "Jinjo Collection Retention", WIDGET_CVAR_CHECKBOX) .CVar(CVAR_ENHANCEMENT("Gameplay.JinjoRetention")) .RaceDisable(false) + .PreFunc([](WidgetInfo& info) { + if (mLighthouseMenu->disabledMap.at(FORCED_ON_FOR_ANCHOR_CONNECTED).active) { + info.activeDisables.push_back(FORCED_ON_FOR_ANCHOR_CONNECTED); + } + }) .Options(CheckboxOptions().Tooltip( "Jinjos you've already collected stay collected across visits instead of resetting each time " "you enter a level, so you no longer need all five in one go. Collection is always tracked; " diff --git a/src/port/UI/MenuTypes.h b/src/port/UI/MenuTypes.h index b0ef5b269..8131e25af 100644 --- a/src/port/UI/MenuTypes.h +++ b/src/port/UI/MenuTypes.h @@ -23,6 +23,7 @@ typedef enum { DISABLE_FOR_SINGLE_LANGUAGE, DISABLE_DURING_PARADE, DISABLE_FOR_ROMHACK, + FORCED_ON_FOR_ANCHOR_CONNECTED, } DisableOption; struct WidgetInfo; From a42d4f7f5d4fab7e5ac2fdc5e264f321c6f51b97 Mon Sep 17 00:00:00 2001 From: Malkierian Date: Thu, 23 Jul 2026 19:17:27 -0700 Subject: [PATCH 014/131] Clang-format for anchor-game-sync PR. --- src/port/DevTools/RemoteCollectSim.cpp | 18 +++-- src/port/Enhancements/Events/Hooks/Events.h | 10 +-- .../Enhancements/Gameplay/SkipSMTutorial.cpp | 2 +- .../Enhancements/Retention/JinjoRetention.cpp | 18 +++-- src/port/Enhancements/Retention/Retention.h | 3 +- src/port/Network/Anchor/Authority.cpp | 6 +- src/port/Network/Anchor/DummyPlayer.h | 4 +- src/port/Network/Anchor/FightSync.c | 71 +++++++++---------- src/port/Network/Anchor/FightSync.h | 33 ++++----- src/port/Network/Anchor/HookHandlers.cpp | 69 ++++++++++-------- src/port/Network/Anchor/Menu.cpp | 3 +- .../Network/Anchor/Packets/BreakObject.cpp | 5 +- .../Network/Anchor/Packets/CollectItem.cpp | 39 ++++++---- .../Anchor/Packets/EntranceDiscovered.cpp | 2 +- .../Network/Anchor/Packets/FightEvent.cpp | 3 +- .../Network/Anchor/Packets/FightUpdate.cpp | 3 +- src/port/Network/Anchor/Packets/PlayerSfx.cpp | 3 +- .../Network/Anchor/Packets/PlayerUpdate.cpp | 3 +- src/port/Network/Anchor/Packets/SetFlag.cpp | 33 ++++++--- .../Network/Anchor/Packets/VileEatResult.cpp | 2 +- src/port/Network/Anchor/Packets/WaterRise.cpp | 12 ++-- .../Rando/ObjectBehavior/ObjectBehavior.cpp | 3 +- src/port/Rando/Rando.h | 6 +- src/port/UI/LighthouseInputEditorWindow.cpp | 19 +++-- 24 files changed, 211 insertions(+), 159 deletions(-) diff --git a/src/port/DevTools/RemoteCollectSim.cpp b/src/port/DevTools/RemoteCollectSim.cpp index 5d6ef3c16..db226648d 100644 --- a/src/port/DevTools/RemoteCollectSim.cpp +++ b/src/port/DevTools/RemoteCollectSim.cpp @@ -37,12 +37,18 @@ bool sPreferNote = true; // alternate note/jinjo across successful ticks const char* jinjoColorName(int32_t bit) { switch (bit) { - case 1 << 0: return "blue"; - case 1 << 1: return "green"; - case 1 << 2: return "orange"; - case 1 << 3: return "pink"; - case 1 << 4: return "yellow"; - default: return "?"; + case 1 << 0: + return "blue"; + case 1 << 1: + return "green"; + case 1 << 2: + return "orange"; + case 1 << 3: + return "pink"; + case 1 << 4: + return "yellow"; + default: + return "?"; } } diff --git a/src/port/Enhancements/Events/Hooks/Events.h b/src/port/Enhancements/Events/Hooks/Events.h index a1055d476..5def299b7 100644 --- a/src/port/Enhancements/Events/Hooks/Events.h +++ b/src/port/Enhancements/Events/Hooks/Events.h @@ -64,11 +64,11 @@ typedef enum VBehaviorID { } VBehaviorID; typedef enum DoorCameraId { - GV_DOOR_CAM_SUN, // sun switch (flag 3) - GV_DOOR_CAM_STAR, // star switch / trapdoor (flag 5) - GV_DOOR_CAM_KAZOOIE, // beak-bomb door (flag 6) - GV_DOOR_CAM_JINXY, // Jinxy sneeze (flags 0, 1) - MMM_DOOR_CAM_CHURCH, // church door, Tumblar challenge (flag 0) + GV_DOOR_CAM_SUN, // sun switch (flag 3) + GV_DOOR_CAM_STAR, // star switch / trapdoor (flag 5) + GV_DOOR_CAM_KAZOOIE, // beak-bomb door (flag 6) + GV_DOOR_CAM_JINXY, // Jinxy sneeze (flags 0, 1) + MMM_DOOR_CAM_CHURCH, // church door, Tumblar challenge (flag 0) } DoorCameraId; DEFINE_EVENT(VanillaBehavior, VBehaviorID id; bool* should; va_list * originalArgs;); diff --git a/src/port/Enhancements/Gameplay/SkipSMTutorial.cpp b/src/port/Enhancements/Gameplay/SkipSMTutorial.cpp index 0273698dc..144de4c6e 100644 --- a/src/port/Enhancements/Gameplay/SkipSMTutorial.cpp +++ b/src/port/Enhancements/Gameplay/SkipSMTutorial.cpp @@ -51,7 +51,7 @@ void RegisterSkipSMTutorial_Init() { } func_8034789C(); item_adjustByDiffWithoutHud(ITEM_14_HEALTH, - item_getCount(ITEM_15_HEALTH_TOTAL) - item_getCount(ITEM_14_HEALTH)); + item_getCount(ITEM_15_HEALTH_TOTAL) - item_getCount(ITEM_14_HEALTH)); } fileProgressFlag_set(FILEPROG_BD_ENTER_LAIR_CUTSCENE, 1); diff --git a/src/port/Enhancements/Retention/JinjoRetention.cpp b/src/port/Enhancements/Retention/JinjoRetention.cpp index fc74bb170..ed5dc7a65 100644 --- a/src/port/Enhancements/Retention/JinjoRetention.cpp +++ b/src/port/Enhancements/Retention/JinjoRetention.cpp @@ -108,12 +108,18 @@ static u8 jinjoBitFromActor(int32_t actorId) { static int32_t jinjoActorFromBit(u8 bit) { switch (bit) { - case 1 << 0: return ACTOR_60_JINJO_BLUE; - case 1 << 1: return ACTOR_62_JINJO_GREEN; - case 1 << 2: return ACTOR_5F_JINJO_ORANGE; - case 1 << 3: return ACTOR_61_JINJO_PINK; - case 1 << 4: return ACTOR_5E_JINJO_YELLOW; - default: return 0; + case 1 << 0: + return ACTOR_60_JINJO_BLUE; + case 1 << 1: + return ACTOR_62_JINJO_GREEN; + case 1 << 2: + return ACTOR_5F_JINJO_ORANGE; + case 1 << 3: + return ACTOR_61_JINJO_PINK; + case 1 << 4: + return ACTOR_5E_JINJO_YELLOW; + default: + return 0; } } diff --git a/src/port/Enhancements/Retention/Retention.h b/src/port/Enhancements/Retention/Retention.h index 67b045462..140dbbc7b 100644 --- a/src/port/Enhancements/Retention/Retention.h +++ b/src/port/Enhancements/Retention/Retention.h @@ -47,8 +47,7 @@ void port_carriedSync_beginMapLoad(int32_t mapId); // Registers a world object, attaching spawn-position identity to the marker. Sets *suppress // non-zero if a teammate already collected it. -void port_carriedSync_register(int32_t kind, void* marker, int32_t x, int32_t y, int32_t z, - int32_t* suppress); +void port_carriedSync_register(int32_t kind, void* marker, int32_t x, int32_t y, int32_t z, int32_t* suppress); void port_carriedSync_onLocalCollect(int32_t kind, void* marker); diff --git a/src/port/Network/Anchor/Authority.cpp b/src/port/Network/Anchor/Authority.cpp index 6d593ad30..f714e21ba 100644 --- a/src/port/Network/Anchor/Authority.cpp +++ b/src/port/Network/Anchor/Authority.cpp @@ -18,9 +18,9 @@ static ActivityState sActivities[NET_ACTIVITY_COUNT]; // The map each activity lives in. A claim is only valid while its owner is in this map. static const int32_t sActivityMap[NET_ACTIVITY_COUNT] = { - MAP_10_BGS_MR_VILE, // NET_ACTIVITY_VILE_MINIGAME - MAP_90_GL_BATTLEMENTS, // NET_ACTIVITY_FINAL_BOSS - MAP_27_FP_FREEZEEZY_PEAK, // NET_ACTIVITY_FP_TWINKLY + MAP_10_BGS_MR_VILE, // NET_ACTIVITY_VILE_MINIGAME + MAP_90_GL_BATTLEMENTS, // NET_ACTIVITY_FINAL_BOSS + MAP_27_FP_FREEZEEZY_PEAK, // NET_ACTIVITY_FP_TWINKLY }; static bool Authority_IsValidActivity(NetworkActivityId activity) { diff --git a/src/port/Network/Anchor/DummyPlayer.h b/src/port/Network/Anchor/DummyPlayer.h index a544f1d2b..aa068af5c 100644 --- a/src/port/Network/Anchor/DummyPlayer.h +++ b/src/port/Network/Anchor/DummyPlayer.h @@ -79,7 +79,9 @@ class DummyPlayer { // eye/mouth void dummy_setEyeState(bool squint, bool wink, bool isHat); AnimCtrl* dummy_getAnimCtrl(); - ActorMarker* dummy_getMarker() const { return dummyMarker; } + ActorMarker* dummy_getMarker() const { + return dummyMarker; + } void dummy_despawnActor(void); private: diff --git a/src/port/Network/Anchor/FightSync.c b/src/port/Network/Anchor/FightSync.c index bdddf6fd5..f4cd9107a 100644 --- a/src/port/Network/Anchor/FightSync.c +++ b/src/port/Network/Anchor/FightSync.c @@ -12,12 +12,12 @@ extern f32 D_80392758[3]; extern f32 D_80392768[3]; extern f32 D_80392778[3]; extern f32 __chFinalBossFireballFlightTime; -extern ActorMarker *__chFinalBossFlightPadMarker; +extern ActorMarker* __chFinalBossFlightPadMarker; extern u8 __chFinalBossSpellBarrierActive; -extern ActorArray *suBaddieActorArray; +extern ActorArray* suBaddieActorArray; extern u8 sFinalBossJinjoStatueActivated; // Collision radius for the jinjo-into-Grunty test. -extern f32 func_8033229C(ActorMarker *marker); +extern f32 func_8033229C(ActorMarker* marker); // Set once the ending script takes over (chfinalboss_setBossDefeated). static u8 sFightNetCinematic = 0; @@ -38,8 +38,8 @@ static bool FightSync_IsLiveAuthority(void) { return NetAuthority_IsClaimed(NET_ACTIVITY_FINAL_BOSS) && NetAuthority_IsSelf(NET_ACTIVITY_FINAL_BOSS); } -static Actor *FightSync_FindBoss(void) { - Actor *boss = actorArray_findActorFromActorId(ACTOR_38B_GRUNTILDA_FINAL_BOSS); +static Actor* FightSync_FindBoss(void) { + Actor* boss = actorArray_findActorFromActorId(ACTOR_38B_GRUNTILDA_FINAL_BOSS); if (boss == NULL || !boss->volatile_initialized || boss->despawn_flag) { return NULL; @@ -48,14 +48,14 @@ static Actor *FightSync_FindBoss(void) { } // The jinjo statue bases share one actor id, so find by their statue id (1-4). -static Actor *FightSync_FindStatueBase(s32 statue_id) { +static Actor* FightSync_FindStatueBase(s32 statue_id) { s32 i; if (suBaddieActorArray == NULL) { return NULL; } for (i = 0; i < suBaddieActorArray->cnt; i++) { - Actor *actor = &suBaddieActorArray->data[i]; + Actor* actor = &suBaddieActorArray->data[i]; if (actor->marker == NULL || actor->marker->id != MARKER_27A_JINJO_STATUE_BASE) { continue; } @@ -69,7 +69,7 @@ static Actor *FightSync_FindStatueBase(s32 statue_id) { // Apply a networked egg via getHitByEgg(other == NULL), the counting path. static void FightSync_ApplyJinjoStatueEgg(s32 statue_id) { - Actor *base = FightSync_FindStatueBase(statue_id); + Actor* base = FightSync_FindStatueBase(statue_id); if (base != NULL) { chBossJinjoBase_getHitByEgg(base->marker, NULL); @@ -171,9 +171,9 @@ bool FightSync_ForwardEgg(s32 statue_id, s32 pad_index) { // --- stream: gather (authority) / apply (follower) --------------------------------------------- -bool FightSync_GatherUpdate(f32 pos[3], f32 *yaw, s32 *state, s32 *phase, s32 *mirror, s32 *vuln) { - Actor *boss; - ActorLocal_FinalBoss *local; +bool FightSync_GatherUpdate(f32 pos[3], f32* yaw, s32* state, s32* phase, s32* mirror, s32* vuln) { + Actor* boss; + ActorLocal_FinalBoss* local; if (sFightNetCinematic) { return false; @@ -182,7 +182,7 @@ bool FightSync_GatherUpdate(f32 pos[3], f32 *yaw, s32 *state, s32 *phase, s32 *m if (boss == NULL) { return false; } - local = (ActorLocal_FinalBoss *)&boss->local; + local = (ActorLocal_FinalBoss*)&boss->local; pos[0] = boss->position[0]; pos[1] = boss->position[1]; pos[2] = boss->position[2]; @@ -195,8 +195,8 @@ bool FightSync_GatherUpdate(f32 pos[3], f32 *yaw, s32 *state, s32 *phase, s32 *m return true; } -static void FightSync_ApplyBossState(Actor *this, s32 phase, s32 state) { - ActorLocal_FinalBoss *local = (ActorLocal_FinalBoss *)&this->local; +static void FightSync_ApplyBossState(Actor* this, s32 phase, s32 state) { + ActorLocal_FinalBoss* local = (ActorLocal_FinalBoss*)&this->local; // unk44_31 = broomstick motor sfx source. if (this->unk44_31 != 0 && phase != FINALBOSS_PHASE_1_BROOMSTICK) { @@ -226,8 +226,8 @@ static void FightSync_ApplyBossState(Actor *this, s32 phase, s32 state) { } void FightSync_ApplyUpdate(const f32 pos[3], f32 yaw, s32 state, s32 phase, s32 mirror, s32 vuln) { - Actor *boss; - ActorLocal_FinalBoss *local; + Actor* boss; + ActorLocal_FinalBoss* local; if (!FightSync_IsFollower() || sFightNetCinematic) { return; @@ -237,7 +237,7 @@ void FightSync_ApplyUpdate(const f32 pos[3], f32 yaw, s32 state, s32 phase, s32 return; } sFightNetWasFollower = 1; - local = (ActorLocal_FinalBoss *)&boss->local; + local = (ActorLocal_FinalBoss*)&boss->local; boss->position[0] = pos[0]; boss->position[1] = pos[1]; boss->position[2] = pos[2]; @@ -253,8 +253,8 @@ void FightSync_ApplyUpdate(const f32 pos[3], f32 yaw, s32 state, s32 phase, s32 // --- latecomer world snapshot ------------------------------------------------------------------- -bool FightSync_GatherWorld(FightWorldSnapshot *snap) { - Actor *base; +bool FightSync_GatherWorld(FightWorldSnapshot* snap) { + Actor* base; s32 i; if (sFightNetCinematic || !FightSync_IsLiveAuthority() || FightSync_FindBoss() == NULL) { @@ -279,7 +279,7 @@ bool FightSync_GatherWorld(FightWorldSnapshot *snap) { return true; } -void FightSync_ApplyWorld(const FightWorldSnapshot *snap) { +void FightSync_ApplyWorld(const FightWorldSnapshot* snap) { s32 i; if (!FightSync_IsFollower() || sFightNetCinematic) { @@ -296,9 +296,9 @@ void FightSync_ApplyWorld(const FightWorldSnapshot *snap) { } } -static void FightSync_CatchupTick(Actor *boss) { - Actor *base; - Actor *jinjo; +static void FightSync_CatchupTick(Actor* boss) { + Actor* base; + Actor* jinjo; u8 pads[4]; s32 i; s32 done = 1; @@ -369,8 +369,8 @@ static void FightSync_CatchupTick(Actor *boss) { } } -bool FightSync_BossFollowerTick(void *bossPtr) { - Actor *boss = (Actor *)bossPtr; +bool FightSync_BossFollowerTick(void* bossPtr) { + Actor* boss = (Actor*)bossPtr; if (!FightSync_IsFollower() || sFightNetCinematic) { return false; @@ -378,13 +378,12 @@ bool FightSync_BossFollowerTick(void *bossPtr) { FightSync_CatchupTick(boss); // Detect a jinjo-into-Grunty collision locally (display-only) ahead of the authority's slam event. - if (((ActorLocal_FinalBoss *)&boss->local)->phase == FINALBOSS_PHASE_4_JINJOS) { - ActorMarker *jinjoMarker = chfinalboss_findCollidingJinjo(boss, func_8033229C(boss->marker)); + if (((ActorLocal_FinalBoss*)&boss->local)->phase == FINALBOSS_PHASE_4_JINJOS) { + ActorMarker* jinjoMarker = chfinalboss_findCollidingJinjo(boss, func_8033229C(boss->marker)); if (jinjoMarker != NULL) { - Actor *jinjo = marker_getActor(jinjoMarker); + Actor* jinjo = marker_getActor(jinjoMarker); s32 sid = (jinjo != NULL) ? jinjo->actorTypeSpecificField : 0; - if (sid >= BOSSJINJO_1_ORANGE && sid <= BOSSJINJO_4_YELLOW && - (sFightNetJinjoSlammed & (1 << sid))) { + if (sid >= BOSSJINJO_1_ORANGE && sid <= BOSSJINJO_4_YELLOW && (sFightNetJinjoSlammed & (1 << sid))) { marker_despawn(jinjoMarker); } else { if (sid >= BOSSJINJO_1_ORANGE && sid <= BOSSJINJO_4_YELLOW) { @@ -415,7 +414,7 @@ bool FightSync_BossFollowerTick(void *bossPtr) { // --- one-shot event dispatch -------------------------------------------------------------------- void FightSync_ApplyEvent(s32 ev, s32 a, s32 b, const f32 v0[3], const f32 v1[3], const f32 v2[3]) { - Actor *boss = FightSync_FindBoss(); + Actor* boss = FightSync_FindBoss(); s32 i; switch (ev) { @@ -488,7 +487,7 @@ void FightSync_ApplyEvent(s32 ev, s32 a, s32 b, const f32 v0[3], const f32 v1[3] break; case FIGHT_EV_JINJO_ATTACK: { - Actor *jinjo; + Actor* jinjo; if (!FightSync_IsFollower() || a < BOSSJINJO_1_ORANGE || a > BOSSJINJO_4_YELLOW) { return; } @@ -508,7 +507,7 @@ void FightSync_ApplyEvent(s32 ev, s32 a, s32 b, const f32 v0[3], const f32 v1[3] if (getGameMode() == GAME_MODE_4_PAUSED) { return; } - if (((ActorLocal_FinalBoss *)&boss->local)->phase != (u8)a) { + if (((ActorLocal_FinalBoss*)&boss->local)->phase != (u8)a) { return; } chfinalboss_collisionPassive(boss->marker, NULL); @@ -534,8 +533,8 @@ void FightSync_ApplyEvent(s32 ev, s32 a, s32 b, const f32 v0[3], const f32 v1[3] } void FightSync_OnAuthorityChanged(void) { - Actor *boss; - ActorLocal_FinalBoss *local; + Actor* boss; + ActorLocal_FinalBoss* local; FightSyncSeq_Reset(); if (sFightNetCinematic) { @@ -547,7 +546,7 @@ void FightSync_OnAuthorityChanged(void) { } if (sFightNetWasFollower && FightSync_IsLiveAuthority()) { sFightNetWasFollower = 0; - local = (ActorLocal_FinalBoss *)&boss->local; + local = (ActorLocal_FinalBoss*)&boss->local; if (local->phase != FINALBOSS_PHASE_0_INTRO) { chfinalboss_setPhase(boss->marker, local->phase); } diff --git a/src/port/Network/Anchor/FightSync.h b/src/port/Network/Anchor/FightSync.h index 64081a31e..2c6127966 100644 --- a/src/port/Network/Anchor/FightSync.h +++ b/src/port/Network/Anchor/FightSync.h @@ -15,16 +15,16 @@ // FIGHT_EVENT ids ('ev' field). enum FightSyncEvent { // authority -> followers - FIGHT_EV_SPELL = 0, // a = kind (0 fireball, 1 final fireball, 2 green blast); p/v/w = spawn vectors - FIGHT_EV_PAD_SPAWN, // flight pad appears (end of phase 2) - FIGHT_EV_PAD_DESPAWN, // flight pad removed (during phase 3 barrier cast) - FIGHT_EV_BARRIER, // spell barrier spawns on Grunty - FIGHT_EV_STATUE_SPAWN, // a = ch_bossjinjo_e statue id (1-4 jinjos, 5 jinjonator) - FIGHT_EV_EGG_FED, // a = statue id (1-4 jinjos, 5 jinjonator), b = jinjonator pad index - FIGHT_EV_JINJO_ATTACK, // a = jinjo statue id whose jinjo just slammed Grunty + FIGHT_EV_SPELL = 0, // a = kind (0 fireball, 1 final fireball, 2 green blast); p/v/w = spawn vectors + FIGHT_EV_PAD_SPAWN, // flight pad appears (end of phase 2) + FIGHT_EV_PAD_DESPAWN, // flight pad removed (during phase 3 barrier cast) + FIGHT_EV_BARRIER, // spell barrier spawns on Grunty + FIGHT_EV_STATUE_SPAWN, // a = ch_bossjinjo_e statue id (1-4 jinjos, 5 jinjonator) + FIGHT_EV_EGG_FED, // a = statue id (1-4 jinjos, 5 jinjonator), b = jinjonator pad index + FIGHT_EV_JINJO_ATTACK, // a = jinjo statue id whose jinjo just slammed Grunty // followers -> authority - FIGHT_EV_BOSS_HIT, // a = the phase the hitting client believed Grunty was in - FIGHT_EV_EGG, // a = statue id, b = jinjonator pad index + FIGHT_EV_BOSS_HIT, // a = the phase the hitting client believed Grunty was in + FIGHT_EV_EGG, // a = statue id, b = jinjonator pad index }; // FIGHT_STATE catch-up snapshot for a client joining mid-fight. @@ -70,11 +70,9 @@ bool chjinjonatorbase_netGetPads(uint8_t pads[4]); // --- C -> network (bridges implemented in the packet .cpp files) ----------------------- -void FightSync_SendUpdate(const float pos[3], float yaw, int32_t state, int32_t phase, int32_t mirror, - int32_t vuln); +void FightSync_SendUpdate(const float pos[3], float yaw, int32_t state, int32_t phase, int32_t mirror, int32_t vuln); // v0/v1/v2 may be NULL for events that carry no vectors. -void FightSync_SendEvent(int32_t ev, int32_t a, int32_t b, const float v0[3], const float v1[3], - const float v2[3]); +void FightSync_SendEvent(int32_t ev, int32_t a, int32_t b, const float v0[3], const float v1[3], const float v2[3]); void FightSync_SendSnapshot(uint32_t clientId); uint32_t FightSyncSeq_Next(void); @@ -86,13 +84,10 @@ void FightSyncSeq_Reset(void); void FightSync_OnAuthorityChanged(void); // Fill the stream fields from the live boss; false if there's no boss to stream. -bool FightSync_GatherUpdate(float pos[3], float* yaw, int32_t* state, int32_t* phase, int32_t* mirror, - int32_t* vuln); +bool FightSync_GatherUpdate(float pos[3], float* yaw, int32_t* state, int32_t* phase, int32_t* mirror, int32_t* vuln); -void FightSync_ApplyUpdate(const float pos[3], float yaw, int32_t state, int32_t phase, int32_t mirror, - int32_t vuln); -void FightSync_ApplyEvent(int32_t ev, int32_t a, int32_t b, const float v0[3], const float v1[3], - const float v2[3]); +void FightSync_ApplyUpdate(const float pos[3], float yaw, int32_t state, int32_t phase, int32_t mirror, int32_t vuln); +void FightSync_ApplyEvent(int32_t ev, int32_t a, int32_t b, const float v0[3], const float v1[3], const float v2[3]); // Gather on the authority (false = nothing to send) / apply on a joining follower. bool FightSync_GatherWorld(FightWorldSnapshot* snap); diff --git a/src/port/Network/Anchor/HookHandlers.cpp b/src/port/Network/Anchor/HookHandlers.cpp index 28f01d518..ce25b4983 100644 --- a/src/port/Network/Anchor/HookHandlers.cpp +++ b/src/port/Network/Anchor/HookHandlers.cpp @@ -79,14 +79,10 @@ static void Anchor_UpdateFightSync() { static bool Anchor_ShouldBroadcastVolatileFlag(s32 index) { static const std::unordered_set syncList = { - VOLATILE_FLAG_B6_WITCH_SWITCH_PRESSED_MM, - VOLATILE_FLAG_B7_WITCH_SWITCH_PRESSED_MMM, - VOLATILE_FLAG_B8_WITCH_SWITCH_PRESSED_TTC, - VOLATILE_FLAG_B9_WITCH_SWITCH_PRESSED_RBB, - VOLATILE_FLAG_BA_WITCH_SWITCH_PRESSED_CCW, - VOLATILE_FLAG_BB_WITCH_SWITCH_PRESSED_FP, - VOLATILE_FLAG_BC_WITCH_SWITCH_PRESSED_CC, - VOLATILE_FLAG_BD_WITCH_SWITCH_PRESSED_BGS, + VOLATILE_FLAG_B6_WITCH_SWITCH_PRESSED_MM, VOLATILE_FLAG_B7_WITCH_SWITCH_PRESSED_MMM, + VOLATILE_FLAG_B8_WITCH_SWITCH_PRESSED_TTC, VOLATILE_FLAG_B9_WITCH_SWITCH_PRESSED_RBB, + VOLATILE_FLAG_BA_WITCH_SWITCH_PRESSED_CCW, VOLATILE_FLAG_BB_WITCH_SWITCH_PRESSED_FP, + VOLATILE_FLAG_BC_WITCH_SWITCH_PRESSED_CC, VOLATILE_FLAG_BD_WITCH_SWITCH_PRESSED_BGS, VOLATILE_FLAG_BE_WITCH_SWITCH_PRESSED_GV, }; return syncList.contains(index); @@ -96,7 +92,7 @@ bool Anchor_ScopedFlagExcluded(s32 space, s32 index) { static const std::unordered_set excluded = { (ANCHOR_FLAGSPACE_LEVEL_SPECIFIC << 16) | LEVEL_FLAG_5_TTC_UNKNOWN, // TTC sandcastle drain (ANCHOR_FLAGSPACE_LEVEL_SPECIFIC << 16) | LEVEL_FLAG_29_FP_XMAS_TREE_COMPLETE, // FP xmas-tree ice shatter - (ANCHOR_FLAGSPACE_LEVEL_SPECIFIC << 16) | LEVEL_FLAG_30_RBB_UNKNOWN, // RBB anchor/Snorkel chain cutscene + (ANCHOR_FLAGSPACE_LEVEL_SPECIFIC << 16) | LEVEL_FLAG_30_RBB_UNKNOWN, // RBB anchor/Snorkel chain cutscene // GV water-pyramid rise: reapplied live from JIGGY_42 in water_pyramidrot.c. (ANCHOR_FLAGSPACE_LEVEL_SPECIFIC << 16) | LEVEL_FLAG_6_GV_UNKNOWN, (ANCHOR_FLAGSPACE_MAP_SPECIFIC << 16) | MM_SPECIFIC_FLAG_2_ORANGE_HAS_BEEN_RETURNED, @@ -131,8 +127,7 @@ bool Anchor_ScopedFlagExcluded(s32 space, s32 index) { // FP bear cubs' presents-received flags: kept local; ANCHOR_PUZZLE_FP_PRESENTS syncs the result. if (space == ANCHOR_FLAGSPACE_LEVEL_SPECIFIC && (s32)map_getLevel(gsworld_getMap()) == (s32)LEVEL_5_FREEZEEZY_PEAK && - (index == LEVEL_FLAG_11_FP_UNKNOWN || index == LEVEL_FLAG_12_FP_UNKNOWN || - index == LEVEL_FLAG_13_FP_UNKNOWN)) { + (index == LEVEL_FLAG_11_FP_UNKNOWN || index == LEVEL_FLAG_12_FP_UNKNOWN || index == LEVEL_FLAG_13_FP_UNKNOWN)) { return true; } // SM_SPECIFIC_FLAG_10: Bottles-conversation position lock; kept local. @@ -182,23 +177,41 @@ void Anchor::RegisterHooks() { // Anchor::GetInstance()->SendPacket_PlayerUpdate(true); auto* anchor = Anchor::GetInstance(); - if (anchor->isConnected && anchor->roomState.syncItemsAndFlags && - ev->nextMap != MAP_91_FILE_SELECT && ev->nextMap != MAP_1E_CS_START_NINTENDO && - ev->nextMap != MAP_1F_CS_START_RAREWARE) { + if (anchor->isConnected && anchor->roomState.syncItemsAndFlags && ev->nextMap != MAP_91_FILE_SELECT && + ev->nextMap != MAP_1E_CS_START_NINTENDO && ev->nextMap != MAP_1F_CS_START_RAREWARE) { anchor->SendPacket_RequestScopedState((GameMap)ev->nextMap); s32 enteredFlag = -1; switch (ev->nextMap) { - case MAP_2_MM_MUMBOS_MOUNTAIN: enteredFlag = FILEPROG_B0_HAS_ENTERED_MM; break; - case MAP_7_TTC_TREASURE_TROVE_COVE: enteredFlag = FILEPROG_B2_HAS_ENTERED_TTC; break; - case MAP_B_CC_CLANKERS_CAVERN: enteredFlag = FILEPROG_B8_HAS_ENTERED_CC; break; - case MAP_D_BGS_BUBBLEGLOOP_SWAMP: enteredFlag = FILEPROG_B1_HAS_ENTERED_BGS; break; - case MAP_12_GV_GOBIS_VALLEY: enteredFlag = FILEPROG_B3_HAS_ENTERED_GV; break; - case MAP_1B_MMM_MAD_MONSTER_MANSION:enteredFlag = FILEPROG_B7_HAS_ENTERED_MMM; break; - case MAP_27_FP_FREEZEEZY_PEAK: enteredFlag = FILEPROG_B6_HAS_ENTERED_FP; break; - case MAP_31_RBB_RUSTY_BUCKET_BAY: enteredFlag = FILEPROG_B4_HAS_ENTERED_RBB; break; - case MAP_40_CCW_HUB: enteredFlag = FILEPROG_B5_HAS_ENTERED_CCW; break; - default: break; + case MAP_2_MM_MUMBOS_MOUNTAIN: + enteredFlag = FILEPROG_B0_HAS_ENTERED_MM; + break; + case MAP_7_TTC_TREASURE_TROVE_COVE: + enteredFlag = FILEPROG_B2_HAS_ENTERED_TTC; + break; + case MAP_B_CC_CLANKERS_CAVERN: + enteredFlag = FILEPROG_B8_HAS_ENTERED_CC; + break; + case MAP_D_BGS_BUBBLEGLOOP_SWAMP: + enteredFlag = FILEPROG_B1_HAS_ENTERED_BGS; + break; + case MAP_12_GV_GOBIS_VALLEY: + enteredFlag = FILEPROG_B3_HAS_ENTERED_GV; + break; + case MAP_1B_MMM_MAD_MONSTER_MANSION: + enteredFlag = FILEPROG_B7_HAS_ENTERED_MMM; + break; + case MAP_27_FP_FREEZEEZY_PEAK: + enteredFlag = FILEPROG_B6_HAS_ENTERED_FP; + break; + case MAP_31_RBB_RUSTY_BUCKET_BAY: + enteredFlag = FILEPROG_B4_HAS_ENTERED_RBB; + break; + case MAP_40_CCW_HUB: + enteredFlag = FILEPROG_B5_HAS_ENTERED_CCW; + break; + default: + break; } if (enteredFlag >= 0 && fileProgressFlag_get((enum file_progress_e)enteredFlag)) { anchor->SendPacket_SetFlag((u8)ANCHOR_FLAGSPACE_FILE_PROGRESS, (s16)enteredFlag); @@ -399,7 +412,8 @@ void Anchor::RegisterHooks() { if (Anchor_ScopedFlagExcluded(ev->flagSpace, index)) { continue; } - anchor->SendPacket_ScopedFlag((u8)ev->flagSpace, (s16)index, (u8)(levelSpecificFlags_get(index) ? 1 : 0)); + anchor->SendPacket_ScopedFlag((u8)ev->flagSpace, (s16)index, + (u8)(levelSpecificFlags_get(index) ? 1 : 0)); continue; } if (ev->flagSpace == ANCHOR_FLAGSPACE_MAP_SPECIFIC) { @@ -497,9 +511,8 @@ void Anchor::RegisterHooks() { port_jiggySpawn_remove(ev->jiggyId); }); - COND_HOOK(OnSaveFileSave, EVENT_PRIORITY_NORMAL, isConnected, [](IEvent* event) { - Anchor::GetInstance()->SendPacket_UpdateTeamState(); - }); + COND_HOOK(OnSaveFileSave, EVENT_PRIORITY_NORMAL, isConnected, + [](IEvent* event) { Anchor::GetInstance()->SendPacket_UpdateTeamState(); }); // #endregion diff --git a/src/port/Network/Anchor/Menu.cpp b/src/port/Network/Anchor/Menu.cpp index f9219ef11..5b84ff2f2 100644 --- a/src/port/Network/Anchor/Menu.cpp +++ b/src/port/Network/Anchor/Menu.cpp @@ -219,7 +219,8 @@ void AnchorAdminMenu(WidgetInfo& info) { UIWidgets::CheckboxOptions().DefaultValue(true).Color(THEME_COLOR))) { anchor->SendPacket_UpdateRoomState(); } - if (UIWidgets::CVarCheckbox("Share Consumables (Eggs/Feathers)", CVAR_REMOTE_ANCHOR("RoomSettings.ShareConsumables"), + if (UIWidgets::CVarCheckbox("Share Consumables (Eggs/Feathers)", + CVAR_REMOTE_ANCHOR("RoomSettings.ShareConsumables"), UIWidgets::CheckboxOptions().DefaultValue(false).Color(THEME_COLOR))) { anchor->SendPacket_UpdateRoomState(); } diff --git a/src/port/Network/Anchor/Packets/BreakObject.cpp b/src/port/Network/Anchor/Packets/BreakObject.cpp index 947e77315..0b8570a1f 100644 --- a/src/port/Network/Anchor/Packets/BreakObject.cpp +++ b/src/port/Network/Anchor/Packets/BreakObject.cpp @@ -42,8 +42,9 @@ void port_breakable_restoreBroken(const std::vector& flat) { } void port_breakable_clearForLevel(int32_t levelId) { - std::erase_if(sBrokenObjects, - [levelId](const std::array& e) { return (int32_t)map_getLevel((enum map_e)e[0]) == levelId; }); + std::erase_if(sBrokenObjects, [levelId](const std::array& e) { + return (int32_t)map_getLevel((enum map_e)e[0]) == levelId; + }); } void Anchor::SendPacket_BreakObject(s16 markerId, s32 x, s32 y, s32 z, s32 map, bool replay) { diff --git a/src/port/Network/Anchor/Packets/CollectItem.cpp b/src/port/Network/Anchor/Packets/CollectItem.cpp index 7ae89ad4e..034e8a767 100644 --- a/src/port/Network/Anchor/Packets/CollectItem.cpp +++ b/src/port/Network/Anchor/Packets/CollectItem.cpp @@ -10,9 +10,8 @@ extern "C" { } static const char* const kJiggyLevelNames[10] = { - "Mumbo's Mountain", "Treasure Trove Cove", "Clanker's Cavern", "Bubblegloop Swamp", - "Freezeezy Peak", "Gruntilda's Lair", "Gobi's Valley", "Click Clock Wood", - "Rusty Bucket Bay", "Mad Monster Mansion", + "Mumbo's Mountain", "Treasure Trove Cove", "Clanker's Cavern", "Bubblegloop Swamp", "Freezeezy Peak", + "Gruntilda's Lair", "Gobi's Valley", "Click Clock Wood", "Rusty Bucket Bay", "Mad Monster Mansion", }; /** @@ -57,9 +56,9 @@ void Anchor::HandlePacket_CollectItem(nlohmann::json& payload) { } if (!IS_RANDO && ShouldShowNotifications()) { size_t levelIdx = (size_t)(id - 1) / 10; - const char* where = - levelIdx < (sizeof(kJiggyLevelNames) / sizeof(kJiggyLevelNames[0])) ? kJiggyLevelNames[levelIdx] - : "an unknown level"; + const char* where = levelIdx < (sizeof(kJiggyLevelNames) / sizeof(kJiggyLevelNames[0])) + ? kJiggyLevelNames[levelIdx] + : "an unknown level"; Notification::Emit({ .prefix = GetClientName(payload.value("clientId", 0u)), .message = "collected Jiggy #" + std::to_string(((id - 1) % 10) + 1) + " in " + where, @@ -117,13 +116,27 @@ void Anchor::HandlePacket_CollectItem(nlohmann::json& payload) { case ANCHOR_COLLECTIBLE_ORANGE: { enum item_e item; switch (kind) { - case ANCHOR_COLLECTIBLE_WORM: item = ITEM_22_CATERPILLAR; break; - case ANCHOR_COLLECTIBLE_ACORN: item = ITEM_23_ACORNS; break; - case ANCHOR_COLLECTIBLE_PRESENT_BLUE: item = ITEM_20_BLUE_PRESENT; break; - case ANCHOR_COLLECTIBLE_PRESENT_GREEN: item = ITEM_1F_GREEN_PRESENT; break; - case ANCHOR_COLLECTIBLE_PRESENT_RED: item = ITEM_21_RED_PRESENT; break; - case ANCHOR_COLLECTIBLE_ORANGE: item = ITEM_19_ORANGE; break; - default: item = ITEM_18_GOLD_BULLIONS; break; + case ANCHOR_COLLECTIBLE_WORM: + item = ITEM_22_CATERPILLAR; + break; + case ANCHOR_COLLECTIBLE_ACORN: + item = ITEM_23_ACORNS; + break; + case ANCHOR_COLLECTIBLE_PRESENT_BLUE: + item = ITEM_20_BLUE_PRESENT; + break; + case ANCHOR_COLLECTIBLE_PRESENT_GREEN: + item = ITEM_1F_GREEN_PRESENT; + break; + case ANCHOR_COLLECTIBLE_PRESENT_RED: + item = ITEM_21_RED_PRESENT; + break; + case ANCHOR_COLLECTIBLE_ORANGE: + item = ITEM_19_ORANGE; + break; + default: + item = ITEM_18_GOLD_BULLIONS; + break; } bool noHud = (kind == ANCHOR_COLLECTIBLE_ORANGE) && !sameMap; s32 delta = (id < 0) ? -1 : 1; diff --git a/src/port/Network/Anchor/Packets/EntranceDiscovered.cpp b/src/port/Network/Anchor/Packets/EntranceDiscovered.cpp index 06e41b718..fd4017e11 100644 --- a/src/port/Network/Anchor/Packets/EntranceDiscovered.cpp +++ b/src/port/Network/Anchor/Packets/EntranceDiscovered.cpp @@ -4,7 +4,7 @@ /** * ENTRANCE_DISCOVERED - * + * * currently unimplemented */ diff --git a/src/port/Network/Anchor/Packets/FightEvent.cpp b/src/port/Network/Anchor/Packets/FightEvent.cpp index a5644bf10..79cfbe8ea 100644 --- a/src/port/Network/Anchor/Packets/FightEvent.cpp +++ b/src/port/Network/Anchor/Packets/FightEvent.cpp @@ -68,6 +68,5 @@ void Anchor::HandlePacket_FightEvent(nlohmann::json& payload) { } } - FightSync_ApplyEvent(ev, a, b, hasVectors ? p : nullptr, hasVectors ? v : nullptr, - hasVectors ? w : nullptr); + FightSync_ApplyEvent(ev, a, b, hasVectors ? p : nullptr, hasVectors ? v : nullptr, hasVectors ? w : nullptr); } diff --git a/src/port/Network/Anchor/Packets/FightUpdate.cpp b/src/port/Network/Anchor/Packets/FightUpdate.cpp index 18ab5d99a..d34041a40 100644 --- a/src/port/Network/Anchor/Packets/FightUpdate.cpp +++ b/src/port/Network/Anchor/Packets/FightUpdate.cpp @@ -71,6 +71,5 @@ void Anchor::HandlePacket_FightUpdate(nlohmann::json& payload) { } FightSync_ApplyUpdate(pos.data(), payload.value("yaw", 0.0f), payload.value("st", (s32)1), - payload.value("ph", (s32)0), payload.value("mir", (s32)0), - payload.value("vuln", (s32)0)); + payload.value("ph", (s32)0), payload.value("mir", (s32)0), payload.value("vuln", (s32)0)); } diff --git a/src/port/Network/Anchor/Packets/PlayerSfx.cpp b/src/port/Network/Anchor/Packets/PlayerSfx.cpp index 3ebe1e6c8..29d1ecd27 100644 --- a/src/port/Network/Anchor/Packets/PlayerSfx.cpp +++ b/src/port/Network/Anchor/Packets/PlayerSfx.cpp @@ -27,4 +27,5 @@ void Anchor::SendPacket_PlayerSfx(u16 sfxId) { payload["quiet"] = true; } -void Anchor::HandlePacket_PlayerSfx(nlohmann::json& payload) {} +void Anchor::HandlePacket_PlayerSfx(nlohmann::json& payload) { +} diff --git a/src/port/Network/Anchor/Packets/PlayerUpdate.cpp b/src/port/Network/Anchor/Packets/PlayerUpdate.cpp index 592ab1466..1a9e8c03e 100644 --- a/src/port/Network/Anchor/Packets/PlayerUpdate.cpp +++ b/src/port/Network/Anchor/Packets/PlayerUpdate.cpp @@ -34,8 +34,7 @@ void Anchor::SendToCurrentMapPlayers(nlohmann::json& payload) { void Anchor::SendToCurrentLevelPlayers(nlohmann::json& payload) { enum level_e myLevel = map_getLevel(gsworld_getMap()); for (auto& [clientId, client] : clients) { - if (client.online && client.isSaveLoaded && !client.self && - map_getLevel((enum map_e)client.map) == myLevel) { + if (client.online && client.isSaveLoaded && !client.self && map_getLevel((enum map_e)client.map) == myLevel) { payload["targetClientId"] = clientId; SendJsonToRemote(payload); } diff --git a/src/port/Network/Anchor/Packets/SetFlag.cpp b/src/port/Network/Anchor/Packets/SetFlag.cpp index 37538f00e..658120ec5 100644 --- a/src/port/Network/Anchor/Packets/SetFlag.cpp +++ b/src/port/Network/Anchor/Packets/SetFlag.cpp @@ -18,17 +18,28 @@ extern "C" { static const char* LevelOpenSeenFlagName(s16 flag) { switch (flag) { - case 0x28: return "Mumbo's Mountain"; - case 0x29: return "Treasure Trove Cove"; - case 0x2A: return "Clanker's Cavern"; - case 0x2B: return "Bubblegloop Swamp"; - case 0x2C: return "Freezeezy Peak"; - case 0x2D: return "Gobi's Valley"; - case 0x2E: return "Mad Monster Mansion"; - case 0x2F: return "Rusty Bucket Bay"; - case 0x30: return "Click Clock Wood"; - case FILEPROG_E2_DOOR_OF_GRUNTY_OPEN: return "the door to Gruntilda"; - default: return nullptr; + case 0x28: + return "Mumbo's Mountain"; + case 0x29: + return "Treasure Trove Cove"; + case 0x2A: + return "Clanker's Cavern"; + case 0x2B: + return "Bubblegloop Swamp"; + case 0x2C: + return "Freezeezy Peak"; + case 0x2D: + return "Gobi's Valley"; + case 0x2E: + return "Mad Monster Mansion"; + case 0x2F: + return "Rusty Bucket Bay"; + case 0x30: + return "Click Clock Wood"; + case FILEPROG_E2_DOOR_OF_GRUNTY_OPEN: + return "the door to Gruntilda"; + default: + return nullptr; } } diff --git a/src/port/Network/Anchor/Packets/VileEatResult.cpp b/src/port/Network/Anchor/Packets/VileEatResult.cpp index 04032093e..01e5abd0d 100644 --- a/src/port/Network/Anchor/Packets/VileEatResult.cpp +++ b/src/port/Network/Anchor/Packets/VileEatResult.cpp @@ -11,7 +11,7 @@ extern "C" { /** * VILE_EAT_RESULT * - * Sent by the minigame authority to confirm a successful VILE_EAT_REQUEST. + * Sent by the minigame authority to confirm a successful VILE_EAT_REQUEST. * Catches up on animations and sounds as necessary */ diff --git a/src/port/Network/Anchor/Packets/WaterRise.cpp b/src/port/Network/Anchor/Packets/WaterRise.cpp index 85c0d62ef..566b5f187 100644 --- a/src/port/Network/Anchor/Packets/WaterRise.cpp +++ b/src/port/Network/Anchor/Packets/WaterRise.cpp @@ -34,10 +34,14 @@ static std::map sLairPendingLevel; static int32_t lairLevelForFlag(int32_t levelFlag) { switch (levelFlag) { - case FILEPROG_23_LAIR_WATER_LEVEL_1: return 1; - case FILEPROG_25_LAIR_WATER_LEVEL_2: return 2; - case FILEPROG_27_LAIR_WATER_LEVEL_3: return 3; - default: return 0; + case FILEPROG_23_LAIR_WATER_LEVEL_1: + return 1; + case FILEPROG_25_LAIR_WATER_LEVEL_2: + return 2; + case FILEPROG_27_LAIR_WATER_LEVEL_3: + return 3; + default: + return 0; } } diff --git a/src/port/Rando/ObjectBehavior/ObjectBehavior.cpp b/src/port/Rando/ObjectBehavior/ObjectBehavior.cpp index 97e542402..b18729cae 100644 --- a/src/port/Rando/ObjectBehavior/ObjectBehavior.cpp +++ b/src/port/Rando/ObjectBehavior/ObjectBehavior.cpp @@ -173,8 +173,7 @@ static void EmitCheckNotification(RandoCheckId randoCheckId, const std::string& if (randoSaveCheck.randoItemId == RI_MOLEHILL) { prefix = subject + " learned"; message = abilityNameList[randoSaveCheck.randoCollectionId].c_str(); - } else if (randoSaveCheck.randoItemId == RI_STOP_N_SWOP_EGG || - randoSaveCheck.randoItemId == RI_STOP_N_SWOP_KEY) { + } else if (randoSaveCheck.randoItemId == RI_STOP_N_SWOP_EGG || randoSaveCheck.randoItemId == RI_STOP_N_SWOP_KEY) { int32_t totalsnsItems = Rando::Logic::GetTotalSnsItemsCollected(); prefix = subject + " collected "; prefix += Rando::StaticData::Items[randoSaveCheck.randoItemId].article; diff --git a/src/port/Rando/Rando.h b/src/port/Rando/Rando.h index faf0f56bc..7d5f7ecb4 100644 --- a/src/port/Rando/Rando.h +++ b/src/port/Rando/Rando.h @@ -23,10 +23,8 @@ extern int16_t selectedFileNum; #define RANDO_SAVE_FLAGS gameFile_saveData[selectedFileNum].shipSaveData.randoSaveData.randoSaveFlag // Loaded rando file's seed id, or 0 if none. -#define RANDO_SEED \ - (selectedFileNum == DEFAULT_FILE_NUM \ - ? 0 \ - : gameFile_saveData[selectedFileNum].shipSaveData.randoSaveData.seedId) +#define RANDO_SEED \ + (selectedFileNum == DEFAULT_FILE_NUM ? 0 : gameFile_saveData[selectedFileNum].shipSaveData.randoSaveData.seedId) // #define RANDO_SAVE_ENTRANCES(fileNum) gSaveBuffer.files[fileNum]->shipSaveData.randoSaveData.randoSaveEntrances // #define RANDO_EVENTS gSaveContext.save.shipSaveInfo.rando.randoEvents diff --git a/src/port/UI/LighthouseInputEditorWindow.cpp b/src/port/UI/LighthouseInputEditorWindow.cpp index 1bd9e1977..e577e199f 100644 --- a/src/port/UI/LighthouseInputEditorWindow.cpp +++ b/src/port/UI/LighthouseInputEditorWindow.cpp @@ -14,11 +14,13 @@ #define SCALE_IMGUI_SIZE(value) ((value / 13.0f) * ImGui::GetFontSize()) LighthouseInputEditorWindow::~LighthouseInputEditorWindow() { - auto ignored = Ship::Context::GetRawInstance()->GetControlDeck()->GetConnectedPhysicalDeviceManager()->GetIgnoredInstanceIdsForPort(0); + auto ignored = Ship::Context::GetRawInstance() + ->GetControlDeck() + ->GetConnectedPhysicalDeviceManager() + ->GetIgnoredInstanceIdsForPort(0); if (!ignored.empty()) { Ship::Context::GetRawInstance()->GetConfig()->SetBlock("CVars.gSettings.IgnoredControllers", ignored); - } - else { + } else { Ship::Context::GetRawInstance()->GetConfig()->EraseBlock("CVars.gSettings.IgnoredControllers"); } } @@ -48,11 +50,16 @@ void LighthouseInputEditorWindow::InitElement() { addButtonName(BTN_DLEFT, "D-pad left"); addButtonName(BTN_DRIGHT, "D-pad right"); addButtonName(0, "None"); - if (Ship::Context::GetRawInstance()->GetConfig()->GetNestedJson()["CVars"]["gSettings"].contains("IgnoredControllers")) { - std::vector ignored = Ship::Context::GetRawInstance()->GetConfig()->GetNestedJson()["CVars"]["gSettings"]["IgnoredControllers"]; + if (Ship::Context::GetRawInstance()->GetConfig()->GetNestedJson()["CVars"]["gSettings"].contains( + "IgnoredControllers")) { + std::vector ignored = + Ship::Context::GetRawInstance()->GetConfig()->GetNestedJson()["CVars"]["gSettings"]["IgnoredControllers"]; if (!ignored.empty()) { for (int id : ignored) { - Ship::Context::GetRawInstance()->GetControlDeck()->GetConnectedPhysicalDeviceManager()->IgnoreInstanceIdForPort(0, id); + Ship::Context::GetRawInstance() + ->GetControlDeck() + ->GetConnectedPhysicalDeviceManager() + ->IgnoreInstanceIdForPort(0, id); } } } From a3d6ef595c479063ced37e8bafd441b0de6605ab Mon Sep 17 00:00:00 2001 From: Jeod <47716344+JeodC@users.noreply.github.com> Date: Thu, 23 Jul 2026 22:17:44 -0400 Subject: [PATCH 015/131] Add a differ in Default and Authentic boot logos (#256) --- port/anim/lighthouse_shrug | Bin 0 -> 408 bytes port/anim/lighthouse_walk | Bin 0 -> 288 bytes port/models/lighthouse | Bin 0 -> 5688 bytes port/models/lighthouse_GEO | Bin 0 -> 212 bytes port/models/lighthouse_VTX | Bin 0 -> 7684 bytes port/models/lighthouse_tex_0 | Bin 0 -> 1104 bytes port/models/lighthouse_tex_1 | Bin 0 -> 1104 bytes port/models/lighthouse_tex_2 | Bin 0 -> 1104 bytes port/textures/intro/xylophone | Bin 0 -> 131164 bytes .../{background_decor.c => cutscene_actors.c} | 0 .../Enhancements/Cutscenes/IntroLogos.cpp | 59 ++++++++++++++++++ src/port/ResourceHelpers.cpp | 18 ++++-- src/port/ResourceHelpers.h | 1 + src/port/ShipUtils.cpp | 5 +- src/port/UI/LighthouseMenuSettings.cpp | 4 +- 15 files changed, 77 insertions(+), 10 deletions(-) create mode 100644 port/anim/lighthouse_shrug create mode 100644 port/anim/lighthouse_walk create mode 100644 port/models/lighthouse create mode 100644 port/models/lighthouse_GEO create mode 100644 port/models/lighthouse_VTX create mode 100644 port/models/lighthouse_tex_0 create mode 100644 port/models/lighthouse_tex_1 create mode 100644 port/models/lighthouse_tex_2 create mode 100644 port/textures/intro/xylophone rename src/core2/fx/{background_decor.c => cutscene_actors.c} (100%) create mode 100644 src/port/Enhancements/Cutscenes/IntroLogos.cpp diff --git a/port/anim/lighthouse_shrug b/port/anim/lighthouse_shrug new file mode 100644 index 0000000000000000000000000000000000000000..e751332baea9b383a8971b84151888ef31da6f35 GIT binary patch literal 408 zcmZQzU|{fb^mYPL4Da`?y$8Y|Ht}Eq11C_i76T<1vX1nFdCTLvau7;J#-NenJPasg08i-8%dDv2Wcx}vz>zI$%BF(ih>~Cw6s);?sk0NdoStCxZOWxZ4JBp=H*Mi zeD8hl&+mNz00$53?;*e+mp=JP{j1+=y)^i;aJ7IJ0RE}#{Q7kyW4;7sQr_vQM(p- z{1?^7@xuG}Ki(+*B)&TBmRd*J?FhDJNuKM@=Kib3H#!b| zFQD&~e8GU@uTm1s;xCKG72=Te`5(oXT95L7Ww*fRyi*DUy?fVF%~xL`->C6s!u!~6 z3br_}cH4rTJNr8vpR4Te1NC2}*ZBGjjq{W#dCSx#udJ~SY^49)%f7S{-j77;Uef5| zG>|rC1!LZ)cuuf7$MJ}DbJ!l5PWdC%4MEeOc}z<%%ezjNf2A&Zg5saP_@`fzcq|J_ zU95!cw>8PTk<`H`uJgJh#+j(Wa$V}6)WcST^KLU~(|D)J*ln^MI&JYw^iPUs;RV^g zOCC*4W-6%#T$fB;>XFIlnyi;&bG-Rd{{zRT?^dL)gi==`$uD6^>bvBbIIPk0wW{b> z6a8wd>zCzMLahHdQJT!~d(A|!vGzEnc`(1Jc`|!!6dzh|9KVCG*d37;7 zD|{r7zQFgGf0m?fd%54ReihL_j5z;BRmLKP2c%UCwL|?Z$(xSFe&z^|^&GPIczylP z`G4mBm5BGXGRCK?G3URyF4&MfI3u_|ew}utuFcMM$l==C+^dUq1Wf}XaHWa9z z+I@R!ac*&xzb{N;Lz?%m@b>_oc~{GCX?ZVNwa5Bcw&r%>;mqk3ol3zDC8;bDgG zQB!!BCFc@Zo_6G1!WAAC6e;nhrGT+4=M*__DRX{~q#rJ6lxWf#^Ox~BxQM!|3-422 z%J%m>gmj;^a@agipV?JcuivVPwc-sxJx z$5`KNofn4Jf%81D^^WJEv3*?YdNaFbc9#6JZL#y`5}hCX_~apFp#1#ojdRxq%5Jc0 z%%3!0*)>1+(sY)&-NE|?%j{-==Qb>J_+Z_(SZ24w`eU=q$2gGM!iPEhAaz_GXW9U% z>#nT&DaT?-ttxd+NHPY{W88kEbqdTLbG|L|FOL9!{!lr z2X+wI_lsw)^v$8~D|ri8G`|1Do9g?03$~8PTfxr1r=AanzOUqIJla#=KY;I}e*F?m zjmSHJPR`IEmwL)7FXpD%Gp~NW1RnfQJKF0W{(k=Q!@ur(0k*?i$EN#_fA;OXef?PP WWt8=Ek1jmFcz*uWH|@(uQ2qz=^ZoV! literal 0 HcmV?d00001 diff --git a/port/models/lighthouse_GEO b/port/models/lighthouse_GEO new file mode 100644 index 0000000000000000000000000000000000000000..166eeaa4ffea73290c9b3fece13e129f5d9f9b32 GIT binary patch literal 212 zcmZQzU|?|aaqVIq`=i+w43X#-0wRnsksnf!S*EyUOIU~l1f}iD`e}Uhr>m`rZAIIww?B|GmiS}{4>#@IP3HRi2z9xWwS$Kc) zIN!6u2MVtukN3+A@Gepyp}xPzw!Q`=+^tM=zPB9Wk1h>=JTnY+l03U zxA;eTnuLll6X{>c~E!{Q=l7 z6n>fZ$6!A}b!2~)_M2dTtMDT255b=Kr+utHb-YU)Zv)2Dc=vF;c>DtxpZhJEPcQvn zga7N2k8b+E3w!R@$UaZ|NA_K`AB_073a_Jm>faFgH_(3o^0Qa% zqw$7vytx?fRpGVtza94PsE+K1(7p-w?+dS?{Y=<*s*daj(f(1`50U&-(f(8STQ%+D z{q{N6=w8D3y>(r>|4t;0PS58C>QhOR+ak|zxGLKj=XaBn^Srl?dOG}fK^JRjACDK? zPl3P0t5{3_rSLx~x`zG>!9Re$SVO)7T+Zua75M|;gH@B~z~y}C?N2@re41+VJHQ`= z9$i5`5_~aq!IO^ye@Hd?5a{nfzu~AaVEs#=yGyk1MSLDsP5w6Yz0h5kso#P9T-CJS z0zOi7k$eaEaOln=`5(aLJn!lu-wK{rO}-mkzNg*Y6aIq`k3z_A4!lM+`3&&MqCUmcpzlilp zz6v3qe*@R=eaPQG!S51&nd83>-XJ>UZ$J1@)#N+Ddt^N!e|x~st0q4PenfQ0Upx4F zs>#!Qg#4xXNb|SKZx#Exv-*CXPFDHXL^n{!=Tm%sO?0dLn_^!}`}jOs0DeYz4S9V2 zECgqM$m8>77P!W%KlzR9ZwfPhkH0@@K03(Le1z{!4eCYKyH<}~U+^GP1pyR*QVPx83l9RbdKk;nD!jqHn9FY`(N zxE?+V&U})`_3$om=94_Ghj)N8pX6~p+y>5klE?LMnvV|h?qs9?neNZG^!@8hHu$xw z3#u#J1~1>2U5@%7?3kH@Vx3W|HI(&eJps+=Mea3Rnvbf_&DgX738mgkAb%NZULA4 zzFfu^iGNs+jQ_*PznsVGKb*Ar$6!CKg6oaru@muG0KT$<@i~?pXa12z`HSP#2Yabk zpK-L0;}^%P6VJaH_7?9rUhNof7Ryf|Ll;D0-~%|DLUO5}&%AI5hw@+bAT<7!wPcfeC2g~0t!25}P$j_7D{h=*? ztHDp6M?7oYVgnc3qH^KJL?y+et_KiJL?y+{(;>3JL?Cs{(#*2JL?Cs z{(wB|@3`KqKOnb$t`PcxtUn;P{;d%Dfvi6uxBkugfvi6uxBkugfvi6uxBkugfg9Op z{R92ee1!Ka%}3}L()TfN>mM7t>7Ty8!TwKpclY3Tcj!;7AAPPs`;B1#!EZx>@w9$+ z%mwmSz((PWxaR`7^~2*oCO-r&XV{{T$*q5G?<1F9N$$H&_mNxw-Q>vSuIc;u{WA39 zc77HT)(4}}4NAXX2=$75D^w@^-r9LusCYx`>w4Jh_chq3{eR$9;PU;p@oYZkUj?Q- zjBoR^`B?ql>O1|fanoV-WFET3IcWB8d4HuOdLa5A>F-*h#op@s9PHn8FF><@%Ylow z`abVEy>l(l?BDY4N=dZU_pRWwVQ>9dE4XN@?{nZk#`COy%Ylow`aYj@`gNF}^=J9y zN=dZU@2%i#-F#^FXRY9(t$xpe&vebu?9X!GqOE?(5%jMO*!z17DBlS$~!T7oEnt6vey5cw7FO67DzKFD;d(xu04px&PAr67Cahe>5fJ zmy)OaBZ+ullc;&lfqLellLx zUo@*e3xDayFn`t7pTJ*r8lP~VZT*eiZTip0 z>~Hlq)_2|WkUx!AR)15c^9%8``rG20u0O=r>T8Q{y8aMPtFJA-)=xm|{`nEsH7^TW!XHwk)NneGSsv1R&RjMrD@|6fz91O5O2 literal 0 HcmV?d00001 diff --git a/port/models/lighthouse_tex_0 b/port/models/lighthouse_tex_0 new file mode 100644 index 0000000000000000000000000000000000000000..dd7712dbb22e30163152cb041c5c395f17712929 GIT binary patch literal 1104 zcma(~$&%t$5ai(Sclc-K?28ZnqnUwjV44P+O$b_I*9J%kNg$zp7h-D|(ZEdj?q6^* zwj+FWzE|}svr?&4DwX>E!*9RBllpT>T<&$B|1W+9<1hbI>Zerdw2xiy?Rq{RPhY>^ z4!h&=a{c4m>2SIxr#LvC-!|JY*e91OoZGj{*VE~oyk9O!@_xJQT`xSu+s%4^x_!SU zZ-?Y|0sn5dPZDq?JI6GWT^z6D-W^OwQw_s5RL!ysBk*0{cWuLP z+;tRfcl)hstyU}5Q01j+IhG%U(b~5xUDaKG9YK;}X}YFbmbTI?$Fw~^3?t7rG|h5D z&+!~lQB+ki?%}GcYHkoj>%g-N-S*?aGE{LPtyD#^99>i3PnPGou4NjwY5I|C$ihNd zYPu>Lrn*{6lDLEnIJ#@;wxcfjxuz-FY9X#vc_E78d@e0zQ4kbU2bV0)L}?)@i@6}L zmi&z4d43@;W-KSk@^T?bf*|vvAo9GVECqJT@`5NU!gMl&h}o2#bAmEvS&o}Q20t0I z+>DzGEHmXLk>@CK%r{C-LJ9xL>g&l@)OT|*D1R`jFLZR>kb;onz2~Ys-hx(My=kj0jfX8e$ zpUc6J%V+NmG_WGl2BNLnfU`r$2uD1oso%zX9}L_Cx;* D4uaQS literal 0 HcmV?d00001 diff --git a/port/models/lighthouse_tex_1 b/port/models/lighthouse_tex_1 new file mode 100644 index 0000000000000000000000000000000000000000..4313a78346eb58bdee5df841b6c09ebfbc6faf21 GIT binary patch literal 1104 zcma)*-%nCu7{{NB*5A=>i#1$PcWqsCXG1Nj)r}LT7kbf#OGVi9#%yUqZc4~fTdcS+ z-AteqHf&Ct4iW`Z87Bn=M*I-TBXHiA-uE0mqIS`;`HrbVIrLllslX>E0$=LLT|R83_trhF!Ork-OnKl>!I;VAki$GOn#ccV;VU=U6@&-X|1 z$){F}9NPUwoObJUZsK&gKD0IZ*gR2B9m4yb{(jH?8P1p$Z@y}Hf%*9Iay-vlB7Pqt z-1N;Lx&D?2%;$1>QhusGRI2bx{uqtW%DK(CmbLA=v7)HzbEcO z$GWgDl#BDnxy9~=PrKP^1+=W3@c5|gN?(ZR!5O!<*^yx9mC)!Z3hL?G&sCsZqlP5x zYOOm{@HB#Ip01`4?3@ysyd)n*tg0UGLDBaN9ytGq28j8E;LwwyV1e_u!M!hZbV6_| zEufgrVSM22QCTC1^J}2Skv-w-9Z)%u!c?Bxp1@o{OAOu1qmrqQm^kq3Brs3-Ze#MlX?##KZyM%v2R!ITZO&XIMQfq3r=_g=y!Q{{^aG8omGk literal 0 HcmV?d00001 diff --git a/port/models/lighthouse_tex_2 b/port/models/lighthouse_tex_2 new file mode 100644 index 0000000000000000000000000000000000000000..5a1a396cd86cdba73b1dfd59c83a625eb3da2fc1 GIT binary patch literal 1104 zcmb_b$!)|i4Aeng)UhpWGkNEeN199vDJ3nWg$%W}Y}pR52tq)r1NGSp_ z1GIHMrkqQyrDRUQPXMGt;!@iU(Q3({*aHmtluOSF;#M<9Z$}@ReB@nP04ca}1OxUd zEdW$l2(4B?AwLH-(e-p RFi!tGU9=vqo4)_~ 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 +#include +#include +#include + +#include "port/Enhancements/Events/Hooks/Events.h" +#include "port/ShipInit.hpp" +#include "port/UI/cvar_prefixes.h" +#include "port/UI/enhancementTypes.h" + +#include + +extern "C" { +#include "enums.h" +int port_getBootSequence(void); +void ResourceMgr_RegisterAssetOverride(uint32_t assetId, const char* customPath); +} + +namespace { + +constexpr const char* kXylophoneNintendoTex = "assets/model/ASSET_3B1_UNNAMED_tex_6"; +constexpr const char* kXylophoneReplacementTex = "textures/intro/xylophone"; +constexpr const char* kIntroCubeReplacementModel = "models/lighthouse"; +constexpr uint32_t kAssetNintendoWalkAnim = 0x8F; +constexpr uint32_t kAssetNintendoShrugAnim = 0x90; +constexpr const char* kIntroCubeWalkAnim = "anim/lighthouse_walk"; +constexpr const char* kIntroCubeShrugAnim = "anim/lighthouse_shrug"; + +bool bootSequenceIsDefault() { + return port_getBootSequence() == BOOTSEQUENCE_DEFAULT; +} + +void stripXylophoneNintendoLogo() { + auto& rm = *Ship::Context::GetRawInstance()->GetResourceManager(); + if (!rm.GetArchiveManager()->HasFile(kXylophoneReplacementTex)) { + return; + } + auto replacement = rm.LoadResource(kXylophoneReplacementTex); + if (replacement != nullptr && std::static_pointer_cast(replacement)->ImageData != nullptr) { + rm.CacheExternalResource(kXylophoneNintendoTex, replacement); + } +} + +} // namespace + +void RegisterIntroLogos_Init() { + COND_HOOK(OnMapLoad, EVENT_PRIORITY_NORMAL, bootSequenceIsDefault(), [](IEvent* event) { + auto* ev = (OnMapLoad*)event; + ResourceMgr_RegisterAssetOverride(ASSET_3A6_MODEL_INTRO_N64_CUBE, kIntroCubeReplacementModel); + ResourceMgr_RegisterAssetOverride(kAssetNintendoWalkAnim, kIntroCubeWalkAnim); + ResourceMgr_RegisterAssetOverride(kAssetNintendoShrugAnim, kIntroCubeShrugAnim); + + if (ev->nextMap == MAP_1E_CS_START_NINTENDO || ev->nextMap == MAP_1F_CS_START_RAREWARE) { + stripXylophoneNintendoLogo(); + } + }); +} + +static RegisterShipInitFunc introLogosInit(RegisterIntroLogos_Init, { CVAR_SETTING("BootSequence") }); diff --git a/src/port/ResourceHelpers.cpp b/src/port/ResourceHelpers.cpp index 933b692ac..7e16a1567 100644 --- a/src/port/ResourceHelpers.cpp +++ b/src/port/ResourceHelpers.cpp @@ -303,14 +303,20 @@ extern "C" size_t ResourceMgr_GetResourceSize(uint32_t assetId) { return 0; } -// On N64, sprites and models were raw binary blobs that could be type-punned. -// On PC, they're separate resource types from different importers. Actors with sprite -// assets can be spawned as "model" props (unk8_1=1), causing collision code to call -// marker_loadModelBin which reinterprets sprite data as BKModelBin. This helper lets -// decomp code detect and skip the model path for sprite assets. +// Force an asset id to resolve to a custom resource shipped at `customPath`. +extern "C" void ResourceMgr_RegisterAssetOverride(uint32_t assetId, const char* customPath) { + auto res = GetResourceByName(customPath); + if (res != nullptr && res->GetRawPointer() != nullptr) { + sResourceRefCache[assetId] = res; + } +} + +// Actors with sprite assets can be spawned as "model" props (unk8_1=1), causing collision +// code to call marker_loadModelBin which reinterprets sprite data as BKModelBin. This helper +// lets decomp code detect and skip the model path for sprite assets. extern "C" int ResourceMgr_IsModelAsset(uint32_t assetId) { if (auto it = sResourceRefCache.find(assetId); it != sResourceRefCache.end()) { - return it->second->GetInitData()->Type == 0x424B4D4F; // Torch::ResourceType::BKModel + return it->second->GetInitData()->Type == 0x424B4D4F; } return 0; } diff --git a/src/port/ResourceHelpers.h b/src/port/ResourceHelpers.h index 1fb9957a8..532b452a2 100644 --- a/src/port/ResourceHelpers.h +++ b/src/port/ResourceHelpers.h @@ -14,6 +14,7 @@ extern "C" { #include char* ResourceMgr_LoadByAssetId(uint32_t assetId); +void ResourceMgr_RegisterAssetOverride(uint32_t assetId, const char* customPath); size_t ResourceMgr_GetResourceSize(uint32_t assetId); int ResourceMgr_IsModelAsset(uint32_t assetId); int ResourceMgr_GetDialogLanguageCount(void); diff --git a/src/port/ShipUtils.cpp b/src/port/ShipUtils.cpp index a0d6ebd23..77116aa28 100644 --- a/src/port/ShipUtils.cpp +++ b/src/port/ShipUtils.cpp @@ -10,6 +10,7 @@ #include #include #include "UI/cvar_prefixes.h" +#include "UI/enhancementTypes.h" #include "fast/Fast3dGui.h" #ifdef _WIN32 #include @@ -296,8 +297,8 @@ int port_getBootSequence(void) { // Romhacks always boot to file select; their intros aren't compatible with the // vanilla cutscene/demo path. if (port_isRomhack()) - return 2; // BOOTSEQUENCE_FILESELECT - return CVarGetInteger(CVAR_SETTING("BootSequence"), 0); + return BOOTSEQUENCE_FILESELECT; + return CVarGetInteger(CVAR_SETTING("BootSequence"), BOOTSEQUENCE_DEFAULT); } float port_getRumbleScale(void) { diff --git a/src/port/UI/LighthouseMenuSettings.cpp b/src/port/UI/LighthouseMenuSettings.cpp index f70c67990..e4bbe7847 100644 --- a/src/port/UI/LighthouseMenuSettings.cpp +++ b/src/port/UI/LighthouseMenuSettings.cpp @@ -156,8 +156,8 @@ void LighthouseMenu::AddMenuSettings() { .ComponentAlignment(ComponentAlignments::Right) .ComboMap(bootSequenceLabels) .Tooltip("Configure what happens when starting or resetting the game.\n\n" - "Default: LUS logo -> N64 logo\n" - "Authentic: N64 logo only\n" + "Default: Replace the N64 branding with LUS branding\n" + "Authentic: Keep the authentic N64 branding\n" "File Select: Skip to file select menu")); path.column = SECTION_COLUMN_2; From 7eb554a3fa40ae3d65b02284040fe9d7db02ad78 Mon Sep 17 00:00:00 2001 From: Jeod <47716344+JeodC@users.noreply.github.com> Date: Fri, 24 Jul 2026 14:26:20 -0400 Subject: [PATCH 016/131] Code cleanup (#252) * Code cleanup: ResourceMgr region dialog checks * Code cleanup: consolidate port functions for dialog fonts * Code cleanup: duplicate declarations for romhacks and lus/port type changes * Code cleanup: Remove declarations with no callers * Code cleanup: Remove duplicate declarations * Stop functions.h pulling C++ headers into extern "C" * Guard decomp headers with extern "C", drop redundant wrappers * Restore ShipUtils.h includes lost when functions.h dropped it * Fix spawn queue not scaling with draw distance setting * Remove more dead code, fixups and comment clarity * Fix orbit camers getting stuck on rare occasions * Resolve more extern "C" cleanups after anchor rebase * Polish Cheats (Levitate, Transforms) * Adjust camera orbit core smoothing when player is on uneven terrain * Clang format --- Torch | 2 +- include/bool.h | 2 + include/bs_funcs.h | 8 ++ include/core1/core1.h | 8 ++ include/core1/main.h | 8 ++ include/core1/sns.h | 8 ++ include/core1/sprite.h | 8 ++ include/core1/viewport.h | 8 ++ include/core2/ba/model.h | 8 ++ include/core2/ba/physics.h | 10 ++ include/core2/bonetransform.h | 8 ++ include/core2/commonParticle.h | 8 ++ include/core2/particle.h | 8 ++ include/core2/statetimer.h | 8 ++ include/functions.h | 21 ++-- include/gc/gctransition.h | 8 ++ include/model.h | 8 ++ include/structs.h | 8 ++ include/variables.h | 8 ++ libultraship | 2 +- src/core1/audio_instruments.c | 1 + src/core1/display_list.c | 1 + src/core1/init.c | 1 + src/core1/io/pfsmanager.c | 1 + src/core2/anim/anim_buffer.c | 1 + src/core2/anim/anim_defrag.c | 1 + src/core2/dialog/binload.c | 3 +- src/core2/font/print.c | 34 +++--- src/core2/frame/auxbuffer.c | 2 +- src/core2/map/cutscene_skip.c | 1 - src/core2/sfx/source.c | 1 + src/core2/spawn_queue.c | 35 ++++-- src/core2/vtx/transform.c | 1 + src/port/DevTools/OcclusionDebug.cpp | 2 - src/port/DevTools/RemoteCollectSim.cpp | 2 +- src/port/Engine.cpp | 15 +-- src/port/Enhancements/Backports/EggAim.cpp | 2 - src/port/Enhancements/Backports/FastSwim.cpp | 2 - src/port/Enhancements/Backports/Honeyback.cpp | 2 - .../Backports/TooieJiggyDance.cpp | 3 +- .../Enhancements/Camera/OrbitCameraCore.cpp | 102 ++++++++++++------ .../Enhancements/Camera/OrbitCameraCore.h | 29 ++--- src/port/Enhancements/Cheats/Cheats.cpp | 29 +++-- src/port/Enhancements/Fixes/GameFixes.cpp | 2 +- .../Gameplay/EasierBoggyRaces.cpp | 2 - .../Enhancements/Gameplay/FurnaceFunMoves.cpp | 2 - .../Enhancements/Gameplay/SkipSMTutorial.cpp | 2 - .../Gameplay/WaterPyramidTimer.cpp | 2 - .../Restorations/ReturnToLair.cpp | 6 +- .../Enhancements/Retention/JinjoRetention.cpp | 2 - .../Enhancements/Retention/NoteRetention.cpp | 2 +- src/port/Enhancements/Retention/Retention.cpp | 2 +- src/port/Enhancements/Retention/WormSync.cpp | 2 +- .../Enhancements/Trackers/DisplayOverlay.cpp | 6 -- src/port/GameStatus.cpp | 15 +-- src/port/Localization/Localization.cpp | 15 +-- src/port/Network/Anchor/Anchor.cpp | 2 - src/port/Network/Anchor/AnchorRoomWindow.cpp | 2 - src/port/Network/Anchor/Authority.cpp | 2 - src/port/Network/Anchor/DummyPlayer.cpp | 2 +- src/port/Network/Anchor/DummyPlayer.h | 2 - src/port/Network/Anchor/HookHandlers.cpp | 4 +- .../Network/Anchor/Packets/AllClientState.cpp | 2 - .../Network/Anchor/Packets/BreakObject.cpp | 2 - .../Network/Anchor/Packets/CarryThrow.cpp | 2 - .../Network/Anchor/Packets/CollectItem.cpp | 2 - .../Network/Anchor/Packets/DamagePlayer.cpp | 2 - src/port/Network/Anchor/Packets/EggToll.cpp | 2 - .../Network/Anchor/Packets/FightEvent.cpp | 2 +- .../Network/Anchor/Packets/FightState.cpp | 2 +- .../Network/Anchor/Packets/FightUpdate.cpp | 2 +- src/port/Network/Anchor/Packets/GiveItem.cpp | 2 - src/port/Network/Anchor/Packets/HutSmash.cpp | 2 - .../Network/Anchor/Packets/JiggyCrane.cpp | 2 - src/port/Network/Anchor/Packets/MapLoad.cpp | 2 - src/port/Network/Anchor/Packets/PlayerSfx.cpp | 2 - .../Network/Anchor/Packets/PlayerUpdate.cpp | 5 +- .../Network/Anchor/Packets/PuzzleStep.cpp | 2 +- .../Network/Anchor/Packets/ScopedFlag.cpp | 2 +- .../Network/Anchor/Packets/ScopedState.cpp | 2 +- .../Network/Anchor/Packets/SetAbility.cpp | 2 - .../Network/Anchor/Packets/SetCheckStatus.cpp | 2 +- src/port/Network/Anchor/Packets/SetFlag.cpp | 2 - .../Network/Anchor/Packets/SetItemCount.cpp | 2 +- .../Network/Anchor/Packets/SpawnJiggy.cpp | 2 - .../Network/Anchor/Packets/TeleportTo.cpp | 5 - src/port/Network/Anchor/Packets/UnsetFlag.cpp | 2 - .../Anchor/Packets/UpdateClientState.cpp | 2 - .../Anchor/Packets/UpdateRoomState.cpp | 2 - .../Anchor/Packets/UpdateTeamState.cpp | 2 - .../Network/Anchor/Packets/VileEatRequest.cpp | 2 - .../Network/Anchor/Packets/VileEatResult.cpp | 2 - .../Network/Anchor/Packets/VileGameState.cpp | 2 - .../Network/Anchor/Packets/VileHoleState.cpp | 2 - .../Network/Anchor/Packets/VileUpdate.cpp | 2 - src/port/Network/Anchor/Packets/WaterRise.cpp | 2 +- src/port/Network/Anchor/VileSync.c | 1 - src/port/Patches/CameraPatches.cpp | 4 - src/port/Patches/FramebufferPatches.cpp | 9 +- src/port/Patches/GraphicsPatches.cpp | 11 +- src/port/Patches/MirrorPatches.cpp | 2 +- src/port/Patches/Patches.h | 8 +- src/port/Patches/SpritePatches.cpp | 11 +- src/port/Patches/TransitionPatches.cpp | 2 - src/port/Rando/CustomObject/CustomObject.cpp | 3 +- src/port/Rando/LighthouseMenuRando.cpp | 2 - src/port/Rando/Logic/GenerateSaveData.cpp | 2 - src/port/Rando/Logic/Logic.h | 19 +--- src/port/Rando/MiscBehavior/OnFileLoad.cpp | 4 - src/port/Rando/MiscBehavior/WorldState.cpp | 12 +-- src/port/Rando/ObjectBehavior/Molehill.cpp | 8 -- src/port/Rando/ObjectBehavior/MusicNote.cpp | 4 - .../Rando/ObjectBehavior/ObjectBehavior.cpp | 7 -- src/port/Rando/ObjectBehavior/Switch.cpp | 6 -- src/port/Rando/StaticData/Checks.cpp | 5 - src/port/Resource/Alt/AltDialogFont.cpp | 3 +- src/port/Resource/Importers/ModelFactory.cpp | 6 -- src/port/Resource/Type/Sprite.cpp | 21 ---- src/port/ResourceHelpers.cpp | 9 +- src/port/ResourceHelpers.h | 1 + src/port/Romhack/RomhackConfig.cpp | 33 ------ src/port/Save/SaveManager.cpp | 2 - src/port/ShipUtils.cpp | 1 - src/port/UI/DeveloperTools/GameplayTools.cpp | 17 --- src/port/UI/DeveloperTools/SaveEditor.cpp | 10 -- src/port/UI/LighthouseMenuDevTools.cpp | 2 - src/port/UI/LighthouseMenuEnhancements.cpp | 2 +- src/port/UI/LighthouseMenuNetwork.cpp | 2 - src/port/UI/LighthouseMenuSettings.cpp | 2 - src/port/UI/Menu.cpp | 1 - .../Gameplay/DisableSnackerSpawn.cpp | 2 - .../enhancements/Gameplay/EasierMrVile.cpp | 2 - 132 files changed, 364 insertions(+), 448 deletions(-) diff --git a/Torch b/Torch index 024b7877b..75956acb7 160000 --- a/Torch +++ b/Torch @@ -1 +1 @@ -Subproject commit 024b7877b4f26e08f48ef1e59d8d7f98d657c842 +Subproject commit 75956acb7c2210427d3ac4cc7213421f6e1c490c diff --git a/include/bool.h b/include/bool.h index 51ec6ef6e..6283d150d 100644 --- a/include/bool.h +++ b/include/bool.h @@ -3,8 +3,10 @@ #include +#ifndef __cplusplus #define NOT(boolean) ((boolean) ^ 1) #define BOOL(boolean) ((boolean) ? true : false) +#endif #if 0 #include diff --git a/include/bs_funcs.h b/include/bs_funcs.h index 717d3099d..e45e808a6 100644 --- a/include/bs_funcs.h +++ b/include/bs_funcs.h @@ -1,6 +1,10 @@ #ifndef __BS_FUNCS__ #define __BS_FUNCS__ +#ifdef __cplusplus +extern "C" { +#endif + //interrupt void func_802B5350(void); void func_80296608(void); @@ -712,4 +716,8 @@ void bsDroneEnter_end(void); void bsDroneVanish_init(void); void bsDroneVanish_update(void); void bsDroneVanish_end(void); +#ifdef __cplusplus +} +#endif + #endif diff --git a/include/core1/core1.h b/include/core1/core1.h index f63707888..8386436ba 100644 --- a/include/core1/core1.h +++ b/include/core1/core1.h @@ -23,6 +23,10 @@ #include "core1/viewport.h" #include "core1/vimgr.h" +#ifdef __cplusplus +extern "C" { +#endif + /* need to sort out in individual header files */ void* malloc(size_t size); @@ -201,4 +205,8 @@ void defragManager_init(void); void defragManager_free(void); void defragManager_setPriority(OSPri pri); +#ifdef __cplusplus +} +#endif + #endif diff --git a/include/core1/main.h b/include/core1/main.h index 4774cb689..b3bed72e4 100644 --- a/include/core1/main.h +++ b/include/core1/main.h @@ -3,6 +3,10 @@ #include #include "enums.h" +#ifdef __cplusplus +extern "C" { +#endif + void core1_main(s32 arg0); void func_8023DA74(void); void func_8023DA9C(s32 arg0); @@ -25,4 +29,8 @@ void mainThread_create(void); OSThread *mainThread_get(void); void disableInput_set(void); +#ifdef __cplusplus +} +#endif + #endif diff --git a/include/core1/sns.h b/include/core1/sns.h index 11301e48f..321bb9d95 100644 --- a/include/core1/sns.h +++ b/include/core1/sns.h @@ -1,6 +1,10 @@ #ifndef BANJO_KAZOOIE_CORE1_SNS_H #define BANJO_KAZOOIE_CORE1_SNS_H +#ifdef __cplusplus +extern "C" { +#endif + /** * sns sets */ @@ -133,4 +137,8 @@ void sns_stub (void); void snspayload_append_key_to_outgoing_payload (struct SnsPayload *payload, s32 key); void snspayload_calc_checksum (struct SnsPayload *payload); +#ifdef __cplusplus +} +#endif + #endif diff --git a/include/core1/sprite.h b/include/core1/sprite.h index d78f57896..1ae8be8a6 100644 --- a/include/core1/sprite.h +++ b/include/core1/sprite.h @@ -1,6 +1,10 @@ #ifndef BANJO_KAZOOIE_CORE1_SPRITE_H #define BANJO_KAZOOIE_CORE1_SPRITE_H +#ifdef __cplusplus +extern "C" { +#endif + u32 sprite_getUnk8(BKSprite *self); u32 sprite_getUnkA(BKSprite *self); u32 sprite_getUnk6(BKSprite *self); @@ -8,4 +12,8 @@ u32 sprite_getUnk4(BKSprite *self); s32 sprite_getFrameCount(BKSprite *self); BKSpriteFrame *sprite_getFramePtr(BKSprite *self, u32 frame_id); +#ifdef __cplusplus +} +#endif + #endif diff --git a/include/core1/viewport.h b/include/core1/viewport.h index 64e6daf61..2e9877061 100644 --- a/include/core1/viewport.h +++ b/include/core1/viewport.h @@ -1,6 +1,10 @@ #ifndef BANJO_KAZOOIE_CORE1_VIEWPORT_H #define BANJO_KAZOOIE_CORE1_VIEWPORT_H +#ifdef __cplusplus +extern "C" { +#endif + void viewport_moveAlongZAxis(f32 offset); f32 viewport_getDistance(f32 arg0[3]); void viewport_getLookbk_vector(f32 arg0[3]); @@ -50,4 +54,8 @@ void viewport_backupState(void); void viewport_restoreState(void); void viewport_adjustPointDistance(f32 pos[3], f32 distance); +#ifdef __cplusplus +} +#endif + #endif diff --git a/include/core2/ba/model.h b/include/core2/ba/model.h index 47324d8c4..2a22a4c20 100644 --- a/include/core2/ba/model.h +++ b/include/core2/ba/model.h @@ -1,6 +1,10 @@ #ifndef _PLAYER_MODEL_H_ #define _PLAYER_MODEL_H_ +#ifdef __cplusplus +extern "C" { +#endif + typedef enum player_model_direction_e { PLAYER_MODEL_DIR_NONE = 0, PLAYER_MODEL_DIR_BANJO = 1, @@ -15,4 +19,8 @@ void baModel_setYDisplacement(f32); void baModel_8029217C(f32); void baModel_setVisible(s32 arg0); +#ifdef __cplusplus +} +#endif + #endif diff --git a/include/core2/ba/physics.h b/include/core2/ba/physics.h index e2d49e0c7..c29a820a9 100644 --- a/include/core2/ba/physics.h +++ b/include/core2/ba/physics.h @@ -3,6 +3,11 @@ #include #include "libultraship/libultra/types.h" + +#ifdef __cplusplus +extern "C" { +#endif + typedef enum ba_physics_type_e{ BA_PHYSICS_NONE, BA_PHYSICS_UNK1, @@ -50,4 +55,9 @@ void baphysics_set_gravity(f32); void baphysics_set_terminal_velocity(f32); int baphysics_is_slower_than(f32); int baphysics_goto_done(void); + +#ifdef __cplusplus +} +#endif + #endif diff --git a/include/core2/bonetransform.h b/include/core2/bonetransform.h index dfd76f140..80be38b91 100644 --- a/include/core2/bonetransform.h +++ b/include/core2/bonetransform.h @@ -2,6 +2,10 @@ #define _BONE_TRANSFORMATION_H_ #include +#ifdef __cplusplus +extern "C" { +#endif + typedef struct { f32 unk0[4]; f32 scale[3]; @@ -16,4 +20,8 @@ typedef struct bone_transform_list_s{ BoneTransformList *boneTransformList_new(void); BoneTransformList *boneTransformList_defrag(BoneTransformList *self); void boneTransformList_free(BoneTransformList *self); +#ifdef __cplusplus +} +#endif + #endif diff --git a/include/core2/commonParticle.h b/include/core2/commonParticle.h index bf6ded7a8..2283965b3 100644 --- a/include/core2/commonParticle.h +++ b/include/core2/commonParticle.h @@ -7,6 +7,10 @@ #include "prop.h" #include "core2/anim/sprite.h" +#ifdef __cplusplus +extern "C" { +#endif + #define PARTICLE_LIMIT 40 #ifndef FUNCUNK40_DEFINED @@ -76,4 +80,8 @@ void func_80344E3C(u8, f32[3]); void func_80344D94(u8, f32[3]); void func_80344EE4(u8, f32, f32); +#ifdef __cplusplus +} +#endif + #endif diff --git a/include/core2/particle.h b/include/core2/particle.h index 8ad811a4a..28487e577 100644 --- a/include/core2/particle.h +++ b/include/core2/particle.h @@ -3,6 +3,10 @@ #include "structs.h" +#ifdef __cplusplus +extern "C" { +#endif + #define PART_EMIT_NO_OPA 0x20 #define PART_EMIT_NO_DEPTH 0x10 #define PART_EMIT_NO_LOOP 0x8 @@ -24,4 +28,8 @@ void func_802EFF9C(ParticleEmitter *self, f32); void partEmitMgr_freeEmitter(ParticleEmitter *self); +#ifdef __cplusplus +} +#endif + #endif diff --git a/include/core2/statetimer.h b/include/core2/statetimer.h index 0d15969f0..3863783e8 100644 --- a/include/core2/statetimer.h +++ b/include/core2/statetimer.h @@ -4,6 +4,10 @@ #include #include "structs.h" +#ifdef __cplusplus +extern "C" { +#endif + enum state_timer_e{ STATE_TIMER_0_UNKNOWN, STATE_TIMER_1_THROW = 1, @@ -24,4 +28,8 @@ void stateTimer_init(void); void stateTimer_clear(enum state_timer_e timer_id); void stateTimer_set(enum state_timer_e timer_id, f32 value); void stateTimer_update(void); +#ifdef __cplusplus +} +#endif + #endif diff --git a/include/functions.h b/include/functions.h index 6852845e6..d184fa8c6 100644 --- a/include/functions.h +++ b/include/functions.h @@ -2,10 +2,18 @@ #define FUNCTIONS_H #include +#include "string.h" +#include "math.h" + +#include "port/UI/cvar_prefixes.h" +#include "port/Enhancements/Events/Hooks/Events.h" + +#ifdef __cplusplus +extern "C" { +#endif #include "enums.h" #include "structs.h" -#include "string.h" #include "rand.h" #include "prop.h" @@ -25,18 +33,11 @@ #include "core2/ba/timer.h" #include "core2/nc/camera.h" -#include "port/ShipUtils.h" -#include "port/UI/cvar_prefixes.h" -#include "port/Enhancements/Events/Hooks/Events.h" - -#include "math.h" #include "bk_time.h" #include "bs_funcs.h" #include "bsint.h" #include "generic.h" -#include - // FuncUnk40 defined in core2/commonParticle.h — forward-typedef here to avoid circular include #ifndef FUNCUNK40_DEFINED #define FUNCUNK40_DEFINED @@ -3533,4 +3534,8 @@ void _guMtxIdentF_80245D44(float mf[4][4]); //static should NOT be here void func_80241304(Mtx *m, float x, float y, float z); BKModelBin * marker_loadModelBin(ActorMarker *marker); +#ifdef __cplusplus +} +#endif + #endif // FUNCTIONS_H diff --git a/include/gc/gctransition.h b/include/gc/gctransition.h index a891672a7..97988bfe1 100644 --- a/include/gc/gctransition.h +++ b/include/gc/gctransition.h @@ -1,6 +1,10 @@ #ifndef __GC_TRANSITION__ #define __GC_TRANSITION__ +#ifdef __cplusplus +extern "C" { +#endif + void gctransition_defrag(void); void gctransition_draw(Gfx **arg0, Mtx **arg1, Vtx **arg2); void gctransition_8030BD4C(void); @@ -14,4 +18,8 @@ void gctransition_8030BEA4(s32 arg0); void gctransition_update(void); void gctransition_reset(void); +#ifdef __cplusplus +} +#endif + #endif diff --git a/include/model.h b/include/model.h index 282b9d5e8..3125d8c3e 100644 --- a/include/model.h +++ b/include/model.h @@ -4,6 +4,10 @@ #include #include "bool.h" +#ifdef __cplusplus +extern "C" { +#endif + /* Model header * Contains offsets relative to the start of the file to the various sections * If a section is not present in the file, the offset will be zero @@ -512,4 +516,8 @@ void model_free(BKModel *self); void gclights_recolor_vertices(BKVertexList *arg0, f32 position[3], f32 rotation[3], f32 scale, f32 arg4[3], BKVertexList *arg5); +#ifdef __cplusplus +} +#endif + #endif diff --git a/include/structs.h b/include/structs.h index 9652e2d14..3c6eac19f 100644 --- a/include/structs.h +++ b/include/structs.h @@ -8,6 +8,10 @@ #include "enums.h" #include "bool.h" +#ifdef __cplusplus +extern "C" { +#endif + // [port] Forward-declare struct tags used in function pointers inside structs below. // Without these, clang treats the struct tag as file-local to each struct definition. struct actor_s; @@ -794,4 +798,8 @@ typedef struct { struct ALHeap *unkC; //heap u16 unk10; }Struct87s; +#ifdef __cplusplus +} +#endif + #endif diff --git a/include/variables.h b/include/variables.h index cb494bd33..fef76269d 100644 --- a/include/variables.h +++ b/include/variables.h @@ -1,6 +1,10 @@ #ifndef VARIABLES_H #define VARIABLES_H +#ifdef __cplusplus +extern "C" { +#endif + #define BAD_PI 3.141592654 #define BAD_DTOR (BAD_PI/ 180.0) #define M_TAU (2*M_PI) @@ -9,4 +13,8 @@ extern f32 climbPoleBottom[3]; extern f32 climbPoleTop[3]; +#ifdef __cplusplus +} +#endif + #endif diff --git a/libultraship b/libultraship index e8a161877..2c63e7ede 160000 --- a/libultraship +++ b/libultraship @@ -1 +1 @@ -Subproject commit e8a161877862edfcf79d3b33280a333e07461d5c +Subproject commit 2c63e7edef577cd2a3726ce24dfedd7f088f12ae diff --git a/src/core1/audio_instruments.c b/src/core1/audio_instruments.c index e30440c74..5712a9080 100644 --- a/src/core1/audio_instruments.c +++ b/src/core1/audio_instruments.c @@ -3,6 +3,7 @@ #include "core1/core1.h" #include "functions.h" #include "variables.h" +#include "port/ShipUtils.h" // gPortResetPending #include "music.h" #include diff --git a/src/core1/display_list.c b/src/core1/display_list.c index 4305dba31..07bcd6cf1 100644 --- a/src/core1/display_list.c +++ b/src/core1/display_list.c @@ -2,6 +2,7 @@ #include "core1/core1.h" #include #include "functions.h" +#include "port/ShipUtils.h" // BK_LOG_*, port_shapeControllerInput #include "port/Engine.h" #include diff --git a/src/core1/init.c b/src/core1/init.c index 249b786d5..f2cc2687f 100644 --- a/src/core1/init.c +++ b/src/core1/init.c @@ -3,6 +3,7 @@ #include "core1/core1.h" #include "functions.h" #include "variables.h" +#include "port/ShipUtils.h" // gPortResetPending #include "version.h" #include "gc/gctransition.h" diff --git a/src/core1/io/pfsmanager.c b/src/core1/io/pfsmanager.c index 0c56322bc..30afe7642 100644 --- a/src/core1/io/pfsmanager.c +++ b/src/core1/io/pfsmanager.c @@ -2,6 +2,7 @@ #include #include "core1/core1.h" #include "functions.h" +#include "port/ShipUtils.h" // BK_LOG_*, port_shapeControllerInput #include "variables.h" #include "core1/pfsmanager.h" diff --git a/src/core2/anim/anim_buffer.c b/src/core2/anim/anim_buffer.c index 97b3f4933..7bdeb906e 100644 --- a/src/core2/anim/anim_buffer.c +++ b/src/core2/anim/anim_buffer.c @@ -1,5 +1,6 @@ #include #include "functions.h" +#include "port/ShipUtils.h" // BK_LOG_*, port_shapeControllerInput #include "variables.h" #include "animation.h" diff --git a/src/core2/anim/anim_defrag.c b/src/core2/anim/anim_defrag.c index a700817d9..f364a2353 100644 --- a/src/core2/anim/anim_defrag.c +++ b/src/core2/anim/anim_defrag.c @@ -1,5 +1,6 @@ #include #include "functions.h" +#include "port/ShipUtils.h" // BK_LOG_*, port_shapeControllerInput #include "variables.h" #include "animation.h" diff --git a/src/core2/dialog/binload.c b/src/core2/dialog/binload.c index b5919ff20..9b25f9d38 100644 --- a/src/core2/dialog/binload.c +++ b/src/core2/dialog/binload.c @@ -3,8 +3,7 @@ #include "variables.h" #include "structs.h" #include "port/Patches/Patches.h" - -extern int ResourceMgr_GetDialogLanguageCount(void); +#include "port/ResourceHelpers.h" /* .bss */ s32 D_80383150; diff --git a/src/core2/font/print.c b/src/core2/font/print.c index 39da4a82b..fe7722af4 100644 --- a/src/core2/font/print.c +++ b/src/core2/font/print.c @@ -3,17 +3,8 @@ #include "functions.h" #include "variables.h" -extern int ResourceMgr_GetDialogLanguageCount(void); -extern int ResourceMgr_IsJapanese(void); -extern void port_dialogFontHd_rebuild(void); -// [port] PAL font has 75 glyphs (0x21-0x6B), overlapping NTSC control codes b,d,e,f,h,j. -// When PAL, fmtStrings use shifted codes above the glyph range. -#define PRINT_PAL (ResourceMgr_GetDialogLanguageCount() > 1) -// [port] JP uses font index 2 (sprite 1770, 256 I4 glyphs) for dialog text. -// Dialog strings begin with "\xFD\x6A" (escape + 'j') which switches to font index 2. -#define PRINT_JP (ResourceMgr_IsJapanese()) - - +#include "port/Patches/Patches.h" +#include "port/ResourceHelpers.h" typedef struct{ s8 pad0[0x20]; @@ -481,8 +472,7 @@ void print_init(void){ print_sDialogFontGlyphCount = sprite_getFramePtr(D_80380AB8[0], 0)->chunkCnt; port_dialogFontHd_rebuild(); print_sFonts[1] = print_getLettersFromFont(D_80380AB8[1], D_80380AB8[4]); - if (PRINT_JP) { - // [port] JP font index 2 = the Japanese dialog font (sprite 1770, 256 I4 glyphs). + if (ResourceMgr_IsJapanese()) { D_80380AB8[2] = assetcache_get(SPRITE_JP_DIALOG_FONT_ALPHAMASK); print_sFonts[2] = print_getLettersFromFont(D_80380AB8[2], D_80380AB8[4]); } @@ -619,7 +609,7 @@ void _printbuffer_draw_letter(char letter, f32* xPtr, f32* yPtr, f32 arg3, Gfx * sp20C += (D_80380B04 << 8) - 0x100; D_80380B04 = 0; } - else if(PRINT_JP){ + else if(ResourceMgr_IsJapanese()){ if(sp20C > 0 && sp20C != 0xFD && sp20C != 0x0F){ t0 = 1; if(sp20C == 0x36) @@ -637,7 +627,7 @@ void _printbuffer_draw_letter(char letter, f32* xPtr, f32* yPtr, f32 arg3, Gfx * print_sInFontFormatMode = false; switch((u8)letter){ case '\x0F': // [port] JP font-2 word space; no-op for US/PAL - if(!PRINT_JP) + if(!ResourceMgr_IsJapanese()) break; // fallthrough case ' '://802F5818 @@ -843,8 +833,8 @@ void _printbuffer_draw_letter(char letter, f32* xPtr, f32* yPtr, f32 arg3, Gfx * gSP1Quadrangle((*gfx)++, 0, 1, 3, 2, 0); } else{ - // [port] Wide variant: widescreen-anchored HUD text can start left of x=0; the Scis - // macro would CPU-clamp it to the 4:3 edge and crop the glyph. + // [port] Wide variant: widescreen-anchored HUD text can start left of x=0 + // the Scis macro would CPU-clamp it to the 4:3 edge and crop the glyph. gSPWideTextureRectangle((*gfx)++, (s32)(sp200*4.0f), (s32)(f28*4.0f), (s32)((sp200 + sp214->x*arg3)*4.0f), (s32)((f28 + sp214->y*arg3)*4.0f), 0, 0, 0, (s32)(1024.0f / arg3), (s32)(1024.0f / arg3)); } *xPtr += sp1F8 * arg3; @@ -991,7 +981,7 @@ void _printbuffer_push_new(s32 x, s32 y, u8 * string) { void print_bold_overlapping(s32 x, s32 y, f32 arg2, u8* string){ _printbuffer_push_new(x, y, string); if(print_sCurrentPtr){ - strcpy(print_sCurrentPtr->fmtString, PRINT_PAL ? "\x72l" : "fl"); + strcpy(print_sCurrentPtr->fmtString, ResourceMgr_IsPal() ? "\x72l" : "fl"); print_sCurrentPtr->scale = arg2; } } @@ -999,21 +989,21 @@ void print_bold_overlapping(s32 x, s32 y, f32 arg2, u8* string){ void print_bold_spaced(s32 x, s32 y, u8* string){ _printbuffer_push_new(x, y, string); if(print_sCurrentPtr){ - strcpy(print_sCurrentPtr->fmtString, PRINT_PAL ? "\x72" : "f"); + strcpy(print_sCurrentPtr->fmtString, ResourceMgr_IsPal() ? "\x72" : "f"); } } void print_dialog(s32 x, s32 y, u8* string){ _printbuffer_push_new(x, y, string); if(print_sCurrentPtr){ - strcpy(print_sCurrentPtr->fmtString, PRINT_PAL ? "\x6Flq" : "elq"); + strcpy(print_sCurrentPtr->fmtString, ResourceMgr_IsPal() ? "\x6Flq" : "elq"); } } void print_dialog_w_bg(s32 x, s32 y, u8* string){ _printbuffer_push_new(x, y, string); if(print_sCurrentPtr){ - strcpy(print_sCurrentPtr->fmtString, PRINT_PAL ? "p\x6D" : "pb"); + strcpy(print_sCurrentPtr->fmtString, ResourceMgr_IsPal() ? "p\x6D" : "pb"); } } @@ -1031,7 +1021,7 @@ void print_dialog_gradient2(s32 x, s32 y, u8* string, s32 arg3, s32 arg4){ if(print_sCurrentPtr){ print_sCurrentPtr->topVertexAlpha = arg3; print_sCurrentPtr->bottomVertexAlpha = arg4; - strcpy(print_sCurrentPtr->fmtString, PRINT_PAL ? "\x6E\x6Flq" : "delq"); + strcpy(print_sCurrentPtr->fmtString, ResourceMgr_IsPal() ? "\x6E\x6Flq" : "delq"); } } diff --git a/src/core2/frame/auxbuffer.c b/src/core2/frame/auxbuffer.c index 28b1ca355..2b8a35ce9 100644 --- a/src/core2/frame/auxbuffer.c +++ b/src/core2/frame/auxbuffer.c @@ -4,7 +4,7 @@ #include "variables.h" int gfx_create_framebuffer(unsigned int width, unsigned int height, unsigned int native_width, - unsigned int native_height, unsigned char resize, unsigned char force_fixed_aspect); + unsigned int native_height, unsigned char resize, bool force_fixed_aspect); s32 sAuxGpuFbId = -1; diff --git a/src/core2/map/cutscene_skip.c b/src/core2/map/cutscene_skip.c index 79c3e1bdd..3938f7cbf 100644 --- a/src/core2/map/cutscene_skip.c +++ b/src/core2/map/cutscene_skip.c @@ -7,7 +7,6 @@ extern void player_walkToPosition(f32 *, f32, void(*)(ActorMarker *), ActorMark extern void func_8028F760(s32, f32, f32); extern void func_8031CE70(f32 *arg0, enum map_e arg1, s32 arg2); extern void func_8031FFAC(void); -extern void fileProgressFlag_set(enum file_progress_e index, s32 set); extern NodeProp *func_80304ED0(void*, f32 *); extern void func_8031CD44(enum map_e, s32, f32, f32, s32); extern void mapSpecificFlags_set(s32, s32); diff --git a/src/core2/sfx/source.c b/src/core2/sfx/source.c index 2b46b5988..071215159 100644 --- a/src/core2/sfx/source.c +++ b/src/core2/sfx/source.c @@ -2,6 +2,7 @@ #include "core1/core1.h" #include "functions.h" #include "variables.h" +#include "port/ShipUtils.h" // gPortResetPending #include extern void func_80335394(intptr_t, f32); diff --git a/src/core2/spawn_queue.c b/src/core2/spawn_queue.c index 44dcacee7..d20633915 100644 --- a/src/core2/spawn_queue.c +++ b/src/core2/spawn_queue.c @@ -1,11 +1,13 @@ #include #include "core1/core1.h" #include "functions.h" +#include "port/ShipUtils.h" // BK_LOG_*, port_shapeControllerInput #include "variables.h" #include "actor.h" #include "prop.h" #include "functions.h" #include "core2/ch/snacker.h" +#include "port/Patches/Patches.h" // port_getDrawDistanceLevel #include "port/Romhack/RomhackConfig.h" void spawnQueue_unlock(void); @@ -179,18 +181,32 @@ u8 spawnQueueLength = 0; FunctionQueue *spawnQueue = NULL; /* .code */ -// [port] N64 used 15 entries. If this overflows, find the root cause — -// something is adding entries faster than they're being flushed. -#define SPAWN_QUEUE_DEFAULT_SIZE 32 +// [port] N64 used 15 entries, sized for the N64's draw distance. +// Scales with the Draw Distance enhancement. +#define SPAWN_QUEUE_DEFAULT_SIZE 15 #define SPAWN_QUEUE_GL_SIZE 50 +// [port] Capacity of the live allocation. +static u32 sSpawnQueueMax = 0; + static u32 __spawnQueue_getMax(void) { +#if 0 return (gsworld_getMap() == MAP_90_GL_BATTLEMENTS) ? SPAWN_QUEUE_GL_SIZE : SPAWN_QUEUE_DEFAULT_SIZE; +#endif + return sSpawnQueueMax; } void spawnQueue_malloc(void){ +#if 0 u32 tmp = __spawnQueue_getMax(); spawnQueue = (FunctionQueue *) bk_malloc(tmp * sizeof(FunctionQueue)); +#endif + u32 base = (gsworld_getMap() == MAP_90_GL_BATTLEMENTS) ? SPAWN_QUEUE_GL_SIZE : SPAWN_QUEUE_DEFAULT_SIZE; + // [port] The setting, not the render-time level: this runs during a map load, where + // port_getDrawDistanceLevel() clamps to 1x and would under-size the queue for the + // gameplay that follows. + sSpawnQueueMax = base * (u32) port_getDrawDistanceSetting(); + spawnQueue = (FunctionQueue *) bk_malloc(sSpawnQueueMax * sizeof(FunctionQueue)); } void spawnQueue_reset(void){ @@ -439,6 +455,7 @@ void spawnQueue_free(void){ bk_free(spawnQueue); spawnQueue = NULL; spawnQueueLength = 0; + sSpawnQueueMax = 0; // [port] no capacity without an allocation } @@ -495,7 +512,7 @@ void spawnQueue_lock(void){ void __spawnQueue_add_0(void (* arg0)(void)){ u32 tmp = __spawnQueue_getMax(); - if(tmp != spawnQueueLength){ + if(tmp > spawnQueueLength){ // [port] decomp used !=; < also holds if length ever exceeds tmp spawnQueue[spawnQueueLength].func0 = arg0; spawnQueue[spawnQueueLength].arg_cnt = 0; spawnQueueLength++; @@ -506,7 +523,7 @@ void __spawnQueue_add_0(void (* arg0)(void)){ void __spawnQueue_add_1(GenFunction_1 arg0, uintptr_t arg1){ u32 tmp = __spawnQueue_getMax(); - if(tmp != spawnQueueLength){ + if(tmp > spawnQueueLength){ // [port] decomp used !=; < also holds if length ever exceeds tmp spawnQueue[spawnQueueLength].func0 = (void (*)(void))arg0; spawnQueue[spawnQueueLength].arg[0] = arg1; spawnQueue[spawnQueueLength].arg_cnt = 1; @@ -518,7 +535,7 @@ void __spawnQueue_add_1(GenFunction_1 arg0, uintptr_t arg1){ void __spawnQueue_add_2(void (* arg0)(void), uintptr_t arg1, uintptr_t arg2){ u32 tmp = __spawnQueue_getMax(); - if(tmp != spawnQueueLength){ + if(tmp > spawnQueueLength){ // [port] decomp used !=; < also holds if length ever exceeds tmp spawnQueue[spawnQueueLength].func0 = arg0; spawnQueue[spawnQueueLength].arg[0] = arg1; spawnQueue[spawnQueueLength].arg[1] = arg2; @@ -531,7 +548,7 @@ void __spawnQueue_add_2(void (* arg0)(void), uintptr_t arg1, uintptr_t arg2){ void __spawnQueue_add_3(void (* arg0)(void), uintptr_t arg1, uintptr_t arg2, uintptr_t arg3){ u32 tmp = __spawnQueue_getMax(); - if(tmp != spawnQueueLength){ + if(tmp > spawnQueueLength){ // [port] decomp used !=; < also holds if length ever exceeds tmp spawnQueue[spawnQueueLength].func0 = arg0; spawnQueue[spawnQueueLength].arg[0] = arg1; spawnQueue[spawnQueueLength].arg[1] = arg2; @@ -545,7 +562,7 @@ void __spawnQueue_add_3(void (* arg0)(void), uintptr_t arg1, uintptr_t arg2, uin void __spawnQueue_add_4(GenFunction_4 arg0, uintptr_t arg1, uintptr_t arg2, uintptr_t arg3, uintptr_t arg4){ u32 tmp = __spawnQueue_getMax(); - if(tmp != spawnQueueLength){ + if(tmp > spawnQueueLength){ // [port] decomp used !=; < also holds if length ever exceeds tmp spawnQueue[spawnQueueLength].func0 = (void (*)(void))arg0; spawnQueue[spawnQueueLength].arg[0] = arg1; spawnQueue[spawnQueueLength].arg[1] = arg2; @@ -560,7 +577,7 @@ void __spawnQueue_add_4(GenFunction_4 arg0, uintptr_t arg1, uintptr_t arg2, uint void __spawnQueue_add_5(void (* arg0)(void), uintptr_t arg1, uintptr_t arg2, uintptr_t arg3, uintptr_t arg4, uintptr_t arg5){ u32 tmp = __spawnQueue_getMax(); - if(tmp != spawnQueueLength){ + if(tmp > spawnQueueLength){ // [port] decomp used !=; < also holds if length ever exceeds tmp spawnQueue[spawnQueueLength].func0 = arg0; spawnQueue[spawnQueueLength].arg[0] = arg1; spawnQueue[spawnQueueLength].arg[1] = arg2; diff --git a/src/core2/vtx/transform.c b/src/core2/vtx/transform.c index d36550580..48f8cb443 100644 --- a/src/core2/vtx/transform.c +++ b/src/core2/vtx/transform.c @@ -1,5 +1,6 @@ #include #include "functions.h" +#include "port/ShipUtils.h" // BK_LOG_*, port_shapeControllerInput #include "variables.h" #include "model.h" #include diff --git a/src/port/DevTools/OcclusionDebug.cpp b/src/port/DevTools/OcclusionDebug.cpp index 0c3b72519..0c96f60ec 100644 --- a/src/port/DevTools/OcclusionDebug.cpp +++ b/src/port/DevTools/OcclusionDebug.cpp @@ -16,9 +16,7 @@ #include "port/ShipInit.hpp" #include "port/Enhancements/Events/Hooks/Events.h" -extern "C" { #include "functions.h" // gsworld_getMap, mapModel_getModelBin -} // mapModel_getModelBin returns BKModelBin*; the debugger only compares it as an opaque // pointer, so reinterpret to const void* at the call sites. diff --git a/src/port/DevTools/RemoteCollectSim.cpp b/src/port/DevTools/RemoteCollectSim.cpp index db226648d..208b7d09a 100644 --- a/src/port/DevTools/RemoteCollectSim.cpp +++ b/src/port/DevTools/RemoteCollectSim.cpp @@ -13,9 +13,9 @@ #include #include +#include "functions.h" extern "C" { #include "enums.h" -#include "functions.h" } extern "C" void port_noteRetention_applyRemoteCollect(int32_t mapId, int32_t noteIndex, int32_t sameMap); diff --git a/src/port/Engine.cpp b/src/port/Engine.cpp index 8d8bf5e22..24ad983fd 100644 --- a/src/port/Engine.cpp +++ b/src/port/Engine.cpp @@ -123,10 +123,9 @@ OTRVersion ReadPortVersionFromOTR(std::string otrPath) { return version; } -// Checks the program version stored in the otr and compares the major value to soh -// For Windows/Mac/Linux if the version doesn't match, offer to +// Reads the port version recorded in the named o2r. A missing file yields INT16_MAX in every +// field; an o2r that opens without a portVersion record yields zeros. OTRVersion DetectOTRVersion(std::string fileName) { - bool isOtrOld = false; std::string otrPath = Ship::Context::LocateFileAcrossAppDirs(fileName); // Doesn't exist so nothing to do here @@ -228,7 +227,7 @@ bool IsSubpath(const std::filesystem::path& path, const std::filesystem::path& b return !rel.empty() && rel.native()[0] != '.'; } -bool PathTestCleanup(FILE* tfile) { +bool PathTestCleanup() { try { if (std::filesystem::exists("./text.txt")) std::filesystem::remove("./text.txt"); @@ -597,8 +596,10 @@ void GameEngine::RunExtract(int argc, char* argv[]) { "Lighthouse does not have proper file permissions.\nPlease move it to a " "folder that does and run again.", "OK", "", [&]() { - fclose(tfile); - PathTestCleanup(tfile); + if (tfile != NULL) { + fclose(tfile); + } + PathTestCleanup(); threadPool = nullptr; lhFast3dWindow = nullptr; context = nullptr; @@ -606,7 +607,7 @@ void GameEngine::RunExtract(int argc, char* argv[]) { }); } else { fclose(tfile); - if (!PathTestCleanup(tfile)) { + if (!PathTestCleanup()) { LighthouseGui::RegisterPopup( "Lighthouse Permissions Error", "Lighthouse does not have proper file permissions.\nPlease move it to a " diff --git a/src/port/Enhancements/Backports/EggAim.cpp b/src/port/Enhancements/Backports/EggAim.cpp index ef977e452..32437f86c 100644 --- a/src/port/Enhancements/Backports/EggAim.cpp +++ b/src/port/Enhancements/Backports/EggAim.cpp @@ -13,12 +13,10 @@ #include "port/ShipInit.hpp" #include "EggAim.h" -extern "C" { #include "enums.h" #include "functions.h" #include "core2/commonParticle.h" #include "core2/abilityprogress.h" -} #define CVAR_NAME CVAR_ENHANCEMENT("Backports.EggAim") diff --git a/src/port/Enhancements/Backports/FastSwim.cpp b/src/port/Enhancements/Backports/FastSwim.cpp index bb0d3e060..614c12c4c 100644 --- a/src/port/Enhancements/Backports/FastSwim.cpp +++ b/src/port/Enhancements/Backports/FastSwim.cpp @@ -8,9 +8,7 @@ // Include C decomp headers with C linkage before C++ headers to prevent // transitive includes from giving them C++ name mangling. -extern "C" { #include "core2/bonetransform.h" -} #include #include "port/UI/cvar_prefixes.h" diff --git a/src/port/Enhancements/Backports/Honeyback.cpp b/src/port/Enhancements/Backports/Honeyback.cpp index 1f1f41a04..3ae509d0f 100644 --- a/src/port/Enhancements/Backports/Honeyback.cpp +++ b/src/port/Enhancements/Backports/Honeyback.cpp @@ -7,11 +7,9 @@ #include "port/Enhancements/Events/Hooks/Events.h" #include "port/ShipInit.hpp" -extern "C" { #include "enums.h" #include "functions.h" #include "gc/gctransition.h" -} #define CVAR_NAME CVAR_ENHANCEMENT("Backports.Honeyback") diff --git a/src/port/Enhancements/Backports/TooieJiggyDance.cpp b/src/port/Enhancements/Backports/TooieJiggyDance.cpp index 8846ed8c5..64a9b1ecb 100644 --- a/src/port/Enhancements/Backports/TooieJiggyDance.cpp +++ b/src/port/Enhancements/Backports/TooieJiggyDance.cpp @@ -9,13 +9,12 @@ #include "port/Enhancements/Events/Hooks/Events.h" #include "port/ShipInit.hpp" +#include "functions.h" extern "C" { #include "enums.h" -#include "functions.h" #include "core2/particle.h" ParticleEmitter* __fxSparkle_create(s16 position[3], f32 height, enum asset_e sprite_id); -f32 player_getYaw(void); } #define CVAR_TOOIE_JIGGY_DANCE CVAR_ENHANCEMENT("Backports.JiggyAnimation") diff --git a/src/port/Enhancements/Camera/OrbitCameraCore.cpp b/src/port/Enhancements/Camera/OrbitCameraCore.cpp index 3ca4e8d3d..cbfc4ff7c 100644 --- a/src/port/Enhancements/Camera/OrbitCameraCore.cpp +++ b/src/port/Enhancements/Camera/OrbitCameraCore.cpp @@ -15,28 +15,23 @@ void func_80256E24(float dst[3], float pitch, float yaw, float x, float y, float int func_8025801C(float vec[3], float* yaw); // vector -> yaw (degrees) void func_802BC434(float rotOut[3], float fromPos[3], float targetPos[3]); // look-at rotation int func_802BE60C(void); // swept camera collision + slide -float func_802BD8D4(void); // target orbit distance (zoom level) -float func_802BD51C(void); // target camera height +extern float D_8037D948[3]; // dynamicCamera.c collision anchor: the point the camera stays visible from +float func_802BD8D4(void); // target orbit distance (zoom level) +float func_802BD51C(void); // target camera height float ml_acosf(float x); float mlNormalizeAngle(float deg); +float mlDiffDegF(float a, float b); // shortest signed a-b in degrees float gu_sqrtf(float x); float time_getDelta(void); } namespace { -// 1/sec; how fast distance chases the zoom-level target. constexpr float kDistanceRate = 8.0f; -// 1/sec; vertical follow (flat-pitch mode only). Matched to the vanilla camera, -// whose Y lerp is target*dt*2, so the camera stays mostly put during a jump -// (Banjo rises in frame) instead of choppily chasing the parabola up and down. -constexpr float kHeightRate = 2.0f; -// 1/sec; how fast the look-at target's Y chases its raw value. The orbit center -// Y is derived from the floor height under the player, which snaps up in discrete -// steps on stairs; smoothing it de-steps the aim pitch the way the vanilla camera's -// rotation tracker (func_802BD904) does, without adding lag to the stick-driven yaw. -constexpr float kAimHeightRate = 8.0f; +constexpr float kReturnRateFactor = 0.2f; // collision offset relaxes this much slower than it deepens +constexpr float kVertRate = 0.8f; // height + aim Y follow rate; low to filter floor-height churn +constexpr float kRotRate = 12.0f; // look-at damping, mirroring the vanilla follow camera float clampf(float v, float lo, float hi) { return v < lo ? lo : (v > hi ? hi : v); @@ -70,6 +65,7 @@ extern "C" void OrbitCamera_Capture(OrbitCamera* c) { c->justEntered = 1; c->smoothValid = 0; c->aimValid = 0; + c->rotValid = 0; } extern "C" void OrbitCamera_Enter(OrbitCamera* c) { @@ -96,8 +92,21 @@ extern "C" void OrbitCamera_Update(OrbitCamera* c, float yawDelta, float pitchDe } c->justEntered = 0; - // Track the vanilla zoom-level distance so the normal zoom controls still take - // effect while orbiting. + // The collision resolve can trap the camera far from the player; snap home when the gap runs away. + bool driftEscape = false; + float zoomTarget = func_802BD8D4(); + if (c->smoothValid && zoomTarget > 0.0f) { + float rgx = center[0] - c->smoothPos[0]; + float rgz = center[2] - c->smoothPos[2]; + float limit = zoomTarget * 2.0f; + if ((rgx * rgx + rgz * rgz) > (limit * limit)) { + c->distance = zoomTarget; + c->smoothValid = 0; + driftEscape = true; + } + } + + // Track the vanilla zoom-level distance so zoom controls still apply while orbiting. float distTrack = clampf(kDistanceRate * dt, 0.0f, 1.0f); c->distance += (func_802BD8D4() - c->distance) * distTrack; @@ -108,50 +117,73 @@ extern "C" void OrbitCamera_Update(OrbitCamera* c, float yawDelta, float pitchDe pos[0] = center[0] + offset[0]; pos[2] = center[2] + offset[2]; if (c->allowPitch) { - // Pitch carries the vertical offset. - pos[1] = center[1] + offset[1]; + pos[1] = center[1] + offset[1]; // pitch carries the vertical offset } else { - // Flat orbit: height follows the vanilla target, more slowly than distance - // so jumps read as natural rather than choppy. - float heightTrack = clampf(kHeightRate * dt, 0.0f, 1.0f); - c->height += (func_802BD51C() - c->height) * heightTrack; + // Flat orbit: height low-passes the vanilla target, filtering plank/step floor churn. + c->height += (func_802BD51C() - c->height) * clampf(kVertRate * dt, 0.0f, 1.0f); pos[1] = c->height; } ncDynamicCamera_setPosition(pos); - // Resolve geometry. + // Resolve geometry; on a drift escape, anchor at the player so the resolve pulls back in. + if (driftEscape) { + D_8037D948[0] = center[0]; + D_8037D948[1] = center[1]; + D_8037D948[2] = center[2]; + } func_802BE60C(); float resolved[3]; ncDynamicCamera_getPosition(resolved); + // pos already follows the player smoothly; the shake near thin/translucent geometry lives in the + // collision correction, so smooth only that (damps every direction with no added follow lag). + float corr[3] = { resolved[0] - pos[0], resolved[1] - pos[1], resolved[2] - pos[2] }; if (!c->smoothValid) { - c->smoothPos[0] = resolved[0]; - c->smoothPos[1] = resolved[1]; - c->smoothPos[2] = resolved[2]; + c->collisionOffset[0] = corr[0]; + c->collisionOffset[1] = corr[1]; + c->collisionOffset[2] = corr[2]; c->smoothValid = 1; } else { - // Smooth the resolved position to prevent hitching on edges. - float f = clampf(c->smoothRate * dt, 0.0f, 1.0f); - c->smoothPos[0] += (resolved[0] - c->smoothPos[0]) * f; - c->smoothPos[1] += (resolved[1] - c->smoothPos[1]) * f; - c->smoothPos[2] += (resolved[2] - c->smoothPos[2]) * f; + // Deepen the pull-in fast (never clip through geometry), relax slowly so a flickering + // collision settles at its deep value instead of oscillating. + float newSq = corr[0] * corr[0] + corr[1] * corr[1] + corr[2] * corr[2]; + float curSq = c->collisionOffset[0] * c->collisionOffset[0] + c->collisionOffset[1] * c->collisionOffset[1] + + c->collisionOffset[2] * c->collisionOffset[2]; + float rate = (newSq > curSq) ? c->smoothRate : c->smoothRate * kReturnRateFactor; + float f = clampf(rate * dt, 0.0f, 1.0f); + c->collisionOffset[0] += (corr[0] - c->collisionOffset[0]) * f; + c->collisionOffset[1] += (corr[1] - c->collisionOffset[1]) * f; + c->collisionOffset[2] += (corr[2] - c->collisionOffset[2]) * f; } + c->smoothPos[0] = pos[0] + c->collisionOffset[0]; + c->smoothPos[1] = pos[1] + c->collisionOffset[1]; + c->smoothPos[2] = pos[2] + c->collisionOffset[2]; ncDynamicCamera_setPosition(c->smoothPos); - // Aim back at the player from the smoothed position. Smooth only the target's - // Y: the orbit center Y steps with the floor height under the player. - // X/Z follow the player directly so horizontal aim stays responsive. + // Aim at the player; smooth only the target Y (X/Z follow directly for responsive horizontal aim). if (!c->aimValid) { c->aimCenterY = center[1]; c->aimValid = 1; } else { - float aimTrack = clampf(kAimHeightRate * dt, 0.0f, 1.0f); - c->aimCenterY += (center[1] - c->aimCenterY) * aimTrack; + c->aimCenterY += (center[1] - c->aimCenterY) * clampf(kVertRate * dt, 0.0f, 1.0f); } float aimCenter[3] = { center[0], c->aimCenterY, center[2] }; float rot[3]; func_802BC434(rot, aimCenter, c->smoothPos); - ncDynamicCamera_setRotation(rot); + + // Damp the look-at instead of snapping to it, like the vanilla camera; filters residual aim wobble. + if (!c->rotValid) { + c->smoothRot[0] = rot[0]; + c->smoothRot[1] = rot[1]; + c->smoothRot[2] = rot[2]; + c->rotValid = 1; + } else { + float rf = clampf(kRotRate * dt, 0.0f, 1.0f); + c->smoothRot[0] = mlNormalizeAngle(c->smoothRot[0] + mlDiffDegF(rot[0], c->smoothRot[0]) * rf); + c->smoothRot[1] = mlNormalizeAngle(c->smoothRot[1] + mlDiffDegF(rot[1], c->smoothRot[1]) * rf); + c->smoothRot[2] = rot[2]; + } + ncDynamicCamera_setRotation(c->smoothRot); } diff --git a/src/port/Enhancements/Camera/OrbitCameraCore.h b/src/port/Enhancements/Camera/OrbitCameraCore.h index ba10397dc..434dcd6c4 100644 --- a/src/port/Enhancements/Camera/OrbitCameraCore.h +++ b/src/port/Enhancements/Camera/OrbitCameraCore.h @@ -1,27 +1,18 @@ #ifndef PORT_ORBIT_CAMERA_CORE_H #define PORT_ORBIT_CAMERA_CORE_H -// Shared right-stick orbit camera core. -// -// Both the modern control scheme's yaw orbit and the Free Look enhancement are -// configurations of the same machinery: capture the current camera, drive yaw -// (and optionally pitch) from the right stick, track the vanilla zoom-level -// distance, resolve geometry collision, smooth, and aim back at the player. -// -// The two only differ in policy (when to enter/hold/hand back, how the stick is -// read, whether pitch is live) and in a couple of tuning values. Each owns an -// OrbitCamera instance and supplies those via the config fields below; the core -// owns the per-frame math so the behavior stays identical between them. +// Shared right-stick orbit camera core: capture the live camera, drive yaw (and optionally pitch) +// from the stick, track the vanilla zoom distance, resolve collision, smooth, and aim at the player. +// The modern-scheme yaw orbit and Free Look are the same machinery with different policy and tuning. #ifdef __cplusplus extern "C" { #endif typedef struct { - // // Config (set by the owner) + // Config (set by the owner) int stateId; // dynamic camera state this orbit runs as - int allowPitch; // 1: stick Y drives pitch and feeds the vertical offset. - // 0: pitch is locked flat and height tracks the vanilla target. + int allowPitch; // 1: stick Y drives pitch; 0: pitch locked flat, height tracks the vanilla target float minPitch; // pitch clamp, degrees (only used when allowPitch) float maxPitch; float smoothRate; // position smoothing rate, 1/sec @@ -30,17 +21,19 @@ typedef struct { int active; int justEntered; int smoothValid; - int aimValid; // aimCenterY has been seeded + int aimValid; float yaw; float pitch; float distance; // spherical radius; tracks the vanilla zoom-level target float height; // absolute Y, only used when !allowPitch - float aimCenterY; // smoothed Y of the look-at target (de-steps stairs) + float aimCenterY; // smoothed Y of the look-at target float smoothPos[3]; + float collisionOffset[3]; // smoothed collision correction, kept separate from the follow motion + float smoothRot[3]; // damped look-at rotation + int rotValid; } OrbitCamera; -// Seed yaw/pitch/distance(/height) from wherever the live camera currently sits, -// so the orbit starts without a jump. +// Seed yaw/pitch/distance(/height) from the live camera so the orbit starts without a jump. void OrbitCamera_Capture(OrbitCamera* c); // Capture and take ownership of the camera state. diff --git a/src/port/Enhancements/Cheats/Cheats.cpp b/src/port/Enhancements/Cheats/Cheats.cpp index d9d85a36e..3855dd874 100644 --- a/src/port/Enhancements/Cheats/Cheats.cpp +++ b/src/port/Enhancements/Cheats/Cheats.cpp @@ -5,21 +5,16 @@ #include #include "port/UI/cvar_prefixes.h" #include "port/Enhancements/Events/Hooks/Events.h" +#include "port/Romhack/RomhackConfig.h" #include "port/ShipInit.hpp" #include "port/ShipUtils.h" -extern "C" { #include "enums.h" #include "core2/statetimer.h" #include "core2/ba/physics.h" #include "bs_funcs.h" #include "functions.h" -s32 port_getRomhackMaxEggs(void); -s32 port_getRomhackMaxGoldFeathers(void); -s32 port_getRomhackMaxRedFeathers(void); -} - // ============================================================================ // CVAR DEFINITIONS // ============================================================================ @@ -142,7 +137,7 @@ void RegisterTalonTrotCycle_Init() { // D-pad cycling - only works while Talon Trot is active if (bakey_pressed(BUTTON_D_RIGHT) || bakey_pressed(BUTTON_D_LEFT)) { s32 currentState = bs_getState(); - bool inTalonTrot = bsbtrot_inSet((enum bs_e)currentState) || bslongleg_inSet(0); // Also in longleg state + bool inTalonTrot = bsbtrot_inSet(currentState) || bslongleg_inSet(currentState); if (inTalonTrot) { bool inBoots = stateTimer_isActive(STATE_TIMER_2_LONGLEG); @@ -190,8 +185,9 @@ void RegisterLevitate_Init() { static const f32 LEVITATE_VELOCITY = 500.0f; static bool levitateActive = false; COND_HOOK(GameFrameUpdate, EVENT_PRIORITY_NORMAL, CVarGetInteger(CVAR_LEVITATE, 0), [](IEvent* event) { - if (bakey_held(BUTTON_L)) { - // Cancel fall damage and the tumble/splat animation if pressed mid-fall. + // Suspend levitation while dialog is up. + // Cancel fall damage and the tumble/splat animation if pressed mid-fall. + if (bakey_held(BUTTON_L) && !gcdialog_hasCurrentTextId()) { if (bakey_pressed(BUTTON_L) && !player_isStable()) { s32 fallDamage = 0; if (bafalldamage_get_damage(&fallDamage) != 0) { @@ -214,9 +210,14 @@ void RegisterLevitate_Init() { // TRANSFORMATION CHEATS // ============================================================================ +static const s32 BAANIM_WISHYWASHY = 0x80; +static bool isWishyWashyUnlocked() { + return (baanim_getActiveBottlesBonusMask() & BAANIM_WISHYWASHY) != 0; +} + // Transformation cycling with D-pad Up/Down -// D-pad Up: Cycle forward through transformations (Banjo -> Mumbo -> Termite -> ... -> Wishy -> Banjo) -// D-pad Down: Cycle backward through transformations (Banjo -> Wishy -> ... -> Termite -> Mumbo -> Banjo) +// D-pad Up: Cycle forward through transformations (Banjo -> Termite -> ... -> Bee -> [Wishy] -> Banjo) +// D-pad Down: Cycle backward through transformations (Banjo -> [Wishy] -> Bee -> ... -> Termite -> Banjo) void RegisterCycleTransform_Init() { COND_HOOK(GameFrameUpdate, EVENT_PRIORITY_NORMAL, CVarGetInteger(CVAR_CYCLE_TRANSFORM, 0), [](IEvent* event) { s32 currentTransform = (s32)player_getTransformation(); @@ -227,6 +228,9 @@ void RegisterCycleTransform_Init() { if (currentTransform > TRANSFORM_7_WISHWASHY) { currentTransform = TRANSFORM_1_BANJO; } + if (currentTransform == TRANSFORM_7_WISHWASHY && !isWishyWashyUnlocked()) { + currentTransform = TRANSFORM_1_BANJO; // skip Wishy Washy -> wrap to Banjo + } func_8028FB88((enum transformation_e)currentTransform); } // D-pad Down: Cycle backward through transformations @@ -235,6 +239,9 @@ void RegisterCycleTransform_Init() { if (currentTransform < TRANSFORM_1_BANJO) { currentTransform = TRANSFORM_7_WISHWASHY; } + if (currentTransform == TRANSFORM_7_WISHWASHY && !isWishyWashyUnlocked()) { + currentTransform = TRANSFORM_6_BEE; // skip Wishy Washy -> step to Bee + } func_8028FB88((enum transformation_e)currentTransform); } }); diff --git a/src/port/Enhancements/Fixes/GameFixes.cpp b/src/port/Enhancements/Fixes/GameFixes.cpp index d4d5c8dc4..ddb299fdb 100644 --- a/src/port/Enhancements/Fixes/GameFixes.cpp +++ b/src/port/Enhancements/Fixes/GameFixes.cpp @@ -8,9 +8,9 @@ #include "port/Enhancements/Events/Hooks/Events.h" #include "port/ShipInit.hpp" +#include "functions.h" extern "C" { #include "enums.h" -#include "functions.h" enum map_e gsworld_getMap(void); } diff --git a/src/port/Enhancements/Gameplay/EasierBoggyRaces.cpp b/src/port/Enhancements/Gameplay/EasierBoggyRaces.cpp index 26fbfc32e..f422874be 100644 --- a/src/port/Enhancements/Gameplay/EasierBoggyRaces.cpp +++ b/src/port/Enhancements/Gameplay/EasierBoggyRaces.cpp @@ -7,9 +7,7 @@ #include "port/Enhancements/Events/Hooks/Events.h" #include "port/ShipInit.hpp" -extern "C" { #include "enums.h" -} #define CVAR_NAME CVAR_ENHANCEMENT("EasierBoggyRaces") #define CVAR CVarGetInteger(CVAR_NAME, 0) diff --git a/src/port/Enhancements/Gameplay/FurnaceFunMoves.cpp b/src/port/Enhancements/Gameplay/FurnaceFunMoves.cpp index b53ea3979..38e09a8c5 100644 --- a/src/port/Enhancements/Gameplay/FurnaceFunMoves.cpp +++ b/src/port/Enhancements/Gameplay/FurnaceFunMoves.cpp @@ -4,11 +4,9 @@ #include "port/ShipInit.hpp" #include "port/Romhack/RomhackConfig.h" -extern "C" { #include "enums.h" #include "functions.h" #include "core2/abilityprogress.h" -} #define CVAR_NAME CVAR_ENHANCEMENT("Gameplay.FurnaceFunMoves") diff --git a/src/port/Enhancements/Gameplay/SkipSMTutorial.cpp b/src/port/Enhancements/Gameplay/SkipSMTutorial.cpp index 144de4c6e..6c7ee0cc0 100644 --- a/src/port/Enhancements/Gameplay/SkipSMTutorial.cpp +++ b/src/port/Enhancements/Gameplay/SkipSMTutorial.cpp @@ -5,11 +5,9 @@ #include "port/Romhack/RomhackConfig.h" #include "port/Rando/Rando.h" -extern "C" { #include "enums.h" #include "functions.h" #include "core2/abilityprogress.h" -} extern "C" float D_80386000[]; diff --git a/src/port/Enhancements/Gameplay/WaterPyramidTimer.cpp b/src/port/Enhancements/Gameplay/WaterPyramidTimer.cpp index f5e185807..ad5748a71 100644 --- a/src/port/Enhancements/Gameplay/WaterPyramidTimer.cpp +++ b/src/port/Enhancements/Gameplay/WaterPyramidTimer.cpp @@ -7,9 +7,7 @@ #include "port/Enhancements/Events/Hooks/Events.h" #include "port/ShipInit.hpp" -extern "C" { #include "enums.h" -} #define CVAR_NAME CVAR_ENHANCEMENT("Gameplay.WaterPyramidTimer") diff --git a/src/port/Enhancements/Restorations/ReturnToLair.cpp b/src/port/Enhancements/Restorations/ReturnToLair.cpp index 8de5916f2..b19587756 100644 --- a/src/port/Enhancements/Restorations/ReturnToLair.cpp +++ b/src/port/Enhancements/Restorations/ReturnToLair.cpp @@ -8,9 +8,9 @@ #include "include/core2/anctrl.h" #include "include/core2/gc/zoombox.h" -extern "C" struct1Bs D_8036C560[]; -extern "C" enum level_e level_get(void); -extern "C" bool fileProgressFlag_get(enum file_progress_e index); +#include "functions.h" + +extern "C" struct1Bs D_8036C560[]; // not declared in variables.h typedef struct struct_1A_s { f32 delay; diff --git a/src/port/Enhancements/Retention/JinjoRetention.cpp b/src/port/Enhancements/Retention/JinjoRetention.cpp index ed5dc7a65..949adb615 100644 --- a/src/port/Enhancements/Retention/JinjoRetention.cpp +++ b/src/port/Enhancements/Retention/JinjoRetention.cpp @@ -13,12 +13,10 @@ #include "port/Rando/Rando.h" #include "port/Rando/CustomObject/CustomObject.h" -extern "C" { #include "enums.h" #include "actor.h" #include "prop.h" #include "functions.h" -} extern "C" int32_t port_jiggySpawn_isRecorded(int32_t jiggyId); diff --git a/src/port/Enhancements/Retention/NoteRetention.cpp b/src/port/Enhancements/Retention/NoteRetention.cpp index 2f877fb77..a928ff7c1 100644 --- a/src/port/Enhancements/Retention/NoteRetention.cpp +++ b/src/port/Enhancements/Retention/NoteRetention.cpp @@ -19,11 +19,11 @@ #include #include +#include "functions.h" extern "C" { #include "enums.h" #include "actor.h" #include "prop.h" -#include "functions.h" extern f32 gBundle_yaw; extern ActorInfo sumusicNote; diff --git a/src/port/Enhancements/Retention/Retention.cpp b/src/port/Enhancements/Retention/Retention.cpp index a31153472..59c88a3ee 100644 --- a/src/port/Enhancements/Retention/Retention.cpp +++ b/src/port/Enhancements/Retention/Retention.cpp @@ -6,9 +6,9 @@ #include "port/Enhancements/Retention/Retention.h" #include "port/Rando/Rando.h" // selectedFileNum, gameFile_saveData, DEFAULT_FILE_NUM, FILE_TYPE_SAVE_RANDO +#include "functions.h" extern "C" { #include "enums.h" -#include "functions.h" } namespace retention { diff --git a/src/port/Enhancements/Retention/WormSync.cpp b/src/port/Enhancements/Retention/WormSync.cpp index aa2e98928..985530220 100644 --- a/src/port/Enhancements/Retention/WormSync.cpp +++ b/src/port/Enhancements/Retention/WormSync.cpp @@ -13,10 +13,10 @@ #include #include +#include "functions.h" extern "C" { #include "enums.h" #include "actor.h" -#include "functions.h" } namespace { diff --git a/src/port/Enhancements/Trackers/DisplayOverlay.cpp b/src/port/Enhancements/Trackers/DisplayOverlay.cpp index bc8bdf4be..c459bfbc5 100644 --- a/src/port/Enhancements/Trackers/DisplayOverlay.cpp +++ b/src/port/Enhancements/Trackers/DisplayOverlay.cpp @@ -13,17 +13,11 @@ extern "C" { enum map_e gsworld_getMap(void); -enum level_e map_getLevel(enum map_e map); u16 itemscore_timeScores_get(enum level_e level_id); -uint64_t GetUnixTimestamp(); extern SaveData gameFile_saveData[4]; } -float windowScale = 1.0f; -ImVec4 windowBG = ImVec4(0, 0, 0, 0.5f); -static constexpr ImVec4 tintColor = {}; - const std::vector timerDisplayOptions = { "Display Off", // TIMER_DISPLAY_NONE "Real-Time", // TIMER_DISPLAY_RTA diff --git a/src/port/GameStatus.cpp b/src/port/GameStatus.cpp index fd67e994a..5b8287c94 100644 --- a/src/port/GameStatus.cpp +++ b/src/port/GameStatus.cpp @@ -7,23 +7,12 @@ #endif #include "port/Enhancements/Events/Hooks/Events.h" +#include "port/Romhack/RomhackConfig.h" #include "port/ShipInit.hpp" +#include "functions.h" extern "C" { #include "enums.h" -enum level_e map_getLevel(enum map_e map); -s32 itemscore_noteScores_get(enum level_e lvl_id); -s32 jiggyscore_leveltotal(s32 lvl); -s32 honeycombscore_get_level_total(enum level_e level_id); -u16 itemscore_timeScores_get(enum level_e level_id); -int port_getRomhackNotesMax(void); -int port_getRomhackJiggiesPerWorld(void); -int port_getRomhackHoneycombsPerWorld(void); -int port_getRomhackSpecialLevel(void); -int port_getRomhackExtraHcStart(void); -int port_getRomhackHideCollectiblesLevel(void); -int port_getRomhackHideJiggiesLevel(void); -const char* port_getRomhackLevelName(int level_index); // Pause menu level name table (supports romhack string patches via Torch config) typedef struct { diff --git a/src/port/Localization/Localization.cpp b/src/port/Localization/Localization.cpp index 71f42fa1b..b10f58ae3 100644 --- a/src/port/Localization/Localization.cpp +++ b/src/port/Localization/Localization.cpp @@ -6,20 +6,14 @@ #include #include #include "port/Enhancements/Events/Hooks/Events.h" +#include "port/Patches/Patches.h" +#include "port/ResourceHelpers.h" #include "port/ShipInit.hpp" #include "port/UI/cvar_prefixes.h" typedef unsigned char u8; extern "C" { -int ResourceMgr_IsJapanese(void); -int ResourceMgr_GetDialogLanguageCount(void); // 1 = US, 3 = PAL (EN/FR/DE) -int ResourceMgr_GetDialogLanguage(void); // PAL only: 0=English, 1=French, 2=German -int ResourceMgr_GetLanguageGeneration(void); -int ResourceMgr_IsAssetRepointed(uint32_t assetId); -const char* ResourceMgr_GetLangString(const char* english); // active pack's translation, or the key itself -int ResourceMgr_HasLangStrings(void); // active language is a pack carrying UI overrides - bool gameFile_isNotEmpty(int gamenum); int jiggyscore_total(void); int itemscore_noteScores_getTotal(void); @@ -45,8 +39,6 @@ void print_setBoldFontTexture(int textureId); void* assetcache_get(int assetId); void assetcache_release(void* ptr); void bk_free(void* ptr); -void port_refreshDialogFontGlyphCount(void); -void port_dialogFontHd_rebuild(void); } // Live language change reactions @@ -520,8 +512,7 @@ static void buildPalJpParades() { // present in the active language (sDialogOverride) rather than on the base version. static constexpr uint32_t kMotzandParadeCreditId = 0x11CA; static bool port_useMotzandParade() { - return ResourceMgr_IsJapanese() || ResourceMgr_GetDialogLanguageCount() > 1 || - ResourceMgr_IsAssetRepointed(kMotzandParadeCreditId) != 0; + return ResourceMgr_IsJapanese() || ResourceMgr_IsPal() || ResourceMgr_IsAssetRepointed(kMotzandParadeCreditId) != 0; } // Swap the active parade table for the Motzand variant. diff --git a/src/port/Network/Anchor/Anchor.cpp b/src/port/Network/Anchor/Anchor.cpp index 9db72a587..45686f6e8 100644 --- a/src/port/Network/Anchor/Anchor.cpp +++ b/src/port/Network/Anchor/Anchor.cpp @@ -8,10 +8,8 @@ #include "port/ObjectExtension/ObjectExtension.h" #include "port/Enhancements/Retention/Retention.h" -extern "C" { #include "variables.h" #include "functions.h" -} // MARK: - Overrides diff --git a/src/port/Network/Anchor/AnchorRoomWindow.cpp b/src/port/Network/Anchor/AnchorRoomWindow.cpp index 62cd34c72..47cb82725 100644 --- a/src/port/Network/Anchor/AnchorRoomWindow.cpp +++ b/src/port/Network/Anchor/AnchorRoomWindow.cpp @@ -3,11 +3,9 @@ #include "port/Rando/Rando.h" #include "port/GameStatus.h" -extern "C" { #include "variables.h" #include "functions.h" // extern PlayState* gPlayState; -} void AnchorRoomWindow::Draw() { if (!IsVisible() || !Anchor::GetInstance()->isConnected) { diff --git a/src/port/Network/Anchor/Authority.cpp b/src/port/Network/Anchor/Authority.cpp index f714e21ba..1ca9012eb 100644 --- a/src/port/Network/Anchor/Authority.cpp +++ b/src/port/Network/Anchor/Authority.cpp @@ -5,9 +5,7 @@ #include "port/Network/Anchor/FightSync.h" #include -extern "C" { #include "enums.h" -} struct ActivityState { bool claimed = false; diff --git a/src/port/Network/Anchor/DummyPlayer.cpp b/src/port/Network/Anchor/DummyPlayer.cpp index 03e4fd0b0..1bcfa3626 100644 --- a/src/port/Network/Anchor/DummyPlayer.cpp +++ b/src/port/Network/Anchor/DummyPlayer.cpp @@ -1,9 +1,9 @@ #include "Anchor.h" #include "port/Nametag/Nametag.h" +#include "functions.h" extern "C" { #include -#include "functions.h" #include "variables.h" void func_802D729C(Actor* actor, f32 arg1); } diff --git a/src/port/Network/Anchor/DummyPlayer.h b/src/port/Network/Anchor/DummyPlayer.h index aa068af5c..5341ac590 100644 --- a/src/port/Network/Anchor/DummyPlayer.h +++ b/src/port/Network/Anchor/DummyPlayer.h @@ -1,9 +1,7 @@ #pragma once -extern "C" { #include "functions.h" #include "core2/ba/model.h" #include "variables.h" -} class DummyPlayer { public: diff --git a/src/port/Network/Anchor/HookHandlers.cpp b/src/port/Network/Anchor/HookHandlers.cpp index ce25b4983..bd451730d 100644 --- a/src/port/Network/Anchor/HookHandlers.cpp +++ b/src/port/Network/Anchor/HookHandlers.cpp @@ -8,12 +8,10 @@ #include "port/UI/Notification.h" #include +#include "functions.h" extern "C" { #include "variables.h" -#include "functions.h" -float OTRGetDimensionFromLeftEdge(float v); -float OTRGetDimensionFromRightEdge(float v); s32 chvile_netGetAnimMode(Actor* actor); void port_jiggySpawn_remove(int32_t jiggyId); int32_t port_mapFlag_wasSetRemotely(int32_t index); diff --git a/src/port/Network/Anchor/Packets/AllClientState.cpp b/src/port/Network/Anchor/Packets/AllClientState.cpp index afca8105a..e793947e3 100644 --- a/src/port/Network/Anchor/Packets/AllClientState.cpp +++ b/src/port/Network/Anchor/Packets/AllClientState.cpp @@ -6,9 +6,7 @@ #include "port/Engine.h" #include "port/UI/Notification.h" -extern "C" { #include "functions.h" -} /** * ALL_CLIENT_STATE diff --git a/src/port/Network/Anchor/Packets/BreakObject.cpp b/src/port/Network/Anchor/Packets/BreakObject.cpp index 0b8570a1f..ae42e9d20 100644 --- a/src/port/Network/Anchor/Packets/BreakObject.cpp +++ b/src/port/Network/Anchor/Packets/BreakObject.cpp @@ -9,9 +9,7 @@ #include #include -extern "C" { #include "functions.h" -} #include "port/Patches/Patches.h" diff --git a/src/port/Network/Anchor/Packets/CarryThrow.cpp b/src/port/Network/Anchor/Packets/CarryThrow.cpp index 77eef0242..a74d22195 100644 --- a/src/port/Network/Anchor/Packets/CarryThrow.cpp +++ b/src/port/Network/Anchor/Packets/CarryThrow.cpp @@ -4,9 +4,7 @@ #include "port/Patches/Patches.h" -extern "C" { #include "functions.h" -} /** * CARRY_THROW diff --git a/src/port/Network/Anchor/Packets/CollectItem.cpp b/src/port/Network/Anchor/Packets/CollectItem.cpp index 034e8a767..0c02282e9 100644 --- a/src/port/Network/Anchor/Packets/CollectItem.cpp +++ b/src/port/Network/Anchor/Packets/CollectItem.cpp @@ -5,9 +5,7 @@ #include "port/Rando/Rando.h" #include "port/UI/Notification.h" -extern "C" { #include "functions.h" -} static const char* const kJiggyLevelNames[10] = { "Mumbo's Mountain", "Treasure Trove Cove", "Clanker's Cavern", "Bubblegloop Swamp", "Freezeezy Peak", diff --git a/src/port/Network/Anchor/Packets/DamagePlayer.cpp b/src/port/Network/Anchor/Packets/DamagePlayer.cpp index 24002d43a..adb708b7a 100644 --- a/src/port/Network/Anchor/Packets/DamagePlayer.cpp +++ b/src/port/Network/Anchor/Packets/DamagePlayer.cpp @@ -2,10 +2,8 @@ #include #include -extern "C" { #include "macros.h" #include "functions.h" -} /** * DAMAGE_PLAYER diff --git a/src/port/Network/Anchor/Packets/EggToll.cpp b/src/port/Network/Anchor/Packets/EggToll.cpp index 8331d5d84..584372f93 100644 --- a/src/port/Network/Anchor/Packets/EggToll.cpp +++ b/src/port/Network/Anchor/Packets/EggToll.cpp @@ -10,9 +10,7 @@ #include #include -extern "C" { #include "functions.h" -} #include "port/Patches/Patches.h" diff --git a/src/port/Network/Anchor/Packets/FightEvent.cpp b/src/port/Network/Anchor/Packets/FightEvent.cpp index 79cfbe8ea..75babb01c 100644 --- a/src/port/Network/Anchor/Packets/FightEvent.cpp +++ b/src/port/Network/Anchor/Packets/FightEvent.cpp @@ -4,8 +4,8 @@ #include #include -extern "C" { #include "functions.h" +extern "C" { #include "variables.h" } diff --git a/src/port/Network/Anchor/Packets/FightState.cpp b/src/port/Network/Anchor/Packets/FightState.cpp index 613157871..97fb84e25 100644 --- a/src/port/Network/Anchor/Packets/FightState.cpp +++ b/src/port/Network/Anchor/Packets/FightState.cpp @@ -4,8 +4,8 @@ #include #include -extern "C" { #include "functions.h" +extern "C" { #include "variables.h" } diff --git a/src/port/Network/Anchor/Packets/FightUpdate.cpp b/src/port/Network/Anchor/Packets/FightUpdate.cpp index d34041a40..bf3ff9887 100644 --- a/src/port/Network/Anchor/Packets/FightUpdate.cpp +++ b/src/port/Network/Anchor/Packets/FightUpdate.cpp @@ -4,8 +4,8 @@ #include #include -extern "C" { #include "functions.h" +extern "C" { #include "variables.h" } diff --git a/src/port/Network/Anchor/Packets/GiveItem.cpp b/src/port/Network/Anchor/Packets/GiveItem.cpp index 11394429e..8d7f3801e 100644 --- a/src/port/Network/Anchor/Packets/GiveItem.cpp +++ b/src/port/Network/Anchor/Packets/GiveItem.cpp @@ -3,10 +3,8 @@ #include #include "port/UI/Notification.h" -extern "C" { #include "functions.h" // extern PlayState* gPlayState; -} /** * GIVE_ITEM diff --git a/src/port/Network/Anchor/Packets/HutSmash.cpp b/src/port/Network/Anchor/Packets/HutSmash.cpp index d54ced085..25b475646 100644 --- a/src/port/Network/Anchor/Packets/HutSmash.cpp +++ b/src/port/Network/Anchor/Packets/HutSmash.cpp @@ -10,9 +10,7 @@ #include #include -extern "C" { #include "functions.h" -} /** * HUT_SMASH diff --git a/src/port/Network/Anchor/Packets/JiggyCrane.cpp b/src/port/Network/Anchor/Packets/JiggyCrane.cpp index 97369ffc8..863a4b6d1 100644 --- a/src/port/Network/Anchor/Packets/JiggyCrane.cpp +++ b/src/port/Network/Anchor/Packets/JiggyCrane.cpp @@ -2,9 +2,7 @@ #include #include -extern "C" { #include "functions.h" -} #include "port/Patches/Patches.h" diff --git a/src/port/Network/Anchor/Packets/MapLoad.cpp b/src/port/Network/Anchor/Packets/MapLoad.cpp index 8f48cead5..bf831fe53 100644 --- a/src/port/Network/Anchor/Packets/MapLoad.cpp +++ b/src/port/Network/Anchor/Packets/MapLoad.cpp @@ -3,10 +3,8 @@ #include #include -extern "C" { #include "variables.h" #include "functions.h" -} /** * MAP_LOAD diff --git a/src/port/Network/Anchor/Packets/PlayerSfx.cpp b/src/port/Network/Anchor/Packets/PlayerSfx.cpp index 29d1ecd27..bafc83537 100644 --- a/src/port/Network/Anchor/Packets/PlayerSfx.cpp +++ b/src/port/Network/Anchor/Packets/PlayerSfx.cpp @@ -3,11 +3,9 @@ #include #include -extern "C" { #include "macros.h" #include "functions.h" #include "variables.h" -} /** * PLAYER_SFX diff --git a/src/port/Network/Anchor/Packets/PlayerUpdate.cpp b/src/port/Network/Anchor/Packets/PlayerUpdate.cpp index 1a9e8c03e..496b9f95e 100644 --- a/src/port/Network/Anchor/Packets/PlayerUpdate.cpp +++ b/src/port/Network/Anchor/Packets/PlayerUpdate.cpp @@ -3,12 +3,11 @@ #include #include -extern "C" { #include "functions.h" #include "macros.h" #include "variables.h" -ActorMarker* bacarry_get_marker(void); -} + +extern "C" ActorMarker* bacarry_get_marker(void); #include "port/Patches/Patches.h" diff --git a/src/port/Network/Anchor/Packets/PuzzleStep.cpp b/src/port/Network/Anchor/Packets/PuzzleStep.cpp index 455ed4c4a..e926bdb36 100644 --- a/src/port/Network/Anchor/Packets/PuzzleStep.cpp +++ b/src/port/Network/Anchor/Packets/PuzzleStep.cpp @@ -11,8 +11,8 @@ #include #include -extern "C" { #include "functions.h" +extern "C" { void chTreasurehunt_netTick(void); } diff --git a/src/port/Network/Anchor/Packets/ScopedFlag.cpp b/src/port/Network/Anchor/Packets/ScopedFlag.cpp index b947b75e2..2645b5422 100644 --- a/src/port/Network/Anchor/Packets/ScopedFlag.cpp +++ b/src/port/Network/Anchor/Packets/ScopedFlag.cpp @@ -6,8 +6,8 @@ #include "port/Enhancements/Events/PortEnhancements.h" #include "port/Enhancements/Events/Hooks/Events.h" -extern "C" { #include "functions.h" +extern "C" { void chHoneycomb_netRevealFromSwitch(void); } diff --git a/src/port/Network/Anchor/Packets/ScopedState.cpp b/src/port/Network/Anchor/Packets/ScopedState.cpp index a7f35c3b9..50fba3eec 100644 --- a/src/port/Network/Anchor/Packets/ScopedState.cpp +++ b/src/port/Network/Anchor/Packets/ScopedState.cpp @@ -4,8 +4,8 @@ #include #include -extern "C" { #include "functions.h" +extern "C" { void chHoneycomb_netRevealFromSwitch(void); } diff --git a/src/port/Network/Anchor/Packets/SetAbility.cpp b/src/port/Network/Anchor/Packets/SetAbility.cpp index 49778a129..1feea56c8 100644 --- a/src/port/Network/Anchor/Packets/SetAbility.cpp +++ b/src/port/Network/Anchor/Packets/SetAbility.cpp @@ -2,9 +2,7 @@ #include #include -extern "C" { #include "functions.h" -} /** * SET_ABILITY diff --git a/src/port/Network/Anchor/Packets/SetCheckStatus.cpp b/src/port/Network/Anchor/Packets/SetCheckStatus.cpp index 99a78729d..38c992f12 100644 --- a/src/port/Network/Anchor/Packets/SetCheckStatus.cpp +++ b/src/port/Network/Anchor/Packets/SetCheckStatus.cpp @@ -7,8 +7,8 @@ #include "port/Rando/CustomObject/CustomObject.h" #include "port/Rando/StaticData/StaticData.h" -extern "C" { #include "functions.h" +extern "C" { void marker_despawn(ActorMarker* marker); } diff --git a/src/port/Network/Anchor/Packets/SetFlag.cpp b/src/port/Network/Anchor/Packets/SetFlag.cpp index 658120ec5..dd109bcfd 100644 --- a/src/port/Network/Anchor/Packets/SetFlag.cpp +++ b/src/port/Network/Anchor/Packets/SetFlag.cpp @@ -2,9 +2,7 @@ #include #include -extern "C" { #include "functions.h" -} #include "port/Patches/Patches.h" #include "port/Rando/Rando.h" diff --git a/src/port/Network/Anchor/Packets/SetItemCount.cpp b/src/port/Network/Anchor/Packets/SetItemCount.cpp index 6d1d41d76..0ae95b34c 100644 --- a/src/port/Network/Anchor/Packets/SetItemCount.cpp +++ b/src/port/Network/Anchor/Packets/SetItemCount.cpp @@ -2,8 +2,8 @@ #include #include -extern "C" { #include "functions.h" +extern "C" { s32 item_adjustByDiff(enum item_e item, s32 diff, s32 no_hud, s32 triggerEvent); } diff --git a/src/port/Network/Anchor/Packets/SpawnJiggy.cpp b/src/port/Network/Anchor/Packets/SpawnJiggy.cpp index 96097c93a..54827734f 100644 --- a/src/port/Network/Anchor/Packets/SpawnJiggy.cpp +++ b/src/port/Network/Anchor/Packets/SpawnJiggy.cpp @@ -9,9 +9,7 @@ #include #include -extern "C" { #include "functions.h" -} /** * JIGGY_SPAWN diff --git a/src/port/Network/Anchor/Packets/TeleportTo.cpp b/src/port/Network/Anchor/Packets/TeleportTo.cpp index ad7fb4fab..ba66addf4 100644 --- a/src/port/Network/Anchor/Packets/TeleportTo.cpp +++ b/src/port/Network/Anchor/Packets/TeleportTo.cpp @@ -2,12 +2,7 @@ #include #include -extern "C" { #include "functions.h" -void func_8031D04C(enum map_e arg0, s32 exit_id); -// Instant, sweep-free reposition within the current map (sets current + previous position). -void func_8028F85C(f32 arg0[3]); -} // Exit id the game reserves for "spawn at an explicit position" (see func_8028E4B0). #define EXIT_WARP_DESTINATION 0x63 diff --git a/src/port/Network/Anchor/Packets/UnsetFlag.cpp b/src/port/Network/Anchor/Packets/UnsetFlag.cpp index 01666819d..745e60f51 100644 --- a/src/port/Network/Anchor/Packets/UnsetFlag.cpp +++ b/src/port/Network/Anchor/Packets/UnsetFlag.cpp @@ -2,9 +2,7 @@ #include #include -extern "C" { #include "functions.h" -} /** * UNSET_FLAG diff --git a/src/port/Network/Anchor/Packets/UpdateClientState.cpp b/src/port/Network/Anchor/Packets/UpdateClientState.cpp index a315a54dc..43c658b24 100644 --- a/src/port/Network/Anchor/Packets/UpdateClientState.cpp +++ b/src/port/Network/Anchor/Packets/UpdateClientState.cpp @@ -6,9 +6,7 @@ #include "port/Rando/Rando.h" -extern "C" { #include "variables.h" -} /** * UPDATE_CLIENT_STATE diff --git a/src/port/Network/Anchor/Packets/UpdateRoomState.cpp b/src/port/Network/Anchor/Packets/UpdateRoomState.cpp index 3b0395f5c..bd8495ab0 100644 --- a/src/port/Network/Anchor/Packets/UpdateRoomState.cpp +++ b/src/port/Network/Anchor/Packets/UpdateRoomState.cpp @@ -8,9 +8,7 @@ #include "port/UI/LighthouseGui.hpp" #include "port/UI/LighthouseModals.h" -extern "C" { #include "variables.h" -} /** * UPDATE_ROOM_STATE diff --git a/src/port/Network/Anchor/Packets/UpdateTeamState.cpp b/src/port/Network/Anchor/Packets/UpdateTeamState.cpp index ba68b9281..f2e568bd4 100644 --- a/src/port/Network/Anchor/Packets/UpdateTeamState.cpp +++ b/src/port/Network/Anchor/Packets/UpdateTeamState.cpp @@ -8,10 +8,8 @@ #include #include -extern "C" { #include "variables.h" #include "functions.h" -} // In-memory session sets that aren't part of the save but still ride team state. Flat int // tuples; defined in the respective port modules. diff --git a/src/port/Network/Anchor/Packets/VileEatRequest.cpp b/src/port/Network/Anchor/Packets/VileEatRequest.cpp index 6d244a2e9..7576365e7 100644 --- a/src/port/Network/Anchor/Packets/VileEatRequest.cpp +++ b/src/port/Network/Anchor/Packets/VileEatRequest.cpp @@ -3,10 +3,8 @@ #include #include -extern "C" { #include "functions.h" #include "variables.h" -} /** * VILE_EAT_REQUEST diff --git a/src/port/Network/Anchor/Packets/VileEatResult.cpp b/src/port/Network/Anchor/Packets/VileEatResult.cpp index 01e5abd0d..21d8b8142 100644 --- a/src/port/Network/Anchor/Packets/VileEatResult.cpp +++ b/src/port/Network/Anchor/Packets/VileEatResult.cpp @@ -3,10 +3,8 @@ #include #include -extern "C" { #include "functions.h" #include "variables.h" -} /** * VILE_EAT_RESULT diff --git a/src/port/Network/Anchor/Packets/VileGameState.cpp b/src/port/Network/Anchor/Packets/VileGameState.cpp index ebdbc0415..c4f2da03e 100644 --- a/src/port/Network/Anchor/Packets/VileGameState.cpp +++ b/src/port/Network/Anchor/Packets/VileGameState.cpp @@ -3,10 +3,8 @@ #include #include -extern "C" { #include "functions.h" #include "variables.h" -} /** * VILE_GAME_STATE diff --git a/src/port/Network/Anchor/Packets/VileHoleState.cpp b/src/port/Network/Anchor/Packets/VileHoleState.cpp index 379e1094c..f0078cd05 100644 --- a/src/port/Network/Anchor/Packets/VileHoleState.cpp +++ b/src/port/Network/Anchor/Packets/VileHoleState.cpp @@ -3,10 +3,8 @@ #include #include -extern "C" { #include "functions.h" #include "variables.h" -} /** * VILE_HOLE_STATE diff --git a/src/port/Network/Anchor/Packets/VileUpdate.cpp b/src/port/Network/Anchor/Packets/VileUpdate.cpp index 9d0c37d53..21110c7d6 100644 --- a/src/port/Network/Anchor/Packets/VileUpdate.cpp +++ b/src/port/Network/Anchor/Packets/VileUpdate.cpp @@ -3,10 +3,8 @@ #include #include -extern "C" { #include "functions.h" #include "variables.h" -} /** * VILE_UPDATE diff --git a/src/port/Network/Anchor/Packets/WaterRise.cpp b/src/port/Network/Anchor/Packets/WaterRise.cpp index 566b5f187..63ff97663 100644 --- a/src/port/Network/Anchor/Packets/WaterRise.cpp +++ b/src/port/Network/Anchor/Packets/WaterRise.cpp @@ -8,8 +8,8 @@ #include -extern "C" { #include "functions.h" +extern "C" { #include "variables.h" // func_8034C5AC: xform-3 water group. func_8034E78C: animate its dy. } diff --git a/src/port/Network/Anchor/VileSync.c b/src/port/Network/Anchor/VileSync.c index 25f8d4264..3a5bc3c5a 100644 --- a/src/port/Network/Anchor/VileSync.c +++ b/src/port/Network/Anchor/VileSync.c @@ -10,7 +10,6 @@ extern void chyumblie_netApplyState(Actor* actor, s32 state, s32 piece_type); extern s32 chyumblie_netGetState(Actor* actor, s32* piece_type); extern void chvile_netApplyUpdate(Actor* actor, const f32 position[3], f32 pitch, f32 yaw, f32 roll, u8 anim_mode); -extern s32 chvile_netGetAnimMode(Actor* actor); extern bool chvilegame_netGather(Actor* actor, VileGameSnapshot* dst); extern void chvilegame_netApply(Actor* actor, const VileGameSnapshot* src); extern bool chvilegame_netConsumeRemote(Actor* actor, f32 position[3], s32* out_piece_type, s32* out_correct_type); diff --git a/src/port/Patches/CameraPatches.cpp b/src/port/Patches/CameraPatches.cpp index 733372f18..1121995ca 100644 --- a/src/port/Patches/CameraPatches.cpp +++ b/src/port/Patches/CameraPatches.cpp @@ -13,13 +13,9 @@ #include "port/ShipInit.hpp" #include "port/ShipUtils.h" -extern "C" { #include "enums.h" #include "functions.h" #include "variables.h" -enum level_e map_getLevel(enum map_e map); -enum map_e gsworld_getMap(void); -} #include diff --git a/src/port/Patches/FramebufferPatches.cpp b/src/port/Patches/FramebufferPatches.cpp index 06d71ab31..9ae95dfa9 100644 --- a/src/port/Patches/FramebufferPatches.cpp +++ b/src/port/Patches/FramebufferPatches.cpp @@ -5,17 +5,15 @@ #include +#include "port/Engine.h" + extern "C" { #include "core1/core1.h" #include "model.h" -int gfx_create_framebuffer(unsigned int width, unsigned int height, unsigned int native_width, - unsigned int native_height, unsigned char resize, unsigned char force_fixed_aspect); void gfx_register_fb_texture(const void* cpuAddr, int fbId); BKGfxList* modelbin_getGfxList(BKModelBin* arg0); -unsigned int OTRGetGameRenderWidth(void); -unsigned int OTRGetGameRenderHeight(void); // During FADE_IN, the game disables scene drawing one frame before // capturing gFramebuffers. Without freezing, the readback would overwrite @@ -197,9 +195,6 @@ void port_readAuxFbToCpu(Gfx** gfx) { // Picture model patching (Bottles Bonus / SNS pictures) -#define TILE_SIZE 32 -#define IMAGE_WIDTH (TILE_SIZE * 5) -#define IMAGE_HEIGHT (TILE_SIZE * 4) #define SEG4_TAGGED ((uintptr_t)0x04000000 | 1) #define FROM_XZ 0 #define FROM_YZ 1 diff --git a/src/port/Patches/GraphicsPatches.cpp b/src/port/Patches/GraphicsPatches.cpp index bf3d81e9f..7fbc86365 100644 --- a/src/port/Patches/GraphicsPatches.cpp +++ b/src/port/Patches/GraphicsPatches.cpp @@ -1,5 +1,6 @@ #include #include "port/UI/cvar_prefixes.h" +#include "port/Engine.h" #include "port/Enhancements/Events/Hooks/Events.h" #include "port/ShipInit.hpp" #include "port/ShipUtils.h" @@ -16,13 +17,12 @@ static int sDrawDistanceCubeWidth(int mul) { static int sDrawDistanceLevel = 0; static int sDisableLOD = 0; +#include "functions.h" extern "C" { #include "enums.h" -#include "functions.h" extern s32 gFramebufferWidth; extern s32 gFramebufferHeight; -float GameEngine_GetAspectRatio(void); // Widescreen HUD edge anchoring (centered-ortho HUD geometry). float port_hudOrthoShift(float refX) { @@ -40,7 +40,7 @@ float port_hudOrthoShift(float refX) { return 0.0f; // centered } -int port_getDrawDistanceLevel(void) { +int port_getDrawDistanceSetting(void) { int mul = CVarGetInteger(CVAR_ENHANCEMENT("Graphics.DrawDistance"), 1); if (mul < 1) { mul = 1; @@ -48,6 +48,11 @@ int port_getDrawDistanceLevel(void) { if (mul > kMaxDrawDistanceMul) { mul = kMaxDrawDistanceMul; } + return mul; +} + +int port_getDrawDistanceLevel(void) { + int mul = port_getDrawDistanceSetting(); if (IsDemoMode() && getGameMode() != GAME_MODE_4_PAUSED) { mul = 1; } diff --git a/src/port/Patches/MirrorPatches.cpp b/src/port/Patches/MirrorPatches.cpp index 9455105df..e1b7f1ce6 100644 --- a/src/port/Patches/MirrorPatches.cpp +++ b/src/port/Patches/MirrorPatches.cpp @@ -5,10 +5,10 @@ #include #include +#include "functions.h" extern "C" { #include "model.h" #include "prop.h" -#include "functions.h" } static bool sMirrorSceneActive = false; diff --git a/src/port/Patches/Patches.h b/src/port/Patches/Patches.h index b9ab1784c..5dafa405a 100644 --- a/src/port/Patches/Patches.h +++ b/src/port/Patches/Patches.h @@ -21,6 +21,11 @@ int port_pauseMenuNeedsRefresh(void); // language or Return-to-Lair CVar changed void port_pauseMenuRebuild(void); // free + recreate + replay the main menu open void port_setPrintScale(float scale); +// Dialog font (AltDialogFont.cpp, SpritePatches.cpp) + +void port_dialogFontHd_rebuild(void); // rebuild the HD glyph textures for the current base +void port_refreshDialogFontGlyphCount(void); // re-read the reachable glyph count from the active font + // Framebuffer (FramebufferPatches.cpp) void port_setViBlack(int active); @@ -64,7 +69,8 @@ int port_scalePlayerDamage(int damage); // Graphics (GraphicsPatches.cpp) -int port_getDrawDistanceLevel(void); +int port_getDrawDistanceSetting(void); // configured multiplier; safe during map load +int port_getDrawDistanceLevel(void); // render-time multiplier; clamped to 1x outside normal gameplay int port_shouldDisableLOD(void); float port_drawDistanceMul(void); void port_applyModelDrawDistanceCull(int* fadeFlag, float* cullMult, float* cullDist); diff --git a/src/port/Patches/SpritePatches.cpp b/src/port/Patches/SpritePatches.cpp index 496e231d9..88a0f6333 100644 --- a/src/port/Patches/SpritePatches.cpp +++ b/src/port/Patches/SpritePatches.cpp @@ -4,6 +4,8 @@ #include +#include "port/Patches/Patches.h" + extern "C" { #include "structs.h" @@ -19,7 +21,6 @@ void assetcache_release(void* asset); enum asset_e print_getCurrentMapBoldFontTexture(void); char* ResourceMgr_ReloadByAssetId(uint32_t assetId); -int ResourceMgr_IsJapanese(void); enum level_e level_get(void); s32 gcpausemenu_levelToMenuPage(enum level_e level); extern s32 gFramebufferWidth; @@ -132,9 +133,11 @@ BKSprite* port_loadFilledBanner(s32 bannerAssetId, s32 fillId) { u8* maskPx = px + (x + y * cw) * 4; const s32 intensity = maskPx[2]; // mask byte[2] = intensity const u8 alpha = maskPx[3]; // mask byte[3] = alpha - r5 *= (intensity / 0x1F); - g5 *= (intensity / 0x1F); - b5 *= (intensity / 0x1F); + // 5-bit channel * 8-bit intensity / 31 expands to 8-bit exactly (31 * 255 / 31 == 255). + // Dividing first truncates to 0..8, blacking out any intensity below 0x1F. + r5 = (r5 * intensity) / 0x1F; + g5 = (g5 * intensity) / 0x1F; + b5 = (b5 * intensity) / 0x1F; maskPx[0] = (u8)r5; maskPx[1] = (u8)g5; maskPx[2] = (u8)b5; diff --git a/src/port/Patches/TransitionPatches.cpp b/src/port/Patches/TransitionPatches.cpp index 7b4b82afe..116931cbe 100644 --- a/src/port/Patches/TransitionPatches.cpp +++ b/src/port/Patches/TransitionPatches.cpp @@ -8,9 +8,7 @@ #include "port/ShipInit.hpp" #include "port/Patches/Patches.h" -extern "C" { #include "enums.h" -} // Falling-pieces transition uids. #define TRANSITION_FALLING_PIECES_IN 0x10 diff --git a/src/port/Rando/CustomObject/CustomObject.cpp b/src/port/Rando/CustomObject/CustomObject.cpp index 2958bc2f1..dd007f8a7 100644 --- a/src/port/Rando/CustomObject/CustomObject.cpp +++ b/src/port/Rando/CustomObject/CustomObject.cpp @@ -2,6 +2,7 @@ #include #include "port/UI/cvar_prefixes.h" #include "port/Rando/Logic/Logic.h" +#include "port/Rando/ObjectBehavior/ObjectBehavior.h" #include "port/Enhancements/Events/Hooks/Events.h" #include "actor.h" @@ -34,7 +35,6 @@ void ml_vec3f_to_vec3h(s16 dst[3], f32 src[3]); void gcparade_beginFinalParade(void); void coMusicPlayer_playMusic(enum comusic_e track_id, s32 volume); -Actor* marker_getActor(ActorMarker* thisx); void marker_despawn(ActorMarker* marker); Actor* actor_new(s32 position[3], s32 yaw, ActorInfo* actorInfo, u32 flags); extern ActorInfo chJinjoBlue; @@ -86,7 +86,6 @@ std::map> actorInfoMap = { }; // clang-format on -extern int32_t GetJinjoActorMarkerId(actor_e actorId); int32_t currentMap = -1; void CustomObject::ResetRandoSpawnQueue() { diff --git a/src/port/Rando/LighthouseMenuRando.cpp b/src/port/Rando/LighthouseMenuRando.cpp index ee2ab49d7..871509332 100644 --- a/src/port/Rando/LighthouseMenuRando.cpp +++ b/src/port/Rando/LighthouseMenuRando.cpp @@ -10,9 +10,7 @@ #include -extern "C" { #include "variables.h" -} const char* logicModes[2] = { "Glitchless", diff --git a/src/port/Rando/Logic/GenerateSaveData.cpp b/src/port/Rando/Logic/GenerateSaveData.cpp index bce619fa1..bdbc12e6e 100644 --- a/src/port/Rando/Logic/GenerateSaveData.cpp +++ b/src/port/Rando/Logic/GenerateSaveData.cpp @@ -8,11 +8,9 @@ #include "port/Save/Types.h" extern "C" { -void ability_setLearned(s32 move, s32 val); void ability_setHasUsed(enum ability_e move); void item_setMaxCount(s32 item); -void fileProgressFlag_set(enum file_progress_e index, s32 set); } // clang-format off diff --git a/src/port/Rando/Logic/Logic.h b/src/port/Rando/Logic/Logic.h index 88e9f3b04..3e7bedaed 100644 --- a/src/port/Rando/Logic/Logic.h +++ b/src/port/Rando/Logic/Logic.h @@ -6,26 +6,13 @@ #include +#include "functions.h" extern "C" { -void item_set(s32 item, s32 val); -void item_adjustByDiffWithoutHud(enum item_e item, s32 diff); -s32 item_getCount(enum item_e item); -void itemscore_noteScores_clear(void); - -void ability_unlock(enum ability_e); -int ability_isUnlocked(enum ability_e uid); -void ability_setLearned(s32 move, s32 val); +// Decomp functions that functions.h does not declare (defined in smbottles.c, +// mumbo_transforms.c and jigsawpicture.c respectively). void __chSmBottles_skipIntroTutorial(void); - -void fileProgressFlag_set(enum file_progress_e index, s32 set); -bool fileProgressFlag_get(enum file_progress_e index); s32 __transformation_getCost(enum transformation_e trans_id); s32 _puzzleCost(s32 index); - -u32 player_getTransformation(void); - -enum level_e map_getLevel(enum map_e map); -enum map_e gsworld_getMap(void); } extern int32_t randoFinalSeed; diff --git a/src/port/Rando/MiscBehavior/OnFileLoad.cpp b/src/port/Rando/MiscBehavior/OnFileLoad.cpp index f4a3e49f7..ef1247193 100644 --- a/src/port/Rando/MiscBehavior/OnFileLoad.cpp +++ b/src/port/Rando/MiscBehavior/OnFileLoad.cpp @@ -8,10 +8,6 @@ #include "port/Rando/Logic/Logic.h" // #include "port/Rando/Spoiler/Spoiler.h" -extern "C" { -enum map_e gsworld_getMap(void); -} - void Rando::MiscBehavior::OnFileLoad() { REGISTER_LISTENER(OnGameLoad, EVENT_PRIORITY_NORMAL, [](IEvent* event) { OnGameLoad* ev = (OnGameLoad*)event; diff --git a/src/port/Rando/MiscBehavior/WorldState.cpp b/src/port/Rando/MiscBehavior/WorldState.cpp index 81163032b..e6916053e 100644 --- a/src/port/Rando/MiscBehavior/WorldState.cpp +++ b/src/port/Rando/MiscBehavior/WorldState.cpp @@ -5,17 +5,7 @@ #include "spdlog/spdlog.h" #include "enums.h" -extern "C" { -s32 getGameMode(void); -void mapSpecificFlags_set(s32 i, s32 val); -s32 mapSpecificFlags_get(s32 i); - -enum map_e gsworld_getMap(void); -enum level_e map_getLevel(enum map_e map); - -Struct70s* func_8034C5AC(s32 arg0); -void func_8034E71C(Struct73s* arg0, s32 arg1, f32 arg2); -} +#include "functions.h" // These read per-file save data, so they must not be evaluated before a file is selected. #define EMPTY_HONEYCOMB_OPTION_ENABLED \ diff --git a/src/port/Rando/ObjectBehavior/Molehill.cpp b/src/port/Rando/ObjectBehavior/Molehill.cpp index 2faf3459c..e54b87563 100644 --- a/src/port/Rando/ObjectBehavior/Molehill.cpp +++ b/src/port/Rando/ObjectBehavior/Molehill.cpp @@ -18,14 +18,6 @@ typedef struct { s8 ability; } ChMoleDescription; -extern "C" { -void func_80347A14(s32 arg0); -s32 item_adjustByDiffWithHud(enum item_e item, s32 diff); -void ability_unlock(enum ability_e); -s32 mapSpecificFlags_get(s32 i); -void mapSpecificFlags_set(s32 i, s32 val); -} - // clang-format off ChMoleDescription moleDialogTable[MOLETABLE_SIZE] = { //{ ASSET_DF3_DIALOG_BOTTLES_INTRODUCTION, ASSET_E08_DIALOG_BOTTLES_FIND_ANOTHER_MOLEHILL, 0x1, -1 }, diff --git a/src/port/Rando/ObjectBehavior/MusicNote.cpp b/src/port/Rando/ObjectBehavior/MusicNote.cpp index 5a67a9dd5..115d860fe 100644 --- a/src/port/Rando/ObjectBehavior/MusicNote.cpp +++ b/src/port/Rando/ObjectBehavior/MusicNote.cpp @@ -8,10 +8,6 @@ #include "port/Enhancements/Events/PortEnhancements.h" #include "port/Enhancements/Events/Hooks/Events.h" -extern "C" { -void item_inc(enum item_e item); -} - #define OPTION_ENABLED RANDO_SAVE_OPTIONS[RO_SHUFFLE_MUSIC_NOTES].optionValue void Rando::ObjectBehavior::InitMusicNoteBehavior() { diff --git a/src/port/Rando/ObjectBehavior/ObjectBehavior.cpp b/src/port/Rando/ObjectBehavior/ObjectBehavior.cpp index b18729cae..a86462f6e 100644 --- a/src/port/Rando/ObjectBehavior/ObjectBehavior.cpp +++ b/src/port/Rando/ObjectBehavior/ObjectBehavior.cpp @@ -13,13 +13,6 @@ #define CVAR_SHOW_COLLISION_NOTIFICATIONS CVarGetInteger(CVAR_NAME_SHOW_COLLISION_NOTIFICATIONS, 0) extern "C" { -void player_getPosition(f32 dst[3]); -Actor* marker_getActor(ActorMarker* thisx); -bool func_802C9C14(Actor* actor); - -s32 mapSpecificFlags_get(s32 i); - -void coMusicPlayer_playMusic(enum comusic_e track_id, s32 volume); extern ActorArray* suBaddieActorArray; } diff --git a/src/port/Rando/ObjectBehavior/Switch.cpp b/src/port/Rando/ObjectBehavior/Switch.cpp index 619f4979b..c26be158c 100644 --- a/src/port/Rando/ObjectBehavior/Switch.cpp +++ b/src/port/Rando/ObjectBehavior/Switch.cpp @@ -6,13 +6,7 @@ #include "spdlog/spdlog.h" extern "C" { -Actor* actorArray_findActorFromActorId(enum actor_e actor_id); void destroyJiggy(Actor* thisx, s32 arg1, s32 arg2, s32 arg3, s32 arg4, s32 arg5, enum volatile_flags_e arg6); - -s32 mapSpecificFlags_get(s32 i); -void mapSpecificFlags_set(s32 i, s32 val); - -void actor_collisionOff(Actor*); } #define OPTION_ENABLED RANDO_SAVE_OPTIONS[RO_SHUFFLE_JIGGIES].optionValue diff --git a/src/port/Rando/StaticData/Checks.cpp b/src/port/Rando/StaticData/Checks.cpp index 834064a91..2ee062e46 100644 --- a/src/port/Rando/StaticData/Checks.cpp +++ b/src/port/Rando/StaticData/Checks.cpp @@ -4,11 +4,6 @@ #include "prop.h" #include "include/core1/sns.h" -extern "C" { -enum map_e gsworld_getMap(void); -enum level_e map_getLevel(enum map_e map); -} - namespace Rando { namespace StaticData { diff --git a/src/port/Resource/Alt/AltDialogFont.cpp b/src/port/Resource/Alt/AltDialogFont.cpp index 53bcfbf87..f3f477398 100644 --- a/src/port/Resource/Alt/AltDialogFont.cpp +++ b/src/port/Resource/Alt/AltDialogFont.cpp @@ -14,6 +14,7 @@ #include #include "port/Enhancements/Events/Hooks/Events.h" +#include "port/Patches/Patches.h" #include "port/ShipInit.hpp" #include @@ -22,8 +23,6 @@ #include #include -extern "C" void port_dialogFontHd_rebuild(void); - namespace { constexpr const char* kFontBase = "assets/sprite/ASSET_6EB_DIALOG_FONT_ALPHAMASK"; diff --git a/src/port/Resource/Importers/ModelFactory.cpp b/src/port/Resource/Importers/ModelFactory.cpp index c1c4ebc41..ce586d8a1 100644 --- a/src/port/Resource/Importers/ModelFactory.cpp +++ b/src/port/Resource/Importers/ModelFactory.cpp @@ -9,9 +9,7 @@ #include -extern "C" { #include "model.h" -} namespace Factories { namespace { @@ -441,10 +439,6 @@ ResourceFactoryBinaryModelV0::ReadResource(std::shared_ptr file, // Write pixel data area (raw blob from Torch) if (blobPtr) { AppendBytes(out, blobPtr, rawTexDataSize); - } else { - // Fallback: zero-filled if blob was missing - for (uint32_t i = 0; i < rawTexDataSize; i++) - out.push_back(0); } } diff --git a/src/port/Resource/Type/Sprite.cpp b/src/port/Resource/Type/Sprite.cpp index 38c8c0e7e..72c12daef 100644 --- a/src/port/Resource/Type/Sprite.cpp +++ b/src/port/Resource/Type/Sprite.cpp @@ -125,27 +125,6 @@ void Sprite::BuildSpriteStructure() { // SPDLOG_DEBUG(" Frame buffer size: {} bytes, pointer: {}", // frameSizes[frameIdx], static_cast(sprite->frames[frameIdx])); } - - // SPDLOG_INFO("=== Sprite structure complete (total {} bytes) ===", totalSize); - - // Verify - // SPDLOG_INFO("Verification: frameCnt={}, type=0x{:X}", sprite->frameCnt, sprite->type); - if (frameCount > 0) { - BKSpriteFrame* verifyFrame = sprite->frames[0]; - // SPDLOG_INFO("Frame 0: w={}, h={}, chunkCnt={}, frame pointer={}", - // verifyFrame->w, verifyFrame->h, verifyFrame->chunkCnt, - // static_cast(verifyFrame)); - - if (verifyFrame->chunkCnt > 0) { - BKSpriteTextureBlock* verifyChunk = reinterpret_cast(verifyFrame + 1); - // SPDLOG_INFO("First chunk at frame+1: pointer={}, pos=({}, {}), size={}x{}", - // static_cast(verifyChunk), - // verifyChunk->x, verifyChunk->y, verifyChunk->w, verifyChunk->h); - // SPDLOG_INFO("Expected offset from frame: {} bytes, actual: {} bytes", - // sizeof(BKSpriteFrame), - // reinterpret_cast(verifyChunk) - reinterpret_cast(verifyFrame)); - } - } } BKSprite* Sprite::GetPointer() { diff --git a/src/port/ResourceHelpers.cpp b/src/port/ResourceHelpers.cpp index 7e16a1567..922d6c435 100644 --- a/src/port/ResourceHelpers.cpp +++ b/src/port/ResourceHelpers.cpp @@ -27,12 +27,8 @@ #include "GameVersion/AssetVersionRemap.h" #include "GameVersion/BaseGameVersion.h" -extern "C" { #include "enums.h" -} -extern "C" uint16_t ResourceMgr_LoadTexWidthByName(char* texPath); -extern "C" uint16_t ResourceMgr_LoadTexHeightByName(char* texPath); extern "C" void func_8031B5C4(int32_t lang); // decomp: set dialog language index // Dialog language state — detected at boot from o2r version @@ -171,6 +167,11 @@ extern "C" int ResourceMgr_GetDialogLanguageCount(void) { return sDialogLanguageCount; } +// PAL is the only base that carries more than one dialog language (EN/FR/DE). +extern "C" int ResourceMgr_IsPal(void) { + return sDialogLanguageCount > 1 ? 1 : 0; +} + extern "C" int ResourceMgr_IsJapanese(void) { return sIsJapanese ? 1 : 0; } diff --git a/src/port/ResourceHelpers.h b/src/port/ResourceHelpers.h index 532b452a2..bb0381307 100644 --- a/src/port/ResourceHelpers.h +++ b/src/port/ResourceHelpers.h @@ -18,6 +18,7 @@ void ResourceMgr_RegisterAssetOverride(uint32_t assetId, const char* customPath) size_t ResourceMgr_GetResourceSize(uint32_t assetId); int ResourceMgr_IsModelAsset(uint32_t assetId); int ResourceMgr_GetDialogLanguageCount(void); +int ResourceMgr_IsPal(void); int ResourceMgr_IsJapanese(void); int ResourceMgr_GetDialogLanguage(void); void ResourceMgr_SetDialogLanguage(int lang); diff --git a/src/port/Romhack/RomhackConfig.cpp b/src/port/Romhack/RomhackConfig.cpp index e989cca8c..092d875b3 100644 --- a/src/port/Romhack/RomhackConfig.cpp +++ b/src/port/Romhack/RomhackConfig.cpp @@ -444,39 +444,6 @@ static void LoadGameConfig() { } } - int codeConstCount = 0; - for (int i = 0; i < 24; i++) { - // Check each static against its default (-1) - const int* vals[] = { &sNewGameMap, &sStartLevel1, &sStartLevel2, - &sKnowAllMoves, &sMumboCostTermite, &sMumboCostCroc, - &sMumboCostWalrus, &sMumboCostPumpkin, &sMumboCostBee, - &sEggsNormalMax, &sRedFeathersNormalMax, &sGoldFeathersNormalMax, - &sEggsCheatomax, &sRedFeathersCheatomax, &sGoldFeathersCheatomax, - &sNotesMax, &sJiggiesPerWorld, &sHoneycombsPerWorld, - &sExtraHcStart, &sWarpExitBanjosHouse, &sWarpEnterLair, - &sSpecialLevel, &sHideJiggiesLevel, &sHideCollectiblesLevel }; - if (*vals[i] != -1) { - codeConstCount++; - } - } - int levelNameCount = 0; - for (int i = 0; i < 13; i++) { - if (sLevelNames[i]) { - levelNameCount++; - } - } - int noteDoorCount = 0; - for (int i = 0; i < 12; i++) { - if (sNoteDoors[i] != -1) { - noteDoorCount++; - } - } - int jiggyCostCount = 0; - for (int i = 0; i < 11; i++) { - if (sJiggyCosts[i] != -1) { - jiggyCostCount++; - } - } if (sCustomCodeHashHex.empty()) { // Data-only romhack — BB patches only, no injected MIPS to identify. // Fall back to the o2r-derived name for visibility. diff --git a/src/port/Save/SaveManager.cpp b/src/port/Save/SaveManager.cpp index 9b7b5ffd0..ffc65d916 100644 --- a/src/port/Save/SaveManager.cpp +++ b/src/port/Save/SaveManager.cpp @@ -22,8 +22,6 @@ extern "C" { extern SaveData gameFile_saveData[4]; extern s8 gameFile_GameIdToFileIdMap[4]; -void savedata_update_crc(void* buffer, s32 size); -s32 item_getCount(enum item_e item); extern u8 gCompletedBottlesBonusGames[7]; } diff --git a/src/port/ShipUtils.cpp b/src/port/ShipUtils.cpp index 77116aa28..d1df32c95 100644 --- a/src/port/ShipUtils.cpp +++ b/src/port/ShipUtils.cpp @@ -75,7 +75,6 @@ extern "C" { #include "enums.h" // game_mode_e // Furnace Fun active flag -s32 volatileFlag_get(s32); s32 getGameMode(void); int gPortResetPending = 0; diff --git a/src/port/UI/DeveloperTools/GameplayTools.cpp b/src/port/UI/DeveloperTools/GameplayTools.cpp index d1b7d1af3..0c40e009d 100644 --- a/src/port/UI/DeveloperTools/GameplayTools.cpp +++ b/src/port/UI/DeveloperTools/GameplayTools.cpp @@ -20,23 +20,6 @@ #include "include/core1/sns.h" extern "C" { -void sns_set_item_state(enum StopNSwop_Item item, s32 set, s32 state); -void jiggy_spawn(enum jiggy_e jiggy_id, f32 pos[3]); -void player_getPosition(f32 dst[3]); -void player_getPosition_s32(s32 arg0[3]); -enum map_e gsworld_getMap(void); -Actor* actor_new(s32 position[3], s32 yaw, ActorInfo* actorInfo, u32 flags); -void func_8031D04C(enum map_e arg0, s32 exit_id); - -void item_set(s32 item, s32 val); -void ability_setAllLearned(s32 val); -void ability_setAllUsed(s32 val); - -s32 mapSpecificFlags_get(s32 i); -void mapSpecificFlags_set(s32 i, s32 val); -enum map_e gsworld_getMap(void); -enum level_e map_getLevel(enum map_e map); - typedef struct { enum honeycomb_e uid; s32 unk4; diff --git a/src/port/UI/DeveloperTools/SaveEditor.cpp b/src/port/UI/DeveloperTools/SaveEditor.cpp index 92ed90fd0..259b79c30 100644 --- a/src/port/UI/DeveloperTools/SaveEditor.cpp +++ b/src/port/UI/DeveloperTools/SaveEditor.cpp @@ -13,10 +13,8 @@ #include "port/UI/LighthouseGui.hpp" #include "port/UI/cvar_prefixes.h" -extern "C" { #include "enums.h" #include "prop.h" -} #define DEFAULT_MAX_HEALTH 8 #define DEFAULT_MAX_EGGS 100 @@ -27,16 +25,8 @@ extern "C" { #define HONEYCOMB_ID_MULTIPLIER(levelId) (1 + (2 * (levelId - 1))) extern "C" { -bool player_is_present(void); -s32 item_getCount(enum item_e item); -void item_set(s32 item, s32 val); -bool fileProgressFlag_get(enum file_progress_e index); -void fileProgressFlag_set(enum file_progress_e index, s32 set); int ability_isUnlocked(enum ability_e uid); -void ability_setLearned(s32 move, s32 val); -u32 jiggyscore_isCollected(enum jiggy_e jiggy_id); void jiggyscore_setCollected(s32 indx, s32 val); -bool honeycombscore_get(enum honeycomb_e indx); void honeycombscore_set(enum honeycomb_e indx, bool val); void mumboscore_set(enum mumbotoken_e indx, bool val); diff --git a/src/port/UI/LighthouseMenuDevTools.cpp b/src/port/UI/LighthouseMenuDevTools.cpp index b0b171b8c..9c6b40369 100644 --- a/src/port/UI/LighthouseMenuDevTools.cpp +++ b/src/port/UI/LighthouseMenuDevTools.cpp @@ -9,9 +9,7 @@ #include "UIWidgets.hpp" #include -extern "C" { #include "variables.h" -} namespace LighthouseGui { diff --git a/src/port/UI/LighthouseMenuEnhancements.cpp b/src/port/UI/LighthouseMenuEnhancements.cpp index a672a930b..bd5ba9667 100644 --- a/src/port/UI/LighthouseMenuEnhancements.cpp +++ b/src/port/UI/LighthouseMenuEnhancements.cpp @@ -2,8 +2,8 @@ #include "port/Enhancements/Trackers/DisplayOverlay.h" #include "port/Network/Anchor/Anchor.h" -extern "C" { #include "functions.h" +extern "C" { #include "variables.h" extern u8 gCompletedBottlesBonusGames[7]; } diff --git a/src/port/UI/LighthouseMenuNetwork.cpp b/src/port/UI/LighthouseMenuNetwork.cpp index 42310a6a7..5759914bc 100644 --- a/src/port/UI/LighthouseMenuNetwork.cpp +++ b/src/port/UI/LighthouseMenuNetwork.cpp @@ -7,9 +7,7 @@ #include "UIWidgets.hpp" #include -extern "C" { #include "variables.h" -} namespace LighthouseGui { diff --git a/src/port/UI/LighthouseMenuSettings.cpp b/src/port/UI/LighthouseMenuSettings.cpp index e4bbe7847..989910876 100644 --- a/src/port/UI/LighthouseMenuSettings.cpp +++ b/src/port/UI/LighthouseMenuSettings.cpp @@ -13,9 +13,7 @@ #include "UIWidgets.hpp" #include -extern "C" { #include "variables.h" -} namespace LighthouseGui { diff --git a/src/port/UI/Menu.cpp b/src/port/UI/Menu.cpp index a79fef5f0..187bdd140 100644 --- a/src/port/UI/Menu.cpp +++ b/src/port/UI/Menu.cpp @@ -15,7 +15,6 @@ std::vector windowTypeSizes = { {} }; extern std::unordered_map warpPointSceneList; -extern void Warp(); namespace LighthouseGui { extern std::shared_ptr mModalWindow; diff --git a/src/port/enhancements/Gameplay/DisableSnackerSpawn.cpp b/src/port/enhancements/Gameplay/DisableSnackerSpawn.cpp index aad0f5b07..5d2c7c7a4 100644 --- a/src/port/enhancements/Gameplay/DisableSnackerSpawn.cpp +++ b/src/port/enhancements/Gameplay/DisableSnackerSpawn.cpp @@ -7,9 +7,7 @@ #include "port/Enhancements/Events/Hooks/Events.h" #include "port/ShipInit.hpp" -extern "C" { #include "enums.h" -} #define CVAR_DISABLE_SNACKER CVAR_ENHANCEMENT("Gameplay.DisableSnackerSpawn") #define CVAR CVarGetInteger(CVAR_DISABLE_SNACKER, 0) diff --git a/src/port/enhancements/Gameplay/EasierMrVile.cpp b/src/port/enhancements/Gameplay/EasierMrVile.cpp index 9e3b89d18..94ce8d771 100644 --- a/src/port/enhancements/Gameplay/EasierMrVile.cpp +++ b/src/port/enhancements/Gameplay/EasierMrVile.cpp @@ -7,9 +7,7 @@ #include "port/Enhancements/Events/Hooks/Events.h" #include "port/ShipInit.hpp" -extern "C" { #include "enums.h" -} #define CVAR_EASIER_MR_VILE CVAR_ENHANCEMENT("EasierMrVile") #define CVAR CVarGetInteger(CVAR_EASIER_MR_VILE, 0) From fae0beefc85019316e57aa92ad9929d51fe6cc99 Mon Sep 17 00:00:00 2001 From: Jeod <47716344+JeodC@users.noreply.github.com> Date: Sat, 25 Jul 2026 12:28:31 -0400 Subject: [PATCH 017/131] Decomp pass 5 (#247) * CCW documentation from decomp upstream * audioManager documentation from decomp upstream * RBB documentation from decomp upstream * Model Appendages and BS method table documentation from decomp upstream * Compile fixes and clang-format after decomp pass 5 * Fix clang -Wint-conversion errors in RBB whistle tables * Fix clang -Wint-conversion and pointer-type errors from decomp pass 5 * Align filenames and decomp header comments with upstream * Missed one * Documentation and file renames from decomp upstream * Checksums, 08776d1f * PAL matching from decomp upstream * Rubee & Function Documentation, ac3ddb91 * PAL match func_80240204, 1b2edf8b * PAL matching 2, 485bef33 * Draw code documentation from decomp and pointer truncation fixups * Add decomp's headers split * Missed function renames from past decomp commits * Cleanup functions.h a bit * Post-rebase fixups --- include/bk_math.h | 2 + include/bool.h | 9 + include/bs_funcs.h | 270 +++--- include/checksums.h | 115 +++ include/core1/core1.h | 48 +- include/core1/main.h | 4 +- include/core1/ml.h | 10 +- include/core1/viewport.h | 2 +- include/core2/ba/carry.h | 2 +- include/core2/ba/timer.h | 2 +- include/core2/modelRender.h | 2 +- include/enums.h | 744 ++++++++------- include/functions.h | 844 ++++++++---------- include/gc/gctransition.h | 2 +- include/prop.h | 4 +- .../{actor_spawninit.c => bgsspawnqueue.c} | 12 +- src/BGS/bss_pad.c | 2 - src/BGS/ch/{choir_turtle.c => choirturtle.c} | 6 +- src/BGS/ch/croctus.c | 169 ++-- src/BGS/ch/frogminigame.c | 31 +- src/BGS/ch/leafboat.c | 4 +- src/BGS/ch/mrvile.c | 106 +-- src/BGS/ch/mudhut.c | 4 +- src/BGS/ch/pinkegg.c | 4 +- src/BGS/ch/swampswitch.c | 8 +- src/BGS/ch/tanktup.c | 310 +++---- src/BGS/ch/{tanktup_legs.c => tanktuplegs.c} | 14 +- src/BGS/ch/tiptup.c | 328 ++++--- src/BGS/ch/yumblie.c | 6 +- src/BGS/checksums.c | 7 + src/BGS/crc.c | 9 +- src/BGS/{minigame_vile.c => mrvileminigame.c} | 476 ++++++---- src/CC/bss_pad.c | 2 - src/CC/{actor_spawninit.c => ccspawnqueue.c} | 2 +- src/CC/ch/{clanker.c => ccgrates.c} | 2 +- src/CC/ch/{key.c => clankerkey.c} | 14 +- src/CC/ch/{screw.c => clankerscrew.c} | 18 +- src/CC/ch/clankertoothext.c | 32 +- src/CC/checksums.c | 7 + src/CC/crc.c | 10 +- src/CC/ma/clanker.c | 451 ++++++++++ src/CC/ma/clankerrings.c | 130 +++ src/CC/minigame_rings.c | 127 --- src/CC/model_renderstate.c | 24 +- src/CC/platform_physics.c | 445 --------- src/CCW/actor_spawninit.c | 157 ---- src/CCW/bss_pad.c | 2 - src/CCW/ccwspawnqueue.c | 229 +++++ src/CCW/ch/acorn.c | 122 +-- src/CCW/ch/adulteyrie.c | 129 +++ src/CCW/ch/beanstalk.c | 239 +++++ .../ch/{nabnut_summer.c => bellyfullnabnut.c} | 52 +- src/CCW/ch/caterpillar.c | 129 +-- src/CCW/ch/{gobi_ccw.c => ccwgobi.c} | 143 +-- src/CCW/ch/cutsceneadulteyrie.c | 114 +++ src/CCW/ch/deadbeanstalk.c | 14 +- src/CCW/ch/deadsnarebear.c | 25 + src/CCW/ch/eyrie_baby.c | 314 ------- src/CCW/ch/eyrie_egg.c | 81 -- src/CCW/ch/eyrie_summer.c | 120 --- src/CCW/ch/eyrie_winter.c | 105 --- src/CCW/ch/eyrieegg.c | 94 ++ src/CCW/ch/fairy.c | 129 --- src/CCW/ch/gnawty.c | 143 --- src/CCW/ch/gnawtyboulder.c | 50 +- src/CCW/ch/grublinhood.c | 45 +- src/CCW/ch/indoorsgnawty.c | 98 ++ src/CCW/ch/nabnut_autumn.c | 194 ---- src/CCW/ch/nabnut_dialog.c | 85 -- src/CCW/ch/nabnut_spring.c | 97 -- src/CCW/ch/nabnut_winter.c | 124 --- src/CCW/ch/outsideautumnnabnut.c | 226 +++++ src/CCW/ch/seasonswitchdoors.c | 239 +++++ src/CCW/ch/snarebear.c | 138 ++- src/CCW/ch/snore.c | 28 +- src/CCW/ch/springnabnut.c | 110 +++ src/CCW/ch/summeroutsidegnawty.c | 160 ++++ src/CCW/ch/swimminggnawty.c | 140 +++ src/CCW/ch/vacationtexttrigger.c | 2 +- src/CCW/ch/zubba.c | 216 ----- src/CCW/ch/zubba_hive_npc.c | 133 --- src/CCW/ch/zubbadoor.c | 37 +- src/CCW/ch/zubbahoneylump.c | 244 +++++ src/CCW/checksums.c | 7 + src/CCW/eyrie_baby.c | 382 ++++++++ src/CCW/flower.c | 184 ---- src/CCW/minigame_zubba.c | 221 ----- src/CCW/nabnut_winter.c | 174 ++++ src/CCW/seasonal_switch.c | 179 ---- src/CCW/snarebear_proximity.c | 122 --- src/CCW/zubba.c | 240 +++++ src/CCW/zubba_hive_npc.c | 157 ++++ src/FP/bss_pad.c | 2 - src/FP/ch/bearcub.c | 16 +- src/FP/ch/boggy1.c | 12 +- src/FP/ch/boggy2.c | 52 +- src/FP/ch/boggy3.c | 14 +- .../slalomctrl.c => ch/boggyraceflag1.c} | 8 +- .../slalom2ctrl.c => ch/boggyraceflag2.c} | 8 +- src/FP/ch/cavewozza.c | 10 +- src/FP/ch/racesled.c | 2 +- src/FP/ch/snowmanbutton.c | 4 +- src/FP/ch/twinkly.c | 10 +- src/FP/ch/twinklybox.c | 6 +- src/FP/ch/twinklymuncher.c | 6 +- src/FP/ch/wozza.c | 14 +- src/FP/ch/xmastree.c | 70 +- src/FP/ch/xmastreestar.c | 4 +- src/FP/ch/xmastreeswitch.c | 4 +- src/FP/checksums.c | 7 + src/FP/{actor_spawninit.c => fpspawnqueue.c} | 4 +- src/FP/{mapstate => ma}/slalom.c | 24 +- src/FP/{mapstate => ma}/snowbutton.c | 0 src/FP/{mapstate => ma}/snowy.c | 0 src/FP/{ch => }/wozza_fire.c | 0 src/GV/bss_pad.c | 2 - src/GV/{ch => }/cactus.c | 0 src/GV/{ch => }/carpet1.c | 0 src/GV/{ch => }/carpet2.c | 6 +- src/GV/ch/ancientone.c | 14 +- src/GV/ch/buriedpyramid.c | 2 +- src/GV/ch/{egg_pot.c => eggpot.c} | 2 +- src/GV/ch/gobi1.c | 6 +- src/GV/ch/gobi2.c | 8 +- src/GV/ch/gobi3.c | 4 +- src/GV/ch/gobirock.c | 2 +- src/GV/ch/gobirope.c | 2 +- src/GV/ch/grabba.c | 12 +- src/GV/ch/histup.c | 20 +- src/GV/ch/jinxy.c | 158 ---- src/GV/{ => ch}/mazectrl.c | 16 +- src/GV/ch/mummum.c | 2 +- src/GV/ch/sarcophagus.c | 2 +- src/GV/ch/slappa.c | 2 +- src/GV/ch/toots.c | 2 +- src/GV/ch/trunker.c | 6 +- src/GV/checksums.c | 7 + src/GV/crc.c | 10 +- src/GV/gv_helpers.c | 14 +- src/GV/{actor_spawninit.c => gvspawnqueue.c} | 56 +- src/GV/{ch => }/handshadow.c | 0 src/GV/{ch => }/jinxy_head.c | 0 src/GV/magiccarpet2.c | 171 ++++ .../carpet_shadow.c => magiccarpetshadow.c} | 19 +- src/GV/matchinggame.c | 6 +- src/GV/pyramid_raise.c | 163 ++-- src/GV/{ch => }/rubee.c | 64 +- .../{pyramid_trigger.c => sandybutteggtoll.c} | 13 +- src/GV/smoke_particle.c | 4 +- src/LAIR/bss_pad.c | 2 - src/MM/ch/conga.c | 201 +++-- src/MM/ch/conga.h | 11 + src/MM/ch/hut.c | 4 +- src/MM/ch/juju.c | 3 +- src/MM/ch/lmonkey.c | 2 +- src/MM/ch/orange.c | 2 +- src/MM/ch/orangepad.c | 159 ++-- src/MM/ch/orangepad.h | 14 + src/MM/checksums.c | 7 + src/MM/crc.c | 8 +- src/MM/{actor_spawninit.c => mmspawnqueue.c} | 2 +- src/MMM/bathroom_particles.c | 6 +- src/MMM/bss_pad.c | 2 - src/MMM/ch/{flowerpot.c => cemetarypot.c} | 6 +- src/MMM/ch/loggo.c | 10 +- src/MMM/ch/napper.c | 16 +- src/MMM/ch/portrait.c | 4 +- .../{portrait_chompa.c => portraitchompa.c} | 6 +- src/MMM/ch/{limbo.c => skeleton.c} | 6 +- src/MMM/ch/tumblar.c | 11 +- src/MMM/checksums.c | 7 + src/MMM/crc.c | 9 +- src/MMM/minigame_organ.c | 10 +- src/MMM/minigame_shed.c | 2 +- .../{actor_spawninit.c => mmmspawnqueue.c} | 209 ++--- src/MMM/napper_room.c | 8 +- src/RBB/actor_spawninit.c | 231 ----- src/RBB/bss_pad.c | 2 - src/RBB/ch/anchor.c | 33 +- src/RBB/ch/anchorctrl.c | 45 +- src/RBB/ch/anchorswitch.c | 27 +- src/RBB/ch/axle.c | 138 +-- src/RBB/ch/bellbuoy.c | 153 ++-- src/RBB/ch/boombox.c | 253 +++--- src/RBB/ch/bossboombox.c | 450 +++++----- src/RBB/ch/bossboomboxctrl.c | 18 +- src/RBB/ch/cog.c | 67 +- src/RBB/ch/dolphin.c | 76 +- src/RBB/ch/eggtoll1.c | 151 ++-- src/RBB/ch/enginefan.c | 142 +-- src/RBB/ch/enginefanswitch.c | 29 +- src/RBB/ch/engineparts.c | 104 ++- src/RBB/ch/grimlet.c | 113 +-- src/RBB/ch/propellor.c | 43 +- src/RBB/ch/propellorswitch.c | 35 +- src/RBB/ch/rarewareflag.c | 13 +- src/RBB/ch/rowboat.c | 137 +-- .../ch/{seaman_grublin.c => seamangrublin.c} | 2 +- src/RBB/ch/siren.c | 61 -- src/RBB/ch/whistle.c | 109 +-- src/RBB/ch/whistlectrl.c | 39 +- src/RBB/ch/whistleswitch.c | 134 +-- src/RBB/checksums.c | 7 + src/RBB/crane_boombox.c | 79 +- src/RBB/crane_jiggycage.c | 87 +- src/RBB/miniboombox_container.c | 54 +- src/RBB/propellorctrl.c | 4 +- src/RBB/rbbspawnqueue.c | 239 +++++ src/RBB/siren.c | 81 ++ src/SM/{ch => }/bottles_movecheck.c | 0 src/SM/ch/ambient_fish.c | 2 +- src/SM/ch/jumptutorial.c | 14 +- src/SM/ch/smbottles.c | 4 +- src/SM/ch/vegetables.c | 8 +- src/SM/checksums.c | 7 + src/SM/{ch => }/furniture.c | 0 src/SM/{ch => }/quarrie.c | 0 src/SM/{crc.c => smspawnqueue.c} | 46 +- src/SM/version_compat.c | 168 ++-- src/TTC/actor_spawninit.c | 8 +- src/TTC/ch/blubber.c | 14 +- src/TTC/ch/clam.c | 8 +- src/TTC/ch/leaky.c | 10 +- src/TTC/ch/lockup.c | 10 +- src/TTC/ch/lockup.h | 23 + src/TTC/ch/nipper.c | 12 +- src/TTC/ch/treasure.c | 2 +- src/TTC/ch/treasurehunt.c | 44 +- src/TTC/checksums.c | 7 + src/TTC/crc.c | 23 +- src/TTC/{ => ma}/castle.c | 16 +- src/boot/bk_boot_1050.c | 10 +- src/core1/audio_instruments.c | 13 +- src/core1/audio_manager.c | 687 +++++++------- src/core1/{io => }/bamotor.c | 0 src/core1/debugtext.c | 2 +- src/core1/defragmanager.c | 4 +- src/core1/depthbuffer.c | 54 +- src/core1/display_list.c | 102 ++- src/core1/graphics_thread.c | 2 +- src/core1/{math/ml.c => gu_matrix.c} | 2 +- src/core1/{math/mlmtx.c => gu_perspective.c} | 13 +- src/core1/init.c | 16 +- src/core1/math/longlong_arith.c | 63 -- src/core1/math/longlong_convert.c | 40 - src/core1/{math/vector.c => ml.c} | 136 ++- src/core1/{math/matrix_stack.c => mlmtx.c} | 12 +- src/core1/musicplayer.c | 47 +- src/core1/musicplayer.h | 7 + src/core1/overlay.c | 15 +- src/core1/{io => }/pfsmanager.c | 20 +- src/core1/{stopnswop_payload.c => sns.c} | 2 +- src/core1/stopnswop.c | 4 +- src/core1/syncprintf.c | 17 - src/core1/viewport.c | 20 +- src/core1/vimgr.c | 4 +- src/core2/actor_array.c | 40 +- src/core2/actor_cleanup.c | 5 +- src/core2/actor_cubepropsystem.c | 36 +- src/core2/actor_motioncurve.c | 29 +- src/core2/actor_updatestub.c | 15 +- src/core2/anim/{controller.c => anctrl.c} | 1 + src/core2/anim/anim_bonetransform.c | 6 + src/core2/anim/anim_buffer.c | 1 + src/core2/anim/anim_defrag.c | 1 + src/core2/anim/anim_driver.c | 82 +- src/core2/anim/anim_sequencehandler.c | 1 + src/core2/anim/{anim_cache.c => animcache.c} | 1 + ...anim_texturecache.c => animtexturecache.c} | 1 + src/core2/anim/{sequence.c => anseq.c} | 1 + .../{anim_sequencestruct.c => betavent.c} | 17 +- src/core2/anim/bonetransformlist.c | 1 + .../anim/{anim_spriteframe.c => chumpfish.c} | 3 +- src/core2/anim/{skeletal.c => skeletalanim.c} | 1 + src/core2/anim/sprite.c | 2 +- src/core2/ba/{ba_anim.c => anim.c} | 7 +- src/core2/ba/ba_animcache.c | 1 + src/core2/ba/ba_animstate.c | 197 ---- src/core2/ba/ba_camera.c | 3 +- src/core2/ba/ba_eyeblink_data.c | 1 + src/core2/ba/ba_eyemouth_data.c | 9 +- src/core2/ba/ba_falling.c | 4 +- src/core2/ba/ba_health.c | 5 +- src/core2/ba/ba_hitbox.c | 17 +- src/core2/ba/ba_intensity.c | 1 + src/core2/ba/ba_lookdir.c | 63 +- src/core2/ba/ba_momentum.c | 1 + src/core2/ba/ba_musicstate.c | 1 + src/core2/ba/ba_recoil.c | 9 +- src/core2/ba/ba_state.c | 331 ------- src/core2/ba/ba_statusflags.c | 3 +- src/core2/ba/ba_stickinterp.c | 1 + src/core2/ba/ba_underwater.c | 1 + src/core2/ba/ba_yaw.c | 1 + src/core2/ba/{ba_bounds.c => babounds.c} | 3 +- src/core2/ba/{ba_buzz.c => babuzz.c} | 1 + src/core2/ba/{ba_eyes.c => baeyes.c} | 11 +- src/core2/ba/{ba_flag.c => baflag.c} | 1 + src/core2/ba/{ba_input.c => bainput.c} | 1 + src/core2/ba/{ba_key.c => bakey.c} | 1 + src/core2/ba/{ba_lookat.c => balookat.c} | 1 + src/core2/ba/{ba_sfx.c => basfx.c} | 1 + src/core2/ba/{ba_stick.c => bastick.c} | 3 +- src/core2/ba/{ba_timer.c => batimer.c} | 5 +- src/core2/ba/bsmethods.c | 335 +++++++ .../ba/{ba_carriedobj.c => carriedobj.c} | 7 +- src/core2/ba/{ba_carry.c => carry.c} | 3 +- src/core2/ba/{ba_scripted.c => drone.c} | 1 + .../ba/{ba_falldamage.c => falldamage.c} | 5 +- src/core2/ba/{ba_flap.c => flap.c} | 1 + .../ba/{ba_groundsurface.c => hazards.c} | 4 +- src/core2/ba/{ba_eyeblink.c => iFrame.c} | 2 + src/core2/ba/iFrame.h | 10 + src/core2/ba/{ba_marker.c => marker.c} | 15 +- src/core2/ba/{ba_model.c => model.c} | 15 +- src/core2/ba/modelappendages.c | 209 +++++ src/core2/ba/{ba_physics.c => physics.c} | 17 +- .../ba/{ba_modelselect.c => playermodel.c} | 24 +- .../ba/{ba_position.c => playerposition.c} | 9 +- src/core2/bs/ant.c | 60 +- src/core2/bs/{beak_barge.c => bBarge.c} | 10 +- src/core2/bs/{beak_egg_fire.c => bEggAss.c} | 10 +- src/core2/bs/{beak_egg_aim.c => bEggHead.c} | 10 +- src/core2/bs/{flap_flip.c => bFlap.c} | 8 +- src/core2/bs/{backflip.c => bFlip.c} | 10 +- src/core2/bs/{beak_bomb.c => bFly.c} | 118 +-- src/core2/bs/{stilt_stride.c => bLongLeg.c} | 68 +- src/core2/bs/{beak_peck.c => bPeck.c} | 7 +- src/core2/bs/{shock_spring.c => bShock.c} | 28 +- src/core2/bs/{beak_swim.c => bSwim.c} | 68 +- src/core2/bs/{talon_trot.c => bTrot.c} | 46 +- src/core2/bs/{wonderwing.c => bWhirl.c} | 26 +- src/core2/bs/{beak_buster.c => bbuster.c} | 12 +- src/core2/bs/bee.c | 4 +- src/core2/bs/{bee_fly.c => beeFly.c} | 22 +- src/core2/bs/{bee_main.c => beeMain.c} | 98 +- src/core2/bs/{bs_list.c => bsList.c} | 1 + .../bs/{bs_storedstate.c => bsStoredState.c} | 1 + src/core2/bs/bs_statemachine.c | 1 + src/core2/bs/carry.c | 11 +- src/core2/bs/claw.c | 3 +- src/core2/bs/climb.c | 14 +- src/core2/bs/croc.c | 61 +- src/core2/bs/crouch.c | 6 +- src/core2/bs/die.c | 10 +- src/core2/bs/{scripted.c => drone.c} | 1 + .../bs/{scripted_enter.c => droneenter.c} | 4 +- src/core2/bs/{scripted_goto.c => dronegoto.c} | 4 +- src/core2/bs/{scripted_look.c => dronelook.c} | 16 +- .../bs/{scripted_vanish.c => dronevanish.c} | 4 +- .../bs/{scripted_transform.c => dronexform.c} | 44 +- src/core2/bs/{jiggy_dance.c => jig.c} | 14 +- src/core2/bs/jump.c | 33 +- src/core2/bs/{hurt.c => ow.c} | 1 + src/core2/bs/player_spawn.c | 248 ++--- src/core2/bs/pumpkin.c | 39 +- src/core2/bs/rebound.c | 21 +- src/core2/bs/rest.c | 27 +- src/core2/bs/sled.c | 3 +- src/core2/bs/slide.c | 5 +- src/core2/bs/splat.c | 3 +- src/core2/bs/stand.c | 43 +- src/core2/bs/surf.c | 11 +- src/core2/bs/swim.c | 25 +- src/core2/bs/talk.c | 2 +- src/core2/bs/throw.c | 6 +- src/core2/bs/timeout.c | 37 +- src/core2/bs/turn.c | 4 +- src/core2/bs/walk.c | 55 +- src/core2/bs/walrus.c | 75 +- src/core2/bs/{washing_machine.c => washy.c} | 10 +- src/core2/bundle.c | 1 + src/core2/camera/dynamicCam1.c | 46 - src/core2/ch/beehive.c | 6 +- src/core2/ch/beeswarm.c | 8 +- src/core2/ch/bottlesbonus.c | 25 +- src/core2/ch/bottlesbonuscursor.c | 30 +- src/core2/ch/{climb_base.c => climbBase.c} | 5 +- src/core2/ch/clucker.c | 6 +- src/core2/ch/collectible.c | 12 +- src/core2/ch/crab.c | 169 ++-- src/core2/ch/extralife.c | 1 + src/core2/ch/feather.c | 1 + src/core2/ch/gameSelect.h | 14 + src/core2/ch/ghost.c | 188 ++-- src/core2/ch/gloop.c | 2 +- src/core2/ch/goldfeather.c | 5 +- src/core2/ch/gravestone.c | 4 +- .../ch/{grill_chompa.c => grillechompa.c} | 3 +- src/core2/ch/honeycomb.c | 7 +- src/core2/ch/icecube.c | 2 +- src/core2/ch/jiggy.c | 224 ++--- src/core2/ch/jiggy.h | 21 + src/core2/ch/jinjo.c | 185 ++-- ...level_collectible.c => levelcollectible.c} | 35 +- src/core2/ch/mole.c | 225 ++--- src/core2/ch/molehill.c | 12 +- src/core2/ch/mumbo_sign.c | 26 - src/core2/ch/mumbosign.c | 27 + src/core2/ch/mumbotoken.c | 10 +- src/core2/ch/shock_jumppad.c | 1 + src/core2/ch/snacker.c | 6 +- src/core2/ch/snowball.c | 2 +- src/core2/ch/snowman.c | 4 +- src/core2/ch/trainers.c | 4 +- src/core2/ch/wadingboots.c | 10 +- src/core2/checksums.c | 7 + src/core2/climb.c | 41 +- src/core2/collision/climbsurface.c | 23 +- src/core2/collision/dispatch.c | 1 + src/core2/collision/enemy.c | 5 +- src/core2/collision/filter.c | 19 +- src/core2/collision/geometrybounds.c | 1 + src/core2/collision/hitboxdata.c | 452 +++++----- src/core2/collision/polydetect.c | 1 + src/core2/collision/raycast.c | 1 + .../{raycastmap.c => scarabbeetle.c} | 15 +- src/core2/collision/spherecast.c | 1 + src/core2/collision/tricheck.c | 1 + src/core2/crc_bootvalidation.c | 138 ++- src/core2/{demo_input.c => demo.c} | 1 + src/core2/dialog/binload.c | 3 +- src/core2/dialog/progressDialog.c | 135 +++ src/core2/dialog/progress_dialogs.c | 134 --- src/core2/displaylist_init.c | 7 +- src/core2/fileselect.c | 1 + src/core2/{freelist.c => fla.c} | 1 + src/core2/flags_bitfield.c | 41 +- src/core2/font/print.c | 426 ++++----- src/core2/font/render.c | 39 +- src/core2/frame/auxbuffer.c | 70 +- src/core2/frame/rendermem.c | 13 +- src/core2/frame/texture_capture.c | 1 + src/core2/fx/{enemy_shadow.c => badShad.c} | 5 +- ...effect_spriteanim.c => banjokazooiesign.c} | 38 +- ...{projectile_manager.c => commonParticle.c} | 1 + src/core2/fx/cutscene_actors.c | 47 +- src/core2/fx/drips.c | 1 + src/core2/fx/effect_colordata.c | 1 + src/core2/fx/effect_debris.c | 138 +-- src/core2/fx/effect_ice.c | 4 +- src/core2/fx/effect_jiggy.c | 1 + src/core2/fx/effect_jiggy_list.c | 1 + src/core2/fx/effect_jiggy_spawn.c | 1 + src/core2/fx/effect_modelparticle.c | 1 + src/core2/fx/effect_playerspray.c | 9 +- src/core2/fx/effect_ripple.c | 3 +- src/core2/fx/effect_simplesprite.c | 1 + src/core2/fx/effect_soundemit.c | 160 ++-- src/core2/fx/effect_sparkleemit.c | 5 +- .../fx/{effect_eggshatter.c => eggshatter.c} | 1 + .../{effect_generic.c => explosionripple.c} | 1 + src/core2/fx/firefx.c | 1 + .../fx/{droplet.c => piranhaWaterParticles.c} | 3 +- src/core2/fx/projectile_anim.c | 1 + src/core2/fx/projectile_blueegg.c | 11 +- src/core2/fx/projectile_render.c | 1 + src/core2/fx/projectile_smoke.c | 1 + src/core2/fx/projectile_sparkle.c | 1 + src/core2/fx/projectile_spawnfx.c | 1 + src/core2/fx/projectile_system.c | 1 + .../fx/{effect_ripple_spawn.c => ripple.c} | 1 + .../fx/{effect_sparkle.c => shoesparkle.c} | 34 +- src/core2/fx/shrapnel.c | 3 +- .../fx/{effect_sparkle_spawn.c => sparkle.c} | 1 + src/core2/fx/whipcrack.c | 1 + src/core2/gameSelect.c | 105 ++- src/core2/gameloop.c | 114 ++- src/core2/gamestate.c | 31 +- src/core2/{context => gc}/bound.c | 1 + src/core2/{context => gc}/dialog.c | 46 +- src/core2/gc/dialog.h | 22 + .../{context => gc}/enter_text_trigger.c | 21 +- .../{context/gameover.c => gc/gameoversign.c} | 20 +- .../overlaycopyright.c} | 1 + .../overlaynocontroller.c} | 5 +- .../overlaypressstart.c} | 7 +- src/core2/{context => gc}/parade.c | 1 + .../{context/pause_menu.c => gc/pauseMenu.c} | 5 +- src/core2/{context => gc}/pictureframe.c | 13 +- .../{context/map_info.c => gc/section.c} | 1 + src/core2/{context => gc}/sky.c | 23 +- src/core2/{context => gc}/transition.c | 37 +- src/core2/{context => gc}/zoombox.c | 7 +- src/core2/{actor_cubebounds.c => gccube.c} | 32 +- .../{score_honeycomb.c => honeycombscore.c} | 1 + src/core2/inventory_slots.c | 3 +- src/core2/{score_jiggy.c => jiggyscore.c} | 1 + .../{specificflags.c => levelspecificflags.c} | 11 +- src/core2/level/lightconfig.c | 2 +- src/core2/level/metadata.c | 1 + src/core2/map/audioconfig.c | 1 + src/core2/map/cutscene_skip.c | 1 + src/core2/map/cutscene_triggers.c | 1 + src/core2/map/envcolor.c | 1 + src/core2/map/exit.c | 7 +- src/core2/map/gsworld.c | 118 +-- src/core2/map/list.c | 3 +- src/core2/map/loadzone.c | 1 + src/core2/map/{model.c => mapModel.c} | 85 +- src/core2/map/{savestate.c => mapsavestate.c} | 1 + .../{specificflags.c => mapspecificflags.c} | 1 + src/core2/map/overlay.c | 19 +- src/core2/map/warp_dispatch.c | 7 +- src/core2/map/world_reset.c | 1 + src/core2/matrix_interp.c | 1 + src/core2/model/lighting.c | 1 + src/core2/model/mesh_dataaccess.c | 1 + src/core2/model/meshbounds.c | 1 + src/core2/model/{render.c => modelRender.c} | 11 +- src/core2/model/rendernormal.c | 1 + src/core2/model/skinning.c | 1 + src/core2/model/vertex_brightness.c | 1 + src/core2/{mumbo_transforms.c => mumbo.c} | 97 +- src/core2/{score_mumbo.c => mumboscore.c} | 1 + .../{demo_ctrl.c => mumboshandwithpicture.c} | 69 +- .../{camera/firstpersoncamera.c => nc/1p.c} | 39 +- .../{camera => nc}/camera_debug_freecam.c | 1 + src/core2/{camera => nc}/camera_ease.c | 3 +- src/core2/{camera => nc}/camera_focus.c | 1 + src/core2/{camera => nc}/camera_focustarget.c | 1 + src/core2/{camera => nc}/camera_fog.c | 1 + src/core2/{camera => nc}/camera_motor1.c | 13 + src/core2/{camera => nc}/camera_motor2.c | 1 + src/core2/{camera => nc}/camera_nodemanager.c | 13 +- src/core2/{camera => nc}/camera_position.c | 1 + src/core2/{camera => nc}/camera_set.c | 1 + src/core2/{camera => nc}/cameranode_type1.c | 1 + src/core2/{camera => nc}/cameranode_type2.c | 1 + src/core2/{camera => nc}/cameranode_type3.c | 1 + src/core2/{camera => nc}/cameranode_type4.c | 1 + src/core2/{camera => nc}/cameranodelist.c | 1 + src/core2/{camera/dynamicCamD.c => nc/die.c} | 11 +- src/core2/nc/dynamicCam1.c | 50 ++ src/core2/{camera => nc}/dynamicCam10.c | 1 + src/core2/{camera => nc}/dynamicCam11.c | 1 + src/core2/{camera => nc}/dynamicCam12.c | 1 + src/core2/{camera => nc}/dynamicCam13.c | 1 + src/core2/{camera => nc}/dynamicCam3.c | 9 +- src/core2/{camera => nc}/dynamicCam5.c | 3 +- src/core2/{camera => nc}/dynamicCam8.c | 1 + src/core2/{camera => nc}/dynamicCam9.c | 11 +- src/core2/{camera => nc}/dynamicCamA.c | 1 + src/core2/{camera => nc}/dynamicCamB.c | 1 + src/core2/{camera => nc}/dynamicCamC.c | 3 +- src/core2/{camera => nc}/dynamicCamF.c | 1 + src/core2/{camera => nc}/dynamicCamera.c | 161 ++-- src/core2/{camera/dynamicCam4.c => nc/fly.c} | 31 +- src/core2/{camera => nc}/randomCamera.c | 1 + src/core2/{camera => nc}/staticCamera.c | 3 +- .../{factory.c => commonParticleTypeMap.c} | 1 + .../{colordefault.c => dustemitter.c} | 1 + src/core2/particle/emitter1.c | 1 + src/core2/particle/emitter2.c | 1 + src/core2/particle/emitterstruct.c | 3 +- src/core2/particle/initcallback.c | 1 + src/core2/particle/lifescale.c | 1 + src/core2/particle/particle.c | 1 + .../{accel.c => particleemittermanager.c} | 1 + src/core2/particle/positionset.c | 1 + src/core2/particle/samplerate.c | 1 + src/core2/particle/scale1.c | 1 + src/core2/particle/scale2.c | 1 + src/core2/particle/spawn.c | 1 + src/core2/particle/typeindex.c | 1 + src/core2/particle/velocityrange.c | 1 + src/core2/particle/velocityset.c | 1 + src/core2/playerutils.c | 82 +- .../{prop_assetcache.c => propModelList.c} | 1 + src/core2/quiz/game.c | 476 +++++----- .../quiz/{minigamemanager.c => minigame.c} | 3 +- src/core2/quiz/questionmanager.c | 1 + ...bitfield.c => quizquestionaskedbitfield.c} | 5 +- src/core2/quiz/storage.c | 3 +- .../core2/quiz/storage.h | 14 +- src/core2/savedata.c | 1 + .../scorequeue/{drawui_air.c => airscore.c} | 1 + .../{drawui_stub.c => common1score.c} | 1 + .../{drawui_sprites.c => common2score.c} | 11 +- .../{drawui_models.c => common3score.c} | 7 +- src/core2/scorequeue/dispatch.c | 1 + .../{drawui_health.c => healthscore.c} | 1 + ...wui_honeycarrier.c => honeycarrierscore.c} | 1 + .../{drawui_jinjo.c => jinjoscore.c} | 1 + .../{drawui_lives.c => lifescore.c} | 1 + src/core2/scorequeue/manager.c | 5 +- src/core2/scorequeue/queue_collectibles.c | 1 + src/core2/scorequeue/queue_honeycombs.c | 1 + src/core2/scorequeue/queue_lives.c | 1 + src/core2/scorequeue/queue_major_items.c | 1 + src/core2/scorequeue/queue_notes.c | 1 + src/core2/scorequeue/queue_timers.c | 1 + src/core2/scorequeue/queue_totals.c | 1 + src/core2/sfx/filedata.c | 1 + src/core2/sfx/init.c | 1 + src/core2/sfx/instruments.c | 6 +- src/core2/sfx/pitched.c | 1 + src/core2/sfx/playstate.c | 3 +- src/core2/sfx/randompitch.c | 1 + src/core2/sfx/sequenceindex.c | 1 + src/core2/sfx/soundsource.c | 1 + src/core2/sfx/source.c | 11 +- src/core2/sfx/streamctrl.c | 3 +- src/core2/sfx/trackmanager.c | 1 + src/core2/sfx/volume.c | 1 + src/core2/{snacker_ctl.c => snackerctl.c} | 9 +- src/core2/{spawn_queue.c => spawnqueue.c} | 284 +++--- src/core2/spline_bezier.c | 1 + src/core2/spline_pathfollow.c | 1 + src/core2/sprite/render.c | 7 +- src/core2/sprite/rendertex.c | 1 + src/core2/sprite/screenoverlay.c | 1 + src/core2/sprite/texblock.c | 1 + src/core2/{state_timer.c => statetimer.c} | 1 + src/core2/texture_dataaccess.c | 7 +- src/core2/time.c | 9 +- src/core2/time_framedelta.c | 20 +- .../{timed_funcqueue.c => timedfuncqueue.c} | 1 + src/core2/{vector.c => vla.c} | 1 + src/core2/vtx/alphablend.c | 1 + src/core2/vtx/colorapply.c | 1 + src/core2/vtx/colorintensity.c | 1 + src/core2/vtx/colorset.c | 1 + src/core2/vtx/convert.c | 1 + src/core2/vtx/{lighting.c => gclights.c} | 5 +- src/core2/vtx/list.c | 7 +- src/core2/vtx/listutils.c | 6 +- src/core2/vtx/meshcount.c | 1 + src/core2/vtx/normalset.c | 1 + src/core2/vtx/positionset.c | 11 +- src/core2/vtx/renderstart.c | 3 +- src/core2/vtx/scale.c | 1 + src/core2/vtx/transform.c | 1 + src/core2/vtx/uvset.c | 1 + src/cutscenes/bss_pad.c | 2 - src/cutscenes/checksums.c | 7 + src/cutscenes/cutscene_trigger.c | 2 +- ...ctor_spawninit.c => cutscenesspawnqueue.c} | 2 +- src/cutscenes/{fx => }/glow_sparkle.c | 0 src/cutscenes/{fx => }/smoke.c | 0 src/cutscenes/{fx => }/sparkle.c | 0 .../{character_parade.c => theendsign.c} | 15 +- src/emptyLvl/checksums.c | 7 + src/{overlay_stub => emptyLvl}/empty_level.c | 2 +- src/{FINALE/ch => fight}/chbossjinjo.c | 2 +- src/{FINALE/ch => fight}/chbossjinjobase.c | 2 +- src/{FINALE/ch => fight}/chbossshadow.c | 2 +- src/fight/checksums.c | 7 + src/{FINALE/ch => fight}/chfinalboss.c | 78 +- src/{FINALE => fight}/chgreenblast.c | 0 src/{FINALE/ch => fight}/chjinjonator.c | 2 +- src/{FINALE/ch => fight}/chjinjonatorbase.c | 2 +- src/{FINALE => fight}/chspellbarrier.c | 0 src/{FINALE => fight}/chspellfireball.c | 0 src/{FINALE => fight}/chstonejinjo.c | 0 src/{FINALE => fight}/fight.c | 2 - src/{FINALE => fight}/fight.h | 8 +- src/{LAIR => lair}/ch/brentilda.c | 2 +- src/{LAIR => lair}/ch/cauldron.c | 8 +- src/{LAIR => lair}/ch/cheato.c | 8 +- .../ch/furnacefunprizes.c} | 6 +- src/{LAIR => lair}/ch/gruntling.c | 2 +- .../ch/lairgruntilda.c} | 8 +- .../item_pillows.c => lair/ch/refillpillow.c} | 6 +- src/lair/checksums.c | 7 + src/{LAIR/ch => lair}/fall_damagedetect.c | 0 src/{LAIR/ch => lair}/ff_lava_fireball.c | 0 .../ch => lair}/ff_lava_fireball_actor.c | 0 src/{LAIR => lair}/ff_manager.c | 40 +- src/{LAIR => lair}/jigsawpicture.c | 16 +- src/lair/jigsawpicture.h | 11 + .../lairspawnqueue.c} | 410 +++++++-- src/{LAIR/ch => lair}/tooty_parade.c | 0 src/port/Controller/ControlSchemes.cpp | 2 +- src/port/Controller/ModernCamera.cpp | 8 +- src/port/Engine.cpp | 4 +- src/port/Enhancements/Backports/EggAim.cpp | 4 +- src/port/Enhancements/Cheats/Cheats.cpp | 4 +- src/port/Localization/Localization.cpp | 28 +- src/port/Network/Anchor/DummyPlayer.cpp | 92 +- src/port/Network/Anchor/DummyPlayer.h | 2 +- src/port/Network/Anchor/FightSync.c | 4 +- src/port/Network/Anchor/HookHandlers.cpp | 8 +- .../Network/Anchor/Packets/PlayerUpdate.cpp | 18 +- .../Network/Anchor/Packets/VileUpdate.cpp | 2 +- src/port/Network/Anchor/VileSync.c | 7 +- src/port/Network/Anchor/VileSync.h | 2 +- src/port/Patches/FramebufferPatches.cpp | 8 +- src/port/Patches/MirrorPatches.cpp | 22 +- src/port/Patches/SpritePatches.cpp | 8 +- src/port/Rando/CustomObject/CustomObject.cpp | 32 +- src/port/UI/DeveloperTools/GameplayTools.cpp | 16 +- src/port/UI/DeveloperTools/SaveEditor.cpp | 2 +- src/unused/datalookup.c | 2 +- src/unused/debug_assert.c | 2 +- src/unused/debug_boxdraw.c | 2 +- src/unused/unused_block.c | 2 +- 697 files changed, 15074 insertions(+), 12530 deletions(-) create mode 100644 include/checksums.h rename src/BGS/{actor_spawninit.c => bgsspawnqueue.c} (91%) delete mode 100644 src/BGS/bss_pad.c rename src/BGS/ch/{choir_turtle.c => choirturtle.c} (95%) rename src/BGS/ch/{tanktup_legs.c => tanktuplegs.c} (85%) create mode 100644 src/BGS/checksums.c rename src/BGS/{minigame_vile.c => mrvileminigame.c} (58%) delete mode 100644 src/CC/bss_pad.c rename src/CC/{actor_spawninit.c => ccspawnqueue.c} (98%) rename src/CC/ch/{clanker.c => ccgrates.c} (99%) rename src/CC/ch/{key.c => clankerkey.c} (95%) rename src/CC/ch/{screw.c => clankerscrew.c} (88%) create mode 100644 src/CC/checksums.c create mode 100644 src/CC/ma/clanker.c create mode 100644 src/CC/ma/clankerrings.c delete mode 100644 src/CC/minigame_rings.c delete mode 100644 src/CC/platform_physics.c delete mode 100644 src/CCW/actor_spawninit.c delete mode 100644 src/CCW/bss_pad.c create mode 100644 src/CCW/ccwspawnqueue.c create mode 100644 src/CCW/ch/adulteyrie.c create mode 100644 src/CCW/ch/beanstalk.c rename src/CCW/ch/{nabnut_summer.c => bellyfullnabnut.c} (61%) rename src/CCW/ch/{gobi_ccw.c => ccwgobi.c} (55%) create mode 100644 src/CCW/ch/cutsceneadulteyrie.c create mode 100644 src/CCW/ch/deadsnarebear.c delete mode 100644 src/CCW/ch/eyrie_baby.c delete mode 100644 src/CCW/ch/eyrie_egg.c delete mode 100644 src/CCW/ch/eyrie_summer.c delete mode 100644 src/CCW/ch/eyrie_winter.c create mode 100644 src/CCW/ch/eyrieegg.c delete mode 100644 src/CCW/ch/fairy.c delete mode 100644 src/CCW/ch/gnawty.c create mode 100644 src/CCW/ch/indoorsgnawty.c delete mode 100644 src/CCW/ch/nabnut_autumn.c delete mode 100644 src/CCW/ch/nabnut_dialog.c delete mode 100644 src/CCW/ch/nabnut_spring.c delete mode 100644 src/CCW/ch/nabnut_winter.c create mode 100644 src/CCW/ch/outsideautumnnabnut.c create mode 100644 src/CCW/ch/seasonswitchdoors.c create mode 100644 src/CCW/ch/springnabnut.c create mode 100644 src/CCW/ch/summeroutsidegnawty.c create mode 100644 src/CCW/ch/swimminggnawty.c delete mode 100644 src/CCW/ch/zubba.c delete mode 100644 src/CCW/ch/zubba_hive_npc.c create mode 100644 src/CCW/ch/zubbahoneylump.c create mode 100644 src/CCW/checksums.c create mode 100644 src/CCW/eyrie_baby.c delete mode 100644 src/CCW/flower.c delete mode 100644 src/CCW/minigame_zubba.c create mode 100644 src/CCW/nabnut_winter.c delete mode 100644 src/CCW/seasonal_switch.c delete mode 100644 src/CCW/snarebear_proximity.c create mode 100644 src/CCW/zubba.c create mode 100644 src/CCW/zubba_hive_npc.c delete mode 100644 src/FP/bss_pad.c rename src/FP/{mapstate/slalomctrl.c => ch/boggyraceflag1.c} (94%) rename src/FP/{mapstate/slalom2ctrl.c => ch/boggyraceflag2.c} (89%) create mode 100644 src/FP/checksums.c rename src/FP/{actor_spawninit.c => fpspawnqueue.c} (99%) rename src/FP/{mapstate => ma}/slalom.c (91%) rename src/FP/{mapstate => ma}/snowbutton.c (100%) rename src/FP/{mapstate => ma}/snowy.c (100%) rename src/FP/{ch => }/wozza_fire.c (100%) delete mode 100644 src/GV/bss_pad.c rename src/GV/{ch => }/cactus.c (100%) rename src/GV/{ch => }/carpet1.c (100%) rename src/GV/{ch => }/carpet2.c (93%) rename src/GV/ch/{egg_pot.c => eggpot.c} (95%) delete mode 100644 src/GV/ch/jinxy.c rename src/GV/{ => ch}/mazectrl.c (90%) create mode 100644 src/GV/checksums.c rename src/GV/{actor_spawninit.c => gvspawnqueue.c} (89%) rename src/GV/{ch => }/handshadow.c (100%) rename src/GV/{ch => }/jinxy_head.c (100%) create mode 100644 src/GV/magiccarpet2.c rename src/GV/{ch/carpet_shadow.c => magiccarpetshadow.c} (61%) rename src/GV/{ch => }/rubee.c (56%) rename src/GV/{pyramid_trigger.c => sandybutteggtoll.c} (69%) delete mode 100644 src/LAIR/bss_pad.c create mode 100644 src/MM/ch/conga.h create mode 100644 src/MM/ch/orangepad.h create mode 100644 src/MM/checksums.c rename src/MM/{actor_spawninit.c => mmspawnqueue.c} (97%) delete mode 100644 src/MMM/bss_pad.c rename src/MMM/ch/{flowerpot.c => cemetarypot.c} (95%) rename src/MMM/ch/{portrait_chompa.c => portraitchompa.c} (98%) rename src/MMM/ch/{limbo.c => skeleton.c} (95%) create mode 100644 src/MMM/checksums.c rename src/MMM/{actor_spawninit.c => mmmspawnqueue.c} (58%) delete mode 100644 src/RBB/actor_spawninit.c delete mode 100644 src/RBB/bss_pad.c rename src/RBB/ch/{seaman_grublin.c => seamangrublin.c} (97%) delete mode 100644 src/RBB/ch/siren.c create mode 100644 src/RBB/checksums.c create mode 100644 src/RBB/rbbspawnqueue.c create mode 100644 src/RBB/siren.c rename src/SM/{ch => }/bottles_movecheck.c (100%) create mode 100644 src/SM/checksums.c rename src/SM/{ch => }/furniture.c (100%) rename src/SM/{ch => }/quarrie.c (100%) rename src/SM/{crc.c => smspawnqueue.c} (80%) create mode 100644 src/TTC/ch/lockup.h create mode 100644 src/TTC/checksums.c rename src/TTC/{ => ma}/castle.c (98%) rename src/core1/{io => }/bamotor.c (100%) rename src/core1/{math/ml.c => gu_matrix.c} (99%) rename src/core1/{math/mlmtx.c => gu_perspective.c} (93%) delete mode 100644 src/core1/math/longlong_arith.c delete mode 100644 src/core1/math/longlong_convert.c rename src/core1/{math/vector.c => ml.c} (88%) rename src/core1/{math/matrix_stack.c => mlmtx.c} (98%) create mode 100644 src/core1/musicplayer.h rename src/core1/{io => }/pfsmanager.c (97%) rename src/core1/{stopnswop_payload.c => sns.c} (99%) delete mode 100644 src/core1/syncprintf.c rename src/core2/anim/{controller.c => anctrl.c} (99%) rename src/core2/anim/{anim_cache.c => animcache.c} (98%) rename src/core2/anim/{anim_texturecache.c => animtexturecache.c} (98%) rename src/core2/anim/{sequence.c => anseq.c} (99%) rename src/core2/anim/{anim_sequencestruct.c => betavent.c} (88%) rename src/core2/anim/{anim_spriteframe.c => chumpfish.c} (99%) rename src/core2/anim/{skeletal.c => skeletalanim.c} (99%) rename src/core2/ba/{ba_anim.c => anim.c} (98%) delete mode 100644 src/core2/ba/ba_animstate.c delete mode 100644 src/core2/ba/ba_state.c rename src/core2/ba/{ba_bounds.c => babounds.c} (93%) rename src/core2/ba/{ba_buzz.c => babuzz.c} (98%) rename src/core2/ba/{ba_eyes.c => baeyes.c} (88%) rename src/core2/ba/{ba_flag.c => baflag.c} (95%) rename src/core2/ba/{ba_input.c => bainput.c} (98%) rename src/core2/ba/{ba_key.c => bakey.c} (98%) rename src/core2/ba/{ba_lookat.c => balookat.c} (98%) rename src/core2/ba/{ba_sfx.c => basfx.c} (99%) rename src/core2/ba/{ba_stick.c => bastick.c} (98%) rename src/core2/ba/{ba_timer.c => batimer.c} (93%) create mode 100644 src/core2/ba/bsmethods.c rename src/core2/ba/{ba_carriedobj.c => carriedobj.c} (93%) rename src/core2/ba/{ba_carry.c => carry.c} (95%) rename src/core2/ba/{ba_scripted.c => drone.c} (98%) rename src/core2/ba/{ba_falldamage.c => falldamage.c} (96%) rename src/core2/ba/{ba_flap.c => flap.c} (98%) rename src/core2/ba/{ba_groundsurface.c => hazards.c} (99%) rename src/core2/ba/{ba_eyeblink.c => iFrame.c} (92%) create mode 100644 src/core2/ba/iFrame.h rename src/core2/ba/{ba_marker.c => marker.c} (98%) rename src/core2/ba/{ba_model.c => model.c} (96%) create mode 100644 src/core2/ba/modelappendages.c rename src/core2/ba/{ba_physics.c => physics.c} (96%) rename src/core2/ba/{ba_modelselect.c => playermodel.c} (87%) rename src/core2/ba/{ba_position.c => playerposition.c} (87%) rename src/core2/bs/{beak_barge.c => bBarge.c} (94%) rename src/core2/bs/{beak_egg_fire.c => bEggAss.c} (83%) rename src/core2/bs/{beak_egg_aim.c => bEggHead.c} (84%) rename src/core2/bs/{flap_flip.c => bFlap.c} (95%) rename src/core2/bs/{backflip.c => bFlip.c} (94%) rename src/core2/bs/{beak_bomb.c => bFly.c} (87%) rename src/core2/bs/{stilt_stride.c => bLongLeg.c} (88%) rename src/core2/bs/{beak_peck.c => bPeck.c} (93%) rename src/core2/bs/{shock_spring.c => bShock.c} (86%) rename src/core2/bs/{beak_swim.c => bSwim.c} (90%) rename src/core2/bs/{talon_trot.c => bTrot.c} (93%) rename src/core2/bs/{wonderwing.c => bWhirl.c} (91%) rename src/core2/bs/{beak_buster.c => bbuster.c} (94%) rename src/core2/bs/{bee_fly.c => beeFly.c} (91%) rename src/core2/bs/{bee_main.c => beeMain.c} (85%) rename src/core2/bs/{bs_list.c => bsList.c} (97%) rename src/core2/bs/{bs_storedstate.c => bsStoredState.c} (97%) rename src/core2/bs/{scripted.c => drone.c} (97%) rename src/core2/bs/{scripted_enter.c => droneenter.c} (97%) rename src/core2/bs/{scripted_goto.c => dronegoto.c} (94%) rename src/core2/bs/{scripted_look.c => dronelook.c} (84%) rename src/core2/bs/{scripted_vanish.c => dronevanish.c} (96%) rename src/core2/bs/{scripted_transform.c => dronexform.c} (91%) rename src/core2/bs/{jiggy_dance.c => jig.c} (92%) rename src/core2/bs/{hurt.c => ow.c} (98%) rename src/core2/bs/{washing_machine.c => washy.c} (92%) delete mode 100644 src/core2/camera/dynamicCam1.c rename src/core2/ch/{climb_base.c => climbBase.c} (95%) create mode 100644 src/core2/ch/gameSelect.h rename src/core2/ch/{grill_chompa.c => grillechompa.c} (97%) create mode 100644 src/core2/ch/jiggy.h rename src/core2/ch/{level_collectible.c => levelcollectible.c} (96%) delete mode 100644 src/core2/ch/mumbo_sign.c create mode 100644 src/core2/ch/mumbosign.c create mode 100644 src/core2/checksums.c rename src/core2/collision/{raycastmap.c => scarabbeetle.c} (97%) rename src/core2/{demo_input.c => demo.c} (98%) create mode 100644 src/core2/dialog/progressDialog.c delete mode 100644 src/core2/dialog/progress_dialogs.c rename src/core2/{freelist.c => fla.c} (99%) rename src/core2/fx/{enemy_shadow.c => badShad.c} (97%) rename src/core2/fx/{effect_spriteanim.c => banjokazooiesign.c} (61%) rename src/core2/fx/{projectile_manager.c => commonParticle.c} (99%) rename src/core2/fx/{effect_eggshatter.c => eggshatter.c} (98%) rename src/core2/fx/{effect_generic.c => explosionripple.c} (94%) rename src/core2/fx/{droplet.c => piranhaWaterParticles.c} (94%) rename src/core2/fx/{effect_ripple_spawn.c => ripple.c} (99%) rename src/core2/fx/{effect_sparkle.c => shoesparkle.c} (50%) rename src/core2/fx/{effect_sparkle_spawn.c => sparkle.c} (99%) rename src/core2/{context => gc}/bound.c (98%) rename src/core2/{context => gc}/dialog.c (97%) create mode 100644 src/core2/gc/dialog.h rename src/core2/{context => gc}/enter_text_trigger.c (78%) rename src/core2/{context/gameover.c => gc/gameoversign.c} (85%) rename src/core2/{context/overlay_copyright.c => gc/overlaycopyright.c} (97%) rename src/core2/{context/overlay_nocontroller.c => gc/overlaynocontroller.c} (97%) rename src/core2/{context/overlay_pressstart.c => gc/overlaypressstart.c} (94%) rename src/core2/{context => gc}/parade.c (99%) rename src/core2/{context/pause_menu.c => gc/pauseMenu.c} (99%) rename src/core2/{context => gc}/pictureframe.c (89%) rename src/core2/{context/map_info.c => gc/section.c} (99%) rename src/core2/{context => gc}/sky.c (90%) rename src/core2/{context => gc}/transition.c (95%) rename src/core2/{context => gc}/zoombox.c (99%) rename src/core2/{actor_cubebounds.c => gccube.c} (99%) rename src/core2/{score_honeycomb.c => honeycombscore.c} (97%) rename src/core2/{score_jiggy.c => jiggyscore.c} (98%) rename src/core2/level/{specificflags.c => levelspecificflags.c} (92%) rename src/core2/map/{model.c => mapModel.c} (93%) rename src/core2/map/{savestate.c => mapsavestate.c} (99%) rename src/core2/map/{specificflags.c => mapspecificflags.c} (98%) rename src/core2/model/{render.c => modelRender.c} (99%) rename src/core2/{mumbo_transforms.c => mumbo.c} (80%) rename src/core2/{score_mumbo.c => mumboscore.c} (97%) rename src/core2/{demo_ctrl.c => mumboshandwithpicture.c} (69%) rename src/core2/{camera/firstpersoncamera.c => nc/1p.c} (74%) rename src/core2/{camera => nc}/camera_debug_freecam.c (98%) rename src/core2/{camera => nc}/camera_ease.c (96%) rename src/core2/{camera => nc}/camera_focus.c (96%) rename src/core2/{camera => nc}/camera_focustarget.c (97%) rename src/core2/{camera => nc}/camera_fog.c (98%) rename src/core2/{camera => nc}/camera_motor1.c (94%) rename src/core2/{camera => nc}/camera_motor2.c (99%) rename src/core2/{camera => nc}/camera_nodemanager.c (96%) rename src/core2/{camera => nc}/camera_position.c (98%) rename src/core2/{camera => nc}/camera_set.c (98%) rename src/core2/{camera => nc}/cameranode_type1.c (99%) rename src/core2/{camera => nc}/cameranode_type2.c (98%) rename src/core2/{camera => nc}/cameranode_type3.c (99%) rename src/core2/{camera => nc}/cameranode_type4.c (96%) rename src/core2/{camera => nc}/cameranodelist.c (99%) rename src/core2/{camera/dynamicCamD.c => nc/die.c} (73%) create mode 100644 src/core2/nc/dynamicCam1.c rename src/core2/{camera => nc}/dynamicCam10.c (96%) rename src/core2/{camera => nc}/dynamicCam11.c (98%) rename src/core2/{camera => nc}/dynamicCam12.c (99%) rename src/core2/{camera => nc}/dynamicCam13.c (98%) rename src/core2/{camera => nc}/dynamicCam3.c (81%) rename src/core2/{camera => nc}/dynamicCam5.c (87%) rename src/core2/{camera => nc}/dynamicCam8.c (97%) rename src/core2/{camera => nc}/dynamicCam9.c (86%) rename src/core2/{camera => nc}/dynamicCamA.c (98%) rename src/core2/{camera => nc}/dynamicCamB.c (98%) rename src/core2/{camera => nc}/dynamicCamC.c (91%) rename src/core2/{camera => nc}/dynamicCamF.c (95%) rename src/core2/{camera => nc}/dynamicCamera.c (85%) rename src/core2/{camera/dynamicCam4.c => nc/fly.c} (70%) rename src/core2/{camera => nc}/randomCamera.c (97%) rename src/core2/{camera => nc}/staticCamera.c (96%) rename src/core2/particle/{factory.c => commonParticleTypeMap.c} (98%) rename src/core2/particle/{colordefault.c => dustemitter.c} (98%) rename src/core2/particle/{accel.c => particleemittermanager.c} (98%) rename src/core2/{prop_assetcache.c => propModelList.c} (99%) rename src/core2/quiz/{minigamemanager.c => minigame.c} (98%) rename src/core2/quiz/{bitfield.c => quizquestionaskedbitfield.c} (81%) rename include/core2/quiz_storage.h => src/core2/quiz/storage.h (85%) rename src/core2/scorequeue/{drawui_air.c => airscore.c} (99%) rename src/core2/scorequeue/{drawui_stub.c => common1score.c} (91%) rename src/core2/scorequeue/{drawui_sprites.c => common2score.c} (97%) rename src/core2/scorequeue/{drawui_models.c => common3score.c} (96%) rename src/core2/scorequeue/{drawui_health.c => healthscore.c} (99%) rename src/core2/scorequeue/{drawui_honeycarrier.c => honeycarrierscore.c} (99%) rename src/core2/scorequeue/{drawui_jinjo.c => jinjoscore.c} (99%) rename src/core2/scorequeue/{drawui_lives.c => lifescore.c} (99%) rename src/core2/{snacker_ctl.c => snackerctl.c} (95%) rename src/core2/{spawn_queue.c => spawnqueue.c} (69%) rename src/core2/{state_timer.c => statetimer.c} (97%) rename src/core2/{timed_funcqueue.c => timedfuncqueue.c} (99%) rename src/core2/{vector.c => vla.c} (99%) rename src/core2/vtx/{lighting.c => gclights.c} (98%) delete mode 100644 src/cutscenes/bss_pad.c create mode 100644 src/cutscenes/checksums.c rename src/cutscenes/{actor_spawninit.c => cutscenesspawnqueue.c} (99%) rename src/cutscenes/{fx => }/glow_sparkle.c (100%) rename src/cutscenes/{fx => }/smoke.c (100%) rename src/cutscenes/{fx => }/sparkle.c (100%) rename src/cutscenes/{character_parade.c => theendsign.c} (79%) create mode 100644 src/emptyLvl/checksums.c rename src/{overlay_stub => emptyLvl}/empty_level.c (75%) rename src/{FINALE/ch => fight}/chbossjinjo.c (99%) rename src/{FINALE/ch => fight}/chbossjinjobase.c (99%) rename src/{FINALE/ch => fight}/chbossshadow.c (97%) create mode 100644 src/fight/checksums.c rename src/{FINALE/ch => fight}/chfinalboss.c (97%) rename src/{FINALE => fight}/chgreenblast.c (100%) rename src/{FINALE/ch => fight}/chjinjonator.c (99%) rename src/{FINALE/ch => fight}/chjinjonatorbase.c (99%) rename src/{FINALE => fight}/chspellbarrier.c (100%) rename src/{FINALE => fight}/chspellfireball.c (100%) rename src/{FINALE => fight}/chstonejinjo.c (100%) rename src/{FINALE => fight}/fight.c (99%) rename src/{FINALE => fight}/fight.h (97%) rename src/{LAIR => lair}/ch/brentilda.c (99%) rename src/{LAIR => lair}/ch/cauldron.c (98%) rename src/{LAIR => lair}/ch/cheato.c (96%) rename src/{LAIR/ch/minigame_ffprize.c => lair/ch/furnacefunprizes.c} (97%) rename src/{LAIR => lair}/ch/gruntling.c (99%) rename src/{LAIR/ch/grunty_final.c => lair/ch/lairgruntilda.c} (95%) rename src/{LAIR/ch/item_pillows.c => lair/ch/refillpillow.c} (94%) create mode 100644 src/lair/checksums.c rename src/{LAIR/ch => lair}/fall_damagedetect.c (100%) rename src/{LAIR/ch => lair}/ff_lava_fireball.c (100%) rename src/{LAIR/ch => lair}/ff_lava_fireball_actor.c (100%) rename src/{LAIR => lair}/ff_manager.c (97%) rename src/{LAIR => lair}/jigsawpicture.c (97%) create mode 100644 src/lair/jigsawpicture.h rename src/{LAIR/actor_spawninit.c => lair/lairspawnqueue.c} (84%) rename src/{LAIR/ch => lair}/tooty_parade.c (100%) diff --git a/include/bk_math.h b/include/bk_math.h index 53d2e4c3f..54928bb9a 100644 --- a/include/bk_math.h +++ b/include/bk_math.h @@ -18,6 +18,8 @@ out[2] = c;\ } +#define TUPLE_SET(dst, value) { dst[0] = dst[1] = dst[2] = value; } + #define TUPLE_COPY(dst, src) {\ dst[0] = src[0];\ dst[1] = src[1];\ diff --git a/include/bool.h b/include/bool.h index 6283d150d..fbbfd6d75 100644 --- a/include/bool.h +++ b/include/bool.h @@ -8,6 +8,15 @@ #define BOOL(boolean) ((boolean) ? true : false) #endif +// Lighthouse [port] Decomp code uses TRUE/FALSE (typedef int bool upstream). +// Windows headers may also define these; values are identical. +#ifndef TRUE +#define TRUE true +#endif +#ifndef FALSE +#define FALSE false +#endif + #if 0 #include diff --git a/include/bs_funcs.h b/include/bs_funcs.h index e45e808a6..16c904417 100644 --- a/include/bs_funcs.h +++ b/include/bs_funcs.h @@ -46,9 +46,9 @@ void bsturn_init(void); void bsturn_update(void); void bsturn_end(void); //0xd -void func_802B63F8(void); -void func_802B64D0(void); -void func_802B6500(void); +void timeout_transformation_init(void); +void timeout_transformation_update(void); +void timeout_transformation_end(void); //bsow void bsow_init(void); void bsow_update(void); @@ -90,9 +90,9 @@ void bsbtrot_exit_init(void); void bsbtrot_exit_update(void); void bsbtrot_exit_end(void); //bsfly_knockback -void func_802A4D90(void); -void func_802A4EC8(void); -void func_802A4F44(void); +void bsbfly_knockback_init(void); +void bsbfly_knockback_update(void); +void bsbfly_knockback_end(void); //BS_1A_WONDERWING_ENTER void bsbwhirl_enter_init(void); void bsbwhirl_enter_update(void); @@ -121,17 +121,17 @@ void bsegghead_end(void); void bseggass_init(void); void bseggass_update(void); void bseggass_end(void); -//BS_WALK_CREEP(void); +//BS_1F_WALK_CREEP(void); void bswalk_creep_init(void); void bswalk_creep_update(void); //BS_20_LANDING(void); void bsstand_landing_init(void); void bsstand_landing_update(void); -//BS_BSHOCK_CHARGE(void); +//BS_21_BSHOCK_CHARGE(void); void bsbshock_charge_init(void); void bsbshock_charge_update(void); void bsbshock_charge_end(void); -//BS_BSHOCK_JUMP(void); +//BS_22_BSHOCK_JUMP(void); void bsbshock_init(void); void bsbshock_update(void); void bsbshock_end(void); @@ -143,7 +143,7 @@ void func_802A505C(void); //BS_FLY(void); void bsbfly_init(void); void bsbfly_update(void); -void func_802A3F70(void); +void bsbfly_end(void); //BS_25_LONGLEG_ENTER(void); void bsblongleg_enter_init(void); void bsblongleg_enter_update(void); @@ -152,30 +152,30 @@ void bsblongleg_enter_end(void); void bsblongleg_stand_enter(void); void bsblongleg_stand_update(void); void bsblongleg_stand_end(void); -//BS_LONGLEG_WALK(void); +//BS_27_LONGLEG_WALK(void); void bsblongleg_walk_init(void); void bsblongleg_walk_update(void); void bsblongleg_walk_end(void); -//BS_LONGLEG_JUMP(void); +//BS_28_LONGLEG_JUMP(void); void bsblongleg_jump_init(void); void bsblongleg_jump_update(void); void bsblongleg_jump_end(void); -//BS_LONGLEG_EXIT(void); +//BS_29_LONGLEG_EXIT(void); void bsblongleg_exit_init(void); void bsblongleg_exit_update(void); void bsblongleg_exit_end(void); -//BS_BOMB(void); -void func_802A3F9C(void); -void func_802A411C(void); -void func_802A4404(void); +//BS_2A_BOMB(void); +void bsbfly_bomb_init(void); +void bsbfly_bomb_update(void); +void bsbfly_bomb_end(void); //BS_2B_DIVE_IDLE(void); -void func_802A762C(void); -void func_802A7674(void); -void func_802A7718(void); +void bsbdive_idle_init(void); +void bsbdive_idle_update(void); +void bsbdive_idle_end(void); //BS_2C_DIVE_B(void); -void func_802A7738(void); -void func_802A7838(void); -void func_802A7A2C(void); +void bsbdiveb_init(void); +void bsbdiveb_update(void); +void bsbdiveb_end(void); //BS_2D_SWIM_IDLE, void bsswim_idle_init(void); void bsswim_idle_update(void); @@ -190,21 +190,21 @@ void bsjump_fall_update(void); void bsjump_fall_end(void); //BS_30_DIVE_ENTER void bsSwim_dive_init(void); -void func_802A7E2C(void); -void func_802A7F4C(void); -//BS_ROLL(void); +void bsSwim_dive_update(void); +void bsSwim_dive_end(void); +//BS_31_ROLL(void); int bstwirl_hitboxActive(void); void bstwirl_init(void); void bstwirl_update(void); void bstwirl_end(void); -//BS_SLIDE +//BS_32_SLIDE void bsslide_init(void); void bsslide_update(void); void bsslide_end(void); //0x33(void); -void func_802B9ACC(void); -void func_802B9B14(void); -void func_802B9AAC(void); +void bswashy_init(void); +void bswashy_update(void); +void bswashy_end(void); void func_802B9D00(void); //BS_34_JIG_NOTEDOOR(void); void bsjig_notedoor_init(void); @@ -214,18 +214,18 @@ void bsjig_notedoor_end(void); void bsant_idle_init(void); void bsant_idle_update(void); void bsant_idle_end(void); -//BS_ANT_WALK +//BS_36_ANT_WALK void bsant_walk_init(void); void bsant_walk_update(void); void bsant_walk_end(void); -//BS_ANT_JUMP +//BS_37_ANT_WALK void bsant_jump_init(void); void bsant_jump_update(void); void bsant_jump_end(void); //BS_39_DIVE_A -void func_802A7A54(void); -void func_802A7AB0(void); -void func_802A7BA8(void); +void bsswim_divea_init(void); +void bsswim_divea_update(void); +void bsswim_divea_end(void); //BS_3A_CARRY_IDLE(void); void bscarry_idle_init(void); void bscarry_idle_update(void); @@ -257,17 +257,17 @@ void func_802B1BF4(void); void func_802B1CF8(void); void func_802B1DA4(void); //0x40 -void func_802B2BF0(void); -void func_802B2C58(void); -void func_802B2D50(void); +void bspumpkin_flush_init(void); +void bspumpkin_flush_update(void); +void bspumpkin_flush_end(void); //BS_41_DIE void bsdie_init(void); void bsdie_update(void); void bsdie_end(void); //BS_42_DINGPOT -void func_802A5120(void); -void func_802A5190(void); -void func_802A51C0(void); +void bsfly_dingpotLaunch_init(void); +void bsfly_dingpotLaunch_update(void); +void bsfly_dingpotLaunch_end(void); //BS_43_ANT_DIE void bsant_die_init(void); void bsant_die_update(void); @@ -302,9 +302,9 @@ void bspumpkin_fall_init(void); void bspumpkin_fall_update(void); void bspumpkin_fall_end(void); //BS_4C_LANDING_IN_WATER -void func_802A846C(void); -void func_802A85EC(void); -void func_802A872C(void); +void bsbswim_landingInWater_init(void); +void bsbswim_landingInWater_update(void); +void bsbswim_landingInWater_end(void); //BS_4D_PUMPKIN_OW void __bspumpkin_ow_init(void); void __bspumpkin_ow_update(void); @@ -323,18 +323,18 @@ void bsclimb_move_init(void); void bsclimb_move_update(void); void bsclimb_move_end(void); //BS_51_CLIMB_EXIT -void func_802B1928(void); -void func_802B1A54(void); -void func_802B1BCC(void); +void bsjump_climbExit_init(void); +void bsjump_climbExit_update(void); +void bsjump_climbExit_end(void); //0x52 -void func_802B5FD0(void); -void func_802B6064(void); -void func_802B60D0(void); +void bssurf_init(void); +void bssurf_update(void); +void bssurf_end(void); void func_802B60D8(void); //0x53 -void func_802B6270(void); -void func_802B6314(void); -void func_802B63C8(void); +void timeout_banjo_init(void); +void timeout_banjo_update(void); +void timeout_banjo_end(void); //0x55 void bsblongleg_slide_init(void); @@ -342,14 +342,14 @@ void bsblongleg_slide_update(void); void bsblongleg_slide_end(void); //0x56 -void func_802B3868(void); -void func_802B3954(void); -void func_802B3A20(void); +void rebound_init(void); +void rebound_update(void); +void rebound_end(void); //0x57 -void func_802A4430(void); -void func_802A4548(void); -void func_802A4664(void); +void bsbfly_beakbombend_init(void); +void bsbfly_beakbombend_update(void); +void bsbfly_beakbombend_end(void); void func_802A505C(void); //0x58 void bsbfly_beakbomb_crash_init(void); @@ -362,9 +362,9 @@ void func_802A4CF0(void); void func_802A4D10(void); void func_802A505C(void); //0x54 -void func_802A7F6C(void); -void func_802A8098(void); -void func_802A82D4(void); +void bsbswim_die_init(void); +void bsbswim_die_update(void); +void bsbswim_die_end(void); //0x5B void bsthrow_init(void); @@ -392,9 +392,9 @@ void bscroc_fall_update(void); void bscroc_fall_end(void); //0x62 -void func_802A6394(void); -void func_802A63F0(void); -void func_802A6450(void); +void bsblongleg_locked_init(void); +void bsblongleg_locked_update(void); +void bsblongleg_locked_end(void); //0x63 void bscroc_ow_init(void); void bscroc_ow_update(void); @@ -426,9 +426,9 @@ void bswalrus_fall_update(void); void bswalrus_fall_end(void); //0x6B -void func_802A1F6C(void); -void func_802A1FC8(void); -void func_802A2014(void); +void bsbee_locked_init(void); +void bsbee_locked_update(void); +void bsbee_locked_end(void); //0x0000006C void bswalrus_ow_init(void); void bswalrus_ow_update(void); @@ -464,23 +464,23 @@ void bssplat_update(void); void bssplat_end(void); //0x00000073 -void func_802B3CEC(void); -void func_802B3D1C(void); -void func_802B3D6C(void); +void bsrest_bs73unknown_init(void); +void bsrest_bs73unknown_update(void); +void bsrest_bs73unknown_end(void); //0x00000074 -void func_802B3E2C(void); -void func_802B3E64(void); -void func_802B3EF4(void); +void bsrest_bs74unknown_init(void); +void bsrest_bs74unknown_update(void); +void bsrest_bs74unknown_end(void); //0x00000075 -void func_802B3D8C(void); -void func_802B3DBC(void); -void func_802B3E0C(void); +void bsrest_bs75unknown_init(void); +void bsrest_bs75unknown_update(void); +void bsrest_bs75unknown_end(void); //0x00000076 -void func_802A4F74(void); -void func_802A4FC8(void); -void func_802A503C(void); +void bsbfly_locked_init(void); +void bsbfly_locked_update(void); +void bsbfly_locked_end(void); //0x00000077 void bsswim_lookat_init(void); @@ -493,9 +493,9 @@ void bsbswim_lookat_update(void); void bsbswim_lookat_end(void); //0x00000079 -void bsbtrot_unk79_init(void); -void bsbtrot_unk79_update(void); -void bsbtrot_unk79_end(void); +void bsbtrot_locked_init(void); +void bsbtrot_locked_update(void); +void bsbtrot_locked_end(void); //0x0000007A void bswalk_mud_init(void); @@ -521,59 +521,59 @@ void bswalrus_sled_jump_update(void); void bswalrus_sled_jump_end(void); void func_802B98C0(void); //0x0000007F -void func_802A7BD0(void); -void func_802A7CA8(void); -void func_802A7D74(void); +void bsbswim_ow_init(void); +void bsbswim_ow_update(void); +void bsbswim_ow_end(void); //0x00000080 void bswalrus_timeout_init(void); -void func_802B9830(void); -void func_802B9880(void); +void bswalrus_timeout_update(void); +void bswalrus_timeout_end(void); //0x00000081 -void func_802B90D0(void); -void func_802B9130(void); -void func_802B917C(void); +void bswalrus_sledlocked_init(void); +void bswalrus_sledlocked_update(void); +void bswalrus_sledlocked_end(void); void func_802B98C0(void); //0x00000082 -void func_802B95A0(void); -void func_802B963C(void); -void func_802B976C(void); +void bswalrus_sledloseinair_init(void); +void bswalrus_sledloseinair_update(void); +void bswalrus_sledloseinair_end(void); void func_802B98C0(void); //0x00000085 -void func_802A1080(void); -void func_802A10D4(void); -void func_802A117C(void); +void bsbeemain_idle_init(void); +void bsbeemain_idle_update(void); +void bsbeemain_idle_end(void); //0x00000086 -void func_802A11A4(void); -void func_802A1214(void); -void func_802A12D4(void); +void bsbeemain_walk_init(void); +void bsbeemain_walk_update(void); +void bsbeemain_walk_end(void); //0x00000087 -void func_802A12FC(void); -void func_802A1438(void); -void func_802A163C(void); +void bsbeemain_jump_init(void); +void bsbeemain_jump_update(void); +void bsbeemain_jump_end(void); //0x00000088 -void func_802A1664(void); -void func_802A170C(void); -void func_802A18C8(void); +void bsbeemain_fall_init(void); +void bsbeemain_fall_update(void); +void bsbeemain_fall_end(void); //0x00000089 -void func_802A1B68(void); -void func_802A1B88(void); -void func_802A1BA8(void); +void bsbeemain_ow_init(void); +void bsbeemain_ow_update(void); +void bsbeemain_ow_end(void); //0x0000008A void bsbeemain_die_init(void); -void func_802A1DD8(void); -void func_802A1F2C(void); +void bsbeemain_die_update(void); +void bsbeemain_die_end(void); //0x0000008B -void func_802A0590(void); -void func_802A0630(void); -void func_802A0704(void); +void bsbeefly_bs8Bunknown_init(void); +void bsbeefly_bs8Bunknown_update(void); +void bsbeefly_bs8Bunknown_end(void); //0x0000008C void bsbeefly_enter(void); @@ -586,19 +586,19 @@ void bscroc_locked_update(void); void bscroc_locked_end(void); //0x0000008E -void func_8029F398(void); -void func_8029F3F4(void); -void func_8029F440(void); +void bsant_locked_init(void); +void bsant_locked_update(void); +void bsant_locked_end(void); //0x0000008F -void func_802B34A0(void); -void func_802B34F8(void); -void func_802B353C(void); +void bspumpkin_locked_init(void); +void bspumpkin_locked_update(void); +void bspumpkin_locked_end(void); //0x00000091 -void func_802A4D30(void); -void func_802A4D50(void); -void func_802A4D70(void); +void bsbfly_ow_init(void); +void bsbfly_ow_update(void); +void bsbfly_ow_end(void); void func_802A505C(void); //0x00000092 void bsant_drone_init(void); @@ -636,9 +636,9 @@ void bswalk_drone_update(void); void bswalk_drone_end(void); void bsdrone_interrupt(void); //0x00000099 -void func_802A50B0(void); -void func_802A50D8(void); -void func_802A50F8(void); +void bsbfly_drone_init(void); +void bsbfly_drone_update(void); +void bsbfly_drone_end(void); void bsdrone_interrupt(void); //0x0000009A void bsbtrot_drone_init(void); @@ -661,9 +661,9 @@ void bsbee_drone_update(void); void bsbee_drone_end(void); void bsdrone_interrupt(void); //0x0000009E -void func_802ABCCC(void); -void func_802ABD0C(void); -void func_802ABD40(void); +void bsclimb_locked_init(void); +void bsclimb_locked_update(void); +void bsclimb_locked_end(void); void func_802ABD60(void); //0x0000009F void bsant_bounce_init(void); @@ -686,9 +686,9 @@ void bswalrus_bounce_update(void); void bswalrus_bounce_end(void); //0x000000A3 -void func_802A1BC8(void); -void func_802A1BE8(void); -void func_802A1C08(void); +void bsbeemain_bounce_init(void); +void bsbeemain_bounce_update(void); +void bsbeemain_bounce_end(void); //0x000000A4 void bsbwhirl_drone_init(void); @@ -696,9 +696,9 @@ void bsbwhirl_drone_update(void); void bsbwhirl_drone_end(void); //0x000000A5 -void func_802AADBC(void); -void func_802AAE08(void); -void func_802AAE4C(void); +void bsbwhirl_bsA5unknown_init(void); +void bsbwhirl_bsA5unknown_update(void); +void bsbwhirl_bsA5unknown_end(void); void bsDroneGoTo_init(void); void bsDroneGoTo_update(void); diff --git a/include/checksums.h b/include/checksums.h new file mode 100644 index 000000000..403428120 --- /dev/null +++ b/include/checksums.h @@ -0,0 +1,115 @@ +#ifndef BANJO_KAZOOIE_CHECKSUMS_H +#define BANJO_KAZOOIE_CHECKSUMS_H + +#include + +/* The checksums for the boot and core1 segments are stored right after the boot segment in ROM + */ + +#define CRC_BOOT_TEXT_CHECKSUM1 0 +#define CRC_BOOT_TEXT_CHECKSUM2 4 +#define CRC_CORE1_TEXT_CHECKSUM1 8 +#define CRC_CORE1_TEXT_CHECKSUM2 12 +#define CRC_CORE1_DATA_CHECKSUM1 16 +#define CRC_CORE1_DATA_CHECKSUM2 20 + +extern u8 crc_ROM_START[]; + +/* Each overlay bss section contains four checksum values, calculated from the rarezip decompressor. + * These values are written by the overlay loader. They are checked with pre-calculated values for + * different anti-tampering measurements. + * The exception is the core1 overlay, which checksums are written to a special place. + */ +struct overlay_checksums_s { + s32 text_checksum1; + s32 text_checksum2; + s32 data_checksum1; + s32 data_checksum2; +}; + +extern struct overlay_checksums_s gChecksumsCore1; +extern struct overlay_checksums_s gChecksumsCore2; +extern struct overlay_checksums_s gChecksumsCC; // (unused) no anti tampering measurements +extern struct overlay_checksums_s gChecksumsGV; // (unused) no anti tampering measurements +extern struct overlay_checksums_s gChecksumsMMM; // (unused) no anti tampering measurements +extern struct overlay_checksums_s gChecksumsTTC; +extern struct overlay_checksums_s gChecksumsMM; // (unused) no anti tampering measurements +extern struct overlay_checksums_s gChecksumsBGS; // (unused) no anti tampering measurements +extern struct overlay_checksums_s gChecksumsRBB; // (unused) no anti tampering measurements +extern struct overlay_checksums_s gChecksumsFP; // (unused) no anti tampering measurements +extern struct overlay_checksums_s gChecksumsSM; +extern struct overlay_checksums_s gChecksumsCutscenes; // (unused) no anti tampering measurements +extern struct overlay_checksums_s gChecksumsLair; // (unused) no anti tampering measurements +extern struct overlay_checksums_s gChecksumsFight; // (unused) no anti tampering measurements +extern struct overlay_checksums_s gChecksumsCCW; // (unused) no anti tampering measurements +extern struct overlay_checksums_s gChecksumsEmptyLvl; // (unused) no anti tampering measurements + +/* The pre-calculated checksums are located in random places. + * + * The calculation process should be as following (needs to be confirmed!!): + * 1. At compile time all checksum variables (listed below) are set to zero + * 2. The text checksums for all overlays (except core1) are calculated and written. + * 3. The data checksums are calculated in two passes: + * 3-1. Data checksum 1 is calculated and written for each overlay (except core1). + * 3-2. Data checksum 2 is calculated and written for each overlay (except core1). + * 4. The boot and core1 checksums are calculated and written to the CRC section. + * + * Notes: + * - Checksums 1 sums up every byte + * - Checksum 2 XORes every byte after it is shifted right by "current checksum 1 AND 0x17" + * (This means checksum 2 must be calculated together with checksum 1) + * (Step 3-1 discards checksum 2 and step 3-2 discards checksum 1) + * - Checksums without a correspondending variable are just discarded. + */ + +extern s32 D_803727F4; // core2 text checksum 2 (location: core2) +extern s32 D_80276574; // core2 data checksum 2 (location: core1) + +extern s32 D_80389BE0; // CC text checksum 1 (location: CC) +extern s32 D_80389BE4; // CC text checksum 2 (location: CC) +extern s32 D_80389BE8; // CC data checksum 1 (location: CC) +extern s32 D_80276570; // CC data checksum 2 (location: core1) + +extern s32 D_80390F30; // GV text checksum 1 (location: GV) +extern s32 D_80390F34; // GV text checksum 2 (location: GV) +extern s32 D_80390F38; // GV data checksum 1 (location: GV) +extern s32 D_80275904; // GV data checksum 2 (location: core1) + +extern s32 D_8038C300; // MMM text checksum 1 (location: MMM) +extern s32 D_8038C304; // MMM text checksum 2 (location: MMM) +extern s32 D_8038C308; // MMM data checksum 1 (location: MMM) +extern s32 D_80275854; // MMM data checksum 2 (location: core1) + +extern s32 D_8038C750; // TTC text checksum 1 (location: TTC) +extern s32 D_8038C754; // TTC text checksum 2 (location: TTC) +extern s32 D_8038C758; // TTC data checksum 1 (location: TTC) +extern s32 D_80276CB0; // TTC data checksum 2 (location: core1) + +extern s32 D_803899C0; // MM text checksum 1 (location: MM) +extern s32 D_803899C4; // MM text checksum 2 (location: MM) +extern s32 D_803899C8; // MM data checksum 1 (location: MM) +extern s32 D_80275654; // MM data checksum 2 (location: core1) + +extern s32 D_80390B20; // BGS text checksum 1 (location: BGS) +extern s32 D_80390B24; // BGS text checksum 2 (location: BGS) +extern s32 D_80390B28; // BGS data checksum 1 (location: BGS) +extern s32 D_802758F0; // BGS data checksum 2 (location: core1) + +extern s32 D_80276CB4; // RBB data checksum 2 (location: core1) + +extern s32 D_802758F4; // FP data checksum 2 (location: core1) + +extern s32 D_8038AAE0; // SM text checksum 1 (location: SM) +extern s32 D_8038AAE4; // SM text checksum 2 (location: SM) +extern s32 D_8038AAE8; // SM data checksum 1 (location: SM) +extern s32 D_80275650; // SM data checksum 2 (location: core1) + +extern s32 D_80275850; // Cutscenes data checksum 2 (location: core1) + +extern s32 D_80275900; // Lair data checksum 2 (location: core1) + +extern s32 D_80275D34; // Fight data checksum 2 (location: core1) + +extern s32 D_80275D30; // CCW data checksum 2 (location: core1) + +#endif diff --git a/include/core1/core1.h b/include/core1/core1.h index 8386436ba..c071c8da2 100644 --- a/include/core1/core1.h +++ b/include/core1/core1.h @@ -2,6 +2,7 @@ #define BANJO_KAZOOIE_CORE1_CORE1_H #include +#include // [port] for ALSeqpConfig/ALHeap in audioManager decls (decomp gets this via SDK ultra64.h) #include "bool.h" #include "enums.h" #include "structs.h" @@ -42,10 +43,19 @@ void func_8025ABB8(enum comusic_e comusic_id, s32 arg1, s32 arg2, s32 arg3); int func_8025AD7C(enum comusic_e arg0); int func_8025ADBC(enum comusic_e arg0); -OSMesgQueue * audioManager_getFrameMesgQueue(void); void piMgr_read(void *vaddr, s32 devaddr, s32 size); +/* src/core1/code_1D00.c */ + +void audioManager_setupSeqp(ALSeqpConfig *config); +void audioManager_init(void); +ALHeap *audioManager_getALHeapInfo(void); +OSMesgQueue *audioManager_getDMANotifyMesgQueue(void); +OSIoMesg *audioManager_getExtraDMAMesg(void); +OSMesgQueue *audioManager_getFrameMesgQueue(void); + + /* src/core1/overlay.c */ void overlay_load( @@ -127,17 +137,17 @@ void core1_ce60_func_8024BD40(s32 arg0, s32 arg1); /* src/core1/depthbuffer.c */ -extern u8 D_8000E800; +extern u8 D_8000E800[]; -void func_80253190(Gfx **gfx); -void func_80253208(Gfx **gfx, s32 x, s32 y, s32 w, s32 h, void *color_buffer); -int func_80253400(void); -bool depthBuffer_isPointerSet(void); -void depthBuffer_stub(void); -void func_80253428(int arg0); -void func_802534A8(int arg0); -void zBuffer_set(Gfx **gfx); -void *zBuffer_get(void); +void depthbuffer_clear(Gfx **gfx); +void depthbuffer_clearRegion(Gfx **gfx, s32 x, s32 y, s32 w, s32 h, void *color_buffer); +bool depthbuffer_getUnk4(void); +bool depthbuffer_isDataPtrSet(void); +void depthbuffer_stub(void); +void depthbuffer_enable(bool enable); +void depthbuffer_setUnk4(bool value); +void depthbuffer_set(Gfx **gfx); +void *depthbuffer_getDataPtr(void); @@ -153,8 +163,8 @@ struct ucode_task_data_s { s32 unk4; // is only set for gfx tasks (0 or 0x40000000) void *data_ptr; // begin of dlist data (was u64* upstream; void* here for port-side casts) void *data_ptr_end; // end of dlist data - OSMesgQueue *unk10; // only relevant for audio tasks - s32 unk14; // only relevant for audio tasks + OSMesgQueue *audio_mesg_queue; // only relevant for audio tasks + OSMesg audio_mesg; // only relevant for audio tasks }; #define DEFAULT_FRAMEBUFFER_WIDTH 292 @@ -166,10 +176,10 @@ extern u16 gFramebuffers[2][DEFAULT_FRAMEBUFFER_WIDTH * DEFAULT_FRAMEBUFFER_HEIG void core1_15B30_requestLockForTaskDataID(void); void core1_15B30_requestReleaseForTaskDataID(void); -void core1_15B30_addAudioTaskData(Gfx **start, Gfx **end, void *mesg_queue, void *msg); -void func_80253640(Gfx ** gdl, void *arg1); -void scissorBox_SetForGameMode(Gfx **gdl, s32 framebuffer_idx); -void setupScissorBoxAndFramebuffer(Gfx **gfx, uintptr_t framebuffer_address); +void core1_15B30_addAudioTaskData(Acmd *start, Acmd *end, OSMesgQueue *mesg_queue, OSMesg msg); +void setupFramebuffer(Gfx **gfx, void *color_buffer); +void setupFramebufferForGamemode(Gfx **gfx, s32 framebuffer_idx); +void setupScissorBoxAndFramebuffer(Gfx **gfx, void *color_buffer); void setupDefaultScissorBoxAndFramebuffer(Gfx **gfx, s32 framebuffer_idx); void core1_15B30_finishDList_renderThread(Gfx **gfx); void core1_15B30_finishDList(Gfx **gfx); @@ -190,8 +200,8 @@ void graphicsCache_checkFrame(Gfx *gfxStart, Gfx *gfxEnd, Mtx *mtxStart, Mtx *mt void scissorBox_set(s32 left, s32 top, s32 right, s32 bottom); void scissorBox_setDefault(void); void core1_15B30_addTask7TaskData(s32 framebuffer_id); -void toggleTextureFilterPoint(void); -void getGraphicsStacks(Gfx **gfx, Mtx **mtx, Vtx **vtx); +void core1_15B30_toggleTexturePointFilter(void); +void graphicscache_swapAndGetStacks(Gfx **gfx, Mtx **mtx, Vtx **vtx); void dummy_func_80254464(void); /* src/core1/defragmanager.c */ diff --git a/include/core1/main.h b/include/core1/main.h index b3bed72e4..534adeaa0 100644 --- a/include/core1/main.h +++ b/include/core1/main.h @@ -10,8 +10,8 @@ extern "C" { void core1_main(s32 arg0); void func_8023DA74(void); void func_8023DA9C(s32 arg0); -u32 globalTimer_getTimeMasked(u32 mask); -//s32 globalTimer_getTime(void); +s32 globalTimer_getTimeMasked(s32 mask); +s32 globalTimer_getTime(void); void globalTimer_reset(void); enum map_e getSpecialBootMap(void); enum map_e getDefaultBootMap(void); diff --git a/include/core1/ml.h b/include/core1/ml.h index 8968621c8..04ef38101 100644 --- a/include/core1/ml.h +++ b/include/core1/ml.h @@ -14,7 +14,7 @@ void ml_vec3f_cross_product(f32 dst[3], f32 vec1[3], f32 vec2[3]); void ml_vec3f_interpolate_fast(f32 dst[3], f32 start[3], f32 end[3], f32 t); f32 ml_vec3f_dot_product(f32 vec1[3], f32 vec2[3]); f32 ml_vec3f_distance(f32 vec1[3], f32 vec2[3]); -f32 ml_func_802560D0(f32 arg0[3], f32 arg1[3], f32 arg2[3]); +f32 ml_vec3f_distance_to_point(f32 arg0[3], f32 arg1[3], f32 arg2[3]); f32 ml_distanceSquared_vec3f(f32 vec1[3], f32 vec2[3]); void func_802562DC(f32 vec1[3], f32 vec2[3], f32 vec3[3]); f32 ml_vec3f_length_unused(f32 vec[3]); @@ -23,7 +23,7 @@ void ml_vec3f_normalize(f32 vec[3]); void ml_vec2f_normalize(f32 vec[2]); void ml_3f_normalize(f32 *x, f32 *y, f32 *z); void ml_vec3f_set_length_copy(f32 dst[3], f32 src[3], f32 len); -void func_80256664(f32 ptr[3]); +void ml_vec3f_clamp_deg360(f32 ptr[3]); void func_80256740(f32 vec[3]); void ml_vec3f_pitch_rotate_copy(f32 dst[3], f32 src[3], f32 pitch); void ml_vec3f_yaw_rotate_copy(f32 dst[3], f32 src[3], f32 yaw); @@ -39,7 +39,7 @@ f32 ml_acosf(f32 x); f32 func_8025715C(f32 val1, f32 val2); f32 func_80257204(f32 val1, f32 val2, f32 val3, f32 val4); f32 func_80257248(f32 vec1[3], f32 vec2[3]); -void func_8025727C(f32 x1, f32 y1, f32 z1, f32 x2, f32 y2, f32 z2, f32 *o1, f32 *o2); +void ml_horizontal_and_vertical_angles(f32 x1, f32 y1, f32 z1, f32 x2, f32 y2, f32 z2, f32 *o1, f32 *o2); void ml_init(void); void ml_free(void); f32 func_802575BC(f32 val); @@ -110,7 +110,7 @@ void ml_translate_y_local(f32 position[3], f32 rotation[3], f32 dy); void ml_translate_z_local(f32 dst[3], f32 src[3], f32 dz); void ml_translate_x_local(f32 dst[3], f32 src[3], f32 dx); void func_8025901C(f32 arg0, f32 arg1[3], f32 arg2[3], f32 arg3); -f32 func_80259198(f32 arg0, f32 arg1); +f32 ml_clamp_abs_f(f32 arg0, f32 arg1); f32 mlDiffDegF(f32 arg0, f32 arg1); bool ml_vec3f_point_within_horizontal_distance(f32 vec[3], f32 x, f32 z, f32 distance); bool ml_vec3f_within_horizontal_distance(f32 vec1[3], f32 vec2[3], f32 distance); @@ -118,7 +118,7 @@ bool ml_vec3w_within_horizontal_distance(s32 vec1[3], s32 vec2[3], s32 distance) bool ml_vec3f_within_distance(f32 vec1[3], f32 vec2[3], f32 distance); bool ml_stub_80259400(f32 x); void ml_sub_delta_time(f32 *x); -void func_8025947C(f32 a0[3], f32 a1[3], f32 a2[3], f32 a3[3]); +void ml_project_point_onto_vecf3(f32 a0[3], f32 a1[3], f32 a2[3], f32 a3[3]); f32 func_80259554(f32 dst[3], f32 vec1[3], f32 vec2[3], f32 vec3[3]); void func_802596AC(f32 a0[3], f32 a1[3], f32 a2[3], f32 a3[3]); s32 ml_getViewportYawWithOffset(f32 x); diff --git a/include/core1/viewport.h b/include/core1/viewport.h index 2e9877061..1a5bafaa8 100644 --- a/include/core1/viewport.h +++ b/include/core1/viewport.h @@ -7,7 +7,7 @@ extern "C" { void viewport_moveAlongZAxis(f32 offset); f32 viewport_getDistance(f32 arg0[3]); -void viewport_getLookbk_vector(f32 arg0[3]); +void viewport_getLookVector(f32 arg0[3]); void viewport_getPosition_vec3f(f32 arg0[3]); void viewport_getPosition_vec3w(s32 dst[3]); void viewport_getPosition_vec3s(s16 dst[3]); diff --git a/include/core2/ba/carry.h b/include/core2/ba/carry.h index 5c74db27c..af50dfa28 100644 --- a/include/core2/ba/carry.h +++ b/include/core2/ba/carry.h @@ -9,7 +9,7 @@ void bacarry_end(void); void bacarry_update(void); void bacarry_reset_marker(void); -ActorMarker *bacarry_get_marker(void); +ActorMarker *bacarry_getMarker(void); void bacarry_set_marker(ActorMarker *arg0); void bacarry_set_offsets(f32 height, f32 rotation); diff --git a/include/core2/ba/timer.h b/include/core2/ba/timer.h index 186cf9ab0..95d191aca 100644 --- a/include/core2/ba/timer.h +++ b/include/core2/ba/timer.h @@ -4,7 +4,7 @@ #include void batimer_incrementBy(s32 id, f32 inc_value_sec); -int batimer_decrement(s32 id); +bool batimer_decrement(s32 id); void batimer_increment(s32 id); f32 batimer_get(s32 id); int batimer_isAt(s32 id, f32 value_sec); diff --git a/include/core2/modelRender.h b/include/core2/modelRender.h index 2da2e1174..2b955bd7f 100644 --- a/include/core2/modelRender.h +++ b/include/core2/modelRender.h @@ -41,7 +41,7 @@ void modelRender_setEnvColor(s32 r, s32 g, s32 b, s32 a); void modelRender_setAlpha(s32 a); void modelRender_func_8033A444(AnimMtxList *arg0); void modelRender_setRefPoints(Vec3fArray *ref_points); -void func_8033A45C(s32 arg0, s32 arg1); +void modelRender_setAppendageVisibility(s32 arg0, s32 arg1); void modelRender_func_8033A470(s32 arg0, s32 arg1); void modelRender_setTextureList(BKTextureList *texture_list); void modelRender_setAnimatedTexturesCacheId(s32 arg0); diff --git a/include/enums.h b/include/enums.h index 90de73ab1..bf7e8ae57 100644 --- a/include/enums.h +++ b/include/enums.h @@ -449,7 +449,7 @@ enum level_flags_e LEVEL_FLAG_23_RBB_OPEN, LEVEL_FLAG_24_CCW_OPEN, - LEVEL_FLAG_25_CCW_UNKNOWN, + LEVEL_FLAG_25_CCW_GNAWTY_JIGGY_COLLECTED, LEVEL_FLAG_26_FP_WALRUS_JIGGY_DROPPED, LEVEL_FLAG_27_RBB_UNKNOWN, LEVEL_FLAG_28_RBB_UNKNOWN, @@ -632,7 +632,7 @@ typedef enum map_e MAP_5A_CCW_SUMMER_ZUBBA_HIVE = 0x5A, // Summer & Spring are swapped here MAP_5B_CCW_SPRING_ZUBBA_HIVE, MAP_5C_CCW_AUTUMN_ZUBBA_HIVE, - // Unused + MAP_5D_UNUSED, MAP_5E_CCW_SPRING_NABNUTS_HOUSE = 0x5E, MAP_5F_CCW_SUMMER_NABNUTS_HOUSE = 0x5F, MAP_60_CCW_AUTUMN_NABNUTS_HOUSE = 0x60, @@ -654,7 +654,7 @@ typedef enum map_e MAP_70_GL_CC_LOBBY = 0x70, MAP_71_GL_STATUE_ROOM, MAP_72_GL_BGS_LOBBY, - // Unused + MAP_73_UNUSED, MAP_74_GL_GV_PUZZLE = 0x74, MAP_75_GL_MMM_LOBBY, MAP_76_GL_640_NOTE_DOOR, @@ -1468,6 +1468,7 @@ enum sfx_e SFX_3F9_UNKNOWN, //chmole SFX_3FA_HONEYCOMB_TALKING, SFX_3FB_UNKNOWN, //conga + SFX_3FC_ZUBBA_UNK, SFX_405_UNKNOWN = 0x405, SFX_406_GOLD_BULLION_TALKING, @@ -1762,10 +1763,10 @@ enum mumbotoken_e typedef enum actor_e { - ACTOR_1_UNKNOWN = 0x1, + ACTOR_1_UNKNOWN = 0x1, ACTOR_2_UNKNOWN, - ACTOR_4_BIGBUTT = 0x4, + ACTOR_4_BIGBUTT = 0x4, ACTOR_5_TERMITE, ACTOR_6_GRUBLIN, ACTOR_7_MUMBO, @@ -1776,14 +1777,11 @@ typedef enum actor_e ACTOR_C_MUD_HUT, ACTOR_D_WOOD_DEMOLISHED, ACTOR_E_SMALL_BULL, - ACTOR_F_CHIMPY = 0xF, - - ACTOR_10E_BLUBBER_SHIP_TOP_HATCH = 0x10e, + ACTOR_F_CHIMPY, - ACTOR_11_JUJU_CTRL = 0x11, + ACTOR_11_JUJU_CTRL = 0x11, ACTOR_12_BEEHIVE, //ACTOR_13_SINKING_BOBBER - ACTOR_14_ORANGE_PROJECTILE = 0x14, ACTOR_15_UNKNOWN, @@ -1794,10 +1792,15 @@ typedef enum actor_e ACTOR_1B_FRAMERATE_20, ACTOR_1C_FRAMERATE_15, ACTOR_1D_FRAMERATE_12, - - ACTOR_1E_LEAKY = 0x1E, + ACTOR_1E_LEAKY, + ACTOR_1F_UNUSED, // Maybe was supposed to be Termite Transformation? + ACTOR_20_TRANSFORM_PUMPKIN, + ACTOR_21_TRANSFORM_CROC, + ACTOR_22_TRANSFORM_WALRUS, + ACTOR_23_TRANSFORM_BEE, ACTOR_25_CEMETARY_POT = 0x25, + ACTOR_26_CLIMB_BASE, ACTOR_29_ORANGE_COLLECTIBLE = 0x29, ACTOR_2A_GOLD_BULLION, @@ -1813,6 +1816,7 @@ typedef enum actor_e ACTOR_39_NAPPER = 0x39, ACTOR_3A_MOTZHAND, + ACTOR_3B_CLANKER_DIALOG_TRIGGER, ACTOR_3C_CC_KEY = 0x3C, ACTOR_3D_CLANKER_SAWBLADE_PROPELLOR_1, @@ -1901,31 +1905,31 @@ typedef enum actor_e ACTOR_BC_BANJOS_CURTAINS = 0xBC, ACTOR_BD_BANJOS_HOUSE_DOOR, - ACTOR_C5_CHIMPY_STUMP = 0xC5, + ACTOR_C5_CHIMPY_STUMP = 0xC5, ACTOR_C7_GRAVESTONE = 0xC7, - ACTOR_C8_BOGGY_2 = 0xC8, + ACTOR_C8_BOGGY_2, ACTOR_CA_TEEHEE = 0xCA, ACTOR_CB_1881_BARREL_TOP, - ACTOR_E4_FLIGHT_PAD = 0xE4, + ACTOR_E4_FLIGHT_PAD = 0xE4, - ACTOR_E6_GLOOP = 0xE6, + ACTOR_E6_GLOOP = 0xE6, ACTOR_E7_GLOOP_BUBBLE, ACTOR_E8_TANKTUP, ACTOR_E9_TANKTUP_LEG_FL, ACTOR_EA_TANKTUP_LEG_BL, ACTOR_EB_TANKTUP_LEG_FR, ACTOR_EC_TANKTUP_LEG_BR, - ACTOR_ED_PINK_EGG_LARGE = 0xED, + ACTOR_ED_PINK_EGG_LARGE, ACTOR_EE_PINK_EGG_MEDIUM, ACTOR_EF_PINK_EGG_SMALL, ACTOR_F0_PINK_EGG_SMALLEST, ACTOR_F1_LEAF_BOAT, ACTOR_F2_BLACK_SNIPPET, ACTOR_F3_EXPLOSION_RIPPLE, - ACTOR_F4_BURIED_TREASURE = 0xF4, + ACTOR_F4_BURIED_TREASURE, ACTOR_F5_MUTIE_SNIPPET, ACTOR_F6_BIG_ALLIGATOR, @@ -1936,12 +1940,13 @@ typedef enum actor_e ACTOR_105_UNKNOWN, ACTOR_106_UNKNOWN, ACTOR_107_UNKNOWN, - - ACTOR_109_SHACK_DOOR = 0x109, + ACTOR_108_MODEL_PLAYER_SHADOW, + ACTOR_109_SHACK_DOOR, ACTOR_10A_MANSION_DOOR, ACTOR_10B_CELLAR_HATCH, ACTOR_10C_CHURCH_GATE_LEFT_LOCK, ACTOR_10D_HEDGE_GATE_RIGHT_LOCK_1, + ACTOR_10E_BLUBBER_SHIP_TOP_HATCH, ACTOR_114_CHURCH_DOOR = 0x114, ACTOR_115_BLUBBER, @@ -1962,12 +1967,13 @@ typedef enum actor_e ACTOR_124_SIR_SLUSH, ACTOR_125_SNOWBALL, ACTOR_126_SIR_SLUSH_HAT, + ACTOR_129_RED_FEATHER = 0x129, ACTOR_12B_TUTORIAL_BOTTLES = 0x12B, ACTOR_12C_MOLEHILL, - ACTOR_12E_GOBI_1 = 0x12E, + ACTOR_12E_GOBI_1 = 0x12E, ACTOR_12F_GOBI_ROPE, ACTOR_130_GOBI_ROCK, ACTOR_131_GOBI_2, @@ -1994,8 +2000,8 @@ typedef enum actor_e ACTOR_147_ANCIENT_ONE, ACTOR_149_TTC_BLUBBER_UNKNOWN = 0x149, - ACTOR_14A_TTC_BLUBBER_UNKNOWN = 0x14a, - ACTOR_14B_TTC_BLUBBER_UNKNOWN = 0x14b, + ACTOR_14A_TTC_BLUBBER_UNKNOWN, + ACTOR_14B_TTC_BLUBBER_UNKNOWN, ACTOR_14E_BGS_ELEVATED_WALKWAY_SWITCH = 0x14E, ACTOR_14F_DESTROYED_JIGGY, @@ -2028,14 +2034,15 @@ typedef enum actor_e ACTOR_16B_CCW_AUTUMN_SEASON_DOOR, ACTOR_16C_CCW_SUMMER_SWITCH, ACTOR_16D_CCW_SUMMER_SEASON_DOOR, - ACTOR_16E_UNKNOWN = 0x16E, + ACTOR_16E_UNKNOWN, ACTOR_16F_QUARRIE, ACTOR_172_RBB_EGG_TOLL = 0x172, - - ACTOR_175_MODEL_RUSTY_BUCKET_REAR_PROPELLER = 0x175, - - ACTOR_177_RBB_SPINNING_SINGLE_PIPE_1 = 0x177, + ACTOR_173_RBB_CAGE_UP_SWITCH, + ACTOR_174_RBB_TNT_DOWN_SWITCH, + ACTOR_175_RUSTY_BUCKET_REAR_PROPELLER, + ACTOR_176_RBB_GREEN_PROPELLOR_SWITCH, + ACTOR_177_RBB_SPINNING_SINGLE_PIPE_1, ACTOR_178_RBB_SPINNING_FLAT_PLATFORM_1, ACTOR_179_RBB_SPINNING_FLAT_PLATFORM_2, ACTOR_17A_RBB_SPINNING_FLAT_PLATFORM_3, @@ -2047,7 +2054,7 @@ typedef enum actor_e ACTOR_180_RBB_SPINNING_DOUBLE_PIPE_2, ACTOR_181_SCARF_SLED = 0x181, - ACTOR_182_RACE_SLED = 0x182, + ACTOR_182_RACE_SLED, ACTOR_188_PIRANHA_WATER_PARTICLES = 0x188, @@ -2058,22 +2065,25 @@ typedef enum actor_e ACTOR_198_BANJOS_BED = 0x198, ACTOR_199_BANJOS_CHAIR, ACTOR_19A_BANJOS_STOVE, - + ACTOR_19B_MUMBOS_HAND_WITH_PICTURE, ACTOR_19C_MODEL_THE_END_SIGN = 0x19C, ACTOR_1BB_ENGINE_ROOM_PROPELLOR_1 = 0x1BB, ACTOR_1BC_ENGINE_ROOM_PROPELLOR_2, ACTOR_1BD_ENGINE_ROOM_PROPELLOR_3, - - ACTOR_1C2_WHISTLE_1 = 0x1C2, + ACTOR_1BE_RBB_GREY_PROPELLOR_SWITCH, + ACTOR_1BF_WHISTLE_SWITCH_1, + ACTOR_1C0_WHISTLE_SWITCH_2, + ACTOR_1C1_WHISTLE_SWITCH_3, + ACTOR_1C2_WHISTLE_1, ACTOR_1C3_WHISTLE_2, ACTOR_1C4_WHISTLE_3, - - ACTOR_1C5_WHISTLE_CTRL = 0x1C5, + ACTOR_1C5_WHISTLE_CTRL, ACTOR_1C6_GRIMLET, ACTOR_1C7_ANCHOR_SWITCH, ACTOR_1C8_SNORKEL, ACTOR_1C9_ANCHOR, + ACTOR_1CA_RAREWARE_FLAG, ACTOR_1CC_GRILLE_CHOMPA = 0x1CC, ACTOR_1CD_UNKNOWN, @@ -2095,6 +2105,7 @@ typedef enum actor_e ACTOR_1E2_CCW_SPRING_SWITCH, ACTOR_1E3_CCW_SPRING_SEASON_DOOR, ACTOR_1E4_TOOTS, + ACTOR_1E5_UNKNOWN, ACTOR_1E9_SNARE_BEAR = 0x1E9, ACTOR_1EA_POLAR_BEAR_CUB_BLUE, @@ -2163,11 +2174,11 @@ typedef enum actor_e ACTOR_230_BREAKABLE_FLOOR_COBWEB = 0x230, ACTOR_231_BREAKABLE_WALL_COBWEB, + ACTOR_233_CCW_MUMBOS_HUT = 0x233, ACTOR_234_CCW_ENTRANCE_DOOR = 0x234, ACTOR_235_FP_ENTRANCE_DOOR_LEFT, ACTOR_236_FP_ENTRANCE_DOOR_RIGHT, - - ACTOR_237_CCW_WITCH_SWITCH = 0x237, + ACTOR_237_CCW_WITCH_SWITCH, ACTOR_239_FP_WITCH_SWITCH = 0x239, ACTOR_23A_GL_ADVENT_CALENDAR_HATCH_DOOR, @@ -2180,8 +2191,7 @@ typedef enum actor_e ACTOR_242_FF_TELEPORT_PAD = 0x242, ACTOR_243_GV_SNS_CHAMBER_DOOR, ACTOR_244_GV_SNS_SARCOPHAGUS, - - ACTOR_245_GV_SNS_SWITCH = 0x245, + ACTOR_245_GV_SNS_SWITCH, ACTOR_246_FLIGHT_PAD_SWITCH, ACTOR_247_LAIR_SWITCH_FLIGHT_PAD, ACTOR_248_SHOCK_JUMP_PAD_SWITCH, @@ -2197,7 +2207,10 @@ typedef enum actor_e ACTOR_25C_SHARKFOOD_ISLAND, ACTOR_25D_ICE_KEY, ACTOR_25E_SNS_EGG, - + ACTOR_25F_CCW_UNKNOWN_NABNUT_WINDOW, + ACTOR_260_CCW_UNKNOWN_NABNUT_WINDOW, + ACTOR_261_CCW_AUTUMN_NABNUT_WINDOW, + ACTOR_262_CCW_WINTER_NABNUT_WINDOW, ACTOR_263_SUNNY_LIFEBOAT = 0x263, ACTOR_264_SHADOW_LIFEBOAT, ACTOR_265_DINING_DOOR, @@ -2215,6 +2228,9 @@ typedef enum actor_e ACTOR_282_BOSS_BOOM_BOX_LARGE, ACTOR_283_BOSS_BOOM_BOX_MEDIUM, ACTOR_284_BOSS_BOOM_BOX_SMALL, + ACTOR_285_JINXY_HEAD_SANDYBUTT_1, + ACTOR_286_JINXY_HEAD_SANDYBUTT_2, + ACTOR_287_JINXY_HEAD_SANDYBUTT_3, ACTOR_289_BETA_VENT = 0x289, ACTOR_28A_CLANKER_WHIPCRACK, @@ -2227,32 +2243,46 @@ typedef enum actor_e ACTOR_293_CLANKER_SAWBLADE_PROPELLOR_10, ACTOR_294_CLANKER_SAWBLADE_PROPELLOR_11, ACTOR_295_CLANKER_SAWBLADE_PROPELLOR_12, - - ACTOR_298_ZUBBA_DOOR = 0x298, - - ACTOR_29A_ZUBBA_DOOR = 0x29A, + ACTOR_296_BELL_BUOY, + ACTOR_297_ROWBOAT, + ACTOR_298_ZUBBA_DOOR_SUMMER, + ACTOR_299_ZUBBA_HONEY_LUMP, + ACTOR_29A_ZUBBA_DOOR_AUTUMN = 0x29A, ACTOR_29B_ZUBBA, - + ACTOR_29C_ZUBBA_DOCILE, ACTOR_29D_CCW_BEANSTALK = 0x29D, ACTOR_29E_CCW_GOBI, ACTOR_29F_CLUCKER, ACTOR_2A0_EAGLE_EGG, ACTOR_2A1_EEYRIE_BABY, ACTOR_2A2_CATERPILLAR, - + ACTOR_2A3_EEYRIE_ADULT, ACTOR_2A4_BOOM_BOX_SLOW = 0x2A4, - + ACTOR_2A5_BOOM_BOX_MINIGAME_CTRL = 0x2A5, + ACTOR_2A6_NABNUT_SPRING = 0x2A6, + ACTOR_2A7_NABNUT_FULL_BELLY, ACTOR_2A8_NABNUT = 0x2A8, ACTOR_2A9_ACORN, - - ACTOR_2AC_GNAWTY_BOULDER = 0x2AC, - - ACTOR_2B4_BOTTLES_BONUS_BANJO_HAND = 0x2B4, + ACTOR_2AA_GNAWTY_SWIMMING, + ACTOR_2AB_GNAWTY_SUMMER, + ACTOR_2AC_GNAWTY_BOULDER, + ACTOR_2AD_BOSS_BOOMBOX_CTRL, + ACTOR_2AE_LEAF_EMITTER_CCW_AUTUMN, + ACTOR_2AF_LEAF_EMITTER_CCW_HUB, + ACTOR_2B0_RAIN_EMITTER_CCW_SPRING, + ACTOR_2B1_RAIN_EMITTER_CCW_HUB, + ACTOR_2B2_SNOW_EMITTER_CCW_WINTER, + ACTOR_2B3_SNOW_EMITTER_CCW_HUB, + ACTOR_2B4_BOTTLES_BONUS_BANJO_HAND, + ACTOR_2B5_UNKNOWN, ACTOR_2D8_TWO_ICE_POLES_NEAR_CHEATO_3 = 0x2D8, - - ACTOR_2DB_DINGPOT = 0x2DB, - + ACTOR_2D9_UNKNOWN, + ACTOR_2DA_UNKNOWN, + ACTOR_2DB_DINGPOT, + ACTOR_2DC_GNAWTYS_SHELVES, + ACTOR_2DD_GNAWTYS_BED, + ACTOR_2DE_GNAWTYS_DEN, ACTOR_2DF_LIGHTHOUSE_B = 0x2DF, ACTOR_2E0_TTC_STAIRS_1, ACTOR_2E1_TTC_STAIRS_2, @@ -2260,12 +2290,11 @@ typedef enum actor_e ACTOR_2E3_LEVEL_ENTRY_SIGNS, ACTOR_2E4_WORLD_EXIT_PAD, ACTOR_2E5_LARGE_DOOR_TO_FINAL_BATTLE, - + ACTOR_2E6_NABNUT_DOOR, + ACTOR_2E7_WHIPCRACK_ROOM_DOOR, ACTOR_2E8_WINDOW = 0x2E8, ACTOR_2E9_WIDE_WINDOW, ACTOR_2EA_TALL_WINDOW, - - ACTOR_2E5_DOOR_OF_GRUNTY = 0x2e5, ACTOR_2F4_FISHBOWL = 0x2F4, ACTOR_2F5_CUCKOO_CLOCK, @@ -2273,17 +2302,25 @@ typedef enum actor_e ACTOR_2FF_GREEN_FOG_OUTSIDE_TOWER = 0x2FF, ACTOR_300_BIKINI_GIRL, + ACTOR_30B_DEAD_BEANSTALK = 0x30B, + ACTOR_30C_SNORE_Z, ACTOR_30D_BOOM_BOX_FAST = 0x30D, - + ACTOR_30E_CUTSCENE_ADULT_EYRIE, ACTOR_30F_WHIPCRACK = 0x30f, ACTOR_310_NABNUT_HOUSE_PILE_OF_ACORNS, - + ACTOR_311_PINK_SQUIRREL, + ACTOR_312_NABNUT_BEDSHEETS, ACTOR_313_NABNUT_BED = 0x313, ACTOR_314_NABNUT_IN_AUTUMN_HOUSE, - + ACTOR_315_NABNUT_EATING_ACORNS, + ACTOR_316_UNKNOWN, + ACTOR_317_UNKNOWN, + ACTOR_318_CCW_UNKNOWN = 0x318, ACTOR_319_GV_MAZE_CTRL = 0x319, - - ACTOR_31D_SANDYBUTT_PYRAMID = 0x31D, + ACTOR_31A_INDOORS_GNAWTY, + ACTOR_31B_SPINNING_SINGLE_PIPE_SFX_CTRL, + ACTOR_31C_DOUBLE_SINGLE_PIPE_SFX_CTRL, + ACTOR_31D_SANDYBUTT_PYRAMID, ACTOR_31E_PALM_TREE, ACTOR_32B_UNKNOWN = 0x32B, //something with Tanktup @@ -2309,12 +2346,12 @@ typedef enum actor_e ACTOR_348_BRENTILDA = 0x348, ACTOR_349_UNKNOWN, - ACTOR_34D_BEE_SWARM = 0x34D, + ACTOR_34D_BEE_SWARM = 0x34D, ACTOR_34E_LIMBO, ACTOR_34F_MUMMUM, ACTOR_350_SEAMAN_GRUBLIN, - - ACTOR_352_UNKNOWN = 0x352, + ACTOR_351_UNKNOWN, + ACTOR_352_UNKNOWN, ACTOR_353_XMAS_TREE_EGG_TOLL, ACTOR_354_DRIPS, @@ -2324,22 +2361,22 @@ typedef enum actor_e ACTOR_36A_15_MUMBO_TOKEN_SIGN, ACTOR_36B_10_MUMBO_TOKEN_SIGN, ACTOR_36C_25_MUMBO_TOKEN_SIGN, + ACTOR_36D_COLLYWOBBLE_B, + ACTOR_36E_BAWL_THE_ONION_B, + ACTOR_36F_TOPPER_THE_CARROT_B, + ACTOR_370_GOLD_FEATHER, - ACTOR_COLLYWOBBLE_B = 0x36D, - ACTOR_BAWL_THE_ONION_B = 0x36E, - ACTOR_TOPPER_THE_CARROT_B = 0x36F, - ACTOR_370_GOLD_FEATHER = 0x370, - - ACTOR_374_VACATION_TEXT_TRIGGER = 0x374, + ACTOR_374_VACATION_TEXT_TRIGGER = 0x374, ACTOR_375_GRUBLIN_HOOD, ACTOR_376_FF_MINIGAME, ACTOR_379_UNKNOWN = 0x379, ACTOR_37A_BOTTLES, - ACTOR_37D_ICECUBE_A = 0x37d, + ACTOR_37D_ICECUBE_A = 0x37D, + ACTOR_37E_DEAD_SNAREBEAR, - ACTOR_37F_LOGGO = 0x37F, + ACTOR_37F_LOGGO = 0x37F, ACTOR_380_SCARAB_BEETLE, ACTOR_381_PORTRAIT_CHOMPA, ACTOR_382_PORTRAIT_OF_GRUNTY, @@ -2363,7 +2400,7 @@ typedef enum actor_e ACTOR_3A6_BOSS_JINJO_GREEN, ACTOR_3A7_BOSS_JINJO_PINK, ACTOR_3A8_BOSS_JINJO_YELLOW, - ACTOR_3A9_JINJONATOR_STATUE_BASE = 0x3A9, + ACTOR_3A9_JINJONATOR_STATUE_BASE, ACTOR_3AA_GRUNTY_SPELL_GREEN_ATTACK = 0x3AA, ACTOR_3AB_GRUNTY_SPELL_BARRIER, @@ -2377,8 +2414,7 @@ typedef enum actor_e ACTOR_3BD_SM_BRIDGE_CHECKSUM_TRIGGER = 0x3BD, ACTOR_3BE_LAIR_UNKNOWN, - - ACTOR_3BF_GRUNTLING_BLUE = 0x3BF, + ACTOR_3BF_GRUNTLING_BLUE, ACTOR_3C0_GRUNTLING_BLACK, ACTOR_3C1_PURPLE_TEEHEE, ACTOR_3C2_GIANT_GRAVESTONE, @@ -2388,11 +2424,10 @@ typedef enum actor_e ACTOR_3C7_FF_PRIZE_GRUNTY_DOLL = 0x3C7, ACTOR_3C8_FF_PRIZE_TOOTY, ACTOR_3C9_FURNACE_FUN_PICK_PRICE, - ACTOR_3CA_ROCK_TRAPPING_GRUNTY = 0x3CA, + ACTOR_3CA_ROCK_TRAPPING_GRUNTY, ACTOR_3CB_UNKNOWN, - - ACTOR_3CC_DUMMY_PLAYER_ANCHOR = 0x3CC, -} ActorID; + ACTOR_3CC_DUMMY_PLAYER_ANCHOR = 0x3CC // Lighthouse [port] network anchor dummy player +}; enum bundle_e { BUNDLE_0_MM_HUT_MUSIC_NOTE, @@ -2440,23 +2475,23 @@ enum bs_e { BS_0_NONE = 0x0, BS_1_IDLE = 0x1, BS_2_WALK_SLOW = 0x2, - BS_WALK = 0x3, + BS_3_WALK = 0x3, BS_4_WALK_FAST = 0x4, BS_5_JUMP = 0x5, - BS_CLAW = 0x6, - BS_CROUCH = 0x7, + BS_6_CLAW = 0x6, + BS_7_CROUCH = 0x7, BS_8_BTROT_JUMP = 0x8, BS_9_EGG_HEAD = 0x9, BS_A_EGG_ASS = 0xA, BS_B_UNKOWN = 0xB, - BS_SKID = 0xC, - BS_D_TIMEOUT = 0xD, + BS_C_SKID = 0xC, + BS_D_TIMEOUT_TRANSFORMATION = 0xD, BS_E_OW = 0xE, BS_F_BBUSTER = 0xF, - BS_BFLAP = 0x10, + BS_10_BFLAP = 0x10, BS_11_BPECK = 0x11, BS_12_BFLIP = 0x12, - BS_BBARGE = 0x13, + BS_13_BBARGE = 0x13, BS_14_BTROT_ENTER = 0x14, BS_15_BTROT_IDLE = 0x15, BS_16_BTROT_WALK = 0x16, @@ -2468,31 +2503,31 @@ enum bs_e { BS_1C_WONDERWING_WALK = 0x1C, BS_1D_WONDERWING_JUMP = 0x1D, BS_1E_WONDERWING_EXIT = 0x1E, - BS_WALK_CREEP = 0x1F, + BS_1F_WALK_CREEP = 0x1F, BS_20_LANDING = 0x20, - BS_BSHOCK_CHARGE = 0x21, - BS_BSHOCK_JUMP = 0x22, + BS_21_BSHOCK_CHARGE = 0x21, + BS_22_BSHOCK_JUMP = 0x22, BS_23_FLY_ENTER = 0x23, BS_24_FLY = 0x24, BS_25_LONGLEG_ENTER = 0x25, BS_26_LONGLEG_IDLE = 0x26, - BS_LONGLEG_WALK = 0x27, - BS_LONGLEG_JUMP = 0x28, - BS_LONGLEG_EXIT = 0x29, - BS_BOMB = 0x2A, + BS_27_LONGLEG_WALK = 0x27, + BS_28_LONGLEG_JUMP = 0x28, + BS_29_LONGLEG_EXIT = 0x29, + BS_2A_BOMB = 0x2A, BS_2B_DIVE_IDLE = 0x2B, BS_2C_DIVE_B = 0x2C, BS_2D_SWIM_IDLE = 0x2D, BS_2E_SWIM = 0x2E, BS_2F_FALL = 0x2F, BS_30_DIVE_ENTER = 0x30, - BS_ROLL = 0x31, - BS_SLIDE = 0x32, - + BS_31_ROLL = 0x31, + BS_32_SLIDE = 0x32, + BS_33_WASHY_UNKNOWN = 0x33, BS_34_JIG_NOTEDOOR = 0x34, BS_35_ANT_IDLE = 0x35, - BS_ANT_WALK = 0x36, - BS_ANT_JUMP = 0x37, + BS_36_ANT_WALK = 0x36, + BS_37_ANT_WALK = 0x37, BS_38_ANT_FALL = 0x38, BS_39_DIVE_A = 0x39, BS_3A_CARRY_IDLE = 0x3A, @@ -2500,14 +2535,14 @@ enum bs_e { BS_3C_TALK = 0x3C, BS_3D_FALL_TUMBLING = 0x3D, BS_3E_ANT_OW = 0x3E, - BS_3F = 0x3F, + BS_3F_UNKNOWN = 0x3F, BS_40_PUMPKIN_FLUSH = 0x40, BS_41_DIE = 0x41, BS_42_DINGPOT = 0x42, BS_43_ANT_DIE = 0x43, BS_44_JIG_JIGGY = 0x44, BS_45_BTROT_SLIDE = 0x45, - + BS_46_UNKNOWN = 0x46, BS_48_PUMPKIN_IDLE = 0x48, BS_49_PUMPKIN_WALK = 0x49, @@ -2519,39 +2554,39 @@ enum bs_e { BS_4F_CLIMB_IDLE = 0x4F, BS_50_CLIMB_MOVE = 0x50, BS_51_CLIMB_EXIT = 0x51, - BS_52_UNKNOWN = 0x52, //tumblar??? a.k.a bssurf - BS_53_TIMEOUT = 0x53, + BS_52_SURF = 0x52, //tumblar??? a.k.a bssurf + BS_53_TIMEOUT_BANJO = 0x53, BS_54_SWIM_DIE = 0x54, - BS_LONGLEG_SLIDE = 0x55, + BS_55_LONGLEG_SLIDE = 0x55, BS_56_RECOIL = 0x56, BS_57_BOMB_END = 0x57, BS_58_BEAKBOMB_CRASH = 0x58, BS_59_BFLY_UNK59 = 0x59, BS_5A_LOADZONE = 0x5A, - BS_CARRY_THROW = 0x5B, + BS_5B_CARRY_THROW = 0x5B, BS_5E_CROC_IDLE = 0x5E, - BS_CROC_WALK = 0x5F, - BS_CROC_JUMP = 0x60, + BS_5F_CROC_WALK = 0x5F, + BS_60_CROC_JUMP = 0x60, BS_61_CROC_FALL = 0x61, BS_62_LONGLEG_LOCKED = 0x62, - BS_CROC_OW = 0x63, - BS_CROC_DIE = 0x64, + BS_63_CROC_OW = 0x63, + BS_64_CROC_DIE = 0x64, BS_67_WALRUS_IDLE = 0x67, - BS_WALRUS_WALK = 0x68, - BS_WALRUS_JUMP = 0x69, + BS_68_WALRUS_WALK = 0x68, + BS_69_WALRUS_JUMP = 0x69, BS_6A_WALRUS_FALL = 0x6A, BS_6B_BEE_LOCKED = 0x6B, //[107] = "Locked", -- Bee, Mumbo Transform Cutscene - BS_WALRUS_OW = 0x6C, - BS_WALRUS_DIE = 0x6D, + BS_6C_WALRUS_OW = 0x6C, + BS_6D_WALRUS_DIE = 0x6D, BS_6E_CROC_BITE = 0x6E, - BS_CROC_EAT_BAD = 0x6F, + BS_6F_CROC_EAT_BAD = 0x6F, BS_70_CROC_EAT_GOOD = 0x70, BS_71_BTROT_FALL = 0x71, - BS_SPLAT = 0x72, // Getting up after fall damage + BS_72_SPLAT = 0x72, // Getting up after fall damage BS_73_UNKNOWN = 0x73, // locked_cutscene BS_74_UNKNOWN = 0x74, // locked jiggypad, xform, bottles BS_75_UNKNOWN = 0x75, // locked bottles @@ -2559,8 +2594,8 @@ enum bs_e { BS_77_SWIM_LOOKAT_DRONE = 0x77, BS_78_DIVE_LOOKAT_DRONE = 0x78, BS_79_BTROT_LOCKED = 0x79, - BS_WALK_MUD = 0x7A, - BS_BTROT_OW = 0x7B, + BS_7A_WALK_MUD = 0x7A, + BS_7B_BTROT_OW = 0x7B, BS_7C_SLED = 0x7C, BS_7D_WALRUS_SLED = 0x7D, BS_7E_WALRUS_SLED = 0x7E, @@ -2571,18 +2606,18 @@ enum bs_e { BS_85_BEE_IDLE = 0x85, - BS_BEE_WALK = 0x86, - BS_BEE_JUMP = 0x87, + BS_86_BEE_WALK = 0x86, + BS_87_BEE_JUMP = 0x87, BS_88_BEE_FALL = 0x88, - BS_BEE_OW = 0x89, - BS_BEE_DIE = 0x8A, - - BS_BEE_FLY = 0x8C, + BS_89_BEE_OW = 0x89, + BS_8A_BEE_DIE = 0x8A, + BS_8B_UNKNOWN = 0x8B, + BS_8C_BEE_FLY = 0x8C, BS_8D_CROC_LOCKED = 0x8D, BS_8E_ANT_LOCKED = 0x8E, // "Locked", -- Jiggy podium, Bottles' text outside Mumbo's BS_8F_PUMPKIN_LOCKED = 0x8F, - BS_FLY_OW = 0x91, + BS_91_FLY_OW = 0x91, BS_92_ANT_DRONE = 0x92, BS_93_PUMPKIN_DRONE = 0x93, BS_94_CROC_DRONE = 0x94, @@ -2596,11 +2631,11 @@ enum bs_e { BS_9C_WALRUS_SLED_DRONE = 0x9C, BS_9D_BEE_DRONE = 0x9D, BS_9E_CLIMB_LOCKED = 0x9E, - BS_ANT_BOUNCE = 0x9F, - BS_PUMPKIN_BOUNCE = 0xA0, - BS_CROC_BOUNCE = 0xA1, - BS_WALRUS_BOUNCE = 0xA2, - BS_BEE_BOUNCE = 0xA3, + BS_9F_ANT_BOUNCE = 0x9F, + BS_A0_ANT_BOUNCE = 0xA0, + BS_A1_CROC_BOUNCE = 0xA1, + BS_A2_WALRUS_BOUNCE = 0xA2, + BS_A3_BEE_BOUNCE = 0xA3, BS_A4_WONDERWING_DRONE = 0xA4, BS_A5_WONDERWING_UNKA5 = 0xA5 }; @@ -2650,18 +2685,24 @@ enum ttc_specific_flags { }; enum bgs_specific_flags { - BGS_SPECIFIC_FLAG_1 = 1, - BGS_SPECIFIC_FLAG_WALKWAY_JIGGY_RESET = 2, - BGS_SPECIFIC_FLAG_WALKWAY_JIGGY_TIMER_RUNNING = 3, - BGS_SPECIFIC_FLAG_WALKWAY_JIGGY = 4, - BGS_SPECIFIC_FLAG_WALKWAY_JIGGY_SWITCH_PRESSED = 5, - BGS_SPECIFIC_FLAG_7 = 7, - BGS_SPECIFIC_FLAG_8 = 8, - BGS_SPECIFIC_FLAG_MAZE_JIGGY_SWITCH_PRESSED = 9, - BGS_SPECIFIC_FLAG_A = 0xA, - BGS_SPECIFIC_FLAG_MAZE_JIGGY_RESET = 0xB, - BGS_SPECIFIC_FLAG_MAZE_JIGGY_TIMER_RUNNING = 0xC, - BGS_SPECIFIC_FLAG_MAZE_JIGGY = 0xD + BGS_SPECIFIC_FLAG_1 = 1, // WALKWAY_JIGGY + BGS_SPECIFIC_FLAG_2_WALKWAY_JIGGY_RESET, + BGS_SPECIFIC_FLAG_3_WALKWAY_JIGGY_TIMER_RUNNING, + BGS_SPECIFIC_FLAG_4_WALKWAY_JIGGY, + BGS_SPECIFIC_FLAG_5_WALKWAY_JIGGY_SWITCH_PRESSED, + BGS_SPECIFIC_FLAG_6_MR_VILE, + BGS_SPECIFIC_FLAG_7, // WALKWAY_JIGGY + BGS_SPECIFIC_FLAG_8, // WALKWAY_JIGGY + BGS_SPECIFIC_FLAG_9_MAZE_JIGGY_SWITCH_PRESSED, + BGS_SPECIFIC_FLAG_A, // MAZE_JIGGY + BGS_SPECIFIC_FLAG_B_MAZE_JIGGY_RESET, + BGS_SPECIFIC_FLAG_C_MAZE_JIGGY_TIMER_RUNNING, + BGS_SPECIFIC_FLAG_D_MAZE_JIGGY, + BGS_SPECIFIC_FLAG_E_UNUSED, + BGS_SPECIFIC_FLAG_F_UNUSED, + BGS_SPECIFIC_FLAG_10_FROG_MINIGAME_FIRST_MET, + BGS_SPECIFIC_FLAG_11_UNUSED, + BGS_SPECIFIC_FLAG_12_FROG_MINIGAME_BATTLE_ACTIVE }; enum fp_specific_flags { @@ -2694,6 +2735,38 @@ enum mmm_specific_flags { MMM_SPECIFIC_FLAG_7_UNKNOWN }; +enum rbb_main_specific_flags { + RBB_MAIN_SPECIFIC_FLAG_0_PROPELLER, + RBB_MAIN_SPECIFIC_FLAG_1_WHISTLE_SWITCH_1, + RBB_MAIN_SPECIFIC_FLAG_2_WHISTLE_SWITCH_2, + RBB_MAIN_SPECIFIC_FLAG_3_WHISTLE_SWITCH_3, + RBB_MAIN_SPECIFIC_FLAG_4_ANCHOR_LIFTING, + + RBB_MAIN_SPECIFIC_FLAG_8_UNK = 8 +}; + +enum rbb_boat_room_specific_flags { + RBB_BOAT_ROOM_SPECIFIC_FLAG_0_HONEYCOMB_SPAWNED +}; + +enum ccw_season_e +{ + CCW_SEASON_0_SPRING, + CCW_SEASON_1_SUMMER, + CCW_SEASON_2_AUTUMN, + CCW_SEASON_3_WINTER +}; + +enum ccw_zubba_specific_flags { + CCW_ZUBBA_SPECIFIC_FLAG_7_SPRING_DIALOG = 0x7, + CCW_ZUBBA_SPECIFIC_FLAG_8_AUTUMN_DIALOG +}; + +enum ccw_winter_specific_flags { + CCW_WINTER_SPECIFIC_FLAG_5_EEYRIE_ADULT = 0x5, + CCW_WINTER_SPECIFIC_FLAG_6_CUTSCENE_EEYRIE_ADULT +}; + enum lair_specific_flags { LAIR_SPECIFIC_FLAG_7_UKNOWN = 0x7, LAIR_SPECIFIC_FLAG_9_UKNOWN = 0x9 @@ -3042,17 +3115,19 @@ typedef enum asset_e ASSET_132_ANIM_FLOTSAM_MOVE = 0x132, ASSET_133_ANIM_NIPPER_DIE = 0x133, - ASSET_138_ANIM_ZOOMBOX = 0x138, - ASSET_139_ANIM_BOTTLES_EXIT = 0x139, - ASSET_13A_ANIM_BOTTLES_ENTER = 0x13A, - ASSET_13B_ANIM_BOTTLES_IDLE = 0x13B, - - ASSET_13E_ANIM_SNORKEL_SWIM = 0x13E, - ASSET_13F_ANIM_SNORKEL_STUCK = 0x13F, - - ASSET_141_ANIM_ANCHOR_LOWERED = 0x141, - ASSET_142_ANIM_ANCHOR_RISING = 0x142, - ASSET_143_ANIM_SNOWMAN_BUTTON = 0x143, + ASSET_137_ANIM_GRIMLET_ATTACK = 0x137, + ASSET_138_ANIM_ZOOMBOX, + ASSET_139_ANIM_BOTTLES_EXIT, + ASSET_13A_ANIM_BOTTLES_ENTER, + ASSET_13B_ANIM_BOTTLES_IDLE, + ASSET_13C_ANIM_MOLEHILL_UNKNOWN, + ASSET_13D_ANIM_MOLEHILL_UNKNOWN, + ASSET_13E_ANIM_SNORKEL_SWIM, + ASSET_13F_ANIM_SNORKEL_STUCK, + ASSET_140_ANIM_RAREWARE_FLAG, + ASSET_141_ANIM_ANCHOR_LOWERED, + ASSET_142_ANIM_ANCHOR_RISING, + ASSET_143_ANIM_SNOWMAN_BUTTON, ASSET_146_ANIM_BOSS_BOOMBOX_APPEAR = 0x146, ASSET_147_ANIM_BOOMBOX_MOVE = 0x147, @@ -3079,12 +3154,18 @@ typedef enum asset_e ASSET_166_ANIM_BURIED_TREASURE_BOUNCE = 0x166, ASSET_167_ANIM_BSREST_MOVE = 0x167, + ASSET_16A_ANIM_BELL_BUOY = 0x16A, + ASSET_16B_ANIM_SNAREBEAR_ATTACK = 0x16B, + ASSET_16C_ANIM_SNAREBEAR_IDLE = 0x16C, + ASSET_16E_ANIM_MUMBO_RECLINE = 0x16E, ASSET_16F_ANIM_ZUBBA_FLY_MOVE = 0x16F, ASSET_170_ANIM_ZUBBA_FLY_IDLE = 0x170, ASSET_171_ANIM_ZUBBA_DIE = 0x171, ASSET_172_ANIM_ZUBBA_LAND = 0x172, - + ASSET_173_ANIM_BEANSTALK_UNK = 0x173, + ASSET_174_ANIM_BEANSTALK_UNK = 0x174, + ASSET_175_ANIM_BEANSTALK_UNK = 0x175, ASSET_176_ANIM_GOBI_YAWN = 0x176, ASSET_177_ANIM_GOBI_SLEEP = 0x177, @@ -3093,7 +3174,9 @@ typedef enum asset_e ASSET_17E_ANIM_POLAR_BEAR_CUB_SAD = 0x17E, ASSET_17F_ANIM_MUMBO_SWEEP = 0x17F, ASSET_180_ANIM_MUMBO_ROTATE = 0x180, - + ASSET_181_ANIM_BEANSTALK_UNK = 0x181, + ASSET_182_ANIM_BEANSTALK_UNK = 0x182, + ASSET_183_ANIM_BEANSTALK_UNK = 0x183, ASSET_184_ANIM_CLUCKER_ATTACK_SHORT = 0x184, ASSET_185_ANIM_CLUCKER_ATTACK_LONG = 0x185, ASSET_186_ANIM_CLUCKER_DIE = 0x186, @@ -3102,17 +3185,25 @@ typedef enum asset_e ASSET_189_ANIM_FLOTSAM_DIE = 0x189, ASSET_18A_ANIM_XMAS_GIFT = 0x18A, + ASSET_18D_ANIM_CATERPILLAR_UNK = 0x18D, ASSET_18E_ANIM_CATERPILLAR_IDLE = 0x18E, + ASSET_199_ANIM_EEYRIE_ADULT_UNK = 0x199, + ASSET_19A_ANIM_EEYRIE_ADULT_UNK = 0x19A, ASSET_19B_ANIM_UNKNOWN = 0x19B, - + ASSET_19C_ANIM_BSWALRUS_BOUNCE = 0x19C, ASSET_19D_ANIM_BSWALRUS_DIE = 0x19D, ASSET_19E_ANIM_BSWALRUS_SLED = 0x19E, ASSET_19F_ANIM_BSWALRUS_SLED_JUMP = 0x19F, ASSET_1A1_ANIM_SLED = 0x1A1, ASSET_1A2_ANIM_NABNUT_SLEEP = 0x1A2, + ASSET_1A3_ANIM_NABNUT_SPRING_LOOKING_AROUND = 0x1A3, + ASSET_1A4_ANIM_NABNUT_SPRING_EATING = 0x1A4, + ASSET_1A6_ANIM_GNAWTY_IDLE = 0x1A6, + ASSET_1A7_ANIM_GNAWTY_CHEERING = 0x1A7, + ASSET_1A8_ANIM_GNAWTY_RUNNING = 0x1A8, ASSET_1A9_ANIM_BSWALRUS_LOSS = 0x1A9, ASSET_1AF_ANIM_TWINKLY_MUNCHER_APPEAR = 0x1AF, @@ -3156,6 +3247,10 @@ typedef enum asset_e ASSET_217_ANIM_UNKNOWN = 0x217, + ASSET_21C_ANIM_SNORE_Z = 0x21C, + ASSET_21D_ANIM_ADULT_EYRIE_UNK = 0x21D, + ASSET_21E_ANIM_ADULT_EYRIE_UNK = 0x21E, + ASSET_220_ANIM_SIR_SLUSH_DIE = 0x220, ASSET_221_ANIM_WOZZA_IN_CAVE = 0x221, @@ -3172,8 +3267,11 @@ typedef enum asset_e ASSET_22D_ANIM_NABNUT_BACKFLIP = 0x22D, ASSET_22E_ANIM_NABNUT_STAND = 0x22E, ASSET_22F_ANIM_NABNUT_RUN = 0x22F, + ASSET_230_ANIM_PINK_SQUIRREL_UNK = 0x230, + ASSET_231_ANIM_NABNUT_BEDSHEETS_UNK = 0x231, ASSET_233_ANIM_ICECUBE = 0x233, + ASSET_234_ANIM_DEAD_SNAREBEAR = 0x234, ASSET_236_ANIM_BSPUMPKIN_REBOUND = 0x236, @@ -3209,12 +3307,24 @@ typedef enum asset_e ASSET_288_ANIM_FLIBBIT_OW = 0x288, - ASSET_2A9_ANIM_BAT_FALL = 0x2A9, - ASSET_2AA_ANIM_BAT_DIE = 0x2AA, - ASSET_2AB_ANIM_TEEHEE_DIE = 0x2AB, + ASSET_2A1_ANIM_BOTTLES_BONUS_CURSOR_UNKNOWN = 0x2A1, + ASSET_2A2_ANIM_BOTTLES_BONUS_CURSOR_UNKNOWN, + ASSET_2A3_ANIM_BOTTLES_BONUS_CURSOR_UNKNOWN, + ASSET_2A4_ANIM_BOTTLES_BONUS_CURSOR_UNKNOWN, + ASSET_2A5_ANIM_BOTTLES_BONUS_CURSOR_UNKNOWN, + ASSET_2A6_ANIM_BOTTLES_BONUS_CURSOR_UNKNOWN, + ASSET_2A7_ANIM_BOTTLES_BONUS_CURSOR_UNKNOWN, + ASSET_2A8_ANIM_BOTTLES_BONUS_CURSOR_UNKNOWN, + ASSET_2A9_ANIM_BAT_FALL, + ASSET_2AA_ANIM_BAT_DIE, + ASSET_2AB_ANIM_TEEHEE_DIE, ASSET_2C0_ANIM_CHUMP_DIE = 0x2C0, + ASSET_2C6_ANIM_MUMBOS_HAND_WITH_PICTURE = 0x2C6, + ASSET_2C7_ANIM_MUMBOS_HAND_WITH_PICTURE, + ASSET_2C8_ANIM_MUMBOS_HAND_WITH_PICTURE, + // 2d1 Grey House Brick (Upon Smashing MM Huts) ASSET_2D2_MODEL_ORANGE = 0x2d2, //projectile // 2d3 MM Conga Tree @@ -3442,11 +3552,11 @@ typedef enum asset_e ASSET_3B0_SNACKER = 0x3B0, // 3b1 Concert Mumbo ASSET_3B2_MODEL_TWO_ICE_POLES_NEAR_CHEATO_3 = 0x3B2, - // 3b3 Mumbo's Hut - // Unused - // Unused - ASSET_3B6_MODEL_TTC_STAIRS_1 = 0x3B6, - ASSET_3B7_MODEL_TTC_STAIRS_1 = 0x3B7, + ASSET_3B3_MODEL_CCW_MUMBOS_HUT, + ASSET_3B4_MODEL_UNUSED, + ASSET_3B5_MODEL_UNUSED, + ASSET_3B6_MODEL_TTC_STAIRS_1, + ASSET_3B7_MODEL_TTC_STAIRS_2, // Unused // Unused // Unused @@ -3483,30 +3593,30 @@ typedef enum asset_e ASSET_3D9_MODEL_GV_KAZOOIE_DOOR = 0x3D9, // 3da GV Sun Door ASSET_3DB_MODEL_GV_STAR_HATCH = 0x3db, - ASSET_3DC_MODEL_MAGIC_CARPET = 0x3DC, - ASSET_3DD_MODEL_RUBEE = 0x3DD, - ASSET_3DE_MODEL_HISTUP = 0x3DE, - ASSET_3DF_MODEL_TRUNKER = 0x3DF, - ASSET_3E0_MODEL_GOBI = 0x3E0, - ASSET_3E1_MODEL_RUBEES_EGG_POT = 0x3E1, - ASSET_3E2_MODEL_GV_KAZOOIE_TARGET = 0x3E2, - ASSET_3E3_MODEL_GOBI_ROPE = 0x3E3, - ASSET_3E4_MODEL_GOBI_ROCK = 0x3E4, - ASSET_3E5_MODEL_GRABBA_SHADOW = 0x3E5, - // 3e6 GV Jinxy Head 2 - ASSET_3E7_MODEL_MAGIC_CARPET_SHADOW = 0x3e7, - ASSET_3E8_MODEL_ANCIENT_ONE = 0x3E8, - ASSET_3E9_MODEL_RED_ARROW = 0x3E9, - ASSET_3EA_MODEL_RED_X = 0x3EA, - ASSET_3EB_MODEL_RED_QUESTION_MARK = 0x3EB, - ASSET_3EC_MODEL_SHRAPNEL = 0x3EC, - ASSET_3ED_MODEL_BUZZBOMB = 0x3ED, - ASSET_3EE_TANKTUP = 0x3EE, - ASSET_3EF_MODEL_TANKTUP_LEG_FL = 0x3EF, - ASSET_3F0_MODEL_TANKTUP_LEG_BL = 0x3F0, - ASSET_3F1_MODEL_TANKTUP_LEG_FR = 0x3F1, - ASSET_3F2_MODEL_TANKTUP_LEG_BR = 0x3F2, - ASSET_3F3_MODEL_GOBI_SPIT = 0x3F3, + ASSET_3DC_MODEL_MAGIC_CARPET, + ASSET_3DD_MODEL_RUBEE, + ASSET_3DE_MODEL_HISTUP, + ASSET_3DF_MODEL_TRUNKER, + ASSET_3E0_MODEL_GOBI, + ASSET_3E1_MODEL_RUBEES_EGG_POT, + ASSET_3E2_MODEL_GV_KAZOOIE_TARGET, + ASSET_3E3_MODEL_GOBI_ROPE, + ASSET_3E4_MODEL_GOBI_ROCK, + ASSET_3E5_MODEL_GRABBA_SHADOW, + ASSET_3E6_JINXY_HEAD_KING_SANDYBUTT, + ASSET_3E7_MODEL_MAGIC_CARPET_SHADOW, + ASSET_3E8_MODEL_ANCIENT_ONE, + ASSET_3E9_MODEL_RED_ARROW, + ASSET_3EA_MODEL_RED_X, + ASSET_3EB_MODEL_RED_QUESTION_MARK, + ASSET_3EC_MODEL_SHRAPNEL, + ASSET_3ED_MODEL_BUZZBOMB, + ASSET_3EE_TANKTUP, + ASSET_3EF_MODEL_TANKTUP_LEG_FL, + ASSET_3F0_MODEL_TANKTUP_LEG_BL, + ASSET_3F1_MODEL_TANKTUP_LEG_FR, + ASSET_3F2_MODEL_TANKTUP_LEG_BR, + ASSET_3F3_MODEL_GOBI_SPIT, // Unused // 3f5 BGS Green Jiggy Switch ASSET_3F5_BGS_JIGGY_SWITCH = 0x3F5, @@ -3522,7 +3632,7 @@ typedef enum asset_e ASSET_3FF_MODEL_GV_SUN_DOOR = 0x3FF, ASSET_400_MODEL_SUN_SWITCH = 0x400, ASSET_401_MODEL_FLOTSAM = 0x401, - ASSET_402_MODEL_EGG_TOLL = 0x402, + ASSET_402_MODEL_EGG_TOLL = 0x402, // Floating Green Orb ASSET_403_MODEL_RUSTY_BUCKET_REAR_PROPELLER = 0x403, ASSET_404_MODEL_RBB_GREEN_PROPELLER_SWITCH = 0x404, ASSET_405_MODEL_RBB_GREY_PROPELLER_SWITCH = 0x405, @@ -3550,7 +3660,7 @@ typedef enum asset_e ASSET_41B_MODEL_ANCHOR_SWITCH = 0x41B, ASSET_41C_MODEL_SNORKEL = 0x41C, ASSET_41D_MODEL_ANCHOR = 0x41D, - // 41e RBB Rareware Flag + ASSET_41E_MODEL_RAREWARE_FLAG = 0x41E, // 41f (Gruntilda's Final Battle Forcefield?) // 420 (Explosion 2D?) ASSET_421_MODEL_FP_SNOWMAN_BUTTON = 0x421, @@ -3559,7 +3669,7 @@ typedef enum asset_e // 424 GV Cactus ASSET_425_MODEL_CROCTUS = 0x425, ASSET_426_MODEL_XMAS_TREE_STAR = 0x426, - // 427 (Wooden Plank) + ASSET_427_MODEL_WOODEN_PLANK = 0x427, ASSET_428_MODEL_BOSS_BOOM_BOX = 0x428, ASSET_429_MODEL_CC_KEY = 0x429, ASSET_42A_UNKNOWN = 0x42A, // 42a (Smoke 2D?) @@ -3580,15 +3690,15 @@ typedef enum asset_e ASSET_438_MODEL_HONEYCOMB_SWITCH = 0x438, // 439 (Unknown?) ASSET_43A_MODEL_CLANKER_SAWBLADE_PROPELLOR = 0x43A, - // 43b RBB Bell Buoy - // 43c RBB Row Boat + ASSET_43B_MODEL_BELL_BUOY, + ASSET_43C_MODEL_ROWBOAT, ASSET_43D_MODEL_MMM_CLOCK_SWITCH = 0x43D, ASSET_43E_MODEL_HEDGE_GATE_RIGHT_LOCK_2 = 0x43E, // 43f (White Star?) ASSET_440_MODEL_SNAREBEAR = 0x440, // 441 (Sir Slush Snowball?) ASSET_442_MODEL_TWINKLY_BOX = 0x442, - // 443 CCW Zubba Honey Lump + ASSET_443_MODEL_ZUBBA_HONEY_LUMP = 0x443, ASSET_444_MODEL_CCW_ZUBBA_DOOR = 0x444, ASSET_445_MODEL_CCW_ZUBBA_DOOR = 0x445, ASSET_446_MODEL_ZUBBA = 0x446, @@ -3619,9 +3729,9 @@ typedef enum asset_e // 45f (Firey Rock?) ASSET_460_MODEL_KAZOOIE_RACK_FEATHERS = 0x460, ASSET_461_MODEL_GREEN_FOG_OUTSIDE_TOWER, - // 462 Nabnut's Girlfriend - // 463 Nabnut's Bed Sheet - // 464 Nabnut's Bed + ASSET_462_MODEL_PINK_SQUIRREL = 0x462, + ASSET_463_MODEL_NABNUT_BEDSHEETS = 0x463, + ASSET_464_MODEL_NABNUT_BED = 0x464, // 465 Dead Snarebear // 466 (Sparkle 2D?) ASSET_467_MODEL_TRANSITION_FALLING_JIGGIES = 0x467, @@ -3636,12 +3746,12 @@ typedef enum asset_e ASSET_46F_MODEL_CUCKOO_CLOCK = 0x46F, // 470 Banjo's Bookshelves // 471 Empty Blow Picture Frame - // 472 Blank Picture - ASSET_473_MODEL_BBQ_MUMBO = 0x473, - ASSET_474_MODEL_BBQ_GRILL_AND_FISH = 0x474, - ASSET_475_SPRITE_GAME_OVER_HEART = 0x475, - ASSET_476_SPRITE_BLUE_GLOW = 0x476, - ASSET_477_SPRITE_YELLOW_GLOW = 0x477, + ASSET_472_UNKNOWN = 0x472, // Blank Picture? + ASSET_473_MODEL_BBQ_MUMBO, + ASSET_474_MODEL_BBQ_GRILL_AND_FISH, + ASSET_475_SPRITE_GAME_OVER_HEART, + ASSET_476_SPRITE_BLUE_GLOW, + ASSET_477_SPRITE_YELLOW_GLOW, // 478 (Yellow Glow?) ASSET_479_MODEL_BIKINI_GIRL = 0x479, // 47a (Brown Ball?) @@ -3663,7 +3773,7 @@ typedef enum asset_e ASSET_48A_MODEL_FLIGHT_PAD = 0x48A, ASSET_48B_MODEL_JIGGY_PODIUM = 0x48B, ASSET_48C_MODEL_BOOM_BOX = 0x48C, - // 48d Nabnut Eating Acorns + ASSET_48D_MODEL_NABNUT_EATING_ACORNS = 0x48D, ASSET_48E_MODEL_ACORN = 0x48E, ASSET_48F_MODEL_GNAWTY = 0x48F, ASSET_490_MODEL_GNAWTY_BOULDER = 0x490, @@ -3781,12 +3891,12 @@ typedef enum asset_e ASSET_4FE_MODEL_WHIPCRACK_PART_1 = 0x4FE, ASSET_4FF_MODEL_WHIPCRACK_PART_2 = 0x4FF, ASSET_500_MODEL_WHIPCRACK_PART_3 = 0x500, - // 501 CCW Mound Of Acorns + ASSET_501_MODEL_MOUND_OF_ACORNS = 0x501, ASSET_502_MODEL_NABNUT = 0x502, - // 503 Nabnut (Belly Full) + ASSET_503_MODEL_NABNUT_BELLY_FULL = 0x503, ASSET_504_MODEL_ICECUBE = 0x504, ASSET_505_MODEL_ICECUBE_CHUNK = 0x505, - // 506 CCW Dead Snarebear (Venus Flytrap) + ASSET_506_CCW_DEAD_SNAREBEAR = 0x506, ASSET_507_MODEL_GL_GRUNTY_FLOOR_PICTURE_EYE_1 = 0x507, ASSET_508_MODEL_GL_GRUNTY_FLOOR_PICTURE_EYE_2 = 0x508, ASSET_509_MODEL_GL_SARCOPHAGUS = 0x509, @@ -3809,28 +3919,28 @@ typedef enum asset_e ASSET_51C_MODEL_SCARAB_BEETLE_PART_1 = 0x51C, // 51d SCARAB BEETLE PART (Wing) ASSET_51E_MODEL_SCARAB_BEETLE_PART_2 = 0x51e, - ASSET_51F_MODEL_SCARAB_BEETLE_PART_3 = 0x51F, - ASSET_520_MODEL_SCARAB_BEETLE_PART_4 = 0x520, - ASSET_521_MODEL_PORTRAIT_CHOMPA = 0x521, - ASSET_522_MODEL_PORTRAIT_OF_GRUNTY = 0x522, - ASSET_523_MODEL_PORTRAIT_CHOMPA_TEETH = 0x523, - ASSET_524_MODEL_PORTRAIT_CHOMPA_HEAD = 0x524, - ASSET_525_MODEL_PORTRAIT_CHOMPA_PART = 0x525, - ASSET_526_SPRITE_FIRE = 0x526, - ASSET_527_MODEL_PORTRAIT_OF_BLACKEYE = 0x527, - ASSET_528_MODEL_PORTRAIT_OF_TOWER = 0x528, - ASSET_529_MODEL_PORTRAIT_OF_TREE_AND_MOON = 0x529, - ASSET_52A_MODEL_PORTRAIT_OF_TEEHEE = 0x52A, - ASSET_52B_MODEL_PORTRAIT_OF_MINION = 0x52B, - ASSET_52C_MODEL_GRUBLIN_HOOD = 0x52C, - ASSET_52D_MODEL_GRUBLIN_HOOD_HAT = 0x52D, - ASSET_52E_MODEL_CCW_SEASON_DOOR = 0x52E, - ASSET_52F_MODEL_BANJOS_CHAIR = 0x52F, - ASSET_530_MODEL_BANJOS_BED = 0x530, - // 531 Gnawty's Den - ASSET_532_MODEL_BANJO_KAZOOIE_CUTSCENES = 0x532, // (Gameboy/Beer/Sunglasses/Chair) - // 533 CCW Nabnut's Door - ASSET_534_MODEL_FLIGHT_PAD_SWITCH = 0x534, + ASSET_51F_MODEL_SCARAB_BEETLE_PART_3, + ASSET_520_MODEL_SCARAB_BEETLE_PART_4, + ASSET_521_MODEL_PORTRAIT_CHOMPA, + ASSET_522_MODEL_PORTRAIT_OF_GRUNTY, + ASSET_523_MODEL_PORTRAIT_CHOMPA_TEETH, + ASSET_524_MODEL_PORTRAIT_CHOMPA_HEAD, + ASSET_525_MODEL_PORTRAIT_CHOMPA_PART, + ASSET_526_SPRITE_FIRE, + ASSET_527_MODEL_PORTRAIT_OF_BLACKEYE, + ASSET_528_MODEL_PORTRAIT_OF_TOWER, + ASSET_529_MODEL_PORTRAIT_OF_TREE_AND_MOON, + ASSET_52A_MODEL_PORTRAIT_OF_TEEHEE, + ASSET_52B_MODEL_PORTRAIT_OF_MINION, + ASSET_52C_MODEL_GRUBLIN_HOOD, + ASSET_52D_MODEL_GRUBLIN_HOOD_HAT, + ASSET_52E_MODEL_CCW_SEASON_DOOR, + ASSET_52F_MODEL_BANJOS_CHAIR, + ASSET_530_MODEL_BANJOS_BED, + ASSET_531_MODEL_GNAWTYS_DEN, + ASSET_532_MODEL_BANJO_KAZOOIE_CUTSCENES, // (Gameboy/Beer/Sunglasses/Chair) + ASSET_533_MODEL_NABNUT_DOOR, + ASSET_534_MODEL_FLIGHT_PAD_SWITCH, // 535 Flight Pad Blue Fragment // 536 Flight Pad Red Fragment // 537 Flight Pad Yellow Fragment @@ -3855,40 +3965,40 @@ typedef enum asset_e ASSET_54A_MODEL_GRUNTLING_RED = 0x54A, // 54b (Big Fireball?) ASSET_54C_MODEL_GAME_OVER = 0x54C, - ASSET_54D_MODEL_BANJO_KAZOOIE_SIGN = 0x54D, - ASSET_54E_MODEL_COPYRIGHT_OVERLAY = 0x54E, - ASSET_54F_MODEL_CHEATO = 0x54F, - ASSET_550_MODEL_LARGE_DOOR_TO_FINAL_BATTLE = 0x550, - ASSET_551_MODEL_JINJONATOR = 0x551, - ASSET_552_MODEL_BROOMSTICK_PIECE_HEAD = 0x552, - ASSET_553_MODEL_BROOMSTICK_PIECE_SHORT = 0x553, - ASSET_554_MODEL_BROOMSTICK_PIECE_LONG = 0x554, - ASSET_555_MODEL_BROOMSTICK_PIECE_EYE = 0x555, - ASSET_556_MODEL_YELLOW_JINJO_BLAST = 0x556, - ASSET_557_MODEL_ORANGE_JINJO_BLAST = 0x557, - ASSET_558_MODEL_GREEN_JINJO_BLAST = 0x558, - ASSET_559_MODEL_PINK_JINJO_BLAST = 0x559, - ASSET_55A_MODEL_WORLD_EXIT_PAD = 0x55A, - ASSET_55B_MODEL_BOGGY_IGLOO = 0x55B, - ASSET_55C_MODEL_PRESS_START_OVERLAY = 0x55C, - ASSET_55D_MODEL_NO_CONTROLLER_OVERLAY = 0x55D, - ASSET_55E_MODEL_NAPPER = 0x55E, - ASSET_55F_MODEL_FF_PRIZE_WASHING_CAULDRON = 0x55F, - ASSET_560_MODEL_FF_PRIZE_GRUNTY_DOLL = 0x560, - ASSET_561_MODEL_GRUNTLING_BLUE = 0x561, - ASSET_562_MODEL_GRUNTLING_BLACK = 0x562, - ASSET_563_MODEL_LEVEL_ENTRY_SIGNS = 0x563, - ASSET_564_MODEL_PURPLE_TEEHEE = 0x564, - ASSET_565_MODEL_BOTTLES_BONUS_BANJO_HAND = 0x565, - ASSET_566_MODEL_BLACK_SNIPPET = 0x566, - ASSET_567_MODEL_BLACK_CRAB_HEAD = 0x567, - ASSET_568_MODEL_BLACK_CRAB_LEG = 0x568, - ASSET_569_MODEL_BLACK_CRAB_CLAW = 0x569, - ASSET_56A_MODEL_FP_HOUSE_CHIMNEY = 0x56A, - ASSET_56B_MODEL_SANDYBUTT_PYRAMID = 0x56B, - ASSET_56C_MODEL_THE_END_SIGN = 0x56C, - ASSET_56D_MUMBOS_HAND_WITH_PICTURE = 0x56D, // Mumbo's Hand with SNS pictures - // 56E Hammerhead Beach Scenery + ASSET_54D_MODEL_BANJO_KAZOOIE_SIGN, + ASSET_54E_MODEL_COPYRIGHT_OVERLAY, + ASSET_54F_MODEL_CHEATO, + ASSET_550_MODEL_LARGE_DOOR_TO_FINAL_BATTLE, + ASSET_551_MODEL_JINJONATOR, + ASSET_552_MODEL_BROOMSTICK_PIECE_HEAD, + ASSET_553_MODEL_BROOMSTICK_PIECE_SHORT, + ASSET_554_MODEL_BROOMSTICK_PIECE_LONG, + ASSET_555_MODEL_BROOMSTICK_PIECE_EYE, + ASSET_556_MODEL_YELLOW_JINJO_BLAST, + ASSET_557_MODEL_ORANGE_JINJO_BLAST, + ASSET_558_MODEL_GREEN_JINJO_BLAST, + ASSET_559_MODEL_PINK_JINJO_BLAST, + ASSET_55A_MODEL_WORLD_EXIT_PAD, + ASSET_55B_MODEL_BOGGY_IGLOO, + ASSET_55C_MODEL_PRESS_START_OVERLAY, + ASSET_55D_MODEL_NO_CONTROLLER_OVERLAY, + ASSET_55E_MODEL_NAPPER, + ASSET_55F_MODEL_FF_PRIZE_WASHING_CAULDRON, + ASSET_560_MODEL_FF_PRIZE_GRUNTY_DOLL, + ASSET_561_MODEL_GRUNTLING_BLUE, + ASSET_562_MODEL_GRUNTLING_BLACK, + ASSET_563_MODEL_LEVEL_ENTRY_SIGNS, + ASSET_564_MODEL_PURPLE_TEEHEE, + ASSET_565_MODEL_BOTTLES_BONUS_BANJO_HAND, + ASSET_566_MODEL_BLACK_SNIPPET, + ASSET_567_MODEL_BLACK_CRAB_HEAD, + ASSET_568_MODEL_BLACK_CRAB_LEG, + ASSET_569_MODEL_BLACK_CRAB_CLAW, + ASSET_56A_MODEL_FP_HOUSE_CHIMNEY, + ASSET_56B_MODEL_SANDYBUTT_PYRAMID, + ASSET_56C_MODEL_THE_END_SIGN, + ASSET_56D_MUMBOS_HAND_WITH_PICTURE, // Mumbo's Hand with SNS pictures + ASSET_56E_HAMMERHEAD_BEACH_SCENERY, // Credits map // 56F Unused // 570 Unused // Unused @@ -4730,7 +4840,7 @@ typedef enum asset_e ASSET_DA6_DIALOG_BEEHIVE_WITH_BEES = 0xDA6, ASSET_DA7_DIALOG_MUMBO_CCW_SUMMER = 0xDA7, ASSET_DA8_DIALOG_MUMBO_CCW_AUTUMN = 0xDA8, - + ASSET_DA9_DIALOG_MUMBO_CCW_VACATION = 0xDA9, ASSET_DAA_DIALOG_MUMBO_HAS_ENOUGH_TOKENS = 0xDAA, ASSET_DAB_DIALOG_MUMBO_NOT_ENOUGH_TOKENS = 0xDAB, ASSET_DAC_DIALOG_MUMBO_FAIL_TO_BUY = 0xDAC, @@ -4809,14 +4919,20 @@ typedef enum asset_e ASSET_F5D_DIALOG_MUMBO_MAGIC_RUN_OUT_FULL = 0xF5D, ASSET_F5E_DIALOG_MUMBO_MAGIC_RUN_OUT_ABREV = 0xF5E, - ASSET_F64_DIALOG_NOTEDOORS_LEARN = 0xf64, - ASSET_F65_DIALOG_NOTEDOORS_REFRESHER = 0xF65, - ASSET_F66_DIALOG_UNKNOWN = 0xF66, - ASSET_F67_DIALOG_UNKNOWN = 0xF67, + ASSET_F64_DIALOG_NOTEDOORS_LEARN = 0xF64, + ASSET_F65_DIALOG_NOTEDOORS_REFRESHER, + ASSET_F66_DIALOG_UNKNOWN, + ASSET_F67_DIALOG_UNKNOWN, + ASSET_F68_DIALOG_MM_THREE_NEW_MOVES_TO_LEARN, + + ASSET_F6E_DIALOG_DIDNT_LEARN_ALL_MOVES_FROM_MM = 0xF6E, - ASSET_F79_DIALOG_UNKNOWN = 0xf79, - ASSET_F7A_DIALOG_UNKNOWN = 0xF7A, - ASSET_F7B_DIALOG_BOTTLES_JIGSAW_PICTURE_MEET = 0xF7B, + ASSET_F79_DIALOG_UNKNOWN = 0xF79, + ASSET_F7A_DIALOG_UNKNOWN, + ASSET_F7B_DIALOG_BOTTLES_JIGSAW_PICTURE_MEET, + + ASSET_F7F_DIALOG_BOTTLES_MM_ENTRANCE_BEFORE_OPENING_BEFORE_PODIUM = 0xF7F, + ASSET_F80_DIALOG_BOTTLES_MM_ENTRANCE_BEFORE_OPENING_AFTER_PODIUM, ASSET_FA8_EGG_CHEAT_ACTIVATION = 0xFA8, ASSET_FA9_RED_FEATHER_CHEAT_ACTIVATION = 0xFA9, @@ -5285,6 +5401,7 @@ typedef enum asset_e ASSET_1514_MODEL_GL_FF_ENTRANCE_XLU = 0x1514, ASSET_1515_MODEL_GL_BATTLEMENTS_XLU, + // [port] JP-exclusive sprites for world name banners SPRITE_WORLD_NAME_TOTAL = 0x1600, SPRITE_WORLD_NAME_SPIRAL_MOUNTAIN, SPRITE_WORLD_NAME_GRUNTILDAS_LAIR, @@ -5335,8 +5452,8 @@ enum marker_e{ MARKER_13_SNIPPET = 0x13, MARKER_14_SNACKER, MARKER_15_CLAM, - - MARKER_17_CONCERT_BANJO = 0x17, + MARKER_16_UNKNOWN, // src/core2/code_4BE10.c + MARKER_17_CONCERT_BANJO, MARKER_1B_CONCERT_TOOTY = 0x1B, MARKER_1C_INTRO_N64_CUBE, @@ -5359,8 +5476,8 @@ enum marker_e{ MARKER_32_PLAYER_SHADOW, MARKER_33_LEAKY, MARKER_34_CEMETARY_POT, - - MARKER_36_ORANGE_COLLECTIBLE = 0x36, + MARKER_35_CLIMB_BASE, + MARKER_36_ORANGE_COLLECTIBLE, MARKER_37_GOLD_BULLION, MARKER_38_TURBO_TALON_TRAINERS, MARKER_39_MUMBO_TOKEN, @@ -5384,8 +5501,8 @@ enum marker_e{ MARKER_53_EMPTY_HONEYCOMB, MARKER_55_HONEYCOMB = 0x55, - - MARKER_57_STEAM = 0x57, + MARKER_56_UNKNOWN, + MARKER_57_STEAM, MARKER_58_WADING_BOOTS_TOUCH_SPARKLE, MARKER_59_TURBO_TRAINERS_TOUCH_SPARKLE, MARKER_5A_JINJO_BLUE, @@ -5430,8 +5547,8 @@ enum marker_e{ MARKER_99_TEEHEE = 0x99, MARKER_9A_1881_BARREL_TOP, - - MARKER_9C_SHACK_DOOR = 0x9C, + MARKER_9B_MODEL_PLAYER_SHADOW, + MARKER_9C_SHACK_DOOR, MARKER_9D_MANSION_DOOR, MARKER_9E_CELLAR_HATCH, MARKER_9F_CHURCH_GATE_LEFT_LOCK, @@ -5462,7 +5579,7 @@ enum marker_e{ MARKER_B8_MOLEHILL, MARKER_B9_FP_SNOWMAN_BUTTON, MARKER_BA_XMAS_TREE, - MARKER_BB_UNKNOWN, + MARKER_BB_JINXY_HEAD_SANDYBUTT, MARKER_BC_GOBI_1, MARKER_BD_GOBI_ROPE, MARKER_BE_GOBI_ROCK, @@ -5593,7 +5710,7 @@ enum marker_e{ MARKER_167_SHARKFOOD_ISLAND, MARKER_168_ICE_KEY, MARKER_169_SNS_EGG, - // 0x16A src/core2/code_4C020.c + MARKER_16A_FF_TELEPORT_PAD, // src/core2/code_4C020.c MARKER_16B_SNIPPET_UPSIDEDOWN = 0x16B, MARKER_16C_NIPPER, MARKER_16D_CHEATO_1, @@ -5610,13 +5727,13 @@ enum marker_e{ MARKER_178_NO_CONTROLLER_OVERLAY, MARKER_179_JIGSAW_PUZZLE, MARKER_17A_BOTTLES_BONUS_BANJO_HAND, - - MARKER_17C_MODEL_THE_END_SIGN = 0x17C, + MARKER_17B_UNKNOWN, + MARKER_17C_MODEL_THE_END_SIGN, MARKER_17D_IRON_GATE_NO_LOCK, MARKER_182_RBB_EGG_TOLL = 0x182, - MARKER_183_RBB_EGG_TOLL, - MARKER_184_RBB_EGG_TOLL, + MARKER_183_RBB_CAGE_UP_SWITCH, + MARKER_184_RBB_TNT_DOWN_SWITCH, MARKER_185_RBB_REAR_PROPELLER, MARKER_186_RBB_GREEN_PROPELLER_SWITCH, MARKER_187_RBB_SPINNING_SINGLE_PIPE_1, @@ -5636,6 +5753,7 @@ enum marker_e{ MARKER_195_WHISTLE_SWITCH_1, MARKER_196_WHISTLE_SWITCH_2, MARKER_197_WHISTLE_SWITCH_3, + MARKER_198_RAREWARE_FLAG, MARKER_19A_TIPTUP = 0x19A, MARKER_19B_CHOIR_TURTLE_YELLOW, @@ -5653,33 +5771,49 @@ enum marker_e{ MARKER_1A7_CLANKER_WHIPCRACK, MARKER_1A9_CC_BREAKABLE_GRATES = 0x1A9, - - MARKER_1AC_ZUBBA_DOOR = 0x1AC, - + MARKER_1AA_BELL_BUOY, + MARKER_1AB_ROWBOAT, + MARKER_1AC_ZUBBA_DOOR, + MARKER_1AD_ZUBBA_HONEY_LUMP, MARKER_1AE_ZUBBA = 0x1AE, - + MARKER_1AF_ZUBBA_DOCILE, MARKER_1B0_CCW_BEANSTALK = 0x1B0, MARKER_1B1_CCW_GOBI, MARKER_1B2_CLUCKER_A, MARKER_1B3_EAGLE_EGG, MARKER_1B4_EEYRIE_BABY, MARKER_1B5_CATERPILLAR, - + MARKER_1B6_EEYRIE_ADULT, MARKER_1B7_BOOM_BOX = 0x1B7, - + MARKER_1B8_BOOM_BOX_MINIGAME_CTRL = 0x1B8, + MARKER_1B9_NABNUT_SPRING = 0x1B9, + MARKER_1BA_NABNUT_FULL_BELLY, MARKER_1BB_NABNUT = 0x1BB, - + MARKER_1BC_CARRIED_ACORN, + MARKER_1BD_GNAWTY_SWIMMING, + MARKER_1BE_GNAWTY_SUMMER, MARKER_1BF_GNAWTY_BOULDER = 0x1BF, + MARKER_1C0_BOSS_BOOMBOX_CTRL = 0x1C0, + MARKER_1C2_DEAD_BEANSTALK = 0x1C2, + MARKER_1C3_SNORE_Z, + MARKER_1C4_CUTSCENE_ADULT_EYRIE, MARKER_1C5_WHIPCRACK = 0x1C5, - + MARKER_1C6_MOUND_OF_ACORNS, + MARKER_1C7_PINK_SQUIRREL, + MARKER_1C8_NABNUT_BEDSHEETS, + MARKER_1C9_NABNUT_BED, + MARKER_1CA_NABNUT, + MARKER_1CB_NABNUT_EATING_ACORNS, + MARKER_1CC_CCW_UNKNOWN, MARKER_1CD_GV_MAZE_CTRL = 0x1CD, - + MARKER_1CE_INDOOR_GNAWTY, MARKER_1CF_GRILLE_CHOMPA_ATTACKING = 0x1CF, MARKER_1D0_CLUCKER_B, MARKER_1D1_PORTRAIT_CHOMPA_B, - - MARKER_1D4_SANDYBUTT_PYRAMID = 0x1D4, + MARKER_1D2_SPINNING_SINGLE_PIPE_SFX_CTRL, + MARKER_1D3_DOUBLE_SINGLE_PIPE_SFX_CTRL, + MARKER_1D4_SANDYBUTT_PYRAMID, MARKER_1D5_PALM_TREE, MARKER_1E0_BRENTILDA = 0x1E0, @@ -5702,6 +5836,7 @@ enum marker_e{ MARKER_1F2_WIDE_WINDOW, MARKER_1F3_TALL_WINDOW, MARKER_1F4_TOOTS, + MARKER_1F5_UNKNOWN, MARKER_1F9_SNARE_BEAR = 0x1F9, MARKER_1FA_POLAR_BEAR_CUB_BLUE, @@ -5731,6 +5866,9 @@ enum marker_e{ MARKER_218_LIMBO, MARKER_219_MUMMUM, MARKER_21A_SEAMAN_GRUBLIN, + MARKER_21B_UNKNOWN, + + MARKER_21E_CCW_MUMBOS_HUT = 0x21E, MARKER_224_BREAKABLE_FLOOR_COBWEB = 0x224, MARKER_225_BREAKABLE_WALL_COBWEB, @@ -5762,12 +5900,12 @@ enum marker_e{ MARKER_240_LAIR_SWITCH_FLIGHT_PAD, MARKER_241_SHOCK_JUMP_PAD_SWITCH, MARKER_242_LAIR_SWITCH_SHOCK_JUMP_PAD, - + MARKER_243_NABNUT_DOOR, MARKER_244_DINGPOT = 0x244, MARKER_245_XMAS_TREE_EGG_TOLL = 0x245, MARKER_250_ICECUBE_A = 0x250, - + MARKER_251_DEAD_SNAREBEAR, MARKER_252_LOGGO = 0x252, MARKER_253_SCARAB_BEETLE, MARKER_254_PORTRAIT_CHOMPA_A, @@ -5793,11 +5931,12 @@ enum marker_e{ MARKER_268_STAIRS_1, MARKER_269_STAIRS_2, MARKER_26A_LIGHTHOUSE_B, - - // 0x26E src/core2/code_4C020.c - // 0x26F src/core2/code_4C020.c - - MARKER_270_TWO_ICE_POLES_NEAR_CHEATO_3 = 0x270, + MARKER_26B_GNAWTYS_DEN, + MARKER_26C_GNAWTYS_BED, + MARKER_26D_GNAWTYS_SHELVES, + MARKER_26E_UNKNOWN, // src/core2/code_4C020.c + MARKER_26F_UNKNOWN, // src/core2/code_4C020.c + MARKER_270_TWO_ICE_POLES_NEAR_CHEATO_3, MARKER_276_STONE_JINJO = 0x276, @@ -5817,7 +5956,8 @@ enum marker_e{ MARKER_288_GRUNTY_SHADOW = 0x288, - MARKER_295_GRUNTLING_BLUE = 0x295, + MARKER_294_MUMBOS_HAND_WITH_PICTURE = 0x294, + MARKER_295_GRUNTLING_BLUE, MARKER_296_TEEHEE_PURPLE, MARKER_297_GIANT_GRAVESTONE, MARKER_298_MUMMUM_BALL, diff --git a/include/functions.h b/include/functions.h index d184fa8c6..1112a3c6c 100644 --- a/include/functions.h +++ b/include/functions.h @@ -29,9 +29,15 @@ extern "C" { #include "core2/staticcamera.h" #include "core2/anim/sprite.h" #include "core2/ba/anim.h" +#include "core2/ba/carry.h" +#include "core2/ba/drone.h" +#include "core2/lighting.h" +#include "core2/particle.h" #include "core2/ba/model.h" +#include "core2/ba/physics.h" #include "core2/ba/timer.h" #include "core2/nc/camera.h" +#include "core2/yaw.h" #include "bk_time.h" #include "bs_funcs.h" @@ -61,13 +67,14 @@ extern f32 fabsf(f32); f32 cosf(f32); -// --- core2/prop_assetcache.c --- +// --- core2/propModelList.c --- BKModelBin *propModelList_getModelIfActive(s32 arg0); BKSpriteDisplayData *propModelList_getSpriteDisplayList(s32 arg0); BKSprite *propModelList_getSprite(s32 arg0); BKModelBin *propModelList_getModel(s32); // --- core2/actor_cubepropsystem.c --- +BKModelBin *marker_loadModelBin(ActorMarker *marker); ActorMarker *func_8032DCAC(void); BKVertexList *func_80330CFC(Actor *self, s32 arg1); BKModelBin *func_80330E28(Actor *self); @@ -88,7 +95,7 @@ void marker_setActorUpdateFunc(ActorMarker *marker, ActorUpdateFunc method); void marker_setCollisionScripts(ActorMarker *marker, MarkerCollisionFunc ow_func, MarkerCollisionFunc arg2, MarkerCollisionFunc die_func); void marker_setFreeMethod(ActorMarker *, void (*)(Actor *)); -// --- core2/actor_cubebounds.c --- +// --- core2/gccube.c --- NodeProp *cubeList_findNodePropByActorIdAndPosition_s32(enum actor_e actor_id, s32 position[3]); NodeProp *func_80305510(s32 arg0); BKCollisionTriangle *func_80303800(f32 volume_p1[3], f32 volume_p2[3], f32 arg2[3], u32 arg3); @@ -108,10 +115,7 @@ u8 GetCurrentMap(); s32 getGameMode(void); void transitionToMap(enum map_e map, s32 exit, s32 transition); -// --- core2/time.c --- -f32 time_getDelta(void); - -// --- core2/map_list.c --- +// --- core2/map/list.c --- BKCollisionTriangle *func_8029463C(void); BKModelBin *func_802946A8(void); BKCollisionTriangle *func_802946CC(void); @@ -124,7 +128,7 @@ BKCollisionTriangle *func_8031C5F4(struct0 *self); BKModelBin *func_8031C5DC(struct0 *self); struct0 *func_8031B9D8(void); -// --- core2/collision/funcs.c --- +// --- core2/collision/dispatch.c --- BKCollisionTriangle *func_80320B98(f32 arg0[3], f32 arg1[3], f32 arg2[3], u32 arg3); // func_80320C94, func_80320DB0 return BKCollisionTriangle* but // have conflicting local externs (bool/s32/int) in decomp source files. @@ -195,12 +199,6 @@ struct56s *func_80343F00(s32 indx, f32 arg1[3]); Struct83s *func_803406B0(void); Struct83s *func_803406D4(Struct83s *self); -// --- core2/vtx/list.c --- - -// --- core2/spline_bezier.c --- - -// --- core2/model/render.c --- - // --- core2/vtx/colorapply.c --- Struct70s *func_8034C344(s32 arg0); Struct70s *func_8034C448(s32 arg0); @@ -244,8 +242,8 @@ BoneTransformList *anim_getStartTransform(Animation *self); BoneTransformList *anim_getTargetTransform(Animation *self); // --- core1/audio_manager.c --- -void *func_802403B8(void *state); -void *audioManager_getThread_PAL(void); +ALDMAproc audioManager_DMAInitProc(void *state); +OSThread *audioManager_getThread_PAL(void); // --- core2/anim/anim_sequencehandler.c --- u8 *func_8032479C(void); @@ -264,20 +262,12 @@ f32 babuzz_80290890(f32 arg0); f32 babuzz_80290920(f32 arg0, f32 arg1, f32 arg2); f32 baeyes_getEyePosition(s32 id); f32 baanim_getTimer(void); -f32 batimer_get(s32 id); f32 bafalldamage_get_distance_fallen(void); f32 bastick_calculateZonePosition(f32 arg0, f32 arg1, f32 arg2); f32 bastick_getX(void); f32 bastick_getAngle(void); f32 baModel_getYaw(void); -f32 baphysics_get_gravity(void); -f32 baphysics_get_target_horizontal_velocity(void); -f32 baphysics_get_target_vertical_velocity(void); -f32 baphysics_get_target_yaw(void); -f32 baphysics_get_vertical_velocity(void); -f32 baphysics_get_horizontal_velocity(void); -f32 baphysics_get_horizontal_velocity_percentage(void); -f32 climbGetRadius(void); +f32 climb_getRadius(void); f32 func_8029B3B0(f32 arg0); f32 func_8029B56C(f32 arg0, f32 arg1, f32 arg2, f32 arg3); f32 func_8029B9C0(void); @@ -304,7 +294,7 @@ f32 player_getYaw(void); // Only functions that return pointers or have no conflicting local externs. NodeProp *cube_findNodePropByActorId(Cube *cube, enum actor_e actor_id); -// --- core2/camera/cameranodelist.c --- +// --- core2/nc/cameranodelist.c --- PivotCameraNode *ncCameraNodeList_getPivotCameraNode(int camera_node_index); StaticCameraNode *ncCameraNodeList_getStaticCameraNode(int camera_node_index); ZoomCameraNode *ncCameraNodeList_getZoomCameraNode(int camera_node_index); @@ -312,23 +302,23 @@ RandomCameraNode *ncCameraNodeList_getRandomCameraNode(int camera_node_index); // MISC POINTER-RETURNING + OS + GBI PROTOTYPES -s16 *func_8030C704(void); +s16 *picturebox_getColorBuffer(void); // COMMONLY MISSING PROTOTYPES -// --- core2/fx/score_jiggy.c --- +// --- core2/jiggyscore.c --- u32 jiggyscore_isCollected(enum jiggy_e jiggy_id); int jiggyscore_isSpawned(enum jiggy_e jiggy_id); -// --- core2/fx/score_honeycomb.c --- +// --- core2/honeycombscore.c --- bool honeycombscore_get(enum honeycomb_e indx); -// --- core2/map/specificflags.c --- +// --- core2/map/mapspecificflags.c --- s32 mapSpecificFlags_get(s32 i); void mapSpecificFlags_set(s32, s32); void mapSpecificFlags_setEx(s32 i, s32 val, s32 triggerEvent); -// --- core2/level/specificflags.c --- +// --- core2/level/levelspecificflags.c --- s32 levelSpecificFlags_get(s32 i); void levelSpecificFlags_set(s32, s32); void levelSpecificFlags_setEx(s32 index, s32 val, s32 triggerEvent); @@ -338,7 +328,7 @@ void levelSpecificFlags_getSizeAndPtr(s32 *size, u8 **addr); s32 getGameMode(void); void transitionToMap(enum map_e map, s32 exit, s32 transition); -// --- core2/gamestate.c (item system) --- +// --- core2/gamestate.c --- s32 item_empty(enum item_e item); void item_set(s32 item, s32 val); void item_setEx(s32 item, s32 val, s32 triggerEvent); @@ -365,6 +355,8 @@ enum AnchorCollectibleSpace { ANCHOR_COLLECTIBLE_GOLD = 10, ANCHOR_COLLECTIBLE_ORANGE = 11, }; + +// --- core2/flags_bitfield.c --- bool fileProgressFlag_get(enum file_progress_e index); s32 fileProgressFlag_getN(enum file_progress_e offset, s32 numBits); s32 volatileFlag_get(enum volatile_flags_e index); @@ -376,8 +368,8 @@ void volatileFlag_setN(enum volatile_flags_e startIndex, s32 set, s32 length); void fileProgressFlag_setEx(enum file_progress_e index, s32 set, s32 triggerEvent); void volatileFlag_setEx(enum volatile_flags_e index, s32 set, s32 triggerEvent); -// --- core2/dialog/progress_dialogs.c --- -void volatileFlag_setAndTriggerDialog_0(enum volatile_flags_e arg0); +// --- core2/dialog/progressDialog.c --- +void progressDialog_setAndTriggerDialog_0(enum volatile_flags_e arg0); // --- core1/init.c --- s32 globalTimer_getTime(void); @@ -390,14 +382,14 @@ void subaddie_set_ideal_yaw(Actor *self, int arg1); bool subaddie_playerIsWithinSphere(Actor *self, s32 dist); Actor *actor_spawnWithYaw_s32(enum actor_e id, s32 (*pos)[3], s32 rot); -// --- core2/actor_cubebounds.c --- +// --- core2/gccube.c --- bool nodeProp_findPositionFromActorId(enum actor_e actor_id, f32 *arg1); // --- core2/ba/ba_lookdir.c --- enum bsgroup_e player_movementGroup(void); enum hitbox_e player_getActiveHitbox(ActorMarker *marker); bool player_isDead(void); -bool func_8028F20C(void); +bool player_isStableWithExtraSteps(void); s32 func_8028F66C(enum bs_interrupt_e arg0); void func_8028F8F8(s32 arg0, bool arg1); void func_8028F918(s32 arg0); @@ -425,7 +417,8 @@ void func_8030E0FC(u8, f32, f32, f32); void sfxSource_func_8030E2C4(u8); void sfxSource_func_8030E2C4(u8 indx); void func_8030E4E4(enum sfx_e uid); -void gcsfx_playAtSampleRate(enum sfx_e uid); +void gcsfx_playAtSampleRate(enum sfx_e uid, s32 sample_rate); +void gcsfx_play(enum sfx_e uid); void func_8030E560(enum sfx_e uid, s32 arg1); void func_8030E58C(enum sfx_e uid, f32 arg1); void func_8030E5F4(enum sfx_e uid, f32 arg1); @@ -451,7 +444,7 @@ void sfxsource_setSfxId(u8 indx, enum sfx_e uid); void sfxsource_set_fade_distances(u8, f32, f32); void sfxsource_set_position(u8, f32[3]); -// --- core2/camera/camera_motor1.c --- +// --- core2/nc/camera_motor1.c --- void gcStaticCamera_activate(s32 arg0); bool func_802BB270(void); @@ -460,13 +453,13 @@ void func_803114D0(void); int gcdialog_hasCurrentTextId(void); bool gcdialog_showDialog(s32 text_id, s32 arg1, f32 *pos, ActorMarker *marker, void(*callback)(ActorMarker *, enum asset_e, s32), void(*arg5)(ActorMarker *, enum asset_e, s32)); -// --- core2/cutscene/lair.c --- +// --- core2/map/cutscene_skip.c --- void func_8031CD20(NodeProp *arg0, s32 arg1, s32 arg2); // --- core2/collision/polydetect.c --- void func_80340690(Struct83s *self); -// --- core2/actor_cubebounds.c --- +// --- core2/gccube.c --- bool func_803077FC(f32 arg0[3], s32 *arg1, s32 *arg2, s32 arg3, u32 arg4); bool func_80305C30(s32 arg0); bool func_80308F54(s32 cube_index); @@ -484,7 +477,7 @@ bool func_80331158(ActorMarker *arg0, f32 *arg1, f32 *arg2); // --- core2/ba/ba_lookdir.c --- bool func_8028F280(void); -// --- core2/ba/ba_anim.c --- +// --- core2/ba/anim.c --- bool baanim_isStopped(void); bool baanim_isAnimID(enum asset_e anim_id); AnimCtrl *baanim_getAnimCtrlPtr(void); @@ -500,38 +493,38 @@ void baanim_setEnd(f32); void baanim_setEndAndDuration(f32, f32); void baanim_setVelocityMapRanges(f32, f32, f32, f32); -// --- core2/ba/ba_groundsurface.c --- +// --- core2/ba/hazards.c --- bool isOnFloor(void); bool isPlayerInHazard(void); bool canTakeGroundDamage(void); -// --- core2/ba/ba_animstate.c --- -bool func_8029DFE0(void); -f32 func_8029DFC8(void); -f32 func_8029DFD4(void); -void func_8029E090(bool, f32); -void func_8029E0C4(f32); -void func_8029E0D0(f32); -bool func_8029DFBC(void); -bool func_8029DFA4(void); -bool func_8029DFB0(void); -bool func_8029DFEC(void); - -// --- core2/ba/ba_carriedobj.c --- +// --- core2/ba/modelappendages.c --- +bool modelAppendages_hideTurboTrainers(void); +f32 modelAppendages_showBanjosLeftEye(void); +f32 modelAppendages_showBanjosRightEye(void); +void modelAppendages_setKazooiesUpperHalfVisibilityAndTimer(bool, f32); +void modelAppendages_setBanjosLeftEyeVisibility(f32); +void modelAppendages_setBanjosRightEyeVisibility(f32); +bool modelAppendages_showKazooiesUpperHalf(void); +bool modelAppendages_showKazooiesAss(void); +bool modelAppendages_showKazooiesFeetAndShoes(void); +bool modelAppendages_hideWadingBoots(void); + +// --- core2/ba/carriedobj.c --- bool player_setCarryObjectPose(enum actor_e actor_id, Actor **arg1); -// --- core2/camera/camera_nodemanager.c --- +// --- core2/nc/camera_nodemanager.c --- bool func_802BB720(s32 arg0, f32 arg1[3], f32 arg2[3], s32 *arg3); bool func_802BB884(f32 arg0[3], f32 *arg1); bool func_802BC428(void); -// --- core2/camera/camera_fog.c --- +// --- core2/nc/camera_fog.c --- bool func_802BEF64(void); -// --- core2/camera/camera_focus.c --- +// --- core2/nc/camera_focus.c --- bool func_802BAC1C(void); -// --- core2/camera/dynamicCamera.c --- +// --- core2/nc/dynamicCamera.c --- bool func_802BC640(f32 arg0[3], f32 arg1[3], f32 arg2, s32 arg3); bool func_802BCE0C(f32 arg0[3], f32 arg1[3]); f32 func_802BD8D4(void); @@ -539,21 +532,21 @@ void func_802BD8A4(f32, f32, f32); void func_802BE230(f32, f32); void func_802BE244(f32, f32); -// --- core2/camera/dynamicCam12.c --- +// --- core2/nc/dynamicCam12.c --- bool __is_flying_in_FP(void); bool func_802C189C(void); -// --- core2/camera/dynamicCam13.c --- +// --- core2/nc/dynamicCam13.c --- bool func_802C0640(void); -// --- core2/camera/dynamicCamA.c --- +// --- core2/nc/dynamicCamA.c --- bool ncDynamicCamA_func_802C1EE0(void); bool ncDynamicCamA_func_802C1DB0(f32); -// --- core2/camera/firstpersoncamera.c --- -bool __ncFirstPersonCamera_fullyZoomedIn(void); +// --- core2/nc/1p.c --- +bool __ncba1p_fullyZoomedIn(void); -// --- core2/collision/funcs.c --- +// --- core2/collision/dispatch.c --- void func_80320B24(void *arg0, void *arg1, void *arg2); void func_80320B44(void *arg0, void *arg1, void *arg2, void *arg3); @@ -564,37 +557,29 @@ f32 func_80294438(void); f32 floor_getCurrentFloorYPosition(void); void func_80293D48(f32, f32); -// --- core2/spline_bezier.c --- - -// --- core2/vtx/list.c --- - // --- core2/spline_pathfollow.c --- void func_80343DEC(Actor *self); -// --- core2/model/render.c --- - -// --- core2/spawn_queue.c --- +// --- core2/spawnqueue.c --- void __spawnQueue_add_0(void (*arg0)(void)); void __spawnQueue_add_2(void (*arg0)(void), uintptr_t arg1, uintptr_t arg2); Actor *spawnQueue_actor_f32(enum actor_e actor_id, uintptr_t x, uintptr_t y, uintptr_t z); void __spawnQueue_add_1(GenFunction_1, uintptr_t); #define SPAWNQUEUE_ADD_1(method, arg0) __spawnQueue_add_1((GenFunction_1) (method), reinterpret_cast(uintptr_t, (arg0))) +void __spawnQueue_add_3(GenFunction_3, uintptr_t, uintptr_t, uintptr_t); void __spawnQueue_add_4(GenFunction_4, uintptr_t, uintptr_t, uintptr_t, uintptr_t); -// --- core2/sprite/displaydata.c --- +// --- core2/fx/commonParticle.c --- void commonParticle_add(ActorMarker *arg0, s32 arg1, FuncUnk40 arg2); int commonParticle_new(enum common_particle_e particle_id, int arg1); // --- core2/particle/particle.c --- void particleEmitter_setModel(ParticleEmitter *self, enum asset_e model_id); -void particleEmitter_setSfx(ParticleEmitter *self, enum sfx_e sfx_id, s32 arg2); -void particleEmitter_setAlpha(ParticleEmitter *self, s32 arg1); void particleEmitter_setVelocityAccelerationAndPositionRanges(ParticleEmitter *self, ParticleSettingsVelocityAccelerationPosition *settings); void func_802EFC28(ParticleEmitter *self, ParticleSettingsScaleAndLifetimeDrawModeEmitCount *settings); ParticleEmitter *partEmitMgr_defragEmitter(ParticleEmitter *); ParticleEmitter *partEmitMgr_newEmitter(u32); ParticleEmitter *particleEmitter_new(u32 capacity); -void particleEmitter_func_802EFA20(ParticleEmitter *, f32, f32); void func_802EFF50(ParticleEmitter *, f32); void particleEmitter_emitInVolume(ParticleEmitter *, f32[3], f32[3], s32); void particleEmitter_emitN(ParticleEmitter *, int); @@ -622,7 +607,7 @@ void particleEmitter_update(ParticleEmitter *self); void particleEmitter_setVelocityAndAccelerationRanges(ParticleEmitter *, ParticleSettingsVelocityAcceleration *); // --- core2/quiz/game.c --- -void func_802D68F0(s32 seconds); +void code_4C020_setHourglassTimer(s32 seconds); void func_802D4A9C(Actor *self, s32 arg1); void func_802D4AC0(Actor *self, s32 arg1, enum file_progress_e arg2); void func_802D6264(f32, enum map_e, s32, s32, s32, enum file_progress_e); @@ -641,15 +626,14 @@ void coMusicPlayer_playMusic(enum comusic_e, s32); // --- core1/stopnswop.c --- bool sns_get_item_state(enum StopNSwop_Item item, s32 set); -// --- FP/mapstate/slalom.c --- +// --- FP/ma/slalom.c --- bool maSlalom_isActive(void); // --- FP/ch/boggy2.c --- bool func_8038A1A0(ActorMarker *marker); -// code3B10_checkGVChecksums omitted: decomp defines as (void) but callers pass Actor* - // --- CC/model_renderstate.c --- +void code13C0_checkCCChecksums(void); void CC_func_80387D4C(void); // OS function prototypes @@ -665,8 +649,8 @@ void gSPVertex(Gfx* pkt, uintptr_t v, int n, int v0); void gSPInvalidateTexCache(Gfx* pkt, uintptr_t texAddr); int ResourceMgr_OTRSigCheck(char* imgData); -// --- BGS/actor_spawninit.c --- -void BGS_func_8038F1E0(void); +// --- BGS/bgsspawnqueue.c --- +void bgs_updateSpawnableActors(void); // --- BGS/ch/croctus.c --- void BGS_func_803885DC(void); @@ -678,14 +662,14 @@ void func_8038CEA0(void); void func_8038CEB8(void); // --- BGS/ch/mrvile.c --- -bool BGS_func_8038C338(ActorMarker *marker); -bool func_8038C2A8(ActorMarker *marker); -void BGS_func_8038C434(ActorMarker *marker); -void BGS_func_8038C460(ActorMarker *arg0); -void func_8038C384(ActorMarker *marker); -void func_8038C3B0(ActorMarker *marker); -void func_8038C3DC(ActorMarker *marker); -void func_8038C408(ActorMarker *marker); +bool chMrVile_isInitialIdle(ActorMarker *marker); +bool chMrVile_playerWithinRange(ActorMarker *marker); +void chMrVile_setStateRunFromPlayer(ActorMarker *marker); +void chMrVile_setInitialIdleStill(ActorMarker *arg0); +void chMrVile_setStateAttackPlayer(ActorMarker *marker); +void chMrVile_setStateTalkToPlayer(ActorMarker *marker); +void chMrVile_setStatePlayMinigame(ActorMarker *marker); +void chMrVile_setStateIdleWalking(ActorMarker *marker); // --- BGS/ch/mudhut.c --- void chMudHut_checkBGSChecksums(void); @@ -694,66 +678,71 @@ void chMudHut_checkBGSChecksums(void); void func_8038F51C(Actor *self); // --- BGS/ch/tiptup.c --- -s32 func_80388E70(ActorMarker *self); void chTiptup_choirHitReaction(ActorMarker *self, s32 arg1); +s32 chTiptup_getUnkB(ActorMarker *self); void func_80388FFC(ActorMarker *self, s32 *arg1, f32* arg2); // --- BGS/ch/yumblie.c --- bool chyumblie_is_edible(ActorMarker * arg0); bool func_8038B684(ActorMarker * arg0); -// --- BGS/minigame_vile.c --- -bool chvilegame_cpu_consume_piece(ActorMarker *marker, f32 position[3]); -s32 chvilegame_get_piece_count(ActorMarker *marker); -s32 chvilegame_get_score_difference(ActorMarker *marker); -s32 func_8038A9E0(ActorMarker *marker); -void chvilegame_new_piece(ActorMarker *game_marker, ActorMarker *piece_marker, f32 position[3], u32 yumblie_type); +// --- BGS/mrvileminigame.c --- +bool chMrVileMinigame_mrVileConsumePiece(ActorMarker *marker, f32 position[3]); +s32 chMrVileMinigame_getPieceCount(ActorMarker *marker); +s32 chMrVileMinigame_getScoreDifference(ActorMarker *marker); +s32 chMrVileMinigame_getDialogIndex(ActorMarker *marker); +void chMrVileMinigame_newPiece(ActorMarker *game_marker, ActorMarker *piece_marker, f32 position[3], u32 yumblie_type); void chvilegame_remove_piece(ActorMarker *game_marker, ActorMarker *piece_marker); -// --- CC/actor_spawninit.c --- +// --- CC/ccspawnqueue.c --- void CC_func_80387DA0(void); // --- CC/ch/clankertoothext.c --- void CC_func_803870E0(void); void func_803870EC(s32 arg0); -// --- CC/minigame_rings.c --- -void func_803880D4(void); -void func_80388104(void); -void func_8038817C(void); +// --- CC/ma/clankerrings.c --- +void maClankerRings_release(void); +void maClankerRings_init(void); +void maClankerRings_update(void); -// --- CC/platform_physics.c --- +// --- CC/ma/clanker.c --- int CC_func_80388CA0(void); -void CC_func_8038868C(void); -void CC_func_80388760(Gfx **gfx, Mtx **mtx, Vtx **vtx); +void maClanker_raiseClankerCutscene(void); +void maClanker_draw(Gfx **gfx, Mtx **mtx, Vtx **vtx); void CC_func_80388F4C(void); void func_80388B4C(f32 arg0[3]); void func_80388B78(f32 arg0[3], f32 arg1[3]); void func_80388BBC(f32 arg0[3], f32 arg1[3]); void func_80388CB4(void); void func_80388D54(void); -void func_80388ED4(s32 arg0); -void func_803894A0(void); - -// --- CCW/actor_spawninit.c --- +void maClanker_playScrewNoise(s32 arg0); +void maClanker_defrag(void); +void maClanker_release(void); +void maClanker_init(void); +void maClanker_update(void); +s32 maClankerRings_isMinigameActive(void); +void maClankerRings_passRing(s32); + +// --- CCW/ccwspawnqueue.c --- void CCW_func_8038DB6C(void); -// --- CCW/ch/nabnut_winter.c --- -void func_8038BC50(f32 dst[3]); +// --- CCW/nabnut_winter.c --- +void chAutumnOutsideNabnut_getPosition(f32 dst[3]); -// --- CCW/ch/eyrie_baby.c --- +// --- CCW/eyrie_baby.c --- void func_80389BD8(f32 dst[3]); -// --- CCW/flower.c --- -bool func_80388438(); -void func_803883F4(); +// --- CCW/ch/beanstalk.c --- +bool chCCWBeanstalk_hasSpawned(); +void chCCWBeanstalk_growBeanstalk(); -// --- CCW/minigame_zubba.c --- -void func_803867C8(ActorMarker *marker); -void func_80386814(ActorMarker *marker); -void func_80386840(ActorMarker *marker, s32 *score, s32 *total); +// --- CCW/ch/zubbahoneylump.c --- +void chZubbaFight_zubbaKilled(ActorMarker *marker); +void chZubbaFight_zubbaDisappear(ActorMarker *marker); +void chZubbaFight_zubbaScore(ActorMarker *marker, s32 *score, s32 *total); -// --- FP/actor_spawninit.c --- +// --- FP/fpspawnqueue.c --- void FP_func_80391324(void); // --- FP/ch/boggy2.c --- @@ -765,7 +754,7 @@ void chTwinkly_decideShatterColor(f32 position[3], enum marker_e marker_id); // --- FP/ch/twinklybox.c --- bool preventSnowmanAttack(ActorMarker *marker); -// --- FP/mapstate/slalom.c --- +// --- FP/ma/slalom.c --- bool maSlolam_WithinRadiusOfBoggy(f32 position[3], s32 radius); void maSlalom_end(); void maSlalom_init(void); @@ -778,25 +767,25 @@ void maSlalom_start(void); void maSlalom_unlinkBoggy(void); void maSlalom_update(void); -// --- FP/mapstate/snowbutton.c --- +// --- FP/ma/snowbutton.c --- void maSnowButton_decRemaining(void); void maSnowButton_end(void); void maSnowButton_init(void); void maSnowButton_update(void); -// --- FP/mapstate/snowy.c --- +// --- FP/ma/snowy.c --- void maSnowy_decRemaining(void); void maSnowy_end(void); void maSnowy_incTotal(void); void maSnowy_init(void); void maSnowy_update(void); -// --- FP/ch/wozza_fire.c --- +// --- FP/wozza_fire.c --- void func_803918C0(void); void func_8039195C(void); void func_80391994(void); -// --- GV/actor_spawninit.c --- +// --- GV/gvspawnqueue.c --- s32 code7FF0_getMagicCarpetState(Actor *arg0, s32 arg1); void GV_func_8038F154(void); @@ -816,10 +805,10 @@ bool chGobiRock_isDestroyed(void); // --- GV/ch/grabba.c --- s32 GV_func_8038C5BC(void); -// --- GV/ch/handshadow.c --- +// --- GV/handshadow.c --- void func_8038C748(void); -// --- GV/ch/jinxy_head.c --- +// --- GV/jinxy_head.c --- int func_8038E344(ActorMarker *this_marker); void func_8038E2FC(ActorMarker *this_marker); @@ -839,8 +828,8 @@ void gv_matchingGame_init(void); void gv_matchingGame_reset(void); void gv_matchingGame_update(void); -// --- GV/pyramid_trigger.c --- -int func_8038D388(void); +// --- GV/sandybutteggtoll.c --- +bool func_8038D388(void); // --- GV/water_pyramidactivate.c --- void func_803900F8(void); @@ -857,7 +846,7 @@ void gv_waterCtrl_end(void); void gv_waterCtrl_init(void); void gv_waterCtrl_update(void); -// --- MM/actor_spawninit.c --- +// --- MM/mmspawnqueue.c --- void MM_func_803888B0(void); // --- MM/ch/hut.c --- @@ -873,13 +862,13 @@ void func_803892A8(ActorMarker **ptr); // --- MM/ch/jujuhitbox.c --- void chjujuhitbox_setJuju(Actor *self, s32 slave_id, Actor *slavePtr); -// --- MMM/actor_spawninit.c --- +// --- MMM/mmmspawnqueue.c --- void MMM_func_803890E0(void); // --- MMM/organ_tiles.c --- void func_8038B5D8(Struct5Fs *arg0, Struct68s *arg1, s32 arg2, s32 arg3); -// --- MMM/ch/flowerpot.c --- +// --- MMM/ch/cemetarypot.c --- bool chFlowerpot_eggCollision(ActorMarker *marker); void chFlowerpot_reset(); @@ -921,7 +910,7 @@ void func_80389544(void); void func_803895B0(s32 arg0); void func_8038966C(void); -// --- RBB/actor_spawninit.c --- +// --- RBB/rbbspawnqueue.c --- void RBB_func_80386C48(void); // --- RBB/ch/eggtoll1.c --- @@ -931,8 +920,8 @@ void func_8038685C(ActorMarker *marker); s32 chWhistleCtrl_newEvent(Actor *self, s32 whistle_id, Actor *other); // --- RBB/miniboombox_container.c --- -void func_8038FB54(void); -void func_8038FB6C(void); +void chBoomBoxMinigameCtrl_countInc(void); +void chBoomBoxMinigameCtrl_countDec(void); // --- RBB/propellorctrl.c --- void rbb_propellorCtrl_reset(void); @@ -942,7 +931,7 @@ void rbb_propellorCtrl_update(void); // --- SM/quarrie_honeycomb.c --- bool codeBF0_shouldSpawnQuarrieHoneyComb(ActorMarker *marker); -// --- SM/crc.c --- +// --- SM/smspawnqueue.c --- void SM_resetSpawnableActors(); void codeF0_breakAbilitiesIfChecksumsFail(); @@ -961,7 +950,7 @@ void chTreasurehunt_resetProgress(void); // --- TTC/crc.c --- void code3040_checkTTCChecksums(void); -// --- TTC/castle.c --- +// --- TTC/ma/castle.c --- bool maCastle_hasBanjoKazooieCodeBeenEntered(void); bool maCastle_isSecretCheatCodeRelatedValueEqualToScrambledAddressValue(); void maCastle_init(void); @@ -983,10 +972,10 @@ void musicInstruments_init(void); // --- core1/musicplayer.c --- int func_8025AEEC(void); -s32 comusic_active_track_count(void); +s32 coMusicPlayer_getTrackCount(void); s32 func_8025ADD4(enum comusic_e id); -void comusicPlayer_free(void); -void comusicPlayer_init(void); +void coMusicPlayer_free(void); +void coMusicPlayer_init(void); void comusic_defrag(void); void func_8025A23C(s32 arg0); void func_8025A2B0(void); @@ -1010,7 +999,7 @@ void func_80244814(void *arg0); void func_80244978(intptr_t arg0, s16 type, s32 arg2); void func_80244A98(s32 arg0); -// --- core1/io/ba_motor.c --- +// --- core1/bamotor.c --- void baMotor_80250C08(void); void baMotor_80250FC0(void); void baMotor_init(void); @@ -1025,18 +1014,14 @@ void func_802451A4(f32 arg0[3], f32 arg1[3], f32 arg2[3], f32 arg3[3], f32 arg4[ // --- core1/debugtext.c --- s32 gcdebugText_isThreadLocked(void); -void func_80247F24(s32 arg0, s32 arg1); +void gcdebugText_showLargeValue(s32 arg0, s32 arg1); void func_80247F9C(s32 arg0); void gcdebugText_pauseThread(void); -// --- core1/defragmanager.c --- -void defragManager_free(void); -void defragManager_init(void); - -// --- core1/math/mlmtx.c --- +// --- core1/gu_perspective.c --- void _guMtxF2L(float mf[4][4], Mtx *m); -// --- core1/inflate.c --- +// --- boot/inflate.c --- int bk_inflate(void); // --- core1/initthread.c --- @@ -1058,9 +1043,6 @@ void func_80255A04(void); void func_80255A14(void); void func_80255ACC(void); -// --- core1/ml.c --- -void func_802596AC(f32 a0[3], f32 a1[3], f32 a2[3], f32 a3[3]); - // --- core1/mlmtx.c --- void func_802515D4(f32 arg0[3][3]); @@ -1152,7 +1134,7 @@ void func_8032BC18(Actor *self); void func_8032BC60(Actor *self, s32 arg1, f32 arg2[3]); void subaddie_set_state_looped(Actor * self, u32 arg1); -// --- core2/actor_cubebounds.c --- +// --- core2/gccube.c --- bool func_80305248(f32 arg0[3], s32 arg1, f32 *arg2); bool func_8030526C(f32 arg0[3], s32 arg1, f32 *arg2); bool func_80305290(bool (* arg0)(NodeProp *), bool (* arg1)(Prop *)); @@ -1169,7 +1151,7 @@ s32 func_80307164(s32 arg0[3]); s32 func_80307258(f32 arg0[3], s32 arg1, s32 arg2); s32 nodeprop_getRadius(NodeProp *arg0); s32 nodeprop_getScale(NodeProp *nodeProp); -u32 nodeprop_getYaw(NodeProp *nodeProp); +u32 nodeProp_getYaw(NodeProp *nodeProp); void code7AF80_freeTotalCounts(void); void cubeList_defrag(); void cubeList_free(); @@ -1194,9 +1176,9 @@ void spawnableActorList_new(void); // --- core2/actor_cubepropsystem.c --- s32 actor_getAnimatedTexturesCacheId(Actor *actor); -s32 codeA5BC0_getNodePropBit6(NodeProp *arg0); -s32 codeA5BC0_getNodePropUnk8(NodeProp *arg0); -s32 codeA5BC0_getNodePropUnkA(NodeProp *arg0); +s32 codeA5BC0_getNodePropCategory(NodeProp *arg0); +s32 codeA5BC0_getNodePropActorId(NodeProp *arg0); +s32 codeA5BC0_getNodePropMarkerId(NodeProp *arg0); s32 codeA5BC0_getNodePropUnkC(NodeProp *arg0); s32 func_8032E49C(Cube *cube, enum actor_e *actor_id_list, NodeProp **node_list, s32 node_list_capacity); s32 func_8032E5A8(Cube *cube, s32 arg1, f32 (*arg2)[3], s32 capacity); @@ -1210,7 +1192,7 @@ void cube_sortAbsolute(Cube *cube); void cube_sortRelative(Cube *cube); void func_8032D3A8(void); void func_8032D3D8(Gfx **gdl, Mtx **mptr, Vtx **vptr); -void func_8032D474(Gfx **gdl, Mtx **mptr, Vtx **vptr); +void core2_A5BC0_drawScreenOverlayMarkers(Gfx **gdl, Mtx **mptr, Vtx **vptr); void func_8032E070(void); void func_8032EE2C(s32 arg0[3], s32 arg1, s32 arg2); void func_8032EE80(Cube *cube); @@ -1248,7 +1230,7 @@ void func_80296CC0(f32 arg0[3]); // --- core2/scorequeue/queue_timers.c --- bool func_802FCD98(struct8s *arg0); -// --- core2/ambient_fish.c --- +// --- SM/ch/ambient_fish.c --- void func_803500D8(Gfx **gfx, Mtx **mtx, Vtx **vtx); void func_803500E8(void); void func_80350174(void); @@ -1277,7 +1259,7 @@ void anim_resetSmooth(Animation *self); void anim_setIndex(Animation *self, enum asset_e arg1); void anim_update(Animation *self); -// --- core2/anim/anim_cache.c --- +// --- core2/anim/animcache.c --- bool animCache_inUse(s16 index); s16 animCache_getNew(void); void animCache_defrag(void); @@ -1293,14 +1275,7 @@ void func_80361E10(Actor *self); void func_80361E9C(Actor *self); void func_80361EE0(Actor *self); -// --- core2/anim/anim_texturecache.c --- -bool AnimTextureListCache_tryGetTextureOffset(s32 list_index, s32 texture_index, s32 *current_frame); -s32 AnimTextureListCache_newList(void); -void AnimTextureListCache_setAnimTextureList(s32 arg0, BKAnimTextureList *bk_anim_texture_list); -void AnimTextureListCache_free(void); -void AnimTextureListCache_freeList(s32 arg0); -void AnimTextureListCache_init(void); -void AnimTextureListCache_update(void); +// --- core2/anim/animtexturecache.c --- // --- core2/anim/bonetransformlist.c --- void boneTransformList_getBoneScale(BoneTransformList *self, s32 bone_id, f32 scale[3]); @@ -1310,7 +1285,7 @@ void func_8033A6B0(BoneTransformList *self, s32 bone_id, f32 arg2[3]); void func_8033A8F0(BoneTransformList *self, s32 bone_id, f32 arg2[4]); void func_8033A968(BoneTransformList *self, s32 bone_id, f32 arg2[3]); -// --- core2/anim_sequence.c --- +// --- core2/anim/anseq.c --- void anSeq_free(void **ppAnSeq); void anSeq_setActivationFrameDelay(void **ppAnSeq, s32 arg1); void anSeq_update(void **ppAnSeq, AnimCtrl *pAnCtl); @@ -1325,7 +1300,7 @@ void func_803353F4(intptr_t arg0, s32 arg1); void func_80335418(intptr_t arg0, s32 arg1); void sfxInstruments_init(void); -// --- core2/ba/ba_anim.c --- +// --- core2/ba/anim.c --- void baAnim_defrag(void); void baAnim_free(void); void baAnim_init(void); @@ -1342,50 +1317,44 @@ void animBinCache_free(void); void animBinCache_init(void); void animBinCache_update(void); -// --- core2/ba/ba_animstate.c --- -void func_8029DD6C(void); -void func_8029DFF8(void); -void func_8029E058(bool); -void func_8029E064(bool); -void func_8029E070(bool); -void func_8029E0DC(bool); -void func_8029E0E8(bool); -void func_8029E0F4(bool); -void func_8029E100(void); - -// --- core2/ba/ba_bounds.c --- +// --- core2/ba/modelappendages.c --- +void modelAppendages_loadAppendage(void); +void modelAppendages_reset(void); +void modelAppendages_setKazooiesAssVisibility(bool); +void modelAppendages_setKazooiesFeetAndShoesVisibility(bool); +void modelAppendages_setKazooiesUpperHalfVisibility(bool); +void modelAppendages_setTurboTrainersVisibility(bool); +void modelAppendages_setSledVisibility(bool); +void modelAppendages_setWadingBootsVisibility(bool); +void modelAppendages_kazooiesUpperHalfVisibilityTimer(void); + +// --- core2/ba/babounds.c --- void babounds_init(void); void babounds_update(void); -// --- core2/ba/ba_buzz.c --- +// --- core2/ba/babuzz.c --- void babuzz_release(void); void babuzz_reset(void); -// --- core2/ba/ba_carriedobj.c --- +// --- core2/ba/carriedobj.c --- void bacarriedobj_dec(enum actor_e actor_id); void bacarriedobj_displayOnHud(enum actor_e actor_id); void bacarriedobj_inc(enum actor_e actor_id); void bacarriedobj_spawn(enum actor_e actor_id); +void bacarriedobj_incWithExtraSteps(enum actor_e actor_id); +void bacarriedobj_decWithExtraSteps(enum actor_e actor_id); +void bacarriedobj_displayOnHudWithExtraSteps(enum actor_e actor_id); void func_8028DEEC(enum actor_e actor_id, Actor *actor); -// --- core2/ba/ba_carry.c --- -void bacarry_end(void); -void bacarry_init(void); -void bacarry_reset_marker(void); -void bacarry_set_marker(ActorMarker *arg0); -void bacarry_update(void); - -// --- core2/ba/ba_scripted.c --- +// --- core2/ba/drone.c --- enum bs_e badrone_802926E8(void); -enum bs_e badrone_enter(void); enum bs_e badrone_look(void); enum bs_e badrone_transform(void); enum bs_e badrone_vanish(void); -void badrone_get_position_and_duration(f32 position[3], f32 *duration); void badrone_goto_end(void); void badrone_init(void); -// --- core2/ba/ba_eyeblink.c --- +// --- core2/ba/iFrame.c --- s32 baiFrame_getState(void); void baiFrame_reset(void); void baiFrame_start(void); @@ -1404,13 +1373,13 @@ void func_802C7478(Actor *actor); void func_802C75A0(Actor *actor, s32 arg1); void func_802C79C4(void); -// --- core2/ba/ba_eyes.c --- +// --- core2/ba/baeyes.c --- void baeyes_close(void); void baeyes_open(void); void baeyes_reset(void); void baeyes_update(void); -// --- core2/ba/ba_falldamage.c --- +// --- core2/ba/falldamage.c --- s32 bafalldamage_get_damage(s32 *damage); s32 bafalldamage_get_state(void); void bafalldamage_init(void); @@ -1423,7 +1392,7 @@ void func_80350BC8(void); void func_80350BFC(void); void func_80350CA4(void); -// --- core2/ba/ba_groundsurface.c --- +// --- core2/ba/hazards.c --- void freeHazardSfxId(void); void hazards_reset(void); void hazards_update(void); @@ -1438,7 +1407,7 @@ void func_80290298(void); // --- core2/ba/ba_hitbox.c --- enum hitbox_e hitbox_getHitboxForActor(ActorMarker *arg0); -// --- core2/ba/ba_input.c --- +// --- core2/ba/bainput.c --- int bainput_isEnabled(s32 arg0); int bainput_should_beak_barge(void); int bainput_should_beak_bust(void); @@ -1463,7 +1432,7 @@ s32 func_80291660(void); void func_80291590(void); void func_802915B8(void); -// --- core2/ba/ba_key.c --- +// --- core2/ba/bakey.c --- int bakey_getAndSetState(s32 button_indx, s32 val); int bakey_releaseCount(s32 button_indx); int bakey_released(s32 button_indx); @@ -1471,7 +1440,7 @@ void bakey_disableAll(s32 arg0); void bakey_reset(void); void bakey_update(void); -// --- core2/ba/ba_lookat.c --- +// --- core2/ba/balookat.c --- int balookat_try_get_position(f32 arg0[3]); s32 balookat_getState(void); void balookat_init(void); @@ -1486,9 +1455,9 @@ bool func_8028EFC8(void); bool func_8028EFEC(void); bool func_8028F070(void); bool func_8028F098(void); -bool func_8028F0D4(void); +bool player_isBanjoOrWishywashy(void); bool func_8028F150(void); -bool func_8028F170(void); +bool player_isInFirstPersonView(void); bool func_8028F1E0(void); bool func_8028F25C(void); bool func_8028F2A0(void); @@ -1502,16 +1471,16 @@ bool func_8028F530(s32 arg0); bool func_8028F55C(s32 arg0, ActorMarker *marker); bool func_8028F590(s32 arg0, ActorMarker *marker); bool func_8028F5F8(f32 arg0[3]); -bool func_8028FB88(enum transformation_e xform_id); +bool player_transform(enum transformation_e xform_id); bool func_8028FBD4(f32 arg0[3]); bool player_is_in_jiggy_jig(void); bool player_is_present(void); bool player_throwCarriedObject(void); enum actor_e carriedObj_getActorId(void); enum bswatergroup_e player_getWaterState(void); -enum marker_e bacarry_get_markerId(void); +enum marker_e bacarry_getMarkerId(void); f32 func_8028EC64(f32 arg0[3]); -int ability_isUnlocked(enum ability_e uid); +bool ability_isUnlocked(enum ability_e uid); int func_8028EC04(void); s32 func_8028E4A4(void); s32 func_8028F68C(enum bs_interrupt_e arg0, ActorMarker *marker); @@ -1548,7 +1517,7 @@ void player_getVelocity(f32 dst[3]); void player_setIdealRotation(f32 rotation[3]); void player_setRotation(f32 rotation[3]); -// --- core2/ba/ba_marker.c --- +// --- core2/ba/marker.c --- bool baMarker_isCollidable(void); enum actor_e baMarker_getCarriedObjectActorId(void); s32 baMarker_8028D688(void); @@ -1562,7 +1531,7 @@ void baMarker_init(void); void baMarker_setCarriedObject(enum actor_e actor_id); void baMarker_update(void); -// --- core2/ba/ba_model.c --- +// --- core2/ba/model.c --- void assetcache_release(void *); enum asset_e baModel_getModelId(void); s32 baModel_isVisible(void); @@ -1581,14 +1550,16 @@ void baModel_getPosition(f32* dst); void baModel_reset(void); void baModel_setEnvAlpha(s32 alpha); void baModel_setPostDraw(void (*draw_func)(Gfx **gfx, Mtx **mtx, Vtx **vtx)); -void baModel_setVisible(s32 arg0); void baModel_update(void); void baModel_updateModel(void); -// --- core2/ba/ba_modelselect.c --- +// --- core2/ba/playermodel.c --- s32 func_802985F0(void); void func_802986D0(void); void func_80298700(void); +void playerModel_set(void); +void playerModel_free(void); +enum asset_e playerModel_get(void); // --- core2/ba/ba_momentum.c --- void func_8029065C(void); @@ -1602,7 +1573,7 @@ void func_8032196C(void); void func_803219A8(void); void func_803219F4(s32 arg0); -// --- core2/ba/ba_position.c --- +// --- core2/ba/playerposition.c --- void playerPosition_init(void); void playerPosition_func_8029842C(void); void playerPosition_func_80298464(f32 arg0[3]); @@ -1610,7 +1581,7 @@ void playerPosition_func_80298504(f32 arg0[3]); void playerPosition_getOffset(f32 arg0[3]); void playerPosition_setOffset(f32 arg0[3]); void playerPosition_applyOffset(void); -void player_setPosition(f32 arg0[3]); +void playerPosition_set(f32 arg0[3]); void player_setWarpDestination(f32 position[3], f32 yaw, s32 exit_id); // --- core2/ba/ba_recoil.c --- @@ -1629,7 +1600,7 @@ void get_throw_target_position(f32 dst[3]); void set_talk_target_position(f32 src[3]); void set_throw_target_position(f32 src[3]); -// --- core2/ba/ba_sfx.c --- +// --- core2/ba/basfx.c --- void basfx_80299AAC(void); void basfx_80299BD4(void); void basfx_80299DB8(void); @@ -1642,7 +1613,7 @@ void basfx_free(void); void basfx_reset(void); void basfx_update(void); -// --- core2/ba/ba_sfxintensity.c --- +// --- core2/ba/ba_camera.c --- void cameraMode_update(void); void func_80290B6C(void); void func_80291488(s32 arg0); @@ -1650,8 +1621,8 @@ void func_802914CC(s32 arg0); void func_8029151C(s32 arg0); void func_80291548(void); -// --- core2/ba/ba_state.c --- -void func_80295914(void); +// --- core2/ba/bsmethods.c --- +void bsmethods_reset(void); void func_80295B04(void); void func_80295C08(void (* arg0)(void)); void func_80295C14(void); @@ -1668,7 +1639,7 @@ void func_8032320C(void); void func_80323230(void); void func_80323238(void); -// --- core2/ba/ba_stick.c --- +// --- core2/ba/bastick.c --- void bastick_lockAtzero(bool arg0); void bastick_reset(void); void bastick_resetZones(void); @@ -1684,34 +1655,29 @@ void func_802992F0(void); void func_802993C8(void); void func_8029957C(s32 arg0); -// --- core2/ba/ba_timer.c --- -s32 batimer_decrement(s32 timer_id); -void batimer_incrementBy(s32 id, f32 inc_value_sec); -void batimer_set(s32 timer_id, f32 duration); - // --- core2/bs/ant.c --- int bsant_inSet(s32 move_indx); -// --- core2/bs/beak_barge.c --- +// --- core2/bs/bBarge.c --- s32 bsbbarge_hitboxActive(void); -// --- core2/bs/beak_bomb.c --- +// --- core2/bs/bFly.c --- int bsbfly_bombHitboxActive(void); int bsbfly_inSet(enum bs_e arg0); -// --- core2/bs/stilt_stride.c --- +// --- core2/bs/bLongLeg.c --- int bslongleg_inSet(s32 move_indx); -// --- core2/bs/beak_peck.c --- +// --- core2/bs/bPeck.c --- s32 bsbpeck_hitboxActive(void); -// --- core2/bs/beak_swim.c --- +// --- core2/bs/bSwim.c --- bool bsbswim_inSet(enum bs_e move_id); -// --- core2/bs/talon_trot.c --- +// --- core2/bs/bTrot.c --- int bsbtrot_inSet(s32 move_indx); -// --- core2/bs/beak_buster.c --- +// --- core2/bs/bbuster.c --- s32 bsbbuster_hitboxActive(void); s32 func_8029FC4C(void); void func_802A02B4(s32 arg0); @@ -1720,10 +1686,10 @@ void func_802A02B4(s32 arg0); void func_802A02C0(void); void func_802A0340(void); -// --- core2/bs/bee_fly.c --- +// --- core2/bs/beeFly.c --- int bsBeeFly_inSet(s32); -// --- core2/bs/bs_storedstate.c --- +// --- core2/bs/bsStoredState.c --- enum transformation_e bsStoredState_getTransformation(void); s32 bsStoredState_getTrotFlag(void); void bsStoredState_8029A924(void); @@ -1746,12 +1712,12 @@ void bscroc_set_ate_wrong_thing(void); // --- core2/bs/crouch.c --- enum bs_e func_802ADCD4(enum bs_e arg0); -// --- core2/bs/scripted.c --- +// --- core2/bs/drone.c --- void bsdrone_end(void); void bsdrone_init(void); void bsdrone_update(void); -// --- core2/bs/jiggy_dance.c --- +// --- core2/bs/jig.c --- int bsjig_inJiggyJig(enum bs_e state); void func_802B0CD8(void); @@ -1777,44 +1743,44 @@ void func_802B6FA8(void); // --- core2/bs/walrus.c --- int bswalrus_inSledSet(enum bs_e state); -// --- core2/camera/camera_ease.c --- +// --- core2/nc/camera_ease.c --- void func_802C2250(void); void func_802C2258(void); void func_802C22C0(f32 target_position[3], f32 target_rotation[3]); -// --- core2/camera/camera_focus.c --- +// --- core2/nc/camera_focus.c --- void func_802BABD8(void); void func_802BAC10(void); void func_802BAC58(void); -// --- core2/camera/camera_fog.c --- +// --- core2/nc/camera_fog.c --- void func_802BEE2C(Gfx **gfx, Mtx **mtx, Vtx **vtx); void func_802BEF70(void); void func_802BEF78(void); void func_802BEFB0(void); -// --- core2/prop_assetcache.c --- +// --- core2/propModelList.c --- void propModelList_free(void); void propModelList_init(void); void propModelList_flush(s32 arg0); -// --- core2/camera/camera_motor1.c --- +// --- core2/nc/camera_motor1.c --- s32 func_802BB294(void); void func_802BAF20(void); void func_802BAF40(void); -// --- core2/camera/camera_motor2.c --- +// --- core2/nc/camera_motor2.c --- void func_802BB2A0(void); void func_802BB2A8(void); void func_802BB3C4(s32 arg0); void func_802BB41C(s32 arg0); void func_802BB4D8(f32 position[3], f32 rotation[3]); -// --- core2/camera/camera_nodemanager.c --- +// --- core2/nc/camera_nodemanager.c --- s32 ncCamera_getType(void); void camera_setType(enum camera_type_e camera_type); void func_802BBD0C(Gfx **gdl, Mtx **mptr, Vtx **vptr); -void func_802BBD2C(f32 *arg0, f32 *arg1); +void core2_34790_getClipDistances(f32 *arg0, f32 *arg1); void nccamera_init(void); void func_802BC10C(void); void func_802BC21C(s32 arg0, s32 arg1); @@ -1831,26 +1797,26 @@ s32 func_80322758(void); void func_80322764(void); void func_8032278C(s32 arg0, s32 arg1); -// --- core2/camera/camera_position.c --- +// --- core2/nc/camera_position.c --- void func_802BE940(void); -// --- core2/camera/camera_set.c --- +// --- core2/nc/camera_set.c --- void func_803525A0(f32 arg0[3]); -// --- core2/camera/cameranode_type1.c --- +// --- core2/nc/cameranode_type1.c --- bool code336F0_func_802BA87C(PivotCameraNode *self); bool code336F0_func_802BA89C(PivotCameraNode *self); bool code336F0_func_802BA8BC(PivotCameraNode *self); void code336F0_func_802BA7D8(PivotCameraNode *self, f32 arg1[3]); -// --- core2/camera/cameranode_type3.c --- +// --- core2/nc/cameranode_type3.c --- bool code33310_func_802BA4D0(ZoomCameraNode *self); bool code33310_func_802BA4F0(ZoomCameraNode *self); -// --- core2/camera/cameranode_type4.c --- +// --- core2/nc/cameranode_type4.c --- s32 code33250_func_802BA234(RandomCameraNode *self); -// --- core2/camera/cameranodelist.c --- +// --- core2/nc/cameranodelist.c --- s32 ncCameraNodeList_getNodeType(int camera_node_index); s32 ncCameraNodeList_nodeIsValid(int camera_node_index); void ncCameraNodeList_defrag(); @@ -1858,88 +1824,88 @@ void ncCameraNodeList_free(); void ncCameraNodeList_fromFile(File *file_ptr); void ncCameraNodeList_init(); -// --- core2/camera/dynamicCam1.c --- +// --- core2/nc/dynamicCam1.c --- void ncDynamicCam1_end(void); void ncDynamicCam1_init(void); void ncDynamicCam1_update(void); -// --- core2/camera/dynamicCam10.c --- +// --- core2/nc/dynamicCam10.c --- void ncDynamicCam10_end(void); void ncDynamicCam10_init(void); void ncDynamicCam10_update(void); -// --- core2/camera/dynamicCam11.c --- +// --- core2/nc/dynamicCam11.c --- void func_802BF798(s32 camera_node_index); void ncDynamicCam11_end(void); void ncDynamicCam11_init(void); void ncDynamicCam11_update(void); -// --- core2/camera/dynamicCam12.c --- +// --- core2/nc/dynamicCam12.c --- void dynamicCam12_init(void); void func_802C0F4C(void); void ncDynamicCam12_end(void); void ncDynamicCam12_update(void); -// --- core2/camera/dynamicCam13.c --- +// --- core2/nc/dynamicCam13.c --- void func_802C095C(void); void ncDynamicCam13_end(void); void ncDynamicCam13_init(void); void ncDynamicCam13_update(void); -// --- core2/camera/dynamicCam3.c --- +// --- core2/nc/dynamicCam3.c --- void ncDynamicCam3_end(void); void ncDynamicCam3_init(void); void ncDynamicCam3_update(void); -// --- core2/camera/dynamicCam4.c --- -void ncDynamicCam4_end(void); -void ncDynamicCam4_func_802BFE74(bool); -void ncDynamicCam4_init(void); -void ncDynamicCam4_update(void); +// --- core2/nc/fly.c --- +void ncbafly_end(void); +void ncbafly_func_802BFE74(bool); +void ncbafly_init(void); +void ncbafly_update(void); -// --- core2/camera/dynamicCam5.c --- +// --- core2/nc/dynamicCam5.c --- void ncDynamicCam5_end(void); void ncDynamicCam5_func_802BF590(f32 arg0[3]); void ncDynamicCam5_init(void); void ncDynamicCam5_update(void); -// --- core2/camera/dynamicCam8.c --- +// --- core2/nc/dynamicCam8.c --- void ncDynamicCam8_end(void); void ncDynamicCam8_func_802BF9B8(s32 arg0); void ncDynamicCam8_init(void); void ncDynamicCam8_update(void); -// --- core2/camera/dynamicCam9.c --- +// --- core2/nc/dynamicCam9.c --- void ncDynamicCam9_end(void); void ncDynamicCam9_init(void); void ncDynamicCam9_update(void); -// --- core2/camera/dynamicCamA.c --- +// --- core2/nc/dynamicCamA.c --- void ncDynamicCamA_end(void); void ncDynamicCamA_init(void); void ncDynamicCamA_update(void); -// --- core2/camera/dynamicCamB.c --- +// --- core2/nc/dynamicCamB.c --- void ncDynamicCamB_end(void); void ncDynamicCamB_init(void); void ncDynamicCamB_update(void); -// --- core2/camera/dynamicCamC.c --- +// --- core2/nc/dynamicCamC.c --- void ncDynamicCamC_end(void); void ncDynamicCamC_init(void); void ncDynamicCamC_update(void); -// --- core2/camera/dynamicCamD.c --- -void ncDynamicCamD_end(void); -void ncDynamicCamD_init(void); -void ncDynamicCamD_update(void); +// --- core2/nc/die.c --- +void ncbadie_end(void); +void ncbadie_init(void); +void ncbadie_update(void); -// --- core2/camera/dynamicCamF.c --- +// --- core2/nc/dynamicCamF.c --- void ncDynamicCamF_end(void); void ncDynamicCamF_init(void); void ncDynamicCamF_update(void); -// --- core2/camera/dynamicCamera.c --- +// --- core2/nc/dynamicCamera.c --- int func_802BE60C(void); int func_802BE834(f32 arg0[3]); int ncDynamicCamera_getState(void); @@ -1966,21 +1932,21 @@ void ncDynamicCamera_setState(s32 state); void ncDynamicCamera_setUpdateEnabled(bool arg0); void ncDynamicCamera_update(void); -// --- core2/camera/firstpersoncamera.c --- -s32 ncFirstPersonCamera_getState(void); -void ncFirstPersonCamera_getPositionAndRotation(f32 position[3], f32 rotation[3]); -void ncFirstPersonCamera_getZoomedInRotation(f32 dst[3]); -void ncFirstPersonCamera_reset(void); -void ncFirstPersonCamera_setState(enum nc_first_person_state state); -void ncFirstPersonCamera_setZoomedOutPosition(f32 src[3]); -void ncFirstPersonCamera_setZoomedOutRotation(f32 src[3]); +// --- core2/nc/1p.c --- +s32 ncba1p_getState(void); +void ncba1p_getPositionAndRotation(f32 position[3], f32 rotation[3]); +void ncba1p_getZoomedInRotation(f32 dst[3]); +void ncba1p_reset(void); +void ncba1p_setState(enum nc_first_person_state state); +void ncba1p_setZoomedOutPosition(f32 src[3]); +void ncba1p_setZoomedOutRotation(f32 src[3]); -// --- core2/camera/randomCamera.c --- +// --- core2/nc/randomCamera.c --- void ncRandomCamera_end(void); void ncRandomCamera_init(void); void ncRandomCamera_update(void); -// --- core2/camera/staticCamera.c --- +// --- core2/nc/staticCamera.c --- void ncStaticCamera_end(void); void ncStaticCamera_exit(void); void ncStaticCamera_getPosition(f32 dst[3]); @@ -2016,7 +1982,7 @@ s32 chBottlesBonusCursor_getState(void); void chBottlesBonusCursor_draw(Gfx **gfx, Mtx **mtx, Vtx **vtx); void chBottlesBonusCursor_lose(void); -// --- core2/ch/drips.c --- +// --- core2/fx/drips.c --- void func_80359A40(f32 position[3], void *arg1, s32 cnt); // --- core2/ch/goldfeather.c --- @@ -2035,27 +2001,27 @@ void chjiggy_setJiggyId(Actor *self, u32 id); // --- core2/ch/jigsawdance.c --- void chJigsawDance_setState(Actor * self, u32 arg1); -// --- core2/ch/mmm_veggies.c --- +// --- cutscenes/cutscene_trigger.c --- void func_802CDAC4(Actor *); // --- core2/ch/mole.c --- int chmole_learnedAllLevelAbilities(enum level_e level); int chmole_learnedAllSpiralMountainAbilities(void); -// --- core2/ch/overlaycopyright.c --- +// --- core2/gc/overlaycopyright.c --- void chOverlayCopyright_func_802DCB0C(s32 arg0, s32 arg1); void chOverlayCopyright_spawn(s32 arg0, s32 arg1); -// --- core2/ch/overlaynocontroller.c --- +// --- core2/gc/overlaynocontroller.c --- void chOverlayNoController_func_802DD040(s32 arg0, s32 arg1); void chOverlayNoController_spawn(s32 arg0, s32 arg1); -// --- core2/ch/overlaypressstart.c --- +// --- core2/gc/overlaypressstart.c --- void chOverlayPressStart_func_802DCDB0(void); void chOverlayPressStart_func_802DCDC0(NodeProp *arg0, ActorMarker *arg1); void chOverlayPressStart_spawn(NodeProp *arg0, ActorMarker *arg1); -// --- core2/ch/soundsource.c --- +// --- core2/sfx/soundsource.c --- void func_802D09B8(Actor *self, s32 arg1); // --- core2/ch/trainers.c --- @@ -2068,9 +2034,9 @@ void chwadingboots_802D6E54(Actor *self); // --- core2/climb.c --- u8 func_8029825C(void); -void climbClear(void); -void climbRelease(void); -void func_80298344(void); +void climb_clear(void); +void climb_release(void); +void climb_regrab_update(void); // --- core2/bundle.c --- bool func_802C9C14(Actor *actor); @@ -2102,7 +2068,7 @@ void itemPrint_init(void); void itemPrint_reset(void); void itemPrint_update(void); -// --- core2/collision/cachesize.c --- +// --- core2/time_framedelta.c --- void func_8033DC04(void); void func_8033DC10(void); void func_8033DC18(void); @@ -2145,7 +2111,7 @@ void func_80351B28(Struct68s *arg0, f32 arg1[3]); void func_80351C2C(Struct68s *arg0, f32 arg1[3]); void func_80351C48(void); -// --- core2/collision/funcs.c --- +// --- core2/collision/dispatch.c --- bool func_803209F8(f32 arg0[3], f32 arg1[3], f32 *arg2, f32 arg3[3]); void func_80320B7C(void); void func_80320B84(void); @@ -2159,7 +2125,7 @@ s32 collision_getHitsToTrigger(CollisionParams *arg0); s32 collision_getDropBundleNum(CollisionParams *arg0); void func_8033D2F4(void); -// --- core2/collision/init.c --- +// --- core2/map/envcolor.c --- void func_8031B710(void); void func_8031B718(void); void func_8031B790(void); @@ -2190,18 +2156,18 @@ void func_803451B0(u8 index, f32 arg1[3]); void func_80356714(void); void codeCF5F0_forgetAllAbilitiesExceptClawSwipeIfChecksumsFail(void); -// --- core2/cutscene/animated.c --- +// --- GV/ch/mummum.c --- void func_8035D490(ActorMarker *marker); void func_8035D4F0(ActorMarker *marker, s32 arg1); -// --- core2/cutscene/ctrl.c --- +// --- core2/nc/camera_focustarget.c --- s32 func_802C0190(void); void func_802C0120(void); void func_802C0148(void); void func_802C0150(s32 arg0); void func_802C02D4(f32 arg0[3]); -// --- core2/cutscene/lair.c --- +// --- core2/map/cutscene_skip.c --- s32 cutscenetrigger_update(void); void func_8031CC8C(NodeProp *arg0, s32 arg1); void func_8031CC40(enum map_e map_id, s32 arg1); @@ -2215,7 +2181,7 @@ void clearScoreStates(void); void debugScoreStates(void); void warp_mmmEnterLoggo(NodeProp *arg0, ActorMarker *arg1); -// --- core2/cutscene/nodeupdate.c --- +// --- core2/map/warp_dispatch.c --- s32 func_8033451C(s32 arg0); s32 func_80334524(s32 arg0); s32 func_8033452C(s32 arg0); @@ -2225,7 +2191,7 @@ void func_803343F8(s32 indx); void func_80334428(void); void func_80334448(NodeProp *arg0, ActorMarker *arg1); -// --- core2/demo_input.c --- +// --- core2/demo.c --- int demo_readInput(OSContPad* arg0, s32* arg1); void demo_free(void); void demo_load(enum map_e map, s32 demo_id); @@ -2241,10 +2207,10 @@ void dialogBin_terminate(void); void dialogBin_update(void); void func_8031B62C(void); -// --- core2/dialog/progress_dialogs.c --- +// --- core2/dialog/progressDialog.c --- void progressDialog_showDialogMaskZero(enum file_progress_e progress_flag); -void volatileFlag_setAndTriggerDialog_4(enum volatile_flags_e arg0); -void volatileFlag_setAndTriggerDialog_E(enum volatile_flags_e arg0); +void progressDialog_setAndTriggerDialog_4(enum volatile_flags_e arg0); +void progressDialog_setAndTriggerDialog_E(enum volatile_flags_e arg0); // --- core2/inventory_slots.c --- void func_803246F0(u8* self, s32 indx); @@ -2278,7 +2244,7 @@ void func_802E67AC(void); void func_802E67C4(void); void func_802E6820(s32 arg0); -// --- core2/frame/bufferreadback.c --- +// --- core2/frame/rendermem.c --- bool func_802E4424(void); bool func_802E4A08(void); s32 func_802E4A98(s32 arg0); @@ -2307,11 +2273,11 @@ void dummy_func_802E35D0(void); void func_802E3580(void); void func_802E35D8(void); -// --- core2/fx/airscore.c --- +// --- core2/scorequeue/airscore.c --- s32 fxairscore_count_to_time(s32 count); s32 fxairscore_time_to_count(s32 time); -// --- core2/fx/common2score.c --- +// --- core2/scorequeue/common2score.c --- enum item_e func_802FDD0C(struct8s *arg0); // --- core2/fx/effect_colordata.c --- @@ -2322,7 +2288,7 @@ void func_80345C78(f32 arg0[4], f32 arg1[3]); void func_80345CD4(f32 arg0[4], f32 arg1[4]); void func_80345D30(f32 arg0[4], f32 arg1[4], f32 arg2[4]); -// --- core2/fx/effect_eggshatter.c --- +// --- core2/fx/eggshatter.c --- void eggShatter_defrag(void); void eggShatter_draw(Gfx **gPtr, Mtx **mPtr, Vtx **vPtr); void eggShatter_free(void); @@ -2330,7 +2296,7 @@ void eggShatter_init(void); void eggShatter_new(f32 position[3]); void eggShatter_update(void); -// --- core2/fx/effect_enemyrender.c --- +// --- core2/gc/pictureframe.c --- Actor * func_802DF160(Gfx **gfx, Mtx **mtx, Vtx **vtx); void func_802DF270(void); @@ -2341,7 +2307,7 @@ void func_802DAD8C(ParticleEmitter *pCtrl, Actor *self, enum asset_e model_id); void humanoidBaddie_enterInvulnerableState(ActorMarker *marker, s32 arg1); void humanoidBaddie_update(Actor *self); -// --- core2/fx/effect_particle.c --- +// --- core2/mumboshandwithpicture.c --- void func_802DF090(s32 arg0, s32 arg1); void func_802DF0C8(void); void func_802DF11C(s32 arg0, s32 arg1); @@ -2352,11 +2318,11 @@ void func_802929F8(void); // --- core2/fx/effect_simplesprite.c --- void func_802DC110(f32 *position, enum asset_e sprite_id); -// --- core2/fx/effect_spriteanim.c --- +// --- core2/fx/banjokazooiesign.c --- void func_802DC9A4(s32 arg0, s32 arg1); void func_802DC9DC(s32 arg0, s32 arg1); -// --- core2/fx/honeycarrierscore.c --- +// --- core2/scorequeue/honeycarrierscore.c --- void gcpausemenu_80314AC8(int arg0); // --- core2/fx/ripple.c --- @@ -2365,7 +2331,7 @@ void fxRipple_802F3584(s32 arg0, f32 position[3], uintptr_t arg2); void fxRipple_free(void); void fxRipple_init(void); -// --- core2/fx/score_honeycomb.c --- +// --- core2/honeycombscore.c --- s32 honeycombscore_get_level_total(enum level_e level_id); s32 honeycombscore_get_total(void); void honeycombscore_clear(void); @@ -2373,7 +2339,7 @@ void honeycombscore_debug(void); void honeycombscore_getSizeAndPtr(s32 *size, u8 **addr); void honeycombscore_set(enum honeycomb_e indx, bool val); -// --- core2/fx/score_jiggy.c --- +// --- core2/jiggyscore.c --- s32 jiggyscore_leveltotal(s32 lvl); s32 jiggyscore_total(void); void * jiggyscore_clearAllSpawned(void); @@ -2383,7 +2349,7 @@ void jiggyscore_getSizeAndPtr(s32 *size, u8 **addr); void jiggyscore_setCollected(s32 indx, s32 val); void jiggyscore_setSpawned(s32, s32); -// --- core2/fx/score_jiggylist.c --- +// --- core2/fx/effect_jiggy_list.c --- void codeABC00_spawnJiggyAtLocation(enum jiggy_e, f32[3]); void codeABC00_spawnJiggyAtLocationEx(enum jiggy_e, f32[3], s32 triggerEvent); s32 jiggylist_hasSpawnedObject(enum jiggy_e jiggy_id); @@ -2396,7 +2362,7 @@ void jiggylist_draw(Gfx **gfx, Mtx **mtx, Vtx **vtx); void jiggylist_map_actors(void); void jiggylist_set_level(enum map_e map_id); -// --- core2/fx/score_mumbo.c --- +// --- core2/mumboscore.c --- bool mumboscore_get(enum mumbotoken_e indx); void mumboscore_clear(void); void mumboscore_debug(void); @@ -2425,16 +2391,16 @@ void gameSelect_saveAndExit(void); void gameSelect_setGameNumber(s32 arg0); void gameSelect_resetGameNumber(void); -// --- core2/game_complete.c --- -s32 bitfield_get_bit(u8 *array, s32 index); -s32 bitfield_get_n_bits(u8 *array, s32 offset, s32 numBits); +// --- core2/flags_bitfield.c --- +s32 bitfieldarray_getBit(u8 *array, s32 index); +s32 bitfieldarray_getNBits(u8 *array, s32 offset, s32 numBits); s32 dummy_func_80320240(void); s32 dummy_func_80320248(void); s32 fileProgressFlag_getAndSet(enum file_progress_e index, s32 set); s32 func_8032056C(void); s32 func_80320708(void); -void bitfield_set_bit(u8 *array, s32 index, s32 set); -void bitfield_set_n_bits(u8 *array, s32 startIndex, s32 set, s32 length); +void bitfieldarray_setBit(u8 *array, s32 index, s32 set); +void bitfieldarray_setNBits(u8 *array, s32 startIndex, s32 set, s32 length); void fileProgressFlag_getSizeAndPtr(s32 *size, u8 **addr); void volatileFlag_getSizeAndPtr(s32 *size, u8 **addr); void fileProgressFlag_set(enum file_progress_e index, s32 set); @@ -2490,14 +2456,14 @@ void sky_free(void); void sky_reset(void); void sky_update(void); -// --- core2/gfx/displaylistdata.c --- +// --- (data declarations - origin unknown) --- void func_8030C180(void); void func_8030C1A0(void); void func_8030C204(void); void func_8030C2D4(Gfx **gdl, Mtx **mptr, Vtx **vptr); -void scissorBox_setSmall(void); +void picturebox_setScissorBox(void); -// --- core2/gfx/displaylistinit.c --- +// --- core2/displaylist_init.c --- void func_80315084(Gfx **gfx, Mtx **mtx, Vtx **vtx); void func_80315110(Gfx **gfx, Mtx **mtx, Vtx **vtx); void func_803151D0(Gfx **gfx, Mtx **mtx, Vtx **vtx); @@ -2513,14 +2479,11 @@ void func_803411B0(void); void func_80341A54(void); void glspline_defrag(void); -// --- core2/level/lightconfig.c --- -// code35520_getDistanceVectors and code35520_selectTable are declared in core2/core2.h - // --- core2/level/metadata.c --- int barebound_set_active(s32 arg0); s32 barebound_802987B4(void); -// --- core2/level/specificflags.c --- +// --- core2/level/levelspecificflags.c --- s32 levelSpecificFlags_getN(s32 i, s32 n); s32 levelSpecificFlags_getSet(s32 arg0, s32 arg1); s32 levelSpecificFlags_validateCRC1(void); @@ -2528,7 +2491,7 @@ s32 levelSpecificFlags_validateCRC2(void); void levelSpecificFlags_clear(void); void levelSpecificFlags_setN(s32 index, s32 val, s32 n); -// --- core2/load_zone.c --- +// --- core2/map/loadzone.c --- void codeA960_forceLoadzone(s32); void func_80291910(void); void func_802919A0(void); @@ -2547,11 +2510,7 @@ void func_8034B9BC(s32 arg0); void func_8034B9E4(void); void func_8034BA7C(enum map_e map_id, s32 exit_id); -// --- core2/map/model.c --- -// NOTE: func_802E76B0, collisionList_func_802E805C, func_802E8E88, func_802E9118, -// func_802E92AC, func_802E9DD8 return BKCollisionTriangle* but have conflicting -// local externs (bool/s32/void) in decomp source files. Files that need -// the pointer type already have correct local externs. +// --- core2/map/mapModel.c --- BKCollisionTriangle *func_802E76B0(BKCollisionList *collisionList, BKVertexList *vertexList, f32 startPoint[3], f32 endPoint[3], f32 arg4[3], u32 flagFilter); Vec3fArray *func_803097A0(void); BKCollisionTriangle *func_80309B48(f32 startPoint[3], f32 endPoint[3], f32 arg2[3], u32 flagFilter); @@ -2568,26 +2527,25 @@ void mapModel_opa_draw(Gfx **gfx, Mtx **mtx, Vtx **vtx); void mapModel_setEnvColor(s32 r, s32 g, s32 b); void mapModel_xlu_draw(Gfx **gfx, Mtx **mtx, Vtx **vtx); -// --- core2/map/savestate.c --- +// --- core2/map/mapsavestate.c --- int game_is_frozen(void); // --- core2/map/gsworld.c --- -enum map_e gsworld_getMap(void); -// --- core2/map/specificflags.c --- +// --- core2/map/mapspecificflags.c --- s32 mapSpecificFlags_validateCRC1(void); u32 mapSpecificFlags_getClear(s32 i); u32 mapSpecificFlags_getN(s32 idx, s32 n); void mapSpecificFlags_clearAll(void); void mapSpecificFlags_setN(s32 idx, s32 val, s32 n); -// --- core2/map_list.c --- +// --- core2/map/list.c --- void func_8029A47C(s32 arg0[3]); void func_8029A4D0(void); void func_8029A54C(void); void func_8029A554(void); -// --- core2/model/matrixrotate.c --- +// --- core2/fx/projectile_system.c --- void func_8033F9C0(void); void func_8033FA24(void); @@ -2596,21 +2554,21 @@ void func_8033F738(ActorMarker *arg0); void func_8033F784(ActorMarker *arg0); void func_8033F7A4(ActorMarker *arg0, BKVertexList *arg1); -// --- core2/model/render.c --- +// --- core2/model/modelRender.c --- void modelRender_setBoneTransformList(BoneTransformList *arg0); // --- core2/model/rendernormal.c --- void animVerticesList_transform(BKAnimVerticesList *arg0, BKVertexList *arg1, AnimMtxList *mtx_list); -// --- core2/mumbo_transforms.c --- +// --- core2/mumbo.c --- void chmumbo_func_802D1724(void); void func_802D2CB8(void); void func_802D2CDC(void); -// --- core2/overlay.c --- +// --- core2/map/overlay.c --- // leveloverlay_* functions are declared in core2/core2.h -// --- core2/particle/bathroom.c --- +// --- MMM/bathroom_particles.c --- void func_8029ADA8(void); void func_8029ADCC(void); void func_8029AE1C(void); @@ -2618,7 +2576,7 @@ void func_8029AE48(void); void func_8029AE74(s32 arg0); void func_8029AF1C(void); -// --- core2/particle/colordefault.c --- +// --- core2/particle/dustemitter.c --- bool dustEmitter_isActive(s32 arg0); s32 dustEmitter_returnGiven(s32 arg0); void dustEmitter_init(void); @@ -2653,14 +2611,11 @@ void partEmitMgr_draw(Gfx **gdl, Mtx **mptr, Vtx **vptr); void partEmitMgr_drawPass0(Gfx **gdl, Mtx **mptr, Vtx **vptr); void partEmitMgr_drawPass1(Gfx **gdl, Mtx **mptr, Vtx **vptr); void partEmitMgr_free(void); -void partEmitMgr_freeEmitter(ParticleEmitter *self); void partEmitMgr_init(void); void partEmitMgr_update(void); void particleEmitter_draw(ParticleEmitter *self, Gfx **gdl, Mtx **mPtr, Vtx **vPtr); void particleEmitter_emitUniformLine(ParticleEmitter *self, f32 start[3], f32 end[3], s32 count); void particleEmitter_free(ParticleEmitter *self); -void particleEmitter_func_802EFA78(ParticleEmitter *self, s32 arg1); -void particleEmitter_setParticleCallback(ParticleEmitter *self, void (*arg1)(ParticleEmitter *self, f32 pos[3])); // --- core2/bs/player_spawn.c --- bool func_8029BDE8(void); @@ -2693,7 +2648,7 @@ void func_8029C5E8(void); void func_8029C674(void); void func_8029C6D0(void); void func_8029C748(void); -void func_8029C7F4(s32 arg0, s32 yaw_state, s32 arg2, s32 arg3); +void code_14420_setUpdateTypes(enum baanim_update_type_e arg0, enum yaw_state_e yaw_state, s32 arg2, BaPhysicsType arg3); void code_14420_setVoidOutLocation(enum map_e map_id, s32 exit_id); void func_8029C848(AnimCtrl *arg0); void func_8029C984(void); @@ -2738,7 +2693,7 @@ void func_802F4200(f32 arg0[3]); void func_802F422C(void); void func_802F4250(void); -// --- core2/cutscene_triggers.c --- +// --- core2/map/cutscene_triggers.c --- void func_803223AC(void); void func_80322490(void); void func_803224FC(void); @@ -2755,21 +2710,21 @@ bool player_isActive(void); bool player_isFallTumbling(void); bool player_isInRBB(void); bool player_isSwimming(void); -int can_dive(void); -int can_feathery_flap(void); -int can_peck(void); -int can_view_first_person(void); -int func_8028ABB8(void); -int func_8028ADB4(void); -int func_8028B394(void); -int func_8028B4C4(void); -int func_8028B528(void); -int player_isOnDangerousGround(void); -int player_isSliding(void); -int player_isStable(void); -int player_shouldFall(void); -int player_shouldSlideTrot(void); -int wishyWashyFlag_get(void); +bool can_dive(void); +bool can_feathery_flap(void); +bool can_peck(void); +bool can_view_first_person(void); +bool func_8028ABB8(void); +bool func_8028ADB4(void); +bool func_8028B394(void); +bool func_8028B4C4(void); +bool func_8028B528(void); +bool player_isOnDangerousGround(void); +bool player_isSliding(void); +bool player_isStable(void); +bool player_shouldFall(void); +bool player_shouldSlideTrot(void); +bool wishyWashyFlag_get(void); s32 can_beak_barge(void); s32 can_beak_bomb(void); s32 can_beak_bust(void); @@ -2784,12 +2739,12 @@ s32 func_8028B120(void); void func_8028B6FC(void); void func_8028B71C(void); -// --- core2/actor_gameover.c --- +// --- core2/gc/gameoversign.c --- void func_802DC528(NodeProp *arg0, ActorMarker *arg1); void func_802DC560(NodeProp*, ActorMarker*); void func_802DC604(Gfx **gfx, Mtx **mtx, Vtx **vtx); -// --- core2/level_transition.c --- +// --- core2/gc/transition.c --- int func_8032190C(void); enum level_e level_get(void); void func_803216D0(enum map_e map); @@ -2797,7 +2752,7 @@ void func_80321854(void); void func_80321918(int arg0); void func_80321924(void); -// --- core2/quiz/bitfield.c --- +// --- core2/quiz/quizquestionaskedbitfield.c --- void quizQuestionAskedBitfield_defrag(void); void quizQuestionAskedBitfield_free(void); void quizQuestionAskedBitfield_init(void); @@ -2931,15 +2886,15 @@ void func_8034F734(void); void func_8034F774(void); void func_8034F918(void); -// --- core2/snacker_pool1.c --- +// --- core2/scorequeue/queue_collectibles.c --- bool func_802FBE04(void); void func_802FBB18(void); void func_802FBDFC(void); -// --- core2/snacker_pool2.c --- +// --- core2/scorequeue/queue_major_items.c --- bool func_802FC390(void); -// --- core2/spawn_queue.c --- +// --- core2/spawnqueue.c --- void spawnQueue_flush(void); void spawnQueue_free(void); void spawnQueue_func_802C3A18(void); @@ -2950,7 +2905,7 @@ void spawnQueue_unlock(void); // --- core2/spline_bezier.c --- -// --- core2/sprite/displaydata.c --- +// --- core2/fx/commonParticle.c --- s32 func_8033E8AC(void); u8 func_8033E93C(void); void commonParticle_init(void); @@ -3020,9 +2975,7 @@ void itemscore_noteScores_setLevel(enum level_e level, s32 score); void saveditem_getSizeAndPtr(s32 *size, u8 **buffer); void timeScores_getSizeAndPtr(s32 *size, void **ptr); -// --- core2/texture/copy.c --- - -// --- core2/timed_funcqueue.c --- +// --- core2/timedfuncqueue.c --- void func_80324C58(void); void func_80324DBC(f32 time, enum asset_e text_id, s32 arg2, f32 position[3], ActorMarker *caller, void (*callback_method_1)(ActorMarker *, enum asset_e, s32), void (*callback_method_2)(ActorMarker *, enum asset_e, s32)); void timedFuncQueue_defrag(void); @@ -3039,9 +2992,7 @@ void func_8034BF54(ActorMarker *marker); void func_8034BFF8(ActorMarker *marker); void func_8034C21C(ActorMarker *marker); -// --- core2/vtx/lighting.c --- -void lighting_free(); -void lighting_init(); +// --- core2/vtx/gclights.c --- void lightingVectorList_fromFile(File *file_ptr); // --- core2/vtx/listutils.c --- @@ -3065,20 +3016,13 @@ void func_8034C8D8(void); void func_8034C97C(void); void func_8034C9B0(int arg0); -// --- core2/vtx/list.c --- - -// --- core2/yaw.c --- -void yaw_init(void); -void yaw_setUpdateState(s32 arg0); -void yaw_update(void); - -// --- cutscenes/actor_spawninit.c --- +// --- cutscenes/cutscenesspawnqueue.c --- void cutscene_func_8038C4E0(void); -// --- FINALE/fight.c --- +// --- fight/fight.c --- void fight_addSpawnableActors(void); -// --- lair/actor_spawninit.c --- +// --- lair/lairspawnqueue.c --- void lair_func_8038A0C4(void); // --- lair/ch/brentilda.c --- @@ -3093,7 +3037,7 @@ void ff_init(void); void lair_func_8038E0B0(void); void lair_func_8038E768(Gfx **dl, Mtx **m, Vtx **v); -// --- LAIR/jigsawpicture.c --- +// --- lair/jigsawpicture.c --- bool jigsawPicture_isJigsawPictureComplete(s32 arg0); // --- port/stub.c --- @@ -3107,10 +3051,10 @@ void osSpTaskYield(void); void osStartThread(OSThread* thread); void osStopThread(OSThread* t); -// --- unmapped (definition not found in src/) --- +// --- provided by libultraship --- s32 osPiReadIo(u32, u32 *); -// --- core2/ba/ba_stick.c --- +// --- core2/ba/bastick.c --- s32 bastick_getZone(void); // --- core2/ba/ba_lookdir.c --- @@ -3125,7 +3069,7 @@ void particleEmitter_manualFree(ParticleEmitter *self); // --- core2/anim/anim_bonetransform.c --- void func_8033BD20(void **arg0); -// --- core2/timed_funcqueue.c --- +// --- core2/timedfuncqueue.c --- bool timedFuncQueue_is_empty(void); // --- core2/fx/effect_colordata.c --- @@ -3152,13 +3096,13 @@ bool func_80245524(f32 arg0[3], void *arg1, intptr_t *arg2, f32 *arg3); // --- core2/bs/player_spawn.c --- void func_8029BC60(enum asset_e *anim_id, f32 *anim_duration); -// --- core2/frame/bufferreadback.c --- +// --- core2/frame/rendermem.c --- s32 func_802E4AD4(s32 arg0); // --- core2/sfx/instruments.c --- void func_8033543C(Struct81s *arg0); -// --- core2/model/matrixrotate.c --- +// --- core2/fx/projectile_system.c --- void func_8033F7F0(u8 indx, Gfx **gfx, Mtx **mtx, Vtx **vtx); // --- core2/spline_pathfollow.c --- @@ -3172,7 +3116,7 @@ void func_8034CF90(void *arg0, BKModel *arg1, s32 arg2); // --- core2/vtx/renderstart.c --- void setStruct6DsOpacity(Struct6Ds *arg0, s32 arg1); -// --- core2/anim/anim_cache.c --- +// --- core2/anim/animcache.c --- int animCache_getBoneTransformList(s16 index, BoneTransformList **arg1); // --- core2/anim/bonetransformlist.c --- @@ -3191,7 +3135,7 @@ bool chCollectible_collectRedFeather(ActorProp *arg0); bool chNipper_isInState7(s16 arg0[3]); // --- core2/actor_cubepropsystem.c --- -s32 codeA5BC0_getPositionAndReturnRadius(void *arg0, s32 arg1[3]); +s32 codeA5BC0_getPositionAndSelectorOrRadius(void *arg0, s32 arg1[3]); // --- core2/gamestate.c --- void itemscore_timeScores_fromSaveData(u16 *savedata); @@ -3201,25 +3145,23 @@ int savedata_8033CE40(void *buffer); int savedata_8033CC98(s32 filenum, void *buffer); void savedata_clear(void *savedata); -// --- core2/spawn_queue.c --- +// --- core2/spawnqueue.c --- void spawnQueue_defrag(void); -void bkmemcpy64(void *dest, void *src, s32 size); // handwritten assembly code that performs an optimized 8 byte memcpy -void bkmemset64(void *dest, s32 value, s32 size); // handwritten assembly code that performs an optimized 8 byte memset -u32 bkGetSR(void); // handwritten assembly code that replicates the __osGetSR function +// --- port/MemShims.c --- +void bkmemcpy64(void *dest, void *src, s32 size); +void bkmemset64(void *dest, s32 value, s32 size); + +// --- port/stub.c --- +u32 bkGetSR(void); // --- RBB/ch/engineparts.c --- f32 func_8038A6B8(ActorMarker *); -// --- core1/io/ba_motor.c --- +// --- core1/bamotor.c --- void baMotor_80250D94(f32, f32, f32); void baMotor_80250E94(f32, f32, f32, f32, f32, f32); -// --- core1/io/pfsmanager.c --- -OSContPad *func_8024F3F4(void); -OSMesgQueue *pfsManager_getFrameReplyQ(void); -void controller_copyFaceButtons(s32, s32 [6]); - // --- core1/memory.c --- void * bk_malloc(size_t size); void *bk_realloc(void* ptr, size_t size); @@ -3234,16 +3176,16 @@ void *assetcache_reload(enum asset_e assetId); // --- core2/sfx/trackmanager.c --- void musicKeepsPlaying(void); -// --- core2/ba/ba_eyeblink.c --- +// --- core2/ba/iFrame.c --- void baiFrame_startWithValue(f32); -// --- core2/ba/ba_eyes.c --- +// --- core2/ba/baeyes.c --- void baeyes_openSingleEye(s32, f32); -// --- core2/ba/ba_falldamage.c --- +// --- core2/ba/falldamage.c --- void bafalldamage_start(void); -// --- core2/ba/ba_flag.c --- +// --- core2/ba/baflag.c --- bool baflag_isFalse(enum misc_flag_e arg0); bool baflag_isTrue(enum misc_flag_e arg0); void baflag_clear(enum misc_flag_e arg0); @@ -3255,43 +3197,40 @@ void baflag_toggle(enum misc_flag_e arg0); f32 func_802915D8(void); f32 func_80291604(void); -// --- core2/ba/ba_key.c --- +// --- core2/ba/bakey.c --- int bakey_pressed(s32); u32 bakey_held(s32); -// --- core2/ba/ba_marker.c --- +// --- core2/ba/marker.c --- ActorMarker *baMarker_get(void); -// --- core2/ba/ba_model.c --- +// --- core2/ba/model.c --- f32 baModel_80292230(void); void baModel_80291A50(s32 arg0, f32* arg1); void baModel_80292078(s32, f32); void baModel_80292158(f32); -// --- core2/ba/ba_physics.c --- +// --- core2/ba/physics.c --- f32 get_slope_timer(void); -void baphysics_get_velocity(f32 dst[3]); -void baphysics_reset_gravity(void); -void baphysics_set_gravity(f32 gravity); -// --- core2/ba/ba_position.c --- -f32 player_getYPosition(void); -void _player_getPosition(f32 dst[3]); +// --- core2/ba/playerposition.c --- +f32 playerPosition_getY(void); +void playerPosition_get(f32 dst[3]); void playerPosition_addY(f32); -void player_setYPosition(f32); +void playerPosition_setY(f32); // --- core2/ba/ba_recoil.c --- f32 get_turbo_duration(void); void func_80294980(f32 arg0[3]); -// --- core2/ba/ba_sfx.c --- +// --- core2/ba/basfx.c --- void basfx_80299CF4(enum sfx_e, f32, s32); void basfx_80299D2C(enum sfx_e, f32, s32); void basfx_playJumpSfx(f32, f32); void basfx_playOwSfx(f32); void basfx_updateClockSfxSource(f32, f32); -// --- core2/ba/ba_stick.c --- +// --- core2/ba/bastick.c --- f32 bastick_distance(void); f32 bastick_getAngleRelativeToBanjo(void); f32 bastick_getY(void); @@ -3317,7 +3256,7 @@ void bs_setState(s32 state_id); void bs_updateState(void); void bs_setInterruptResponse(s32 arg0); -// --- core2/bs/bs_storedstate.c --- +// --- core2/bs/bsStoredState.c --- f32 bsStoredState_getLongLegTimer(void); f32 bsStoredState_getTurboTimer(void); void bsStoredState_setLongLegTimer(f32); @@ -3327,19 +3266,19 @@ void bsStoredState_setTurboTimer(f32); // --- core2/bs/walk.c --- f32 func_802B6F9C(void); -// --- core2/camera/camera_motor2.c --- +// --- core2/nc/camera_motor2.c --- void func_802BB3DC(s32, f32, f32); -// --- core2/camera/dynamicCam3.c --- +// --- core2/nc/dynamicCam3.c --- void func_802C1B20(f32); -// --- core2/camera/dynamicCamD.c --- -void ncDynamicCamD_func_802BF2C0(f32); +// --- core2/nc/die.c --- +void ncbadie_func_802BF2C0(f32); // --- core2/climb.c --- -f32 climbGetBottomY(void); -f32 climbGetTopY(void); -void climbGetBottom(f32 dst[3]); +f32 climb_getBottomY(void); +f32 climb_getTopY(void); +void climb_getBottom(f32 dst[3]); // --- core2/scorequeue/manager.c --- void func_802FAD64(enum item_e); @@ -3347,25 +3286,25 @@ void func_802FAD64(enum item_e); // --- core2/collision/hitboxdata.c --- enum marker_collision_func_type_e collision_getNextState(CollisionParams *arg0); -// --- core2/fx/airscore.c --- +// --- core2/scorequeue/airscore.c --- struct7s *fxairscore_new(s32); void fxairscore_draw(enum item_e, struct8s *, Gfx**, Mtx**, Vtx **); void fxairscore_free(s32, struct7s *); void fxairscore_update(enum item_e, struct7s *); -// --- core2/fx/common1score.c --- +// --- core2/scorequeue/common1score.c --- struct7s *fxcommon1score_new(enum asset_e item_id); void fxcommon1score_draw(enum item_e arg0, struct8s *arg1, Gfx **arg2, Mtx **arg3, Vtx **arg4); void fxcommon1score_free(enum item_e item_id, struct8s *); void fxcommon1score_update(enum item_e, struct8s *); -// --- core2/fx/common2score.c --- +// --- core2/scorequeue/common2score.c --- struct8s *fxcommon2score_new(enum item_e); void fxcommon2score_draw(enum item_e, struct8s *, Gfx**, Mtx**, Vtx **); void fxcommon2score_free(enum item_e, struct8s *); void fxcommon2score_update(s32, struct8s *); -// --- core2/fx/common3score.c --- +// --- core2/scorequeue/common3score.c --- void *fxcommon3score_new(enum item_e); void fxcommon3score_draw(enum item_e, void *, Gfx**, Mtx**, Vtx **); void fxcommon3score_free(enum item_e item_id, void *); @@ -3384,34 +3323,34 @@ void func_802927E0(f32, f32); void func_80292900(f32, f32); void func_80292974(f32, f32, f32); -// --- core2/fx/effect_spriteanim.c --- +// --- core2/fx/banjokazooiesign.c --- Actor *func_802DC7E0(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx); -// --- core2/fx/healthscore.c --- +// --- core2/scorequeue/healthscore.c --- struct7s *fxhealthscore_new(enum item_e); void fxhealthscore_draw(enum item_e item_id, struct8s *arg1, Gfx **gfx, Mtx **mtx, Vtx **vtx); void fxhealthscore_free(enum item_e, struct8s *); void fxhealthscore_update(enum item_e, struct8s *); -// --- core2/fx/honeycarrierscore.c --- +// --- core2/scorequeue/honeycarrierscore.c --- struct7s *fxhoneycarrierscore_new(s32); void fxhoneycarrierscore_draw(s32, struct8s *, Gfx**, Mtx**, Vtx **); void fxhoneycarrierscore_free(s32, struct8s *); void fxhoneycarrierscore_update(s32, struct8s *); -// --- core2/fx/jinjoscore.c --- +// --- core2/scorequeue/jinjoscore.c --- struct8s *fxjinjoscore_new(enum item_e); void fxjinjoscore_draw(s32, struct8s *, Gfx**, Mtx**, Vtx **); void fxjinjoscore_free(enum item_e, struct8s *); void fxjinjoscore_update(enum item_e, struct8s *); -// --- core2/fx/lifescore.c --- +// --- core2/scorequeue/lifescore.c --- struct8s *fxlifescore_new(s32); void fxlifescore_draw(enum item_e, struct8s *, Gfx**, Mtx**, Vtx **); void fxlifescore_free(s32, struct8s *); void fxlifescore_update(enum item_e, struct8s *); -// --- core2/fx/score_jiggylist.c --- +// --- core2/fx/effect_jiggy_list.c --- void jiggy_spawn(enum jiggy_e jiggy_id, f32 pos[3]); // --- core2/fx/sparkle.c --- @@ -3429,7 +3368,7 @@ f32 barebound_get_vertical_velocity(void); f32 barebound_get_horizontal_velocity(void); f32 barebound_get_gravity(void); -// --- core2/particle/bathroom.c --- +// --- MMM/bathroom_particles.c --- void func_8029AD28(f32, s32); // --- core2/bs/player_spawn.c --- @@ -3451,7 +3390,7 @@ void pitch_setIdeal(f32); // --- core2/playerutils.c --- bool func_8028AED4(f32*, f32); -int player_inWater(void); +bool player_inWater(void); // --- core2/roll.c --- f32 roll_get(void); @@ -3474,7 +3413,7 @@ struct3s *func_802F8264(s32 arg0); // --- core2/fx/projectile_anim.c --- void func_80352CF4(f32 *, f32 *, f32, f32); -// --- core2/timed_funcqueue.c --- +// --- core2/timedfuncqueue.c --- void func_80324D2C(f32, enum comusic_e); void func_80324D54(f32, enum sfx_e, f32, s32, f32 [3], f32, f32); void func_80324E38(f32, s32); @@ -3482,7 +3421,7 @@ void timed_exitStaticCamera(f32 time); void timed_playSfx(f32, enum sfx_e, f32, s32); void timed_setStaticCameraToNode(f32, s32); -// --- core2/vector.c --- +// --- core2/vla.c --- VLA * bk_vector_defrag(VLA *vla); VLA * bk_vector_new(u32 elemSize, u32 cnt); s32 bk_vector_getIndex(VLA *vla, void *element); @@ -3517,22 +3456,25 @@ Struct70s *func_8034C528(s32); Struct70s *func_8034C5AC(s32); s16 func_8034C50C(Struct70s *arg0); -// --- core2/yaw.c --- -f32 yaw_get(void); -f32 yaw_getIdeal(void); -void yaw_applyIdeal(void); -void yaw_rotateTimed(f32); -void yaw_set(f32); -void yaw_setIdeal(f32); -void yaw_setVelocityBounded(f32, f32); - // --- port/stub.c --- float gu_sqrtf(float val); -// --- unknown source (no .c definition found) --- -void _guMtxIdentF_80245D44(float mf[4][4]); //static should NOT be here -void func_80241304(Mtx *m, float x, float y, float z); -BKModelBin * marker_loadModelBin(ActorMarker *marker); +// --- GV/gv_helpers.c --- +void rubeeEggPot_addedEggToPot(void); +s32 rubeeEggPot_getEggGoal(void); + +// --- core2/frame/auxbuffer.c --- +void picturebox_init(void); +void picturebox_free(void); +void picturebox_func_8030C180(void); +void picturebox_resetScissorBoxAndFramebuffer(Gfx **gfx, Mtx **mtx, Vtx **vtx); + +// --- core2/actor_cubepropsystem.c --- +void core2_A5BC0_drawUnknownMarkers(Gfx **gfx, Mtx **mtx, Vtx **vtx); + +// --- core2/crc_bootvalidation.c --- +void codeCF5F0_init(void); +void codeCF5F0_triggerAntiTamperMeasurement(void); #ifdef __cplusplus } diff --git a/include/gc/gctransition.h b/include/gc/gctransition.h index 97988bfe1..d196963df 100644 --- a/include/gc/gctransition.h +++ b/include/gc/gctransition.h @@ -6,7 +6,7 @@ extern "C" { #endif void gctransition_defrag(void); -void gctransition_draw(Gfx **arg0, Mtx **arg1, Vtx **arg2); +void gctransition_draw(Gfx **gfx, Mtx **mtx, Vtx **vtx); void gctransition_8030BD4C(void); f32 gctransition_8030BD88(void); int gctransition_done(void); diff --git a/include/prop.h b/include/prop.h index c51c5c7d9..d61bfbe0f 100644 --- a/include/prop.h +++ b/include/prop.h @@ -58,6 +58,8 @@ typedef struct model_prop_s{ u8 padB_3 :4; } ModelProp; +#define MODEL_ASSET_OFFSET 0x2D1 + // [port] On N64 the marker pointer is 4 bytes, so words[3] (12 bytes) covers // the entire struct. On 64-bit, the pointer is 8 bytes (16 bytes total). @@ -124,7 +126,7 @@ typedef struct actorMarker_s{ u32 unk40_22:1; u32 unk40_21:1; u32 unk40_20:1; - u32 unk40_19:1; + u32 unk40_19:1; // set for screen overlay sprites u32 pad40_18:19; Vec3fArray * unk44; BKModel * unk48; diff --git a/src/BGS/actor_spawninit.c b/src/BGS/bgsspawnqueue.c similarity index 91% rename from src/BGS/actor_spawninit.c rename to src/BGS/bgsspawnqueue.c index 833a7235c..2d2245391 100644 --- a/src/BGS/actor_spawninit.c +++ b/src/BGS/bgsspawnqueue.c @@ -1,4 +1,4 @@ -// BanjoDecomp: code_8DF0.c +// BanjoDecomp: BGS/bgsspawnqueue.c #include #include "functions.h" #include "variables.h" @@ -13,7 +13,7 @@ extern ActorInfo chPinkEggMedium; extern ActorInfo chPinkEggSmall; extern ActorInfo chPinkEggSmallest; extern ActorInfo chMudHut; -extern ActorInfo chTanktup; +extern ActorInfo gChTanktup; extern ActorInfo gChTanktupLegFrontLeft; extern ActorInfo gChTanktupLegBackLeft; extern ActorInfo gChTanktupLegFrontRight; @@ -23,7 +23,7 @@ extern ActorInfo gChYellowFlibbit; extern ActorInfo D_80390960; extern ActorInfo gChYumblie; extern ActorInfo gChVile; -extern ActorInfo chTiptup; +extern ActorInfo gChTiptup; extern ActorInfo chChoirTurtleYellow; extern ActorInfo chChoirTurtleCyan; extern ActorInfo chChoirTurtleBlue; @@ -35,7 +35,7 @@ extern ActorInfo chLargeCrocodile; extern ActorInfo chLongSwampSwitch; extern ActorInfo chShortSwampSwitch; -void BGS_func_8038F1E0(void){//bgs_updateSpawnableActors +void bgs_updateSpawnableActors(void){//bgs_updateSpawnableActors spawnableActorList_add(&gChCroctus, actor_new, ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_3);//croctus spawnableActorList_add(&gChFlibbit, actor_new, ACTOR_FLAG_UNKNOWN_25 | ACTOR_FLAG_UNKNOWN_16 | ACTOR_FLAG_UNKNOWN_11 | ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_5 | ACTOR_FLAG_UNKNOWN_0); //flibbit spawnableActorList_add(&chPinkEggLargest, actor_new, ACTOR_FLAG_UNKNOWN_10); //pink_egg_largest @@ -44,7 +44,7 @@ void BGS_func_8038F1E0(void){//bgs_updateSpawnableActors spawnableActorList_add(&chPinkEggSmall, actor_new, ACTOR_FLAG_UNKNOWN_10); //pink_egg_small spawnableActorList_add(&chPinkEggSmallest, actor_new, ACTOR_FLAG_UNKNOWN_10); //pink_egg_smallest spawnableActorList_add(&chMudHut, actor_new, ACTOR_FLAG_NONE); //mudhut_top - spawnableActorList_add(&chTanktup, actor_new, ACTOR_FLAG_UNKNOWN_26 | ACTOR_FLAG_UNKNOWN_10 | ACTOR_FLAG_UNKNOWN_8 | ACTOR_FLAG_UNKNOWN_6 | ACTOR_FLAG_UNKNOWN_3);//tanktup + spawnableActorList_add(&gChTanktup, actor_new, ACTOR_FLAG_UNKNOWN_26 | ACTOR_FLAG_UNKNOWN_10 | ACTOR_FLAG_UNKNOWN_8 | ACTOR_FLAG_UNKNOWN_6 | ACTOR_FLAG_UNKNOWN_3);//tanktup spawnableActorList_add(&gChTanktupLegFrontLeft, actor_new, ACTOR_FLAG_UNKNOWN_26 | ACTOR_FLAG_UNKNOWN_10 | ACTOR_FLAG_UNKNOWN_5 | ACTOR_FLAG_UNKNOWN_3 | ACTOR_FLAG_UNKNOWN_2);//tanktup_leg spawnableActorList_add(&gChTanktupLegBackLeft, actor_new, ACTOR_FLAG_UNKNOWN_26 | ACTOR_FLAG_UNKNOWN_10 | ACTOR_FLAG_UNKNOWN_5 | ACTOR_FLAG_UNKNOWN_3 | ACTOR_FLAG_UNKNOWN_2);//tanktup_leg spawnableActorList_add(&gChTanktupLegFrontRight, actor_new, ACTOR_FLAG_UNKNOWN_26 | ACTOR_FLAG_UNKNOWN_10 | ACTOR_FLAG_UNKNOWN_5 | ACTOR_FLAG_UNKNOWN_3 | ACTOR_FLAG_UNKNOWN_2);//tanktup_leg @@ -54,7 +54,7 @@ void BGS_func_8038F1E0(void){//bgs_updateSpawnableActors spawnableActorList_add(&D_80390960, actor_new, ACTOR_FLAG_NONE); spawnableActorList_add(&gChYumblie, actor_new, ACTOR_FLAG_UNKNOWN_11 | ACTOR_FLAG_UNKNOWN_7); //yumblie spawnableActorList_add(&gChVile, actor_new, ACTOR_FLAG_UNKNOWN_11 | ACTOR_FLAG_UNKNOWN_8 | ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_5 | ACTOR_FLAG_UNKNOWN_1); //mr. vile - spawnableActorList_add(&chTiptup, actor_new, ACTOR_FLAG_UNKNOWN_11 | ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_3 ); //tiptup + spawnableActorList_add(&gChTiptup, actor_new, ACTOR_FLAG_UNKNOWN_11 | ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_3 ); //tiptup spawnableActorList_add(&chChoirTurtleYellow, actor_new, ACTOR_FLAG_UNKNOWN_11 | ACTOR_FLAG_UNKNOWN_8 | ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_5 | ACTOR_FLAG_UNKNOWN_3 ); //tiptup_chiorMember spawnableActorList_add(&chChoirTurtleCyan, actor_new, ACTOR_FLAG_UNKNOWN_11 | ACTOR_FLAG_UNKNOWN_8 | ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_5 | ACTOR_FLAG_UNKNOWN_3 ); //tiptup_chiorMember spawnableActorList_add(&chChoirTurtleBlue, actor_new, ACTOR_FLAG_UNKNOWN_11 | ACTOR_FLAG_UNKNOWN_8 | ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_5 | ACTOR_FLAG_UNKNOWN_3 ); //tiptup_chiorMember diff --git a/src/BGS/bss_pad.c b/src/BGS/bss_pad.c deleted file mode 100644 index cc6b75e24..000000000 --- a/src/BGS/bss_pad.c +++ /dev/null @@ -1,2 +0,0 @@ -// BanjoDecomp: bss_pad.c -char pad_BGS_D_80391230[0x10]; diff --git a/src/BGS/ch/choir_turtle.c b/src/BGS/ch/choirturtle.c similarity index 95% rename from src/BGS/ch/choir_turtle.c rename to src/BGS/ch/choirturtle.c index 6c358bcb3..fe30576bc 100644 --- a/src/BGS/ch/choir_turtle.c +++ b/src/BGS/ch/choirturtle.c @@ -1,4 +1,4 @@ -// BanjoDecomp: code_3030.c +// BanjoDecomp: BGS/ch/choirturtle.c #include #include "functions.h" #include "variables.h" @@ -62,7 +62,7 @@ void chChoirTurtle_ow2(ActorMarker *marker, ActorMarker *other_marker){ } Actor *chChoirTurtle_draw(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx) { - func_8033A45C(4, marker->id - 0x19A); + modelRender_setAppendageVisibility(4, marker->id - 0x19A); return actor_draw(marker, gfx, mtx, vtx); } @@ -96,7 +96,7 @@ void chChoirTurtle_update(Actor *this) { } } if (this->state == 1) { - if (local->tiptup_marker != NULL && (func_80388E70(local->tiptup_marker) == local->unk0)) { + if (local->tiptup_marker != NULL && (chTiptup_getUnkB(local->tiptup_marker) == local->unk0)) { chChoirTurtle_setState(this, 2); } } diff --git a/src/BGS/ch/croctus.c b/src/BGS/ch/croctus.c index c7a0d520d..cd1db93c0 100644 --- a/src/BGS/ch/croctus.c +++ b/src/BGS/ch/croctus.c @@ -1,4 +1,4 @@ -// BanjoDecomp: croctus.c +// BanjoDecomp: BGS/ch/croctus.c #include #include "functions.h" #include "variables.h" @@ -8,23 +8,24 @@ // Anchor: set while replaying a teammate's feed; suppresses camera/dialog + rebroadcast. static s32 sCroctusRemote = 0; -extern s32 func_80328748(AnimCtrl *, f32, f32); +extern void func_80328748(AnimCtrl *, f32, f32); extern void func_8028F94C(s32, f32[3]); extern void func_80324CFC(f32, enum comusic_e, s32); extern void func_803289EC(Actor *, f32, s32); extern void func_80326310(Actor *); extern void actor_setOpacity(Actor *, s32); +extern void __spawnQueue_add_2(void (*)(s32, s32), s32, s32); extern void gcStaticCamera_activate(s32 arg0); - - void func_80387D18(ActorMarker *, u32); Actor *chCroctus_draw(ActorMarker *, Gfx**, Mtx **, Vtx**); -void chCroctus_updat(Actor *this); +void chCroctus_update(Actor *this); /* .data */ s16 D_803907B0[4] = {0x15, 0x16, 0x17, 0x18}; + ActorMarker *bgs_D_803907B8[5] = {NULL}; + ActorAnimationInfo chCroctusAnimations[] = { {0x000, 0.0f}, {0x14B, 3.3e+7f}, @@ -34,12 +35,23 @@ ActorAnimationInfo chCroctusAnimations[] = { {0x14B, 2.0f}, {0x14B, 2.0f} }; -ActorInfo gChCroctus ={MARKER_FC_CROCTUS, ACTOR_1FA_CROCTUS, ASSET_425_MODEL_CROCTUS, + +ActorInfo gChCroctus ={ + MARKER_FC_CROCTUS, ACTOR_1FA_CROCTUS, ASSET_425_MODEL_CROCTUS, 1, chCroctusAnimations, - chCroctus_updat, actor_update_func_80326224, chCroctus_draw, + chCroctus_update, actor_update_func_80326224, chCroctus_draw, 0, 0, 0.0f, 0 }; +enum chCroctusState { + CHCROCTUS_STATE_1_MOUTH_CLOSED = 1, + CHCROCTUS_STATE_2_MOUTH_OPENING, + CHCROCTUS_STATE_3_MOUTH_OPEN, + CHCROCTUS_STATE_4_MOUTH_CLOSING, + CHCROCTUS_STATE_5_FED, + CHCROCTUS_STATE_6_DESPAWN, +}; + /* .code */ void func_80387C90(Actor *arg0){ anctrl_setDuration(arg0->anctrl, 0.4 + 0.9999999999999999 * ((f32)(5 - arg0->actorTypeSpecificField) * 0.25)); @@ -51,7 +63,7 @@ void func_80387D18(ActorMarker * arg0, u32 arg1){ this = marker_getActor(arg0); nextActPtr = spawn_child_actor(0x6A, &this); - nextActPtr->state = 2; + nextActPtr->state = CHCROCTUS_STATE_2_MOUTH_OPENING; nextActPtr->actorTypeSpecificField = 0x8C; nextActPtr->lifetime_value = 3.0f; nextActPtr->unk38_31 = arg1; @@ -69,18 +81,17 @@ void *chCroctus_jiggySpawn(ActorMarker * arg0){ spawnPos[1] = this->position_y; spawnPos[2] = this->position_z; marker->propPtr->unk8_3 = 0; - gcStaticCamera_activate(0x19); + gcStaticCamera_activate(0x19); //related to temporary switch to fixed camera jiggy_spawn(JIGGY_22_CROCTUS, spawnPos); coMusicPlayer_playMusic(COMUSIC_2D_PUZZLE_SOLVED_FANFARE, 0x7FFF); - return NULL; } -void func_80387E00(uintptr_t arg0){ +void func_80387E00(s32 arg0){ ActorMarker *marker = reinterpret_cast(ActorMarker *, arg0); Actor * this = marker_getActor(marker); func_803262E4(this); - __spawnQueue_add_2((void (*)(void))func_80387D18, (uintptr_t)marker, 0x1E); + __spawnQueue_add_2((GenFunction_2)func_80387D18, reinterpret_cast(uintptr_t, marker), 0x1E); } void func_80387E40(ActorMarker * arg0){ @@ -89,24 +100,24 @@ void func_80387E40(ActorMarker * arg0){ if(arg0); } -void func_80387E68(ActorMarker *caller, enum asset_e text_id, s32 arg2){ +void chCroctus_activateNextCroctus(ActorMarker *caller, enum asset_e text_id, s32 arg2){ Actor *this; - if(text_id == 0xC86){ + if(text_id == VER_SELECT(ASSET_C86_DIALOG_CROCTUS_FIRST_SUCCESS, 0x9C9, 0, 0)){ this = marker_getActor(caller); timed_playSfx(0.4f, SFX_C9_PAUSEMENU_ENTER, 1.0f, 32000); timed_playSfx(1.4f, SFX_C9_PAUSEMENU_ENTER, 1.0f, 32000); func_80324CFC(0.4f, COMUSIC_43_ENTER_LEVEL_GLITTER, 22000); func_80324D2C(4.5f, COMUSIC_43_ENTER_LEVEL_GLITTER); - subaddie_set_state_with_direction(this, 5, 0.79f, 1); + subaddie_set_state_with_direction(this, CHCROCTUS_STATE_5_FED, 0.79f, 1); func_80326310(this); //did not disappear when moved, after cutscene still there with collision but broken - bgs_D_803907B8[this->actorTypeSpecificField]->propPtr->isNotFeatherEggOrNote = true; - timedFunc_set_1(1.1f, (GenFunction_1)func_80387E00, (uintptr_t)bgs_D_803907B8[this->actorTypeSpecificField]); + bgs_D_803907B8[this->actorTypeSpecificField]->propPtr->isNotFeatherEggOrNote = TRUE; + timedFunc_set_1(1.1f, (GenFunction_1)func_80387E00, reinterpret_cast(uintptr_t, bgs_D_803907B8[this->actorTypeSpecificField])); if(!sCroctusRemote){ timed_setStaticCameraToNode(0.8f, 9); - func_80324DBC(3.4f, 0xC87, 0xE, NULL, NULL, func_80387E68, NULL); + func_80324DBC(3.4f, VER_SELECT(ASSET_C87_DIALOG_CROCTUS_SECOND_SPAWN, 0x9CA, 0, 0), 0xE, NULL, NULL, chCroctus_activateNextCroctus, NULL); } - __spawnQueue_add_2((void (*)(void))func_80387D18, (uintptr_t)this->marker, 0x46); + __spawnQueue_add_2((GenFunction_2) func_80387D18, reinterpret_cast(uintptr_t, this->marker), 0x46); } else{ timed_exitStaticCamera(0.0f); @@ -114,7 +125,7 @@ void func_80387E68(ActorMarker *caller, enum asset_e text_id, s32 arg2){ } } -void chCroctus_updat(Actor *this){ +void chCroctus_update(Actor *this){ int j; if(!this->volatile_initialized){ @@ -122,12 +133,12 @@ void chCroctus_updat(Actor *this){ marker_despawn(this->marker); return; } - this->volatile_initialized = true; + this->volatile_initialized = TRUE; if(bgs_D_803907B8[this->actorTypeSpecificField - 1] == 0){ bgs_D_803907B8[this->actorTypeSpecificField - 1] = this->marker; - for(j = this->actorTypeSpecificField; j < 5; j++){ + for(j = this->actorTypeSpecificField; j < 6; j++){ if(bgs_D_803907B8[j] != NULL){ - bgs_D_803907B8[j]->propPtr->isNotFeatherEggOrNote = false; + bgs_D_803907B8[j]->propPtr->isNotFeatherEggOrNote = FALSE; actor_setOpacity(marker_getActor(bgs_D_803907B8[j]), 0); } }//L803880C8 @@ -136,10 +147,10 @@ void chCroctus_updat(Actor *this){ if(j >= 0){ - this->marker->propPtr->isNotFeatherEggOrNote = false; + this->marker->propPtr->isNotFeatherEggOrNote = FALSE; actor_setOpacity(this, 0); } - this->marker->propPtr->unk8_3 = true; + this->marker->propPtr->unk8_3 = TRUE; }//L80388144 func_803289EC(this, 0.0f, 1); this->lifetime_value = 0.0f; @@ -161,7 +172,7 @@ void chCroctus_updat(Actor *this){ } if(this->unk38_31){ - if ((this->state != 5) && (this->state != 6)) { + if ((this->state != CHCROCTUS_STATE_5_FED) && (this->state != CHCROCTUS_STATE_6_DESPAWN)) { if (!sCroctusRemote) { port_puzzleStep_orBits(ANCHOR_PUZZLE_BGS_CROCTUS, 1 << (this->actorTypeSpecificField - 1)); } @@ -172,94 +183,94 @@ void chCroctus_updat(Actor *this){ func_8028F94C(2, this->position); } if (sCroctusRemote) { - func_80387E68(this->marker, ASSET_C86_DIALOG_CROCTUS_FIRST_SUCCESS, 0); + chCroctus_activateNextCroctus(this->marker, VER_SELECT(ASSET_C86_DIALOG_CROCTUS_FIRST_SUCCESS, 0x9C9, 0, 0), 0); } else { - gcdialog_showDialog(ASSET_C86_DIALOG_CROCTUS_FIRST_SUCCESS, 0xE, this->position, this->marker, func_80387E68, NULL); + gcdialog_showDialog(VER_SELECT(ASSET_C86_DIALOG_CROCTUS_FIRST_SUCCESS, 0x9C9, 0, 0), 0xE, this->position, this->marker, chCroctus_activateNextCroctus, NULL); } - subaddie_set_state_with_direction(this, 6, 0.79f, 1); + subaddie_set_state_with_direction(this, CHCROCTUS_STATE_6_DESPAWN, 0.79f, 1); } else { timed_playSfx(0.4f, SFX_C9_PAUSEMENU_ENTER, 1.0f, 32000); timed_playSfx(1.4f, SFX_C9_PAUSEMENU_ENTER, 1.0f, 32000); func_80324CFC(0.4f, COMUSIC_43_ENTER_LEVEL_GLITTER, 22000); func_80324D2C(4.5f, COMUSIC_43_ENTER_LEVEL_GLITTER); - subaddie_set_state_with_direction(this, 5, 0.79f, 1); + subaddie_set_state_with_direction(this, CHCROCTUS_STATE_5_FED, 0.79f, 1); if (this->actorTypeSpecificField == 5) { - timedFunc_set_1(0.9f, (GenFunction_1) func_80387E40, (uintptr_t)this->marker); + timedFunc_set_1(0.9f, (GenFunction_1) func_80387E40, reinterpret_cast(uintptr_t, this->marker)); } else { func_80326310(this); } if (this->actorTypeSpecificField < 5) { - bgs_D_803907B8[this->actorTypeSpecificField]->propPtr->isNotFeatherEggOrNote = true; - timedFunc_set_1(1.1f, (GenFunction_1)func_80387E00, (uintptr_t)bgs_D_803907B8[this->actorTypeSpecificField]); + bgs_D_803907B8[this->actorTypeSpecificField]->propPtr->isNotFeatherEggOrNote = TRUE; + timedFunc_set_1(1.1f, (GenFunction_1)func_80387E00, reinterpret_cast(uintptr_t, bgs_D_803907B8[this->actorTypeSpecificField])); if (!sCroctusRemote) gcStaticCamera_activate(D_803907B0[this->actorTypeSpecificField-1]); } else { - timedFunc_set_1(0.8f, (GenFunction_1)chCroctus_jiggySpawn, (uintptr_t)this->marker); + timedFunc_set_1(0.8f, (GenFunction_1)chCroctus_jiggySpawn, reinterpret_cast(uintptr_t, this->marker)); } - __spawnQueue_add_2((void (*)(void))func_80387D18, (uintptr_t)this->marker, 0x46); + __spawnQueue_add_2((GenFunction_2)func_80387D18, reinterpret_cast(uintptr_t, this->marker), 0x46); } } }//L80388348 sCroctusRemote = 0; switch(this->state){ - case 1:// L80388370 - this->lifetime_value += time_getDelta(); - if(0.7 <= this->lifetime_value){ - subaddie_set_state_with_direction(this, 2, 0.0f, 1); - func_80387C90(this); - this->lifetime_value = 0.0f; - func_80324D54(0.1f, SFX_D0_GRIMLET_SQUEAK, 1.0f, 0x7530, this->position, 0.0f, 1800.0f); - } - break; + case CHCROCTUS_STATE_1_MOUTH_CLOSED:// L80388370 + this->lifetime_value += time_getDelta(); + if(0.7 <= this->lifetime_value){ + subaddie_set_state_with_direction(this, CHCROCTUS_STATE_2_MOUTH_OPENING, 0.0f, 1); + func_80387C90(this); + this->lifetime_value = 0.0f; + func_80324D54(0.1f, SFX_D0_GRIMLET_SQUEAK, 1.0f, 0x7530, this->position, 0.0f, 1800.0f); + } + break; - case 2:// L80388400 - if(actor_animationIsAt(this, 0.62f)){ - subaddie_set_state_with_direction(this, 3, 0.62f, 1); - } - break; - - case 3:// L80388434 - this->lifetime_value += time_getDelta(); - if( this->lifetime_value >= 0.13 + 0.7/4 * (5 - this->actorTypeSpecificField)){ - subaddie_set_state_with_direction(this, 4, 0.62f, 1); - func_80387C90(this); - this->lifetime_value = 0.0f; - func_80324D54(0.3f, 0x406, 1.0f, 0x55f0, this->position, 0.0f, 1800.0f); - } - break; + case CHCROCTUS_STATE_2_MOUTH_OPENING:// L80388400 + if(actor_animationIsAt(this, 0.62f)){ + subaddie_set_state_with_direction(this, CHCROCTUS_STATE_3_MOUTH_OPEN, 0.62f, 1); + } + break; + + case CHCROCTUS_STATE_3_MOUTH_OPEN:// L80388434 + this->lifetime_value += time_getDelta(); + if( this->lifetime_value >= 0.13 + 0.7/4 * (5 - this->actorTypeSpecificField)){ + subaddie_set_state_with_direction(this, CHCROCTUS_STATE_4_MOUTH_CLOSING, 0.62f, 1); + func_80387C90(this); + this->lifetime_value = 0.0f; + func_80324D54(0.3f, SFX_406_GOLD_BULLION_TALKING, 1.0f, 0x55f0, this->position, 0.0f, 1800.0f); + } + break; - case 4:// L8038850C - if(actor_animationIsAt(this, 0.0f)){ - subaddie_set_state_with_direction(this, 1, 0.0f, 1); - } - break; - - case 5:// L80388538 - func_80328748(this->anctrl, 0.79f, 0.97f); - if( actor_animationIsAt(this, 0.84f) - && !anctrl_isPlayedForwards(this->anctrl) - && func_802BB270() - ){ - gcsfx_playWithPitch(SFX_C8_CRUNCH, randf2(0.93f, 1.07f), 22000); - } - break; + case CHCROCTUS_STATE_4_MOUTH_CLOSING:// L8038850C + if(actor_animationIsAt(this, 0.0f)){ + subaddie_set_state_with_direction(this, CHCROCTUS_STATE_1_MOUTH_CLOSED, 0.0f, 1); + } + break; + + case CHCROCTUS_STATE_5_FED:// L80388538 + func_80328748(this->anctrl, 0.79f, 0.97f); + if( actor_animationIsAt(this, 0.84f) + && !anctrl_isPlayedForwards(this->anctrl) + && func_802BB270() + ){ + gcsfx_playWithPitch(SFX_C8_CRUNCH, randf2(0.93f, 1.07f), 22000); + } + break; - case 6:// L803885B0 - func_80328748(this->anctrl, 0.79f, 0.97f); + case CHCROCTUS_STATE_6_DESPAWN:// L803885B0 + func_80328748(this->anctrl, 0.79f, 0.97f); - break; + break; } } void BGS_func_803885DC(void){ s32 i; - for(i = 0; i<5; i++) + for(i = 0; i < 5; i++) bgs_D_803907B8[i] = 0; } Actor *chCroctus_draw(ActorMarker *this, Gfx** gdl, Mtx ** mptr, Vtx **vtx){ Actor *thisActor; thisActor = marker_getActor(this); - func_8033A45C(1, thisActor->actorTypeSpecificField); + modelRender_setAppendageVisibility(1, thisActor->actorTypeSpecificField); return actor_draw(this, gdl, mptr, vtx); } diff --git a/src/BGS/ch/frogminigame.c b/src/BGS/ch/frogminigame.c index 964e069a9..d4752a841 100644 --- a/src/BGS/ch/frogminigame.c +++ b/src/BGS/ch/frogminigame.c @@ -4,7 +4,7 @@ #include "variables.h" -void chfrogminigame_update(Actor *); +void chFrogMinigame_update(Actor *); void chFrogMinigame_setState(Actor * arg0, u32 next_state); void func_8025A58C(u32, u32); void timed_exitStaticCamera(f32); @@ -12,11 +12,20 @@ void timed_exitStaticCamera(f32); ActorInfo chFrogMinigame = {MARKER_C4_YELLOW_FLIBBIT_CTRL, ACTOR_136_YELLOW_FLIBBIT_CONTROLLER, 0x00, 0x00, NULL, - chfrogminigame_update, NULL, func_80325340, + chFrogMinigame_update, NULL, func_80325340, 0, 0, 0.0f, 0 }; +enum chFrogMinigameState { + CH_FROG_MINIGAME_STATE_1_IDLE = 1, + CH_FROG_MINIGAME_STATE_2_ENTER_BATTLE, + CH_FROG_MINIGAME_STATE_3_BATTLE, + CH_FROG_MINIGAME_STATE_4_COMPLETE, + CH_FROG_MINIGAME_STATE_5_SPAWN_JIGGY, + CH_FROG_MINIGAME_STATE_6_DESPAWN +}; + /* .bss */ u8 D_80391240[4]; @@ -37,7 +46,7 @@ static void __chFrogMinigame_textCallback(ActorMarker *marker, enum asset_e text } } -void func_8038CBB4(Actor * arg0){ +void chFrogMinigame_stopFlibbitFightMusic(Actor * arg0){ if(!arg0->bgs_6730.unk4) return; func_8025A58C(-1, 400); @@ -57,13 +66,13 @@ void chFrogMinigame_setState(Actor * arg0, u32 next_state){ mapSpecificFlags_set(0x10, 1); if(!fileProgressFlag_get(FILEPROG_1B_MET_YELLOW_FLIBBITS)){ fileProgressFlag_set(FILEPROG_1B_MET_YELLOW_FLIBBITS, 1); - gcdialog_showDialog(ASSET_C81_DIALOG_YELLOW_FLIBBITS_MEET, 0xf, arg0->position, arg0->marker, __chFrogMinigame_textCallback, 0); + gcdialog_showDialog(VER_SELECT(ASSET_C81_DIALOG_YELLOW_FLIBBITS_MEET, 0x9C4, 0, 0), 0xf, arg0->position, arg0->marker, __chFrogMinigame_textCallback, 0); }else{ if(!arg0->bgs_6730.unk8){ - gcdialog_showDialog(ASSET_C83_DIALOG_YELLOW_FLIBBITS_RETURN, 0x4, arg0->position, arg0->marker, __chFrogMinigame_textCallback, 0); + gcdialog_showDialog(VER_SELECT(ASSET_C83_DIALOG_YELLOW_FLIBBITS_RETURN, 0x9C6, 0, 0), 0x4, arg0->position, arg0->marker, __chFrogMinigame_textCallback, 0); } else{ - __chFrogMinigame_textCallback(arg0->marker, ASSET_C83_DIALOG_YELLOW_FLIBBITS_RETURN, 0); + __chFrogMinigame_textCallback(arg0->marker, VER_SELECT(ASSET_C83_DIALOG_YELLOW_FLIBBITS_RETURN, 0x9C6, 0, 0), 0); return; } } @@ -89,12 +98,12 @@ void chFrogMinigame_setState(Actor * arg0, u32 next_state){ } } else{ - func_8038CBB4(arg0); + chFrogMinigame_stopFlibbitFightMusic(arg0); } } - if (next_state == 4) { - gcdialog_showDialog(ASSET_C82_DIALOG_YELLOW_FLIBBITS_COMPLETE, 0xf, arg0->position, arg0->marker, __chFrogMinigame_textCallback, 0); + if (next_state == CH_FROG_MINIGAME_STATE_4_COMPLETE) { + gcdialog_showDialog(VER_SELECT(ASSET_C82_DIALOG_YELLOW_FLIBBITS_COMPLETE, 0x9C5, 0, 0), 0xf, arg0->position, arg0->marker, __chFrogMinigame_textCallback, 0); } if(next_state == 5){ @@ -128,7 +137,7 @@ void BGS_func_8038CED0(void){ D_80391240[3]++; } -void chfrogminigame_update(Actor *this){ +void chFrogMinigame_update(Actor *this){ f32 player_position[3]; u32 sp28; ActorLocal_BGS_6730 *local; @@ -181,7 +190,7 @@ void chfrogminigame_update(Actor *this){ else{ //L8038D0E0 if(local->unk4 && !local->unk8){ - func_8038CBB4(this); + chFrogMinigame_stopFlibbitFightMusic(this); } } } diff --git a/src/BGS/ch/leafboat.c b/src/BGS/ch/leafboat.c index 4efcf8b16..04d3ac1d0 100644 --- a/src/BGS/ch/leafboat.c +++ b/src/BGS/ch/leafboat.c @@ -153,9 +153,9 @@ void chLeafBoat_update(Actor *this){ local->unk60[1] = this->yaw; local->unk60[2] = this->roll; this->lifetime_value += time_getDelta(); - _player_getPosition(player_position); + playerPosition_get(player_position); if( func_80294660() == 0x100 - && func_8028F20C() + && player_isStableWithExtraSteps() && this->marker->isBanjoOnTop ){ sp44 = local->unk54[0] - player_position[0]; diff --git a/src/BGS/ch/mrvile.c b/src/BGS/ch/mrvile.c index b5c54892a..4ac36b28c 100644 --- a/src/BGS/ch/mrvile.c +++ b/src/BGS/ch/mrvile.c @@ -7,12 +7,12 @@ #include "core2/modelRender.h" #include "port/Enhancements/Events/Hooks/Events.h" -Actor *chvile_draw(ActorMarker*, Gfx **, Mtx **, Vtx **); -void chvile_update(Actor *); -void func_8038BB40(ActorMarker *); +Actor *chMrVile_draw(ActorMarker*, Gfx **, Mtx **, Vtx **); +void chMrVile_update(Actor *); +void chMrVile_attackPlayer(ActorMarker *); extern BKCollisionTriangle *func_80320C94(f32[3], f32[3], f32, f32[3], s32, u32); -extern bool chvilegame_find_closest_piece(ActorMarker *, f32[3], f32, f32[3]); +extern bool chMrVileMinigame_findClosestPiece(ActorMarker *, f32[3], f32, f32[3]); typedef struct chmrvile_s{ u8 unk0; @@ -30,7 +30,7 @@ typedef struct chmrvile_s{ /* .data */ ActorInfo gChVile = {MARKER_C8_MR_VILE, ACTOR_13A_MR_VILE, ASSET_373_MODEL_MR_VILE, 0x00, NULL, - chvile_update, NULL, chvile_draw, + chMrVile_update, NULL, chMrVile_draw, 0, 0, 0.0f, 0 }; @@ -73,13 +73,13 @@ void func_8038B9F0(f32 arg0[3], f32 arg1[3], f32 arg2, f32 arg3, s32 arg4) { } } -void func_8038BB40(ActorMarker * arg0){ +void chMrVile_attackPlayer(ActorMarker * arg0){ Actor *this; ActorLocal_MrVile *local; this = marker_getActor(arg0); local = (ActorLocal_MrVile *)&this->local; - if(func_8038A9E0(local->game_marker) >= 3){ + if(chMrVileMinigame_getDialogIndex(local->game_marker) >= 3){ item_set(ITEM_14_HEALTH, 0); func_8028F66C(BS_INTR_F); } @@ -89,7 +89,7 @@ void func_8038BB40(ActorMarker * arg0){ } } -void BGS_func_8038BBA0(Actor *this, s32 arg1){ +void chMrVile_setAction(Actor *this, s32 arg1){ ActorLocal_MrVile *local; local = (ActorLocal_MrVile *)&this->local; @@ -109,7 +109,7 @@ void BGS_func_8038BBA0(Actor *this, s32 arg1){ skeletalAnim_swap(this->unk148, 0x124, 0.1f, 0.5f); //0x124 = croc_munch if(this->state == 4){ timed_playSfx(0.31f, SFX_4C_LIP_SMACK, 0.90f, 25000); - timedFunc_set_1(0.31f, (GenFunction_1)func_8038BB40, (uintptr_t)this->marker); + timedFunc_set_1(0.31f, (GenFunction_1)chMrVile_attackPlayer, (uintptr_t)this->marker); } else{ timed_playSfx(0.31f, SFX_4C_LIP_SMACK, 0.90f, 25000); @@ -138,7 +138,7 @@ void func_8038BD84(Actor *this){ local->unk28[0] = 0.0f; local->unk28[1] = 0.0f; local->unk28[2] = 0.0f; - BGS_func_8038BBA0(this, 101); + chMrVile_setAction(this, 101); } void func_8038BDD4(Actor *this) { @@ -195,37 +195,37 @@ void func_8038BDD4(Actor *this) { } } -void chVile_setState(Actor * this, s32 next_state){ +void chMrVile_setState(Actor * this, s32 next_state){ ActorLocal_MrVile *local; local = (ActorLocal_MrVile *)&this->local; if(next_state == 1) - BGS_func_8038BBA0(this, 101); + chMrVile_setAction(this, 101); if(next_state == 2) - BGS_func_8038BBA0(this, 101); + chMrVile_setAction(this, 101); if(next_state == 3) - BGS_func_8038BBA0(this, 102); + chMrVile_setAction(this, 102); if(next_state == 4) - BGS_func_8038BBA0(this, 102); + chMrVile_setAction(this, 102); if(next_state == 5){ local->target_position[0] = local->target_position[1] = local->target_position[2] = 0.0f; - BGS_func_8038BBA0(this, 102); + chMrVile_setAction(this, 102); } if(next_state == 6){ local->target_position[0] = local->target_position[1] = local->target_position[2] = 0.0f; local->unk24 = 300.0f; - BGS_func_8038BBA0(this, 102); + chMrVile_setAction(this, 102); } this->state = next_state; } -Actor *chvile_draw(ActorMarker *marker, Gfx **gfx, Mtx** mtx, Vtx **vtx){ +Actor *chMrVile_draw(ActorMarker *marker, Gfx **gfx, Mtx** mtx, Vtx **vtx){ Actor *this; ActorLocal_MrVile *local; f32 position[3]; @@ -246,14 +246,14 @@ Actor *chvile_draw(ActorMarker *marker, Gfx **gfx, Mtx** mtx, Vtx **vtx){ return this; } -f32 *chVile_getPostion(ActorMarker *marker){ +f32 *chMrVile_getPostion(ActorMarker *marker){ Actor *this; this = marker_getActor(marker); return this->position; } -bool func_8038C2A8(ActorMarker *marker) { +bool chMrVile_playerWithinRange(ActorMarker *marker) { f32 player_position[3]; Actor *this; ActorLocal_MrVile *local; @@ -268,14 +268,14 @@ bool func_8038C2A8(ActorMarker *marker) { } -bool BGS_func_8038C338(ActorMarker *marker){ +bool chMrVile_isInitialIdle(ActorMarker *marker){ Actor *this; this = marker_getActor(marker); return this->state == 1; } -void chvile_free(Actor *this){ +void chMrVile_free(Actor *this){ ActorLocal_MrVile *local; local = (ActorLocal_MrVile *)&this->local; @@ -283,46 +283,46 @@ void chvile_free(Actor *this){ } -void func_8038C384(ActorMarker *marker){ +void chMrVile_setStateAttackPlayer(ActorMarker *marker){ Actor *this; this = marker_getActor(marker); - chVile_setState(this, 4); + chMrVile_setState(this, 4); } -void func_8038C3B0(ActorMarker *marker){ +void chMrVile_setStateTalkToPlayer(ActorMarker *marker){ Actor *this; this = marker_getActor(marker); - chVile_setState(this, 2); + chMrVile_setState(this, 2); } -void func_8038C3DC(ActorMarker *marker){ +void chMrVile_setStatePlayMinigame(ActorMarker *marker){ Actor *this; this = marker_getActor(marker); - chVile_setState(this, 3); + chMrVile_setState(this, 3); } -void func_8038C408(ActorMarker *marker){ +void chMrVile_setStateIdleWalking(ActorMarker *marker){ Actor *this; this = marker_getActor(marker); - chVile_setState(this, 5); + chMrVile_setState(this, 5); } -void BGS_func_8038C434(ActorMarker *marker){ +void chMrVile_setStateRunFromPlayer(ActorMarker *marker){ Actor *this; this = marker_getActor(marker); - chVile_setState(this, 6); + chMrVile_setState(this, 6); } -void BGS_func_8038C460(ActorMarker *arg0){ - chVile_setState(marker_getActor(arg0), 1); +void chMrVile_setInitialIdleStill(ActorMarker *arg0){ + chMrVile_setState(marker_getActor(arg0), 1); } -void chvile_update(Actor *this) { +void chMrVile_update(Actor *this) { f32 player_position[3]; f32 sp90; f32 temp_a0; @@ -341,12 +341,12 @@ void chvile_update(Actor *this) { local = (ActorLocal_MrVile *)&this->local; if (!this->volatile_initialized) { this->volatile_initialized = true; - this->marker->actorFreeFunc = chvile_free; + this->marker->actorFreeFunc = chMrVile_free; local->unk0 = 0; local->unk4 = assetcache_get(0x3F6); local->game_marker = NULL; func_8038BD84(this); - chVile_setState(this, 1); + chMrVile_setState(this, 1); return; } if (local->game_marker == NULL) { @@ -372,18 +372,18 @@ void chvile_update(Actor *this) { if (((sp84 > 50.0f) && (0.05 < sp7C)) || (sp7C < -0.05)) { this->yaw += sp7C * 20.0f; } else { - chVile_setState(this, 1); + chMrVile_setState(this, 1); } } if (this->state == 3) { - var_v1 = chvilegame_find_closest_piece(local->game_marker, this->position, this->yaw, local->target_position) && mapSpecificFlags_get(6); + var_v1 = chMrVileMinigame_findClosestPiece(local->game_marker, this->position, this->yaw, local->target_position) && mapSpecificFlags_get(6); if (!var_v1) { local->target_position[0] = 0.0f; local->target_position[1] = 0.0f; local->target_position[2] = 0.0f; } if (local->game_marker != NULL) { - temp_v0 = chvilegame_get_score_difference(local->game_marker); + temp_v0 = chMrVileMinigame_getScoreDifference(local->game_marker); if (temp_v0 >= 2) { local->unk10 = 200.0f; } else if (temp_v0 >= 0) { @@ -393,29 +393,29 @@ void chvile_update(Actor *this) { } else { local->unk10 = 450.0f; } - local->unk10 *= D_80390A94[func_8038A9E0(local->game_marker)]; + local->unk10 *= D_80390A94[chMrVileMinigame_getDialogIndex(local->game_marker)]; CALL_EVENT(OnMrVileSetSpeed, &local->unk10); } - if (func_8038A9E0(local->game_marker) < 7) { + if (chMrVileMinigame_getDialogIndex(local->game_marker) < 7) { func_80258A4C(this->position, this->yaw - 90.0f, local->target_position, &sp70, &sp6C, &sp68); if (local->unkC == 102) { if ((-0.8 < sp68) && (sp68 < 0.8) && (sp70 <= 150.0f) && var_v1) { - BGS_func_8038BBA0(this, 103); + chMrVile_setAction(this, 103); } } if (local->unkC == 103) { if (sp70 <= 50.0f) { - if (chvilegame_cpu_consume_piece(local->game_marker, local->target_position)) { - BGS_func_8038BBA0(this, 104); + if (chMrVileMinigame_mrVileConsumePiece(local->game_marker, local->target_position)) { + chMrVile_setAction(this, 104); } else { - BGS_func_8038BBA0(this, 102); + chMrVile_setAction(this, 102); } } else if (skeletalAnim_getLoopCount(this->unk148) >= 3) { - BGS_func_8038BBA0(this, 102); + chMrVile_setAction(this, 102); } } if ((local->unkC == 104) && (skeletalAnim_getLoopCount(this->unk148) >= 3)) { - BGS_func_8038BBA0(this, 102); + chMrVile_setAction(this, 102); } } } @@ -423,10 +423,10 @@ void chvile_update(Actor *this) { player_getPosition(local->target_position); local->unk10 = 500.0f; if ((local->unkC == 102) && (ml_vec3f_distance(this->position, local->target_position) < 200.0f)) { - BGS_func_8038BBA0(this, 103); + chMrVile_setAction(this, 103); } if ((local->unkC == 103) && (skeletalAnim_getLoopCount(this->unk148) >= 2)) { - chVile_setState(this, 1); + chMrVile_setState(this, 1); } } if (this->state == 5) { @@ -460,7 +460,7 @@ void chvile_update(Actor *this) { // [port] Anchor sync entry points. // Applies a streamed transform + anim mode from the minigame authority. -void chvile_netApplyUpdate(Actor *this, const f32 position[3], f32 pitch, f32 yaw, f32 roll, u8 anim_mode){ +void chMrVile_netApplyUpdate(Actor *this, const f32 position[3], f32 pitch, f32 yaw, f32 roll, u8 anim_mode){ ActorLocal_MrVile *local = (ActorLocal_MrVile *)&this->local; this->position[0] = position[0]; @@ -470,11 +470,11 @@ void chvile_netApplyUpdate(Actor *this, const f32 position[3], f32 pitch, f32 ya this->yaw = yaw; this->roll = roll; if (local->unkC != anim_mode) { - BGS_func_8038BBA0(this, anim_mode); + chMrVile_setAction(this, anim_mode); } } -s32 chvile_netGetAnimMode(Actor *this){ +s32 chMrVile_netGetAnimMode(Actor *this){ ActorLocal_MrVile *local = (ActorLocal_MrVile *)&this->local; return local->unkC; diff --git a/src/BGS/ch/mudhut.c b/src/BGS/ch/mudhut.c index 8eda12cb7..dfb64a49b 100644 --- a/src/BGS/ch/mudhut.c +++ b/src/BGS/ch/mudhut.c @@ -65,7 +65,7 @@ Actor *chMudHut_draw(ActorMarker *this, Gfx** gdl, Mtx** mtx, Vtx **vtx){ Actor *thisActor; thisActor = marker_getActor(this); - func_8033A45C(1, thisActor->state == 1); + modelRender_setAppendageVisibility(1, thisActor->state == 1); if(thisActor->state == 3) return thisActor; @@ -136,7 +136,7 @@ void chMudHut_update(Actor *this){ diffPos[2] = plyrPos[2] - this->position_z; if( (150.0f < diffPos[1]) && (player_getActiveHitbox(this->marker) == HITBOX_1_BEAK_BUSTER) - && (func_8028F20C()) + && (player_isStableWithExtraSteps()) && (LENGTH_VEC3F(diffPos) < 350.f) ){ tmp = (s32)( (this->position_y - 600.f)/430.0f); diff --git a/src/BGS/ch/pinkegg.c b/src/BGS/ch/pinkegg.c index 9cb3fa1db..2c12b5e50 100644 --- a/src/BGS/ch/pinkegg.c +++ b/src/BGS/ch/pinkegg.c @@ -75,8 +75,8 @@ Actor *chPinkEgg_draw(ActorMarker *this, Gfx ** gdl, Mtx** mptr, Vtx **arg3){ u32 t7; t7 = marker_getActor(this)->state == 3; - func_8033A45C(1, NOT(sp18 = t7)); - func_8033A45C(2, sp18); + modelRender_setAppendageVisibility(1, NOT(sp18 = t7)); + modelRender_setAppendageVisibility(2, sp18); return actor_draw(this, gdl, mptr, arg3); } diff --git a/src/BGS/ch/swampswitch.c b/src/BGS/ch/swampswitch.c index 382ff6a76..cc9b28f97 100644 --- a/src/BGS/ch/swampswitch.c +++ b/src/BGS/ch/swampswitch.c @@ -40,7 +40,7 @@ void chLongSwampSwitch_update(Actor *this){ if(mapSpecificFlags_get(7)){ mapSpecificFlags_set(7, 0); if(!mapSpecificFlags_get(3) || (item_getCount(0) > 0)){ - func_802D68F0(45); + code_4C020_setHourglassTimer(45); } } if(!mapSpecificFlags_get(5)){ @@ -60,7 +60,7 @@ void chLongSwampSwitch_update(Actor *this){ } //L8038EFB4 if( this->velocity_x != 0.0f && !mapSpecificFlags_get(3) && func_802BB270()){ mapSpecificFlags_set(3,1); - func_802D68F0(45); //adjusts timer + code_4C020_setHourglassTimer(45); //adjusts timer item_set(ITEM_6_HOURGLASS,1); } //L8038EFB4 } @@ -83,7 +83,7 @@ void chShortSwampSwitch_update(Actor *this){ if(mapSpecificFlags_get(8)){ mapSpecificFlags_set(8, 0); if(!mapSpecificFlags_get(0xC) || (item_getCount(0) > 0)){ - func_802D68F0(10); + code_4C020_setHourglassTimer(10); } } if(!mapSpecificFlags_get(9)){ @@ -103,7 +103,7 @@ void chShortSwampSwitch_update(Actor *this){ } //L8038EFB4 if( this->velocity_x != 0.0f && !mapSpecificFlags_get(0xC) && func_802BB270()){ mapSpecificFlags_set(0xC,1); - func_802D68F0(10); //adjusts timer + code_4C020_setHourglassTimer(10); //adjusts timer item_set(ITEM_6_HOURGLASS,1); } //L8038EFB4 } diff --git a/src/BGS/ch/tanktup.c b/src/BGS/ch/tanktup.c index b731902f4..86943b2fa 100644 --- a/src/BGS/ch/tanktup.c +++ b/src/BGS/ch/tanktup.c @@ -1,4 +1,4 @@ -// BanjoDecomp: tanktup.c +// BanjoDecomp: BGS/ch/tanktup.c #include #include "functions.h" #include "variables.h" @@ -9,10 +9,7 @@ void timed_exitStaticCamera(f32); -#include "core2/timedfunc.h" - void func_8028E668(f32[3], f32, f32, f32); -extern void __spawnQueue_add_3(GenFunction_3, uintptr_t, uintptr_t, uintptr_t); void chTanktup_update(Actor *); @@ -31,11 +28,19 @@ ActorAnimationInfo BGS_D_80390C20[] = { {0x107, 1.75f} }; -ActorInfo chTanktup = {MARKER_6C_TANKTUP, ACTOR_E8_TANKTUP, ASSET_3EE_TANKTUP, 0x01, BGS_D_80390C20, +ActorInfo gChTanktup = { + MARKER_6C_TANKTUP, ACTOR_E8_TANKTUP, ASSET_3EE_TANKTUP, + 0x01, BGS_D_80390C20, chTanktup_update, actor_update_func_80326224, actor_draw, 0, 0x80, 0.0f, 0 }; +enum chTanktupState { + CH_TANKTUP_STATE_1_UNK = 1, + CH_TANKTUP_STATE_2_UNK, + CH_TANKTUP_STATE_3_UNK, +}; + /* .code */ void func_8038F470(ActorMarker *this, s32 arg1, enum chtanktup_leg_e leg_id){ Actor* thisActor; @@ -69,9 +74,7 @@ s32 func_8038F570(s16 *arg0){ pos[1] = (f32)arg0[1]; pos[2] = (f32)arg0[2]; spawnPtr = actorArray_findClosestActorFromActorId(pos, ACTOR_E8_TANKTUP, -1, 0); - return spawnPtr->state == 3; - - + return spawnPtr->state == CH_TANKTUP_STATE_3_UNK; } void func_8038F5E4(ActorMarker *marker, enum asset_e text_id, s32 arg2){ @@ -100,169 +103,166 @@ static s32 sTanktupCameraPushed = 0; void chTanktup_update(Actor *this) { - ActorLocal_TanktupBody *local = (ActorLocal_TanktupBody *) (&this->local); - f32 sp48[3]; - s32 sp44; - NodeProp *temp_v0; - if (!this->initialized) - { - temp_v0 = nodeprop_findByActorIdAndActorPosition(ACTOR_32B_UNKNOWN, this); - if (temp_v0 == 0) + ActorLocal_TanktupBody *local = (ActorLocal_TanktupBody *) (&this->local); + f32 sp48[3]; + s32 sp44; + NodeProp *temp_v0; + if (!this->initialized) { - local->unk18[0] = 3672.0f; - local->unk18[1] = 100.0f; - local->unk18[2] = 987.0f; - } - else - { - nodeprop_getPosition(temp_v0, local->unk18); - } - this->has_met_before = false; - this->initialized = true; - } - if (!this->volatile_initialized) - { - this->volatile_initialized = true; - this->marker->propPtr->unk8_3 = 1; - actor_collisionOff(this); - this->scale = 1.0f; - sTanktupCameraPushed = 0; - // Anchor: adopt the team's already-retracted legs. - { - s32 legBits = port_puzzleStep_get(ANCHOR_PUZZLE_BGS_TANKTUP); - for (sp44 = 0; sp44 < 4; sp44++) - { - if (legBits & (1 << sp44)) + temp_v0 = nodeprop_findByActorIdAndActorPosition(ACTOR_32B_UNKNOWN, this); + if (temp_v0 == 0) { - local->unk0[sp44] = 1; + local->unk18[0] = 3672.0f; + local->unk18[1] = 100.0f; + local->unk18[2] = 987.0f; } - } - } - for (sp44 = 0; sp44 < 4; sp44++) - { - if (local->unk0[sp44] == 0) - { - __spawnQueue_add_3((GenFunction_3)func_8038F470, (uintptr_t)this->marker, local->unk0[sp44], sp44); - } - } - - if (local) - { - ; - } - } - // Anchor: team completed Tanktup but our body is still idle (state 1) — raise the head to match. - if (this->state == 1 && jiggyscore_isSpawned(JIGGY_26_BGS_TANKTUP)) - { - subaddie_set_state_with_direction(this, 3, 0.0f, -1); - actor_playAnimationOnce(this); - } - switch (this->state) - { - case 1: - func_8038F610(this); - player_getPosition(sp48); - if (!this->has_met_before) - { - if ((((ml_vec3f_distance(local->unk18, sp48) < 250.0f) && (ml_vec3f_distance(local->unk18, sp48) > 80.0f)) && (!player_movementGroup())) && (player_getTransformation() == TRANSFORM_1_BANJO)) - { - gcdialog_showDialog(ASSET_C7E_DIALOG_TANKTUP_MEET, 0, 0, 0, 0, 0); - this->has_met_before = true; - } + else + { + nodeprop_getPosition(temp_v0, local->unk18); + } + this->has_met_before = FALSE; + this->initialized = TRUE; } - if (local->unk10) + if (!this->volatile_initialized) { - subaddie_set_state_with_direction(this, 2, 0.0f, -1); - local->unk10 = 0; - sp44 = 0; - (void)&sp44; - local->unk14 = 1; - for (; sp44 < 4; sp44++) - { - if (local->unk0[sp44] == 0) + this->volatile_initialized = TRUE; + this->marker->propPtr->unk8_3 = 1; + actor_collisionOff(this); + this->scale = 1.0f; + sTanktupCameraPushed = 0; + // Anchor: adopt the team's already-retracted legs. { - local->unk14 = 0; + s32 legBits = port_puzzleStep_get(ANCHOR_PUZZLE_BGS_TANKTUP); + for (sp44 = 0; sp44 < 4; sp44++) + { + if (legBits & (1 << sp44)) + { + local->unk0[sp44] = 1; + } + } } - } - - if ((!this->unk138_23) && (!local->unk14)) - { - if (gcdialog_showDialog(ASSET_C80_DIALOG_TANKTUP_HIT, 0, 0, 0, 0, 0)) + for (sp44 = 0; sp44 < 4; sp44++) { - this->unk138_23 = 1; + if (local->unk0[sp44] == 0) + { + __spawnQueue_add_3((GenFunction_3)func_8038F470, reinterpret_cast(uintptr_t, this->marker), local->unk0[sp44], sp44); + } } - } - } - break; - case 2: - func_8038F610(this); - if (actor_animationIsAt(this, 0.6f) && local->unk14) - { - coMusicPlayer_playMusic(COMUSIC_2D_PUZZLE_SOLVED_FANFARE, 28000); - func_8028F94C(2, local->unk18); - sTanktupCameraPushed = 1; + if (local) + { + ; + } } - if (actor_animationIsAt(this, 0.99f)) + // Anchor: team completed Tanktup but our body is still idle (state 1) — raise the head to match. + if (this->state == CH_TANKTUP_STATE_1_UNK && jiggyscore_isSpawned(JIGGY_26_BGS_TANKTUP)) { - if (!local->unk14) - { - subaddie_set_state_with_direction(this, 1, 0.0f, -1); - } - else - { - subaddie_set_state_with_direction(this, 3, 0.0f, -1); + subaddie_set_state_with_direction(this, CH_TANKTUP_STATE_3_UNK, 0.0f, -1); actor_playAnimationOnce(this); - } - } - break; - - case 3: - { - f32 pp[3]; - s32 near; - player_getPosition(pp); - near = ml_vec3f_distance(local->unk18, pp) < 700.0f; - if (actor_animationIsAt(this, 0.1f) != 0 && near) - { - timed_setStaticCameraToNode(0.0f, 0xD); - } - if (actor_animationIsAt(this, 0.55f) != 0) - { - func_8030E624(0x797FF885U); - } - if (actor_animationIsAt(this, 0.4f) != 0 && jiggyscore_isSpawned(JIGGY_26_BGS_TANKTUP) == 0) - { - f32 sp34[3]; - vec3fArray_get_vec3f(this->marker->unk44, 6, sp34); - bundle_setYaw(this->yaw); - sp34[1] -= 125.0f; - jiggy_spawn(JIGGY_26_BGS_TANKTUP, sp34); } - if (actor_animationIsAt(this, 0.9f) != 0) + switch (this->state) { - // Anchor: release the freeze/look-at if state 2 took it, independent of the proximity check below. - if (sTanktupCameraPushed) - { - func_8028F918(0); - sTanktupCameraPushed = 0; - } - if (near) - { - if (jiggyscore_isCollected(JIGGY_26_BGS_TANKTUP) == 0) - { - gcdialog_showDialog(ASSET_C7F_DIALOG_TANKTUP_COMPLETE, 0xF, this->position, this->marker, func_8038F5E4, 0); - } - else + case CH_TANKTUP_STATE_1_UNK: + func_8038F610(this); + player_getPosition(sp48); + if (!this->has_met_before) + { + if ((((ml_vec3f_distance(local->unk18, sp48) < 250.0f) && (ml_vec3f_distance(local->unk18, sp48) > 80.0f)) && (!player_movementGroup())) && (player_getTransformation() == TRANSFORM_1_BANJO)) + { + gcdialog_showDialog(VER_SELECT(ASSET_C7E_DIALOG_TANKTUP_MEET, 0x9C1, 0, 0), 0, 0, 0, 0, 0); + this->has_met_before = TRUE; + } + } + if (local->unk10) + { + subaddie_set_state_with_direction(this, CH_TANKTUP_STATE_2_UNK, 0.0f, -1); + local->unk10 = 0; + sp44 = 0; + if(&sp44); + local->unk14 = 1; + for (; sp44 < 4; sp44++) + { + if (local->unk0[sp44] == 0) + { + local->unk14 = 0; + } + } + + if ((!this->unk138_23) && (!local->unk14)) + { + if (gcdialog_showDialog(VER_SELECT(ASSET_C80_DIALOG_TANKTUP_HIT, 0x9C3, 0, 0), 0, 0, 0, 0, 0)) + { + this->unk138_23 = 1; + } + } + } + break; + + case CH_TANKTUP_STATE_2_UNK: + func_8038F610(this); + if (actor_animationIsAt(this, 0.6f) && local->unk14) + { + coMusicPlayer_playMusic(COMUSIC_2D_PUZZLE_SOLVED_FANFARE, 28000); + func_8028F94C(2, local->unk18); + sTanktupCameraPushed = 1; + } + if (actor_animationIsAt(this, 0.99f)) + { + if (!local->unk14) + { + subaddie_set_state_with_direction(this, CH_TANKTUP_STATE_1_UNK, 0.0f, -1); + } + else + { + subaddie_set_state_with_direction(this, CH_TANKTUP_STATE_3_UNK, 0.0f, -1); + actor_playAnimationOnce(this); + } + } + break; + + case CH_TANKTUP_STATE_3_UNK: { - func_8038F5E4(this->marker, ASSET_C7F_DIALOG_TANKTUP_COMPLETE, -1); + f32 pp[3]; + s32 near; + player_getPosition(pp); + near = ml_vec3f_distance(local->unk18, pp) < 700.0f; + if (actor_animationIsAt(this, 0.1f) != 0 && near) + { + timed_setStaticCameraToNode(0.0f, 0xD); + } + if (actor_animationIsAt(this, 0.55f) != 0) + { + func_8030E624(0x797FF885U); + } + if (actor_animationIsAt(this, 0.4f) != 0 && jiggyscore_isSpawned(JIGGY_26_BGS_TANKTUP) == 0) + { + f32 sp34[3]; + vec3fArray_get_vec3f(this->marker->unk44, 6, sp34); + bundle_setYaw(this->yaw); + sp34[1] -= 125.0f; + jiggy_spawn(JIGGY_26_BGS_TANKTUP, sp34); + } + if (actor_animationIsAt(this, 0.9f) != 0) + { + // Anchor: release the freeze/look-at if state 2 took it, independent of the proximity check below. + if (sTanktupCameraPushed) + { + func_8028F918(0); + sTanktupCameraPushed = 0; + } + if (near) + { + if (jiggyscore_isCollected(JIGGY_26_BGS_TANKTUP) == 0) + { + gcdialog_showDialog(VER_SELECT(ASSET_C7F_DIALOG_TANKTUP_COMPLETE, 0x9C2, 0, 0), 0xF, this->position, this->marker, func_8038F5E4, 0); + } + else + { + func_8038F5E4(this->marker, VER_SELECT(ASSET_C7F_DIALOG_TANKTUP_COMPLETE, 0x9C2, 0, 0), -1); + } + } + } + break; } - } - } } - break; - - } - } - diff --git a/src/BGS/ch/tanktup_legs.c b/src/BGS/ch/tanktuplegs.c similarity index 85% rename from src/BGS/ch/tanktup_legs.c rename to src/BGS/ch/tanktuplegs.c index e71430554..7ca9610ad 100644 --- a/src/BGS/ch/tanktup_legs.c +++ b/src/BGS/ch/tanktuplegs.c @@ -1,4 +1,4 @@ -// BanjoDecomp: code_9750.c +// BanjoDecomp: BGS/ch/tanktuplegs.c #include #include "functions.h" #include "variables.h" @@ -61,7 +61,7 @@ ActorInfo gChTanktupLegBackRight = {MARKER_6D_TANKTUP_LEG, ACTOR_EC_TANKTUP_LEG_ }; /* .code */ -void func_8038FB40(ActorMarker *this, s32 arg1){ +void chTanktupLeg_retractLeg(ActorMarker *this, s32 arg1){ Actor * thisActor; thisActor = marker_getActor(this); @@ -70,12 +70,12 @@ void func_8038FB40(ActorMarker *this, s32 arg1){ FUNC_8030E624(SFX_A_BANJO_LANDING_05, 0.8f, 32750); } -void BGS_func_8038FB84(ActorMarker *this, ActorMarker *other_marker){ +void chTanktupLeg_despawn(ActorMarker *this, ActorMarker *other_marker){ Actor *thisActor; thisActor = marker_getActor(this); sfx_playFadeShorthandDefault( SFX_87_TANKTUP_OOOHW, 1.0f, 32750, thisActor->position, 1000, 3000); - timedFunc_set_2(0.65f, (GenFunction_2) func_8038FB40, (uintptr_t) this, (uintptr_t) other_marker); + timedFunc_set_2(0.65f, (GenFunction_2) chTanktupLeg_retractLeg, (uintptr_t) this, (uintptr_t) other_marker); func_8038F51C(thisActor); this->collidable = false; port_puzzleStep_orBits(ANCHOR_PUZZLE_BGS_TANKTUP, 1 << thisActor->unk10_12); @@ -85,16 +85,16 @@ void chTanktupLeg_update(Actor *this){ if(!this->initialized){ this->initialized = true; this->marker->propPtr->unk8_3 = 1; - marker_setCollisionScripts(this->marker, NULL, NULL, BGS_func_8038FB84); + marker_setCollisionScripts(this->marker, NULL, NULL, chTanktupLeg_despawn); } // Anchor: teammate hit this leg remotely — replay the pull-in. if(this->state == 1 && this->marker->collidable && (port_puzzleStep_get(ANCHOR_PUZZLE_BGS_TANKTUP) & (1 << this->unk10_12))){ - BGS_func_8038FB84(this->marker, NULL); + chTanktupLeg_despawn(this->marker, NULL); } if(this->state == 2){ if(anctrl_isAt(this->anctrl, 0.65f)){ - gcsfx_playAtSampleRate(SFX_7C_CHEBOOF); + gcsfx_play(SFX_7C_CHEBOOF); } if(anctrl_isStopped(this->anctrl)){ marker_despawn(this->marker); diff --git a/src/BGS/ch/tiptup.c b/src/BGS/ch/tiptup.c index c93e4112c..a4d4cf73b 100644 --- a/src/BGS/ch/tiptup.c +++ b/src/BGS/ch/tiptup.c @@ -1,4 +1,4 @@ -// BanjoDecomp: ch/code_2270.c +// BanjoDecomp: BGS/ch/tiptup.c #include #include "functions.h" #include "variables.h" @@ -12,34 +12,72 @@ typedef struct{ typedef struct ch_bgs_2270_s{ u32 unk0; - bk_vector(Struct_BGS_2270_0s) *unk4; + bk_vector(Struct_BGS_2270_0s) *unk4; // vector? u8 unk8; u8 unk9; - u8 unkA; + u8 round; u8 unkB; - f32 unkC; + f32 animTimer; } ActorLocal_Tiptup; void chTiptup_update(Actor *this); Actor *actor_draw(ActorMarker *, Gfx **, Mtx **, Vtx **); -ActorInfo chTiptup = { +ActorInfo gChTiptup = { MARKER_19A_TIPTUP, ACTOR_27A_TIPTUP, ASSET_3F8_MODEL_TIPTUP, 0, NULL, chTiptup_update, NULL, actor_draw, 0, 0, 2.5f, 0 }; -s16 D_80390854[] = {0, ASSET_C78_DIALOG_TIPTUP_LESSON_1_REPEAT, ASSET_C7A_DIALOG_TIPTUP_LESSON_2_REPEAT, ASSET_C7C_DIALOG_TIPTUP_LESSON_3_REPEAT}; //see again texts -s16 D_8039085C[] = {0, ASSET_C77_DIALOG_TIPTUP_LESSON_1_COMPLETE, ASSET_C79_DIALOG_TIPTUP_LESSON_2_COMPLETE, ASSET_C7B_DIALOG_TIPTUP_LESSON_3_COMPLETE}; //success texts -u8 D_80390864[] = {3, 3, 5, 7}; //chchoirgame_sequence_length -f32 D_80390868[3] = {0.0f, 100.0f, -1020.0f}; //chchoirgame_jiggy_position -void BGS_func_80388660(ActorMarker *this){ - chTiptup_setState(marker_getActor(this), 6); +s16 chTiptupRepeatDialogs[] = { + NULL, + VER_SELECT(ASSET_C78_DIALOG_TIPTUP_LESSON_1_REPEAT, 0x9BB, 0, 0), + VER_SELECT(ASSET_C7A_DIALOG_TIPTUP_LESSON_2_REPEAT, 0x9BD, 0, 0), + VER_SELECT(ASSET_C7C_DIALOG_TIPTUP_LESSON_3_REPEAT, 0x9BF, 0, 0) +}; + +s16 chTiptupSuccessDialogs[] = { + NULL, + VER_SELECT(ASSET_C77_DIALOG_TIPTUP_LESSON_1_COMPLETE, 0x9BA, 0, 0), + VER_SELECT(ASSET_C79_DIALOG_TIPTUP_LESSON_2_COMPLETE, 0x9BC, 0, 0), + VER_SELECT(ASSET_C7B_DIALOG_TIPTUP_LESSON_3_COMPLETE, 0x9BE, 0, 0) +}; + +u8 chTiptupSequenceLength[] = {3, 3, 5, 7}; +f32 chTiptupJiggyPosition[3] = {0.0f, 100.0f, -1020.0f}; + +enum chTiptupState { + CH_TIPTUP_STATE_1_IDLE = 1, + CH_TIPTUP_STATE_2_INSTRUCTIONS_DIALOG, + CH_TIPTUP_STATE_3_FF_GIVE_SEQUENCE, + CH_TIPTUP_STATE_4_AWAIT_SEQUENCE_COMPLETION, + CH_TIPTUP_STATE_5_WIN_MINIGAME, + CH_TIPTUP_STATE_6_AFTER_JIGGY_DIALOG +}; + +enum chTiptupSpecificFlag { + CH_TIPTUP_SPECIFIC_FLAG_0_CHOIR_MEMBER_HIT_AFTER_JIGGY, + CH_TIPTUP_SPECIFIC_FLAG_1_TIPTUP_MISS +}; + +enum TiptupRound { + TIPTUP_ROUND_1, + TIPTUP_ROUND_2, + TIPTUP_ROUND_3, + TIPTUP_ROUND_FF +}; + +#define TIPTUP_TIMER 30 // Seconds +#define FIRST_CHOIR_MEMBER 1 +#define LAST_CHOIR_MEMBER 7 + +void chTiptup_minigameComplete(ActorMarker *this){ + chTiptup_setState(marker_getActor(this), CH_TIPTUP_STATE_6_AFTER_JIGGY_DIALOG); } void chTiptup_jiggySpawn(void){ - jiggy_spawn(JIGGY_27_BGS_TIPTUP, D_80390868); //spawn jiggy after minigame + jiggy_spawn(JIGGY_27_BGS_TIPTUP, chTiptupJiggyPosition); } void chTiptup_activatePattern(ActorMarker *this, s32 arg1){ @@ -61,8 +99,8 @@ void chTiptup_activateTimer(ActorMarker *this){ thisActor = marker_getActor(this); item_set(ITEM_6_HOURGLASS, 1); - item_set(ITEM_0_HOURGLASS_TIMER, 30*60-1); - chTiptup_setState(thisActor, 5); + item_set(ITEM_0_HOURGLASS_TIMER, VER_SELECT(TIPTUP_TIMER, 25, 0, 0) * 60 - 1); + chTiptup_setState(thisActor, CH_TIPTUP_STATE_5_WIN_MINIGAME); } void chTiptup_sfxCorrectHit(void){ @@ -78,21 +116,21 @@ void chTiptup_textEvent(ActorMarker *this, enum asset_e text_id, s32 arg2){ thisActor = marker_getActor(this); switch(text_id){ - case ASSET_C72_DIALOG_TIPTUP_MEET_1: - case ASSET_C74_DIALOG_TIPTUP_MEET_3: - chTiptup_setState(thisActor, 3); + case VER_SELECT(ASSET_C72_DIALOG_TIPTUP_MEET_1, 0x9B5, 0, 0): + case VER_SELECT(ASSET_C74_DIALOG_TIPTUP_MEET_3, 0x9B7, 0, 0): + chTiptup_setState(thisActor, CH_TIPTUP_STATE_3_FF_GIVE_SEQUENCE); break; - case ASSET_C78_DIALOG_TIPTUP_LESSON_1_REPEAT: - case ASSET_C7A_DIALOG_TIPTUP_LESSON_2_REPEAT: - case ASSET_C7C_DIALOG_TIPTUP_LESSON_3_REPEAT: - chTiptup_setState(thisActor, 4); + case VER_SELECT(ASSET_C78_DIALOG_TIPTUP_LESSON_1_REPEAT, 0x9BB, 0, 0): + case VER_SELECT(ASSET_C7A_DIALOG_TIPTUP_LESSON_2_REPEAT, 0x9BD, 0, 0): + case VER_SELECT(ASSET_C7C_DIALOG_TIPTUP_LESSON_3_REPEAT, 0x9BF, 0, 0): + chTiptup_setState(thisActor, CH_TIPTUP_STATE_4_AWAIT_SEQUENCE_COMPLETION); break; - case ASSET_C77_DIALOG_TIPTUP_LESSON_1_COMPLETE: - case ASSET_C79_DIALOG_TIPTUP_LESSON_2_COMPLETE: + case VER_SELECT(ASSET_C77_DIALOG_TIPTUP_LESSON_1_COMPLETE, 0x9BA, 0, 0): + case VER_SELECT(ASSET_C79_DIALOG_TIPTUP_LESSON_2_COMPLETE, 0x9BC, 0, 0): func_80324E38(0.0f, 0); - chTiptup_setState(thisActor, 3); + chTiptup_setState(thisActor, CH_TIPTUP_STATE_3_FF_GIVE_SEQUENCE); break; - case ASSET_C7B_DIALOG_TIPTUP_LESSON_3_COMPLETE: + case VER_SELECT(ASSET_C7B_DIALOG_TIPTUP_LESSON_3_COMPLETE, 0x9BE, 0, 0): timedFunc_set_0(0.0f, chTiptup_jiggySpawn); timed_exitStaticCamera(2.5f); func_80324E38(2.5f, 0); @@ -113,113 +151,164 @@ void chTiptup_correctHit(ActorMarker *this){ return; if(volatileFlag_get(VOLATILE_FLAG_2_FF_IN_MINIGAME)){ - item_set(ITEM_6_HOURGLASS,0); - volatileFlag_set(VOLATILE_FLAG_3,0); - volatileFlag_set(VOLATILE_FLAG_5_FF_MINIGAME_WON,1); + item_set(ITEM_6_HOURGLASS, 0); + volatileFlag_set(VOLATILE_FLAG_3, 0); + volatileFlag_set(VOLATILE_FLAG_5_FF_MINIGAME_WON, 1); } else{ - BGS_func_80388660(thisActor->marker); + chTiptup_minigameComplete(thisActor->marker); } } -void chTiptup_setState(Actor *this, s32 arg1){ +void chTiptup_setState(Actor *this, s32 next_state){ ActorLocal_Tiptup *unqPtr; f32 sp54; - - f32 tmpf; - s32 i; + f32 sequence_time; + s32 current_member_index; s32 j; s32 prev_member; s32 rand2; Struct_BGS_2270_0s *s1; unqPtr = (ActorLocal_Tiptup *)&this->local; - this->state = arg1; - unqPtr->unkC = 0.0f; - if(this->state == 1){ + this->state = next_state; + unqPtr->animTimer = 0.0f; + if(this->state == CH_TIPTUP_STATE_1_IDLE){ skeletalAnim_set(this->unk148, ASSET_12B_ANIM_TIPTUP_IDLE, 1.0f, 9.0f); - unqPtr->unkC = randf2(5.0f, 15.0f); + unqPtr->animTimer = randf2(5.0f, 15.0f); } - if(this->state == 2){ + if(this->state == CH_TIPTUP_STATE_2_INSTRUCTIONS_DIALOG){ skeletalAnim_set(this->unk148, ASSET_12B_ANIM_TIPTUP_IDLE, 1.0f, 9.0f); - unqPtr->unkC = randf2(5.0f, 15.0f); + unqPtr->animTimer = randf2(5.0f, 15.0f); if (!this->has_met_before) { - this->has_met_before = true; - - if (unqPtr->unkA == 0) { - gcdialog_showDialog(ASSET_C72_DIALOG_TIPTUP_MEET_1, 0xe, this->position, this->marker, chTiptup_textEvent, 0); + this->has_met_before = TRUE; + + if (unqPtr->round == TIPTUP_ROUND_1) { + gcdialog_showDialog( + VER_SELECT(ASSET_C72_DIALOG_TIPTUP_MEET_1, 0x9B5, 0, 0), + 0xe, + this->position, + this->marker, + chTiptup_textEvent, + 0); } else { - gcdialog_showDialog(ASSET_C74_DIALOG_TIPTUP_MEET_3, 0xf, this->position, this->marker, chTiptup_textEvent, 0); + gcdialog_showDialog( + VER_SELECT(ASSET_C74_DIALOG_TIPTUP_MEET_3, 0x9B7, 0, 0), + 0xf, + this->position, + this->marker, + chTiptup_textEvent, + 0); } } else { - gcdialog_showDialog(D_80390854[unqPtr->unkA], 0xf, this->position, this->marker, chTiptup_textEvent, 0); + gcdialog_showDialog( + chTiptupRepeatDialogs[unqPtr->round], + 0xf, + this->position, + this->marker, + chTiptup_textEvent, + 0); } } - if(this->state == 3){ + if(this->state == CH_TIPTUP_STATE_3_FF_GIVE_SEQUENCE){ unqPtr->unk0 = 0; bk_vector_clear(unqPtr->unk4); func_80324E38(0.0f, 3); timed_setStaticCameraToNode(0.5f, 0); - tmpf = 0.5f; - i = 0; + sequence_time = 0.5f; + current_member_index = 0; prev_member = 0; - for(; i < D_80390864[unqPtr->unkA]; i++){ - tmpf += randf2(1.0f, 1.5f); - while((rand2 = randi2(1,7)) == prev_member); - timedFunc_set_2(tmpf, (GenFunction_2) chTiptup_activatePattern, (uintptr_t)this->marker, rand2); - timedFunc_set_2(tmpf + 0.1, (GenFunction_2)chTiptup_activatePattern, (uintptr_t)this->marker, 0); + for(; current_member_index < chTiptupSequenceLength[unqPtr->round]; current_member_index++){ + sequence_time += randf2(1.0f, 1.5f); + // while loop prevents same choir member in a row + while((rand2 = randi2(FIRST_CHOIR_MEMBER, LAST_CHOIR_MEMBER)) == prev_member); + timedFunc_set_2( + sequence_time, + (GenFunction_2) chTiptup_activatePattern, + reinterpret_cast(uintptr_t, this->marker), + rand2); + timedFunc_set_2( + sequence_time + 0.1, + (GenFunction_2)chTiptup_activatePattern, + reinterpret_cast(uintptr_t, this->marker), + 0); prev_member = rand2; }//L80388B7C - timed_exitStaticCamera(tmpf += 2.5); - if(!unqPtr->unkA && !volatileFlag_get(VOLATILE_FLAG_2_FF_IN_MINIGAME)){ - func_80324DBC(tmpf + 0.5, ASSET_C73_DIALOG_TIPTUP_MEET_2, 0xe, this->position, this->marker, chTiptup_textEvent, 0); - unqPtr->unkA = 1; + timed_exitStaticCamera(sequence_time += 2.5); + if(!unqPtr->round && !volatileFlag_get(VOLATILE_FLAG_2_FF_IN_MINIGAME)){ + func_80324DBC( + sequence_time + 0.5, + VER_SELECT(ASSET_C73_DIALOG_TIPTUP_MEET_2, 0x9B6, 0, 0), + 0xe, + this->position, + this->marker, + chTiptup_textEvent, + 0); + unqPtr->round = TIPTUP_ROUND_2; } - func_80324E38(sp54 = tmpf + 0.6, 0); + func_80324E38(sp54 = sequence_time + 0.6, 0); if(volatileFlag_get(VOLATILE_FLAG_2_FF_IN_MINIGAME)){ - timedFunc_set_1(sp54, (GenFunction_1)chTiptup_activateTimer, (uintptr_t)this->marker); + timedFunc_set_1( + sp54, + (GenFunction_1)chTiptup_activateTimer, + reinterpret_cast(uintptr_t, this->marker)); }else{ - this->state = 0x05; + this->state = CH_TIPTUP_STATE_5_WIN_MINIGAME; } - mapSpecificFlags_set(0, 0); + mapSpecificFlags_set(CH_TIPTUP_SPECIFIC_FLAG_0_CHOIR_MEMBER_HIT_AFTER_JIGGY, 0); }//L80388C6C - if(this->state == 4){ + if(this->state == CH_TIPTUP_STATE_4_AWAIT_SEQUENCE_COMPLETION){ unqPtr->unk0 = 0; func_80324E38(0.0f, 3); timed_setStaticCameraToNode(0.5f, 0); - tmpf = 0.5f; + sequence_time = 0.5f; for(j = 0; j < bk_vector_size(unqPtr->unk4); j++){ s1 = (Struct_BGS_2270_0s *)bk_vector_at(unqPtr->unk4,j); - tmpf += randf2(1.0f, 1.5f); - timedFunc_set_2(tmpf, (GenFunction_2)chTiptup_activatePattern, (uintptr_t)this->marker, s1->unk0); - timedFunc_set_2(tmpf + 0.1, (GenFunction_2)chTiptup_activatePattern, (uintptr_t)this->marker, 0); + sequence_time += randf2(1.0f, 1.5f); + timedFunc_set_2( + sequence_time, + (GenFunction_2)chTiptup_activatePattern, + reinterpret_cast(uintptr_t, this->marker), + s1->unk0); + timedFunc_set_2( + sequence_time + 0.1, + (GenFunction_2)chTiptup_activatePattern, + reinterpret_cast(uintptr_t, this->marker), + 0); } - timed_exitStaticCamera(tmpf += 2.5); - func_80324E38(tmpf + 0.6,0); + timed_exitStaticCamera(sequence_time += 2.5); + func_80324E38(sequence_time + 0.6, 0); bk_vector_clear(unqPtr->unk4); - this->state = 0x05; + this->state = CH_TIPTUP_STATE_5_WIN_MINIGAME; }//L80388D8C - if(this->state == 6){ - if(unqPtr->unkA == 3){ + if(this->state == CH_TIPTUP_STATE_6_AFTER_JIGGY_DIALOG){ + if(unqPtr->round == TIPTUP_ROUND_FF){ coMusicPlayer_playMusic(COMUSIC_2D_PUZZLE_SOLVED_FANFARE, 28000); } func_80324E38(0.5f, 3); timed_setStaticCameraToNode(1.5f, 1); - func_80324DBC(2.0f, D_8039085C[unqPtr->unkA++], 0xF, this->position, this->marker, chTiptup_textEvent, 0); + func_80324DBC( + 2.0f, + chTiptupSuccessDialogs[unqPtr->round++], + 0xF, + this->position, + this->marker, + chTiptup_textEvent, + 0); } } -void func_80388E44(ActorMarker *arg0, ActorMarker *arg1){ - func_8028F428(2,arg0); +void chTiptup_bouncePlayerOff(ActorMarker *arg0, ActorMarker *arg1){ + func_8028F428(2, arg0); } -s32 func_80388E70(ActorMarker *this){ +s32 chTiptup_getUnkB(ActorMarker *this){ Actor *ptr; ActorLocal_Tiptup *local; @@ -236,27 +325,34 @@ void chTiptup_choirHitReaction(ActorMarker *this, s32 arg1){ thisActor = marker_getActor(this); unqPtr = (ActorLocal_Tiptup *)&thisActor->local; if((s32)unqPtr->unk0 >= (s32) bk_vector_size(unqPtr->unk4)){ - if(!mapSpecificFlags_get(0) && gcdialog_showDialog(ASSET_C76_DIALOG_CHOIR_MEMBER_HIT_AFTER_JIGGY, 0, 0, 0, 0, 0)) - mapSpecificFlags_set(0,1); + if(!mapSpecificFlags_get(CH_TIPTUP_SPECIFIC_FLAG_0_CHOIR_MEMBER_HIT_AFTER_JIGGY) + && gcdialog_showDialog(VER_SELECT(ASSET_C76_DIALOG_CHOIR_MEMBER_HIT_AFTER_JIGGY, 0x9B9, 0, 0), 0, 0, 0, 0, 0)) + { + mapSpecificFlags_set(CH_TIPTUP_SPECIFIC_FLAG_0_CHOIR_MEMBER_HIT_AFTER_JIGGY, 1); + } }else{ tmp = (Struct_BGS_2270_0s *)bk_vector_at(unqPtr->unk4, unqPtr->unk0); if(arg1 == tmp->unk0){ - timedFunc_set_1(0.5f, (GenFunction_1)chTiptup_correctHit, (uintptr_t)thisActor->marker); + timedFunc_set_1(0.5f, (GenFunction_1)chTiptup_correctHit, reinterpret_cast(uintptr_t, thisActor->marker)); } else{ func_8028F55C(1, thisActor->marker); timedFunc_set_0(0.5f, chTiptup_sfxIncorrectHit); - if(!mapSpecificFlags_get(1) && !volatileFlag_get(VOLATILE_FLAG_2_FF_IN_MINIGAME) && gcdialog_showDialog(ASSET_C75_DIALOG_TIPTUP_MISS, 0, NULL, NULL, NULL, NULL)) - mapSpecificFlags_set(1,true); + if(!mapSpecificFlags_get(CH_TIPTUP_SPECIFIC_FLAG_1_TIPTUP_MISS) + && !volatileFlag_get(VOLATILE_FLAG_2_FF_IN_MINIGAME) + && gcdialog_showDialog(VER_SELECT(ASSET_C75_DIALOG_TIPTUP_MISS, 0x9B8, 0, 0), 0, NULL, NULL, NULL, NULL)) + { + mapSpecificFlags_set(CH_TIPTUP_SPECIFIC_FLAG_1_TIPTUP_MISS, TRUE); + } } } } -void func_80388FC0(Actor *this){ +void chTiptup_setMinigameProgress(Actor *this){ ActorLocal_Tiptup *local; local = (ActorLocal_Tiptup *)&this->local; - fileProgressFlag_setN(FILEPROG_0_TIPTUP_MINIGAME_PROGRESS, local->unkA, 2); + fileProgressFlag_setN(FILEPROG_0_TIPTUP_MINIGAME_PROGRESS, local->round, 2); bk_vector_free(local->unk4); } @@ -270,80 +366,88 @@ void func_80388FFC(ActorMarker *this, s32 *arg1, f32* arg2){ *arg2 = 0.52 + (f64)localPtr->unk9 * 0.12; localPtr->unk9++; *arg1 = localPtr->unk9; - } void chTiptup_update(Actor *this){ f32 player_position[3]; ActorLocal_Tiptup *unqPtr; - f32 sp3C; - f32 sp38; - f32 sp34; - f32 sp30; + f32 time_delta; + f32 sp38; // unused + f32 sp34; // unused + f32 sp30; // something about yaw unqPtr = (ActorLocal_Tiptup *)&this->local; - sp3C = time_getDelta(); + time_delta = time_getDelta(); if(!this->volatile_initialized){ - this->volatile_initialized = true; - this->marker->actorFreeFunc = func_80388FC0; - marker_setCollisionScripts(this->marker, func_80388E44, NULL, NULL); + this->volatile_initialized = TRUE; + this->marker->actorFreeFunc = chTiptup_setMinigameProgress; + marker_setCollisionScripts(this->marker, chTiptup_bouncePlayerOff, NULL, NULL); unqPtr->unk0 = 0; unqPtr->unk4 = bk_vector_new(sizeof(Struct_BGS_2270_0s), 8); unqPtr->unk8 = 0; unqPtr->unk9 = 0; - unqPtr->unkA = fileProgressFlag_getN(FILEPROG_0_TIPTUP_MINIGAME_PROGRESS, 2); + unqPtr->round = fileProgressFlag_getN(FILEPROG_0_TIPTUP_MINIGAME_PROGRESS, 2); unqPtr->unkB = 0; - unqPtr->unkC = 0.0f; + unqPtr->animTimer = 0.0f; if(volatileFlag_get(VOLATILE_FLAG_2_FF_IN_MINIGAME)){ - unqPtr->unkA = 3; + unqPtr->round = TIPTUP_ROUND_FF; this->position_y = this->position_y - 300.0f; } - chTiptup_setState(this, 1); - if(jiggyscore_isSpawned(JIGGY_27_BGS_TIPTUP) && !volatileFlag_get(VOLATILE_FLAG_2_FF_IN_MINIGAME) && !volatileFlag_get(VOLATILE_FLAG_1)) + chTiptup_setState(this, CH_TIPTUP_STATE_1_IDLE); + if(jiggyscore_isSpawned(JIGGY_27_BGS_TIPTUP) + && !volatileFlag_get(VOLATILE_FLAG_2_FF_IN_MINIGAME) + && !volatileFlag_get(VOLATILE_FLAG_1)) + { marker_despawn(this->marker); + } } else{ player_getPosition(player_position); - if(skeletalAnim_getAnimId(this->unk148) == ASSET_12C_ANIM_TIPTUP_TAPPING && skeletalAnim_getLoopCount(this->unk148) > 0){ + if(skeletalAnim_getAnimId(this->unk148) == ASSET_12C_ANIM_TIPTUP_TAPPING + && skeletalAnim_getLoopCount(this->unk148) > 0) + { skeletalAnim_set(this->unk148, ASSET_12B_ANIM_TIPTUP_IDLE, 1.0f, 9.0f); - unqPtr->unkC = randf2(5.0f, 15.0f); + unqPtr->animTimer = randf2(5.0f, 15.0f); } - if(ml_timer_update(&unqPtr->unkC, sp3C)){ + if(ml_timer_update(&unqPtr->animTimer, time_delta)){ skeletalAnim_set(this->unk148, ASSET_12C_ANIM_TIPTUP_TAPPING, 1.0f, 4.0f); } func_80258A4C(this->position, this->yaw - 90.0f, player_position, &sp38, &sp34, &sp30); - this->yaw = this->yaw + 5.0f*sp30; - if(this->state == 1){ + this->yaw = this->yaw + 5.0f * sp30; + if(this->state == CH_TIPTUP_STATE_1_IDLE){ if(volatileFlag_get(VOLATILE_FLAG_2_FF_IN_MINIGAME)){ if(volatileFlag_get(VOLATILE_FLAG_3)){ - func_80324E38(0.0f,0); - chTiptup_setState(this, 3); + func_80324E38(0.0f, 0); + chTiptup_setState(this, CH_TIPTUP_STATE_3_FF_GIVE_SEQUENCE); } } else{ - if(ml_vec3f_distance(this->position, player_position) < 300.0f && player_getTransformation() == TRANSFORM_1_BANJO && !jiggyscore_isSpawned(JIGGY_27_BGS_TIPTUP)){ - chTiptup_setState(this, 2); + if(ml_vec3f_distance(this->position, player_position) < 300.0f + && player_getTransformation() == TRANSFORM_1_BANJO + && !jiggyscore_isSpawned(JIGGY_27_BGS_TIPTUP)) + { + chTiptup_setState(this, CH_TIPTUP_STATE_2_INSTRUCTIONS_DIALOG); } } } - if(this->state == 5){ + if(this->state == CH_TIPTUP_STATE_5_WIN_MINIGAME){ if(volatileFlag_get(VOLATILE_FLAG_2_FF_IN_MINIGAME)){ if(item_empty(ITEM_0_HOURGLASS_TIMER)){ - item_set(ITEM_6_HOURGLASS,1); - volatileFlag_set(VOLATILE_FLAG_3,0); - volatileFlag_set(VOLATILE_FLAG_5_FF_MINIGAME_WON,0); + item_set(ITEM_6_HOURGLASS, 1); + volatileFlag_set(VOLATILE_FLAG_3, 0); + volatileFlag_set(VOLATILE_FLAG_5_FF_MINIGAME_WON, 0); } } //L80389370 else{ if(ml_vec3f_distance(this->position, player_position) >= 300.0f) - chTiptup_setState(this, 1); + chTiptup_setState(this, CH_TIPTUP_STATE_1_IDLE); } }//L803893A0 - if(this->state == 6){ + if(this->state == CH_TIPTUP_STATE_6_AFTER_JIGGY_DIALOG){ if(ml_vec3f_distance(this->position, player_position) < 300.0f && !unqPtr->unk8){ unqPtr->unk8 = 1; - gcdialog_showDialog(ASSET_C7D_DIALOG_TIPTUP_MEET_AFTER_JIGGY, 4, 0, 0, 0, 0); + gcdialog_showDialog(VER_SELECT(ASSET_C7D_DIALOG_TIPTUP_MEET_AFTER_JIGGY, 0x9C0, 0, 0), 4, 0, 0, 0, 0); } } } diff --git a/src/BGS/ch/yumblie.c b/src/BGS/ch/yumblie.c index 6c37db606..7b2e90594 100644 --- a/src/BGS/ch/yumblie.c +++ b/src/BGS/ch/yumblie.c @@ -45,7 +45,7 @@ bool func_8038B160(Actor *this){ s32 temp_v0; local = (ActorLocal_Yumblie *)&this->local; - temp_v0 = func_8038A9E0(local->game_marker); + temp_v0 = chMrVileMinigame_getDialogIndex(local->game_marker); if ((temp_v0 == 1) || (temp_v0 == 4)) { return false; @@ -70,7 +70,7 @@ void chyumblie_set_state(Actor* this, enum chyumblie_state_e next_state){ if(next_state == 2){ this->yaw = randf2(0.0f, 360.0f); s0->unk4 = (sNetForcedPieceType >= 0) ? (u8)sNetForcedPieceType : func_8038B160(this); - chvilegame_new_piece(s0->game_marker, this->marker, this->position, s0->unk4); + chMrVileMinigame_newPiece(s0->game_marker, this->marker, this->position, s0->unk4); skeletalAnim_set(this->unk148, (s0->unk4)? ASSET_128_ANIM_GRUMBLIE_APPEAR : ASSET_125_ANIM_YUMBLIE_APPEAR, 0.0f, 1.5f); skeletalAnim_setBehavior(this->unk148, SKELETAL_ANIM_2_ONCE); } @@ -198,7 +198,7 @@ void chyumblie_update(Actor *this){ sp50 = skeletalAnim_getProgress(this->unk148); if(this->state == YUMBLIE_STATE_1_UNDER_GROUND){ if(ml_timer_update(&s0->unk8, sp4C)){ - if(EventSystem_Should(VB_VILE_YUMBLIE_EMERGE, mapSpecificFlags_get(6) && (12 > chvilegame_get_piece_count(s0->game_marker)))){ + if(EventSystem_Should(VB_VILE_YUMBLIE_EMERGE, mapSpecificFlags_get(6) && (12 > chMrVileMinigame_getPieceCount(s0->game_marker)))){ chyumblie_set_state(this, YUMBLIE_STATE_2_APPEAR); } else{ diff --git a/src/BGS/checksums.c b/src/BGS/checksums.c new file mode 100644 index 000000000..d802484b3 --- /dev/null +++ b/src/BGS/checksums.c @@ -0,0 +1,7 @@ +// BanjoDecomp: BGS/checksums.c +#include +#include "checksums.h" + +// !! THIS FILE MUST BE LINKED FIRST FOR THIS OVERLAY !! + +/* bss */ struct overlay_checksums_s gChecksumsBGS; diff --git a/src/BGS/crc.c b/src/BGS/crc.c index 96786bf61..86979482f 100644 --- a/src/BGS/crc.c +++ b/src/BGS/crc.c @@ -1,7 +1,8 @@ // BanjoDecomp: crc.c #include +#include "checksums.h" +#include "version.h" -//TODO Implement CRC calculation in Makefile(?) -u32 D_80390B20 = 0x00282B61; //BGS.code CRC1 -u32 D_80390B24 = 0xccdaeea0; //BGS.code CRC2 -u32 D_80390B28 = 0x0002DE6B; //BGS.data CRC1 (with this value = 0) +s32 D_80390B20 = VER_SELECT(0x00282B61, 0x002871C5, 0, 0); // BGS_TEXT_CRC1 +s32 D_80390B24 = VER_SELECT(0xccdaeea0, 0xEDE9F826, 0, 0); // BGS_TEXT_CRC2 +s32 D_80390B28 = VER_SELECT(0x0002DE6B, 0x0002EA91, 0, 0); // BGS_DATA_CRC1 diff --git a/src/BGS/minigame_vile.c b/src/BGS/mrvileminigame.c similarity index 58% rename from src/BGS/minigame_vile.c rename to src/BGS/mrvileminigame.c index 707058982..7b68b78d4 100644 --- a/src/BGS/minigame_vile.c +++ b/src/BGS/mrvileminigame.c @@ -1,4 +1,4 @@ -// BanjoDecomp: code_3420.c +// BanjoDecomp: BGS/mrvileminigame.c #include #include "functions.h" #include "bk_math.h" @@ -6,7 +6,7 @@ #include "port/Enhancements/Events/Hooks/Events.h" #include "port/Network/Anchor/VileSync.h" -extern f32 *chVile_getPostion(ActorMarker *); +extern f32 *chMrVile_getPostion(ActorMarker *); extern void bundle_setRandomVelocity(f32); extern void func_802FDCB8(s32); @@ -21,95 +21,122 @@ typedef struct { // u8 pad1[3]; bk_vector(struct vilegame_piece) *game_pieces; BKModelBin *grumblie_model_bin; - u8 unkC; - u8 unkD; + u8 dialogIndex; + u8 mode; u8 player_score; u8 vile_score; f32 type_change_timer; ActorMarker *vile_marker; -}ActorLocal_BGS_3420; +}chMrVileMinigameActor; -void func_8038A068(Actor *this, s32 next_state); -void chvilegame_update(Actor *this); +void chMrVileMinigame_setState(Actor *this, s32 next_state); +void chMrVileMinigame_update(Actor *this); /* .data */ ActorInfo D_80390960 = { MARKER_C6_VILE_GAME_CTRL, ACTOR_138_VILE_GAME_CTRL, 0, 0, NULL, - chvilegame_update, NULL, func_80325340, + chMrVileMinigame_update, NULL, func_80325340, 0, 0, 0.0f, 0 }; // Vile Wins -enum asset_e D_80390984[] = { +enum asset_e chMrVileMinigamePlayerLosesDialog[] = { 0, - ASSET_C66_DIALOG_MR_VILE_WINS_ROUND_1, - ASSET_C68_DIALOG_MR_VILE_WINS_ROUND_2, - ASSET_C6A_DIALOG_MR_VILE_WINS_ROUND_3, - ASSET_C92_DIALOG_MR_VILE_WINS_EXTRA_CHALLENGE_2, - ASSET_C93_DIALOG_MR_VILE_WINS_EXTRA_CHALLENGE_3, - ASSET_C94_DIALOG_MR_VILE_WINS_EXTRA_CHALLENGE_4, + VER_SELECT(ASSET_C66_DIALOG_MR_VILE_WINS_ROUND_1, 0x9A9, 0, 0), + VER_SELECT(ASSET_C68_DIALOG_MR_VILE_WINS_ROUND_2, 0x9AB, 0, 0), + VER_SELECT(ASSET_C6A_DIALOG_MR_VILE_WINS_ROUND_3, 0x9AD, 0, 0), + VER_SELECT(ASSET_C92_DIALOG_MR_VILE_WINS_EXTRA_CHALLENGE_2, 0x9D5, 0, 0), + VER_SELECT(ASSET_C93_DIALOG_MR_VILE_WINS_EXTRA_CHALLENGE_3, 0x9D6, 0, 0), + VER_SELECT(ASSET_C94_DIALOG_MR_VILE_WINS_EXTRA_CHALLENGE_4, 0x9D7, 0, 0), 0 }; // Player Wins -enum asset_e D_803909A4[] = { +enum asset_e chMrVileMinigamePlayerWinsDialog[] = { 0, - ASSET_C67_DIALOG_MR_VILE_ROUND_2_START, - ASSET_C69_DIALOG_MR_VILE_ROUND_3_START, + VER_SELECT(ASSET_C67_DIALOG_MR_VILE_ROUND_2_START, 0x9AA, 0, 0), + VER_SELECT(ASSET_C69_DIALOG_MR_VILE_ROUND_3_START, 0x9AC, 0, 0), 0, - ASSET_C95_DIALOG_MR_VILE_LOSES_EXTRA_CHALLENGE_1, - ASSET_C96_DIALOG_MR_VILE_LOSES_EXTRA_CHALLENGE_2, - ASSET_C97_DIALOG_MR_VILE_LOSES_EXTRA_CHALLENGE_3 + VER_SELECT(ASSET_C95_DIALOG_MR_VILE_LOSES_EXTRA_CHALLENGE_1, 0x9D8, 0, 0), + VER_SELECT(ASSET_C96_DIALOG_MR_VILE_LOSES_EXTRA_CHALLENGE_2, 0x9D9, 0, 0), + VER_SELECT(ASSET_C97_DIALOG_MR_VILE_LOSES_EXTRA_CHALLENGE_3, 0x9DA, 0, 0) }; // Player Wins Rematch -enum asset_e D_803909C0[] = { +enum asset_e chMrVileMinigamePlayerWinsRematchDialog[] = { 0, - ASSET_C6E_DIALOG_MR_VILE_LOSE_ROUND_2_REMATCH, - ASSET_C6F_DIALOG_MR_VILE_LOSE_ROUND_3_REMATCH, + VER_SELECT(ASSET_C6E_DIALOG_MR_VILE_LOSE_ROUND_2_REMATCH, 0x9B1, 0, 0), + VER_SELECT(ASSET_C6F_DIALOG_MR_VILE_LOSE_ROUND_3_REMATCH, 0x9B2, 0, 0), 0, - ASSET_C95_DIALOG_MR_VILE_LOSES_EXTRA_CHALLENGE_1, - ASSET_C96_DIALOG_MR_VILE_LOSES_EXTRA_CHALLENGE_2, - ASSET_C97_DIALOG_MR_VILE_LOSES_EXTRA_CHALLENGE_3 + VER_SELECT(ASSET_C95_DIALOG_MR_VILE_LOSES_EXTRA_CHALLENGE_1, 0x9D8, 0, 0), + VER_SELECT(ASSET_C96_DIALOG_MR_VILE_LOSES_EXTRA_CHALLENGE_2, 0x9D9, 0, 0), + VER_SELECT(ASSET_C97_DIALOG_MR_VILE_LOSES_EXTRA_CHALLENGE_3, 0x9DA, 0, 0) }; -// Player Declines -enum asset_e D_803909DC[] = { - ASSET_C65_DIALOG_MR_VILE_PLAYER_DECLINES, - ASSET_C65_DIALOG_MR_VILE_PLAYER_DECLINES, - ASSET_C65_DIALOG_MR_VILE_PLAYER_DECLINES, - ASSET_C8F_DIALOG_MR_VILE_PLAYER_DECLINES_EXTRA_CHALLENGE, +enum asset_e chMrVileMinigamePlayerDeclinesDialog[] = { + VER_SELECT(ASSET_C65_DIALOG_MR_VILE_PLAYER_DECLINES, 0x9A8, 0, 0), + VER_SELECT(ASSET_C65_DIALOG_MR_VILE_PLAYER_DECLINES, 0x9A8, 0, 0), + VER_SELECT(ASSET_C65_DIALOG_MR_VILE_PLAYER_DECLINES, 0x9A8, 0, 0), + VER_SELECT(ASSET_C8F_DIALOG_MR_VILE_PLAYER_DECLINES_EXTRA_CHALLENGE, 0x9D2, 0, 0), 0, 0, 0 }; -// Round 1 Regular & Extra Challenge -enum asset_e BGS_D_803909F8[] = { - ASSET_C64_DIALOG_MR_VILE_ROUND_1_START, +enum asset_e chMrVileMinigameRound1AndChallengeDialog[] = { + VER_SELECT(ASSET_C64_DIALOG_MR_VILE_ROUND_1_START, 0x9A7, 0, 0), 0, 0, - ASSET_C8E_DIALOG_MR_VILE_WINS_EXTRA_CHALLENGE_1, + VER_SELECT(ASSET_C8E_DIALOG_MR_VILE_WINS_EXTRA_CHALLENGE_1, 0x9D1, 0, 0), 0, 0, 0, 0 }; -enum asset_e D_80390A18[] = { - ASSET_C6D_DIALOG_MR_VILE_LOSE_ROUND_1_REMATCH, - ASSET_C70_DIALOG_MR_VILE_WIN_ROUND_2_REMATCH, - ASSET_C71_DIALOG_MR_VILE_WIN_ROUND_3_REMATCH, - ASSET_C8E_DIALOG_MR_VILE_WINS_EXTRA_CHALLENGE_1, +enum asset_e chMrVileMinigameRematchDialog[] = { + VER_SELECT(ASSET_C6D_DIALOG_MR_VILE_LOSE_ROUND_1_REMATCH, 0x9B0, 0, 0), + VER_SELECT(ASSET_C70_DIALOG_MR_VILE_WIN_ROUND_2_REMATCH, 0x9B3, 0, 0), + VER_SELECT(ASSET_C71_DIALOG_MR_VILE_WIN_ROUND_3_REMATCH, 0x9B4, 0, 0), + VER_SELECT(ASSET_C8E_DIALOG_MR_VILE_WINS_EXTRA_CHALLENGE_1, 0x9D1, 0, 0), 0, 0, 0, 0 }; +enum MrVileMinigameState { + MR_VILE_MINIGAME_STATE_0_NO_INIT = 0, + MR_VILE_MINIGAME_STATE_1_IDLE, + MR_VILE_MINIGAME_STATE_2_YES_OR_NO, + MR_VILE_MINIGAME_STATE_3_DECLINE_MINIGAME, + MR_VILE_MINIGAME_STATE_4_ROUND_INTRO_EXPLANATION, + MR_VILE_MINIGAME_STATE_5_PLAYING_MINIGAME, + MR_VILE_MINIGAME_STATE_6_VILE_WINS, + MR_VILE_MINIGAME_STATE_7_ATTACK_PLAYER, + MR_VILE_MINIGAME_STATE_8_PLAYER_WINS, + MR_VILE_MINIGAME_STATE_9_DROP_JIGGY, + MR_VILE_MINIGAME_STATE_A_DROP_EXTRA_LIVES +}; + +enum MrVileMinigameMode { + MR_VILE_MINIGAME_MODE_0_ROUND_1 = 0, + MR_VILE_MINIGAME_MODE_1_ROUND_2, + MR_VILE_MINIGAME_MODE_2_ROUND_3, + MR_VILE_MINIGAME_MODE_3_CHALLENGE_1_AND_FF, + MR_VILE_MINIGAME_MODE_4_CHALLENGE_2, + MR_VILE_MINIGAME_MODE_4_CHALLENGE_3 +}; + +#define MR_VILE_MINIGAME_TIMER VER_SELECT(3600, 3000, 0, 0) +#define TYPE_CHANGE_TIMER_REGULAR 10.0f +#define TYPE_CHANGE_TIMER_FF 5.0f +#define EXTRA_LIFE_SCORE 35 +#define MAX_DISTANCE_FROM_PIECE 65.25 + /* .code */ -bool BGS_func_80389810(f32 arg0[3]) { +bool chMrVileMinigame_didPlayerConsumePiece(f32 arg0[3]) { if (player_movementGroup() != BSGROUP_7_CROC_ATTACK) { return false; } @@ -117,8 +144,8 @@ bool BGS_func_80389810(f32 arg0[3]) { return true; } -void BGS_func_80389850(Actor *this, s32 arg1) { - ActorLocal_BGS_3420 *local; +void chMrVileMinigame_spawnJiggy(Actor *this, s32 arg1) { + chMrVileMinigameActor *local; Actor *vile; f32 sp94[3]; f32 sp88[3]; @@ -126,7 +153,7 @@ void BGS_func_80389850(Actor *this, s32 arg1) { s32 var_s0; s32 var_v0; - local = (ActorLocal_BGS_3420 *)&this->local; + local = (chMrVileMinigameActor *)&this->local; vile = marker_getActor(local->vile_marker); if (arg1 != 0) { if (LENGTH_VEC3F(this->position) < 800.0f) { @@ -174,120 +201,127 @@ void BGS_func_80389850(Actor *this, s32 arg1) { ncStaticCamera_setPositionAndRotation(sp94, sp88); } -void func_80389B48(ActorMarker *marker, enum asset_e text_id, s32 arg2){ +void chMrVileMinigame_vileOffersMinigame(ActorMarker *marker, enum asset_e text_id, s32 arg2){ Actor *this; this = marker_getActor(marker); if(arg2 == 1){ - func_8038A068(this, 4); + chMrVileMinigame_setState(this, 4); } else{ - func_8038A068(this, 3); + chMrVileMinigame_setState(this, 3); } } -void func_80389B98(ActorMarker *marker, enum asset_e text_id, s32 arg2){ +void chMrVileMinigame_setStateIdleAfterDeclined(ActorMarker *marker, enum asset_e text_id, s32 arg2){ Actor *this; this = marker_getActor(marker); - func_8038A068(this, 1); + chMrVileMinigame_setState(this, 1); } -void func_80389BC8(ActorMarker *marker, enum asset_e text_id, s32 arg2){ +void chMrVileMinigame_setStatePlayingMinigame(ActorMarker *marker, enum asset_e text_id, s32 arg2){ Actor *this; this = marker_getActor(marker); - func_8038A068(this, 5); + chMrVileMinigame_setState(this, 5); } -void func_80389BF8(ActorMarker *marker, enum asset_e text_id, s32 arg2) { +void chMrVileMinigame_vileAttacksPlayer(ActorMarker *marker, enum asset_e text_id, s32 arg2) { Actor *this; - ActorLocal_BGS_3420 *local; + chMrVileMinigameActor *local; this = marker_getActor(marker); - local = (ActorLocal_BGS_3420 *)&this->local; + local = (chMrVileMinigameActor *)&this->local; timed_exitStaticCamera(0.0f); func_80324E38(0.0f, 0); - local->unkC--; - func_8038A068(this, 7); + local->dialogIndex--; + chMrVileMinigame_setState(this, 7); } -void func_80389C58(ActorMarker *marker) { +void chMrVileMinigame_vileWinsRound(ActorMarker *marker) { Actor *this; - ActorLocal_BGS_3420 *local; + chMrVileMinigameActor *local; this = marker_getActor(marker); - local = (ActorLocal_BGS_3420 *)&this->local; - BGS_func_80389850(this, 0); - gcdialog_showDialog(D_80390984[local->unkC], 0xF, chVile_getPostion(local->vile_marker), this->marker, func_80389BF8, NULL); + local = (chMrVileMinigameActor *)&this->local; + chMrVileMinigame_spawnJiggy(this, 0); + gcdialog_showDialog(chMrVileMinigamePlayerLosesDialog[local->dialogIndex], 0xF, chMrVile_getPostion(local->vile_marker), this->marker, chMrVileMinigame_vileAttacksPlayer, NULL); } -void BGS_func_80389CD8(ActorMarker *marker, enum asset_e text_id, s32 arg2){ +void chMrVileMinigame_startNextRound(ActorMarker *marker, enum asset_e text_id, s32 arg2){ Actor *this; this = marker_getActor(marker); timed_exitStaticCamera(0.0f); func_80324E38(0.0f, 0); - func_8038A068(this, 5); + chMrVileMinigame_setState(this, 5); } -void func_80389D20(ActorMarker *marker) { +void chMrVileMinigame_playerWinsRound(ActorMarker *marker) { Actor *this; - ActorLocal_BGS_3420 *local; + chMrVileMinigameActor *local; this = marker_getActor(marker); - local = (ActorLocal_BGS_3420 *)&this->local; - BGS_func_80389850(this, 0); - if (local->unkC == local->unkD) { - gcdialog_showDialog(D_803909A4[local->unkC], 0xF, chVile_getPostion(local->vile_marker), this->marker, BGS_func_80389CD8, NULL); + local = (chMrVileMinigameActor *)&this->local; + chMrVileMinigame_spawnJiggy(this, 0); + if (local->dialogIndex == local->mode) { + gcdialog_showDialog(chMrVileMinigamePlayerWinsDialog[local->dialogIndex], 0xF, chMrVile_getPostion(local->vile_marker), this->marker, chMrVileMinigame_startNextRound, NULL); } else { - gcdialog_showDialog(D_803909C0[local->unkC], 0xF, chVile_getPostion(local->vile_marker), this->marker, BGS_func_80389CD8, NULL); + gcdialog_showDialog(chMrVileMinigamePlayerWinsRematchDialog[local->dialogIndex], 0xF, chMrVile_getPostion(local->vile_marker), this->marker, chMrVileMinigame_startNextRound, NULL); } func_80347A14(0); } -void func_80389DF8(ActorMarker *marker, enum asset_e text_id, s32 arg2){ +void chMrVileMinigame_setStateIdleAfterDeclinedAfterJiggy(ActorMarker *marker, enum asset_e text_id, s32 arg2){ Actor *this; this = marker_getActor(marker); timed_exitStaticCamera(0.0f); func_80324E38(0.0f, 0); - func_8038A068(this, 1); + chMrVileMinigame_setState(this, 1); } -void func_80389E40(ActorMarker *marker) { +void chMrVileMinigame_vileDropsJiggy(ActorMarker *marker) { Actor *this; - ActorLocal_BGS_3420 *local; + chMrVileMinigameActor *local; this = marker_getActor(marker); - local = (ActorLocal_BGS_3420 *)&this->local; - - BGS_func_80389850(this, 1); - gcdialog_showDialog(0xC6B, 0xF, chVile_getPostion(local->vile_marker), this->marker, func_80389DF8, NULL); + local = (chMrVileMinigameActor *)&this->local; + + chMrVileMinigame_spawnJiggy(this, 1); + gcdialog_showDialog( + VER_SELECT(ASSET_C6B_DIALOG_MR_VILE_PLAYER_WINS, 0x9AE, 0, 0), + 0xF, + chMrVile_getPostion(local->vile_marker), + this->marker, + chMrVileMinigame_setStateIdleAfterDeclinedAfterJiggy, + NULL + ); } -void func_80389EAC(ActorMarker *marker, enum asset_e text_id, s32 arg2){ +void chMrVileMinigame_setStateIdleAfterExtraLives(ActorMarker *marker, enum asset_e text_id, s32 arg2){ Actor *this; - ActorLocal_BGS_3420 *local; + chMrVileMinigameActor *local; this = marker_getActor(marker); - local = (ActorLocal_BGS_3420 *)&this->local; + local = (chMrVileMinigameActor *)&this->local; timed_exitStaticCamera(0.0f); func_80324E38(0.0f, 0); - local->unkC = 3; - func_8038A068(this, 1); + local->dialogIndex = 3; + chMrVileMinigame_setState(this, 1); } -void func_80389F08(ActorMarker *marker) { +void chMrVileMinigame_vileDropsExtraLives(ActorMarker *marker) { Actor *vile; Actor *this; - ActorLocal_BGS_3420 *local; + chMrVileMinigameActor *local; s32 i; s32 var_s2; this = marker_getActor(marker); - local = (ActorLocal_BGS_3420 *)&this->local; - BGS_func_80389850(this, 0); + local = (chMrVileMinigameActor *)&this->local; + chMrVileMinigame_spawnJiggy(this, 0); var_s2 = actorArray_actorCount(ACTOR_49_EXTRA_LIFE); vile = marker_getActor(local->vile_marker); if (var_s2 > 0) { @@ -303,7 +337,14 @@ void func_80389F08(ActorMarker *marker) { item_inc(ITEM_16_LIFE); } } - gcdialog_showDialog(0xC98, 0xF, chVile_getPostion(local->vile_marker), this->marker, func_80389EAC, NULL); + gcdialog_showDialog( + VER_SELECT(ASSET_C98_DIALOG_MR_VILE_GIVES_PRIZE, 0x9DB, 0, 0), + 0xF, + chMrVile_getPostion(local->vile_marker), + this->marker, + chMrVileMinigame_setStateIdleAfterExtraLives, + NULL + ); } @@ -311,46 +352,85 @@ void func_8038A044(void){ func_8025A58C(-1, 400); } -void func_8038A068(Actor *this, s32 next_state) { - ActorLocal_BGS_3420 *local; +void chMrVileMinigame_setState(Actor *this, s32 next_state) { + chMrVileMinigameActor *local; - local = (ActorLocal_BGS_3420 *)&this->local; + local = (chMrVileMinigameActor *)&this->local; mapSpecificFlags_set(6, false); if (next_state == 1) { if (local->vile_marker != NULL) { - func_8038C408(local->vile_marker); + chMrVile_setStateIdleWalking(local->vile_marker); } } - if (next_state == 2) { - func_8038C3B0(local->vile_marker); - if (local->unkC == 3) { - if (local->unkD >= 4) { - gcdialog_showDialog(0xC91, 0xE, chVile_getPostion(local->vile_marker), this->marker, func_80389B48, NULL); + if (next_state == MR_VILE_MINIGAME_STATE_2_YES_OR_NO) { + chMrVile_setStateTalkToPlayer(local->vile_marker); + if (local->dialogIndex == 3) { + if (local->mode >= MR_VILE_MINIGAME_MODE_4_CHALLENGE_2) { + gcdialog_showDialog( + VER_SELECT(ASSET_C91_DIALOG_MR_VILE_EXTRA_CHALLENGE_REMATCH_2, 0x9D4, 0, 0), + 0xE, + chMrVile_getPostion(local->vile_marker), + this->marker, + chMrVileMinigame_vileOffersMinigame, + NULL + ); } else { - gcdialog_showDialog((local->unkC == local->unkD) ? 0xC8D : 0xC90, 0xE, chVile_getPostion(local->vile_marker), this->marker, func_80389B48, NULL); + gcdialog_showDialog( + (local->dialogIndex == local->mode) ? + VER_SELECT(ASSET_C8D_DIALOG_MR_VILE_EXTRA_CHALLENGE_INTRO, 0x9D0, 0, 0) : + VER_SELECT(ASSET_C90_DIALOG_MR_VILE_EXTRA_CHALLENGE_REMATCH_1, 0x9D3, 0, 0), + 0xE, + chMrVile_getPostion(local->vile_marker), + this->marker, + chMrVileMinigame_vileOffersMinigame, + NULL + ); } } else { - gcdialog_showDialog((local->unkC == local->unkD) ? 0xC63 : 0xC6C, 0xE, chVile_getPostion(local->vile_marker), this->marker, func_80389B48, NULL); + gcdialog_showDialog( + (local->dialogIndex == local->mode) ? + VER_SELECT(ASSET_C63_DIALOG_MR_VILE_INTRO, 0x9A6, 0, 0) : + VER_SELECT(ASSET_C6C_DIALOG_MR_VILE_TRY_AGAIN, 0x9AF, 0, 0), + 0xE, + chMrVile_getPostion(local->vile_marker), + this->marker, + chMrVileMinigame_vileOffersMinigame, + NULL + ); } } - if (next_state == 3) { - gcdialog_showDialog(D_803909DC[local->unkC], 4, chVile_getPostion(local->vile_marker), this->marker, func_80389B98, NULL); - } - if (next_state == 4) { - if (local->unkC == local->unkD) { - gcdialog_showDialog(BGS_D_803909F8[local->unkC], 0xE | ((BGS_D_803909F8[local->unkC] == 0xC8E) ? 1 : 0) | 0xE, chVile_getPostion(local->vile_marker), this->marker, func_80389BC8, NULL); + if (next_state == MR_VILE_MINIGAME_STATE_3_DECLINE_MINIGAME) { + gcdialog_showDialog( + chMrVileMinigamePlayerDeclinesDialog[local->dialogIndex], + 4, + chMrVile_getPostion(local->vile_marker), + this->marker, + chMrVileMinigame_setStateIdleAfterDeclined, + NULL + ); + } + if (next_state == MR_VILE_MINIGAME_STATE_4_ROUND_INTRO_EXPLANATION) { + if (local->dialogIndex == local->mode) { + gcdialog_showDialog( + chMrVileMinigameRound1AndChallengeDialog[local->dialogIndex], + 0xE | ((chMrVileMinigameRound1AndChallengeDialog[local->dialogIndex] == VER_SELECT(ASSET_C8E_DIALOG_MR_VILE_WINS_EXTRA_CHALLENGE_1, 0x9D1, 0, 0)) ? 1 : 0) | 0xE, + chMrVile_getPostion(local->vile_marker), + this->marker, + chMrVileMinigame_setStatePlayingMinigame, + NULL + ); } else { - gcdialog_showDialog(D_80390A18[local->unkC], 0xF , chVile_getPostion(local->vile_marker), this->marker, func_80389BC8, NULL); + gcdialog_showDialog(chMrVileMinigameRematchDialog[local->dialogIndex], 0xF , chMrVile_getPostion(local->vile_marker), this->marker, chMrVileMinigame_setStatePlayingMinigame, NULL); } func_80347A14(0); } if (next_state == 5) { - local->unkC++; - if (local->unkD < local->unkC) { - local->unkD = local->unkC; + local->dialogIndex++; + if (local->mode < local->dialogIndex) { + local->mode = local->dialogIndex; } - if (local->unkC == 7) { - BGS_func_8038C434(local->vile_marker); + if (local->dialogIndex == 7) { + chMrVile_setStateRunFromPlayer(local->vile_marker); } else { local->current_type = YUMBLIE; local->player_score = 0; @@ -363,69 +443,69 @@ void func_8038A068(Actor *this, s32 next_state) { item_set(ITEM_0_HOURGLASS_TIMER, 3600-1); item_set(ITEM_6_HOURGLASS, true); mapSpecificFlags_set(6, true); - func_8038C3DC(local->vile_marker); + chMrVile_setStatePlayMinigame(local->vile_marker); func_8025A58C(0, 4000); timedFunc_set_2(1.0f, (GenFunction_2)coMusicPlayer_playMusic, COMUSIC_55_BGS_MR_VILE, 28000); } } if (this->state == 5) { - if (local->unkC != 7) { + if (local->dialogIndex != 7) { item_set(ITEM_6_HOURGLASS, false); if ((next_state != 6) && (next_state != 8) && (next_state != 9)) { func_8038A044(); } } - BGS_func_8038C460(local->vile_marker); + chMrVile_setInitialIdleStill(local->vile_marker); func_80347A14(1); } if (next_state == 6) { - func_8038C3B0(local->vile_marker); + chMrVile_setStateTalkToPlayer(local->vile_marker); func_80324E38(0.0f, 3); timedFunc_set_2(1.0f, (GenFunction_2)coMusicPlayer_playMusic, COMUSIC_3C_MINIGAME_LOSS, 28000); timedFunc_set_0(4.0f, (GenFunction_0)func_8038A044); - timedFunc_set_1(4.0f, (GenFunction_1)func_80389C58, (uintptr_t)this->marker); + timedFunc_set_1(4.0f, (GenFunction_1)chMrVileMinigame_vileWinsRound, (uintptr_t)this->marker); } if (next_state == 8) { - func_8038C3B0(local->vile_marker); + chMrVile_setStateTalkToPlayer(local->vile_marker); func_80324E38(0.0f, 3); timedFunc_set_2(1.0f, (GenFunction_2)coMusicPlayer_playMusic, COMUSIC_3B_MINIGAME_VICTORY, 28000); timedFunc_set_0(3.0f, (GenFunction_0)func_8038A044); - timedFunc_set_1(3.0f, (GenFunction_1)func_80389D20, (uintptr_t)this->marker); + timedFunc_set_1(3.0f, (GenFunction_1)chMrVileMinigame_playerWinsRound, (uintptr_t)this->marker); } if (next_state == 9) { - func_8038C3B0(local->vile_marker); + chMrVile_setStateTalkToPlayer(local->vile_marker); func_80324E38(0.0f, 3); timedFunc_set_2(1.0f, (GenFunction_2)coMusicPlayer_playMusic, COMUSIC_3B_MINIGAME_VICTORY, 28000); timedFunc_set_0(3.0f, (GenFunction_0)func_8038A044); - timedFunc_set_1(3.0f, (GenFunction_1)func_80389E40, (uintptr_t)this->marker); + timedFunc_set_1(3.0f, (GenFunction_1)chMrVileMinigame_vileDropsJiggy, (uintptr_t)this->marker); } if (next_state == 0xA) { - func_8038C3B0(local->vile_marker); + chMrVile_setStateTalkToPlayer(local->vile_marker); func_80324E38(0.5f, 3); timedFunc_set_2(1.0f, (GenFunction_2) coMusicPlayer_playMusic, COMUSIC_3B_MINIGAME_VICTORY, 28000); - timedFunc_set_1(3.0f, (GenFunction_1) func_80389F08, (uintptr_t)this->marker); + timedFunc_set_1(3.0f, (GenFunction_1) chMrVileMinigame_vileDropsExtraLives, (uintptr_t)this->marker); } if (next_state == 7) { - func_8038C384(local->vile_marker); + chMrVile_setStateAttackPlayer(local->vile_marker); } this->state = next_state; // [port] Anchor: authority claim/release and round lifecycle react to this event CALL_EVENT(OnVileGameStateChange, next_state); } -void chvilegame_player_consume_piece(Actor *this) { - ActorLocal_BGS_3420 *local; +void chMrVileMinigame_playerConsumePiece(Actor *this) { + chMrVileMinigameActor *local; bool is_correct_type; f32 sp44[3]; struct vilegame_piece *begin; struct vilegame_piece *end; struct vilegame_piece *i_ptr; - local = (ActorLocal_BGS_3420 *)&this->local; + local = (chMrVileMinigameActor *)&this->local; begin = (struct vilegame_piece *)bk_vector_getBegin(local->game_pieces); end = (struct vilegame_piece *) bk_vector_getEnd(local->game_pieces); - if ((end != begin) && BGS_func_80389810(sp44)){ + if ((end != begin) && chMrVileMinigame_didPlayerConsumePiece(sp44)){ sp44[1] = 0.0f; for(i_ptr = begin; i_ptr < end; i_ptr++){ if ((ml_vec3f_distance(i_ptr->position, sp44) < 65.25) && chyumblie_is_edible(i_ptr->marker)) { @@ -455,15 +535,15 @@ void chvilegame_player_consume_piece(Actor *this) { } } -bool chvilegame_cpu_consume_piece(ActorMarker *marker, f32 position[3]) { +bool chMrVileMinigame_mrVileConsumePiece(ActorMarker *marker, f32 position[3]) { Actor *this; - ActorLocal_BGS_3420 *local; + chMrVileMinigameActor *local; struct vilegame_piece *begin; struct vilegame_piece *end; struct vilegame_piece *i_ptr; this = marker_getActor(marker); - local = (ActorLocal_BGS_3420 *)&this->local; + local = (chMrVileMinigameActor *)&this->local; if (this->state != 5){ return false; } @@ -483,49 +563,49 @@ bool chvilegame_cpu_consume_piece(ActorMarker *marker, f32 position[3]) { BKModelBin *chvilegame_get_grumblie_model(ActorMarker *marker){ Actor *this; - ActorLocal_BGS_3420 *local; + chMrVileMinigameActor *local; this = marker_getActor(marker); - local = (ActorLocal_BGS_3420 *)&this->local; + local = (chMrVileMinigameActor *)&this->local; return local->grumblie_model_bin; } -s32 chvilegame_get_piece_count(ActorMarker *marker){ +s32 chMrVileMinigame_getPieceCount(ActorMarker *marker){ Actor *this; - ActorLocal_BGS_3420 *local; + chMrVileMinigameActor *local; this = marker_getActor(marker); - local = (ActorLocal_BGS_3420 *)&this->local; + local = (chMrVileMinigameActor *)&this->local; return bk_vector_size(local->game_pieces); } -s32 func_8038A9E0(ActorMarker *marker){ +s32 chMrVileMinigame_getDialogIndex(ActorMarker *marker){ Actor *this; - ActorLocal_BGS_3420 *local; + chMrVileMinigameActor *local; this = marker_getActor(marker); - local = (ActorLocal_BGS_3420 *)&this->local; - return local->unkC; + local = (chMrVileMinigameActor *)&this->local; + return local->dialogIndex; } -s32 chvilegame_get_score_difference(ActorMarker *marker){ +s32 chMrVileMinigame_getScoreDifference(ActorMarker *marker){ Actor *this; - ActorLocal_BGS_3420 *local; + chMrVileMinigameActor *local; this = marker_getActor(marker); - local = (ActorLocal_BGS_3420 *)&this->local; + local = (chMrVileMinigameActor *)&this->local; return local->vile_score - local->player_score; } -bool chvilegame_find_closest_piece(ActorMarker *marker, f32 position[3], f32 yaw, f32 dst[3]) { +bool chMrVileMinigame_findClosestPiece(ActorMarker *marker, f32 position[3], f32 yaw, f32 dst[3]) { f32 piece_direction[3]; f32 target_direction[3]; Actor *this; - ActorLocal_BGS_3420 *local; + chMrVileMinigameActor *local; struct vilegame_piece *closest_piece; struct vilegame_piece *begin; struct vilegame_piece *end; @@ -534,7 +614,7 @@ bool chvilegame_find_closest_piece(ActorMarker *marker, f32 position[3], f32 yaw f32 angle_diff; this = marker_getActor(marker); - local = (ActorLocal_BGS_3420 *)&this->local; + local = (chMrVileMinigameActor *)&this->local; target_direction[0] = 0.0f; target_direction[1] = 0.0f; target_direction[2] = 100.0f; @@ -569,13 +649,13 @@ bool chvilegame_find_closest_piece(ActorMarker *marker, f32 position[3], f32 yaw return false; } -void chvilegame_new_piece(ActorMarker *game_marker, ActorMarker *piece_marker, f32 position[3], u32 yumblie_type){ +void chMrVileMinigame_newPiece(ActorMarker *game_marker, ActorMarker *piece_marker, f32 position[3], u32 yumblie_type){ Actor *this; - ActorLocal_BGS_3420 *local; + chMrVileMinigameActor *local; struct vilegame_piece *temp_v0; this = marker_getActor(game_marker); - local = (ActorLocal_BGS_3420 *)&this->local; + local = (chMrVileMinigameActor *)&this->local; temp_v0 = (struct vilegame_piece *)bk_vector_pushBackNew(&local->game_pieces); temp_v0->type = yumblie_type; temp_v0->marker = piece_marker; @@ -585,14 +665,14 @@ void chvilegame_new_piece(ActorMarker *game_marker, ActorMarker *piece_marker, f temp_v0->position[1] = 0.0f; } -void chvilegame_free(Actor *this){ - ActorLocal_BGS_3420 *local; +void chMrVileMinigame_free(Actor *this){ + chMrVileMinigameActor *local; - local = (ActorLocal_BGS_3420 *)&this->local; + local = (chMrVileMinigameActor *)&this->local; // [port] Teardown ordering hazard: if Mr Vile is freed before this controller, its skeletal - // anim (unk148) is already NULL and func_8038A068(this, 0) -> skeletalAnim_set crashes. Skip it. + // anim (unk148) is already NULL and chMrVileMinigame_setState(this, 0) -> skeletalAnim_set crashes. Skip it. #if 0 - func_8038A068(this, 0); + chMrVileMinigame_setState(this, 0); #endif bk_vector_free(local->game_pieces); assetcache_release(local->grumblie_model_bin); @@ -600,13 +680,13 @@ void chvilegame_free(Actor *this){ void chvilegame_remove_piece(ActorMarker *game_marker, ActorMarker *piece_marker) { Actor *this; - ActorLocal_BGS_3420 *local; + chMrVileMinigameActor *local; struct vilegame_piece *begin; struct vilegame_piece *end; struct vilegame_piece *i_ptr; this = marker_getActor(game_marker); - local = (ActorLocal_BGS_3420 *)&this->local; + local = (chMrVileMinigameActor *)&this->local; begin = (struct vilegame_piece *)bk_vector_getBegin(local->game_pieces); end = (struct vilegame_piece *)bk_vector_getEnd(local->game_pieces); for(i_ptr = begin; i_ptr < end; i_ptr++){ @@ -617,8 +697,8 @@ void chvilegame_remove_piece(ActorMarker *game_marker, ActorMarker *piece_marker } } -void chvilegame_update(Actor *this) { - ActorLocal_BGS_3420 *local; +void chMrVileMinigame_update(Actor *this) { + chMrVileMinigameActor *local; f32 sp50; f32 sp4C; u8 temp_v0; @@ -626,28 +706,28 @@ void chvilegame_update(Actor *this) { s32 sp2C; sp50 = time_getDelta(); - local = (ActorLocal_BGS_3420 *)&this->local; + local = (chMrVileMinigameActor *)&this->local; if (!this->volatile_initialized) { this->volatile_initialized = true; - this->marker->actorFreeFunc = &chvilegame_free; + this->marker->actorFreeFunc = &chMrVileMinigame_free; local->game_pieces = bk_vector_new(sizeof(struct vilegame_piece), 0x20); local->grumblie_model_bin = assetcache_get(0x3F7); - local->unkC = 0; + local->dialogIndex = 0; local->vile_marker = NULL; if (this->state == 0) { - local->unkD = 0; + local->mode = 0; } else { this->state = 0; } if (jiggyscore_isSpawned(JIGGY_28_BGS_MR_VILE)) { - local->unkC = 3; - local->unkD = 3; + local->dialogIndex = 3; + local->mode = 3; } if (volatileFlag_get(VOLATILE_FLAG_2_FF_IN_MINIGAME)) { - local->unkC = 2; - local->unkD = 3; + local->dialogIndex = 2; + local->mode = 3; } - func_8038A068(this, 1); + chMrVileMinigame_setState(this, 1); return; } if (local->vile_marker == NULL) { @@ -656,8 +736,8 @@ void chvilegame_update(Actor *this) { // [port] Anchor: followers are driven by snapshots; only local chomp detection (for // eat requests) and HUD mirroring run here. if (!EventSystem_Should(VB_VILE_GAME_UPDATE, true)) { - if ((this->state == 5) && (local->unkC != 7)) { - chvilegame_player_consume_piece(this); + if ((this->state == 5) && (local->dialogIndex != 7)) { + chMrVileMinigame_playerConsumePiece(this); if (local->type_change_timer > 3.5) { if (local->current_type != 0) { item_adjustByDiffWithHud(ITEM_1D_GRUMBLIE, false); @@ -674,21 +754,21 @@ void chvilegame_update(Actor *this) { if (this->state == 1) { if (volatileFlag_get(VOLATILE_FLAG_2_FF_IN_MINIGAME)) { if (volatileFlag_get(VOLATILE_FLAG_3)) { - func_8038A068(this, 5); + chMrVileMinigame_setState(this, 5); } - } else if (func_8038C2A8(local->vile_marker)) { - func_8038A068(this, 2); + } else if (chMrVile_playerWithinRange(local->vile_marker)) { + chMrVileMinigame_setState(this, 2); } } if (this->state == 5) { - if (local->unkC == 7) { + if (local->dialogIndex == 7) { controller_copyFaceButtons(0, sp30); - if ((sp30[FACE_BUTTON(BUTTON_B)] > 0) && func_8038C2A8(local->vile_marker)) { - func_8038A068(this, 0xA); + if ((sp30[FACE_BUTTON(BUTTON_B)] > 0) && chMrVile_playerWithinRange(local->vile_marker)) { + chMrVileMinigame_setState(this, 0xA); } } else { - chvilegame_player_consume_piece(this); - if ((local->unkC == 3) || (local->unkC == 6)) { + chMrVileMinigame_playerConsumePiece(this); + if ((local->dialogIndex == 3) || (local->dialogIndex == 6)) { if (ml_timer_update(&local->type_change_timer, sp50)) { local->current_type = !local->current_type; if (volatileFlag_get(VOLATILE_FLAG_2_FF_IN_MINIGAME)) { @@ -715,21 +795,21 @@ void chvilegame_update(Actor *this) { if (volatileFlag_get(VOLATILE_FLAG_2_FF_IN_MINIGAME)) { volatileFlag_set(VOLATILE_FLAG_3, 0); volatileFlag_set(VOLATILE_FLAG_5_FF_MINIGAME_WON, BOOL(local->vile_score < local->player_score)); - func_8038A068(this, 1); + chMrVileMinigame_setState(this, 1); } else if (local->vile_score < local->player_score) { - if (local->unkC == 3) { - func_8038A068(this, 9); + if (local->dialogIndex == 3) { + chMrVileMinigame_setState(this, 9); } else { - func_8038A068(this, 8); + chMrVileMinigame_setState(this, 8); } } else { - func_8038A068(this, 6); + chMrVileMinigame_setState(this, 6); } } } } - if ((this->state == 7) && (BGS_func_8038C338(local->vile_marker) != 0)) { - func_8038A068(this, 1); + if ((this->state == 7) && (chMrVile_isInitialIdle(local->vile_marker) != 0)) { + chMrVileMinigame_setState(this, 1); } } @@ -738,7 +818,7 @@ void chvilegame_update(Actor *this) { // Fills a snapshot from the live controller. Only the stable states (idle, playing, and // the round-end results) are broadcast; dialog states cannot be reconstructed remotely. bool chvilegame_netGather(Actor *this, VileGameSnapshot *dst){ - ActorLocal_BGS_3420 *local = (ActorLocal_BGS_3420 *)&this->local; + chMrVileMinigameActor *local = (chMrVileMinigameActor *)&this->local; switch (this->state) { case 1: // idle @@ -752,8 +832,8 @@ bool chvilegame_netGather(Actor *this, VileGameSnapshot *dst){ return false; } dst->gameState = this->state; - dst->round = local->unkC; - dst->maxRound = local->unkD; + dst->round = local->dialogIndex; + dst->maxRound = local->mode; dst->currentType = local->current_type; dst->typeChangeTimer = local->type_change_timer; dst->playerScore = local->player_score; @@ -763,13 +843,13 @@ bool chvilegame_netGather(Actor *this, VileGameSnapshot *dst){ } // Forces the controller to match an authoritative snapshot (followers + late joiners). -// Mirrors the state-5 side effects of func_8038A068 without the dialog/round bookkeeping. +// Mirrors the state-5 side effects of chMrVileMinigame_setState without the dialog/round bookkeeping. void chvilegame_netApply(Actor *this, const VileGameSnapshot *src){ - ActorLocal_BGS_3420 *local = (ActorLocal_BGS_3420 *)&this->local; + chMrVileMinigameActor *local = (chMrVileMinigameActor *)&this->local; s32 drift; - local->unkC = src->round; - local->unkD = src->maxRound; + local->dialogIndex = src->round; + local->mode = src->maxRound; local->current_type = src->currentType; local->type_change_timer = src->typeChangeTimer; local->player_score = src->playerScore; @@ -783,14 +863,14 @@ void chvilegame_netApply(Actor *this, const VileGameSnapshot *src){ item_set(ITEM_6_HOURGLASS, true); mapSpecificFlags_set(6, true); if (local->vile_marker != NULL) { - func_8038C3DC(local->vile_marker); + chMrVile_setStatePlayMinigame(local->vile_marker); } func_8025A58C(0, 4000); timedFunc_set_2(1.0f, (GenFunction_2)coMusicPlayer_playMusic, COMUSIC_55_BGS_MR_VILE, 28000); } else { item_set(ITEM_6_HOURGLASS, false); mapSpecificFlags_set(6, false); - // Round-end result presentation, mirroring func_8038A068's timed callbacks + // Round-end result presentation, mirroring chMrVileMinigame_setState's timed callbacks // (dialogs and the static camera stay on the authority). if (src->gameState == 6) { timedFunc_set_2(1.0f, (GenFunction_2)coMusicPlayer_playMusic, COMUSIC_3C_MINIGAME_LOSS, 28000); @@ -813,13 +893,13 @@ void chvilegame_netApply(Actor *this, const VileGameSnapshot *src){ } // Authority-side: consume the piece at position on behalf of a remote player. Mirrors -// chvilegame_player_consume_piece without reading the local player's mouth position. -// position[1] must be 0 to match piece positions (see chvilegame_new_piece). +// chMrVileMinigame_playerConsumePiece without reading the local player's mouth position. +// position[1] must be 0 to match piece positions (see chMrVileMinigame_newPiece). // On success, reports the consumed piece's type and whether it matched the required // type so the requesting client can replay the croc's eat feedback (see // chvilegame_netPlayEatFeedback). bool chvilegame_netConsumeRemote(Actor *this, f32 position[3], s32 *out_piece_type, s32 *out_correct_type){ - ActorLocal_BGS_3420 *local = (ActorLocal_BGS_3420 *)&this->local; + chMrVileMinigameActor *local = (chMrVileMinigameActor *)&this->local; bool is_correct_type; struct vilegame_piece *begin; struct vilegame_piece *end; @@ -853,7 +933,7 @@ bool chvilegame_netConsumeRemote(Actor *this, f32 position[3], s32 *out_piece_ty // remote eat request: the croc chomp animation (which carries the chomp SFX) plus // the wrong-type reaction when the eaten piece didn't match the required type. The // score and piece removal are authority-driven and arrive separately; this is the -// cosmetic half of chvilegame_player_consume_piece that the follower otherwise skips. +// cosmetic half of chMrVileMinigame_playerConsumePiece that the follower otherwise skips. void chvilegame_netPlayEatFeedback(s32 piece_type, s32 correct_type){ func_8028F6B8(BS_INTR_17, (piece_type != YUMBLIE) ? ASSET_3F7_MODEL_GRUMBLIE : ASSET_3F6_MODEL_YUMBLIE); if (!correct_type) { diff --git a/src/CC/bss_pad.c b/src/CC/bss_pad.c deleted file mode 100644 index e4ba390c4..000000000 --- a/src/CC/bss_pad.c +++ /dev/null @@ -1,2 +0,0 @@ -// BanjoDecomp: bss_pad.c -char pad_CC_D_80389F70[0x10]; diff --git a/src/CC/actor_spawninit.c b/src/CC/ccspawnqueue.c similarity index 98% rename from src/CC/actor_spawninit.c rename to src/CC/ccspawnqueue.c index 58cfe57a2..573976ea3 100644 --- a/src/CC/actor_spawninit.c +++ b/src/CC/ccspawnqueue.c @@ -1,4 +1,4 @@ -// BanjoDecomp: code_19B0.c +// BanjoDecomp: CC/ccspawnqueue.c #include #include "functions.h" #include "variables.h" diff --git a/src/CC/ch/clanker.c b/src/CC/ch/ccgrates.c similarity index 99% rename from src/CC/ch/clanker.c rename to src/CC/ch/ccgrates.c index 3dd6a8017..2bfc9f718 100644 --- a/src/CC/ch/clanker.c +++ b/src/CC/ch/ccgrates.c @@ -1,4 +1,4 @@ -// BanjoDecomp: code_3400.c +// BanjoDecomp: CC/ch/ccgrates.c #include #include "functions.h" #include "variables.h" diff --git a/src/CC/ch/key.c b/src/CC/ch/clankerkey.c similarity index 95% rename from src/CC/ch/key.c rename to src/CC/ch/clankerkey.c index bb163b2ad..6b4793514 100644 --- a/src/CC/ch/key.c +++ b/src/CC/ch/clankerkey.c @@ -1,4 +1,4 @@ -// BanjoDecomp: code_530.c +// BanjoDecomp: CC/ch/clankerkey.c #include "functions.h" #include "variables.h" #include @@ -7,7 +7,7 @@ extern void func_8030E730(s32, f32, s32); -void func_80388EA4(void); +void maClanker_raiseClanker(void); typedef struct { @@ -21,12 +21,12 @@ typedef struct { f32 unk14; } ActorLocal_CC_530; -void chClankerKey_update(Actor* this); +void maClankerKey_update(Actor* this); /* .data */ ActorInfo D_80389AD0 = { MARKER_4A_CC_KEY, ACTOR_3C_CC_KEY, ASSET_429_MODEL_CC_KEY, 0, NULL, - chClankerKey_update, actor_update_func_80326224, actor_draw, + maClankerKey_update, actor_update_func_80326224, actor_draw, 0, 0, 0.0f, 0 }; @@ -60,7 +60,7 @@ void CC_func_80386920(Actor *this, s32 next_state){ } if(next_state == 4){ - CC_func_8038868C(); + maClanker_raiseClankerCutscene(); coMusicPlayer_playMusic(COMUSIC_2D_PUZZLE_SOLVED_FANFARE, 0x7FFF); } @@ -83,7 +83,7 @@ void func_80386AF8(Actor *arg0) { sfxsource_freeSfxsourceByIndex(local->sfxsourceIdx); } -void chClankerKey_update(Actor *this){ +void maClankerKey_update(Actor *this){ ActorMarker *marker = this->marker; f32 sp58[3]; ActorLocal_CC_530 * local = (ActorLocal_CC_530 *)&this->local; @@ -200,7 +200,7 @@ void chClankerKey_update(Actor *this){ this->pitch = (f32)local->unk10 + 180.0f*(local->unk14/5.0f); if(5.0f <= local->unk14){ CC_func_80386920(this, 5); - func_80388EA4(); + maClanker_raiseClanker(); } }//L80386FC0 } diff --git a/src/CC/ch/screw.c b/src/CC/ch/clankerscrew.c similarity index 88% rename from src/CC/ch/screw.c rename to src/CC/ch/clankerscrew.c index ec6183ee3..e507fc6f6 100644 --- a/src/CC/ch/screw.c +++ b/src/CC/ch/clankerscrew.c @@ -1,4 +1,4 @@ -// BanjoDecomp: code_0.c +// BanjoDecomp: CC/ch/clankerscrew.c #include "functions.h" #include "variables.h" #include @@ -22,10 +22,10 @@ ActorInfo D_80389AA0 = { }; /* .code */ -void CC_func_803863F0(Actor *this, s32 next_state){ +void maClankersScrew_setNextState(Actor *this, s32 next_state){ ActorLocal_CC_0 * local = (ActorLocal_CC_0 *)this->local; if(this->state == 4){ - func_80388ED4(0); + maClanker_playScrewNoise(0); } this->state = next_state; local->unkC = 1; @@ -36,7 +36,7 @@ void CC_func_803863F0(Actor *this, s32 next_state){ local->unk4 = 2.0f; } if(this->state == 2){ - func_80388ED4(1); + maClanker_playScrewNoise(1); } if(this->state == 3){ local->unk0 = 1.0f; @@ -57,7 +57,7 @@ void func_803864D4(Actor *this){ if(!this->volatile_initialized){ this->volatile_initialized = true; marker->propPtr->unk8_3 = 1; - CC_func_803863F0(this, 1); + maClankersScrew_setNextState(this, 1); }//L80386530 func_80388B4C(sp4C); @@ -74,20 +74,20 @@ void func_803864D4(Actor *this){ local->unk4 = 0.05f; } else{ - CC_func_803863F0(this, 2); + maClankersScrew_setNextState(this, 2); } }//L80386634 if(ml_timer_update(&local->unk0, sp3C)){ - CC_func_803863F0(this, 4); + maClankersScrew_setNextState(this, 4); } if((this->state == 2) && (1.0 <= local->unk8)){ - CC_func_803863F0(this, 3); + maClankersScrew_setNextState(this, 3); }//L803866B4 if((this->state == 4) && (1.0 <= local->unk8)){ - CC_func_803863F0(this, 1); + maClankersScrew_setNextState(this, 1); }//L80386714 if(this->state == 1){ diff --git a/src/CC/ch/clankertoothext.c b/src/CC/ch/clankertoothext.c index 9de9672a6..d0a1b2a2f 100644 --- a/src/CC/ch/clankertoothext.c +++ b/src/CC/ch/clankertoothext.c @@ -13,20 +13,20 @@ typedef struct{ f32 unk8; }ActorLocal_CC_BF0; -void chClankerTooth_update(Actor *this); +void maClankerTooth_update(Actor *this); /* .data */ extern ActorInfo D_80389B00 = { MARKER_4C_CLANKER_TOKEN_TOOTH_EXT, ACTOR_44_CLANKER_TOKEN_TOOTH_EXTERIOR, ASSET_309_MODEL_CLANKER_TOKEN_TOOTH_EXTERIOR, 0, NULL, - chClankerTooth_update, actor_update_func_80326224, actor_draw, + maClankerTooth_update, actor_update_func_80326224, actor_draw, 0, 0, 0.0f, 0 }; extern ActorInfo D_80389B24 = { MARKER_4D_CLANKER_JIGGY_TOOTH_EXT, ACTOR_45_CLANKER_JIGGY_TOOTH_EXTERIOR, ASSET_30A_MODEL_CLANKER_JIGGY_TOOTH_EXTERIOR, 0, NULL, - chClankerTooth_update, actor_update_func_80326224, actor_draw, + maClankerTooth_update, actor_update_func_80326224, actor_draw, 0, 0, 0.0f, 0 }; @@ -34,7 +34,7 @@ extern ActorInfo D_80389B24 = { u8 D_80389F80; /* .code */ -void chClankerTooth_setNextState(Actor *this, s32 next_state){ +void maClankerTooth_setNextState(Actor *this, s32 next_state){ ActorLocal_CC_BF0 *local = (ActorLocal_CC_BF0 *)&this->local; s32 prev_state = this->state; this->state = next_state; @@ -67,7 +67,7 @@ void func_803870EC(s32 arg0) { D_80389F80 = arg0; } -void chClankerTooth_update(Actor *this){ +void maClankerTooth_update(Actor *this){ ActorMarker *marker = this->marker; f32 sp70[3]; ActorLocal_CC_BF0 *local = (ActorLocal_CC_BF0 *)&this->local; @@ -87,9 +87,9 @@ void chClankerTooth_update(Actor *this){ this->roll = 0.0f; local->unk0 = (marker->modelId == 0x309) ? 1 : 2; local->egg_count = 0; - chClankerTooth_setNextState(this, 1); + maClankerTooth_setNextState(this, 1); if(levelSpecificFlags_get((local->unk0 == 1)? LEVEL_FLAG_0_CC_TOKEN_TOOTH_OPEN: LEVEL_FLAG_1_CC_JIGGY_TOOTH_OPEN)){ - chClankerTooth_setNextState(this, 3); + maClankerTooth_setNextState(this, 3); } }//L803871D8 if(this->state == 1){ @@ -99,7 +99,7 @@ void chClankerTooth_update(Actor *this){ while(this->state == 1 && local->egg_count < shared){ local->egg_count++; if(local->egg_count == 3){ - chClankerTooth_setNextState(this, 2); + maClankerTooth_setNextState(this, 2); }else{ coMusicPlayer_playMusic(COMUSIC_2B_DING_B, 28000); } @@ -140,7 +140,7 @@ void chClankerTooth_update(Actor *this){ port_puzzleStep_orBits(ANCHOR_PUZZLE_CC_CLANKER_TEETH, ((1 << local->egg_count) - 1) << ((local->unk0 - 1) * 3)); if(local->egg_count == 3){ - chClankerTooth_setNextState(this, 2); + maClankerTooth_setNextState(this, 2); }else{ coMusicPlayer_playMusic(COMUSIC_2B_DING_B, 28000); } @@ -148,9 +148,19 @@ void chClankerTooth_update(Actor *this){ else if(this->state == 2 && 1.0f <= local->unk8){ flagCnt = levelSpecificFlags_get(LEVEL_FLAG_0_CC_TOKEN_TOOTH_OPEN) + levelSpecificFlags_get(LEVEL_FLAG_1_CC_JIGGY_TOOTH_OPEN); if(!jiggyscore_isCollected(JIGGY_1B_CC_TOOTH)){ - gcdialog_showDialog((local->unk0 == 1)? ((flagCnt == 0)? 0xd30 : 0xd31) : ((flagCnt == 0)? 0xd2e : 0xd2f), 4, NULL, NULL, NULL, NULL); + gcdialog_showDialog( + (local->unk0 == 1)? + ((flagCnt == 0)? + VER_SELECT(ASSET_D30_DIALOG_CLANKER_RIGHT_TOOTH_FIRST, 0xA03, 0, 0) : VER_SELECT(ASSET_D31_DIALOG_CLANKER_RIGHT_TOOTH_SECOND, 0xA04, 0, 0)) : + ((flagCnt == 0)? + VER_SELECT(ASSET_D2E_DIALOG_CLANKER_LEFT_TOOTH_FIRST, 0xA01, 0, 0) : VER_SELECT(ASSET_D2F_DIALOG_CLANKER_LEFT_TOOTH_SECOND, 0xA02, 0, 0)), + 4, + NULL, + NULL, + NULL, + NULL); } - chClankerTooth_setNextState(this, 3); + maClankerTooth_setNextState(this, 3); }//L80387474 if(this->state == 3){ diff --git a/src/CC/checksums.c b/src/CC/checksums.c new file mode 100644 index 000000000..e6997aa4b --- /dev/null +++ b/src/CC/checksums.c @@ -0,0 +1,7 @@ +// BanjoDecomp: CC/checksums.c +#include +#include "checksums.h" + +// !! THIS FILE MUST BE LINKED FIRST FOR THIS OVERLAY !! + +/* bss */ struct overlay_checksums_s gChecksumsCC; diff --git a/src/CC/crc.c b/src/CC/crc.c index 23d6de395..06714581c 100644 --- a/src/CC/crc.c +++ b/src/CC/crc.c @@ -1,8 +1,8 @@ // BanjoDecomp: crc.c #include +#include "checksums.h" +#include "version.h" -/* .data */ -//TODO Implement CRC calculation in Makefile(?) -u32 D_80389BE0 = 0x000D46A1; //CC.code CRC1 -u32 D_80389BE4 = 0x871BA43E; //CC.code CRC2 -u32 D_80389BE8 = 0x0000DF9F; //CC.data CRC1 (with this value = 0) +s32 D_80389BE0 = VER_SELECT(0x000D46A1, 0x000D4EB5, 0, 0); // CC_TEXT_CRC1 +s32 D_80389BE4 = VER_SELECT(0x871BA43E, 0xEE8A9B79, 0, 0); // CC_TEXT_CRC2 +s32 D_80389BE8 = VER_SELECT(0x0000DF9F, 0x0000EACE, 0, 0); // CC_DATA_CRC1 diff --git a/src/CC/ma/clanker.c b/src/CC/ma/clanker.c new file mode 100644 index 000000000..07ecbe059 --- /dev/null +++ b/src/CC/ma/clanker.c @@ -0,0 +1,451 @@ +// BanjoDecomp: CC/ma/clanker.c +#include +#include "core1/core1.h" +#include "functions.h" +#include "variables.h" + +#include "core2/modelRender.h" + +extern BKCollisionTriangle *func_8028EF48(void); +extern void func_8030E9FC(enum sfx_e uid, f32 arg1, f32 arg2, u32 arg3, f32 arg4[3], f32 arg5, f32 arg6); +extern void func_8030EA54(enum sfx_e uid, f32 arg1, f32 arg2, u32 arg3, f32 arg4[3], f32 arg5, f32 arg6); +extern void func_8031CE28(s32, s32, f32); +void timed_exitStaticCamera(f32); +extern BKCollisionTriangle *collisionList_func_802E805C(BKCollisionList *, BKVertexList *, f32[3], f32[3], f32, f32[3], f32[3], f32[3], u32); +extern void func_80340200(Struct83s *, f32[3], f32[3], f32, f32[3], s16[3], BKVertexList *, f32[3]); +extern BKCollisionTriangle *func_802E9118(BKCollisionList *, BKVertexList *, f32[3], f32[3], f32, f32[3], f32[3], f32, f32[3], s32, s32); +extern BKCollisionTriangle *func_802E9DD8(BKCollisionList *, BKVertexList *, f32[3], f32 *, f32, f32[3], f32, f32[3], s32); +extern int func_80340020(Struct83s *, f32[3], f32[3], f32, f32[3], BKVertexList *, f32[3], f32[3]); + +extern void boneTransformList_getBoneScale(BoneTransformList *, s32, f32[3]); +extern void boneTransformList_setBoneScale(BoneTransformList *, s32, f32[3]); +extern void func_8033A9A8(BoneTransformList *, s32, f32[3]); +extern void modelRender_setAppendageVisibility(s32, s32); +extern void modelRender_setBoneTransformList(BoneTransformList *); +extern void func_8028FAB0(f32[3]); +extern void baModel_802921D4(f32[3]); + +/* .data */ +f32 maClankerJiggyPosition[3] = {5700.0f, 4300.0f, 0.0f}; +f32 D_80389C0C[3] = {0.0f, 27.0f, 0.0f}; +f32 D_80389C18[3] = {0.0f, -27.0f, 0.0f}; +f32 maClankerRaisedSoundPosition[3] = {4000.0f, 3500.0f, 0.0f}; + +/* .bss */ +struct { + SkeletalAnimation *skeletonAnim; + u8 sfxsourceIdx; + //u8 pad5[0x3]; + f32 unk8; // screw timer? + f32 meetDialogPosition[3]; + Struct83s *unk18; + BKCollisionList *collisionList; + u8 triggerMeetDialog; + u8 currentState; + //u8 pad22[0x2]; + BKModelBin * model; + f32 position[3]; + Vec3fArray *unk34; + f32 timeDelta; + f32 unk3C; // raised sound timer? + BKVertexList *vertexList1; + BKVertexList *vertexList2; + u8 hasMetPlayer; + u8 unk49; + //u8 pad4A[2]; + f32 unk4C; // timer? + s32 unk50; // related to unk4C & unk54 + f32 unk54; // timer? +} maClanker; + +enum maClankerState_e { + MACLANKER_STATE_0_NOT_INITIALIZED, + MACLANKER_STATE_1_IDLE_UNDERWATER, + MACLANKER_STATE_2_LIFTING, + MACLANKER_STATE_3_IDLE_RAISED +}; + +BKCollisionTriangle *__maClanker_getClankerCollisionTris(f32 arg0[3], f32 arg1[3], f32 arg2[3], u32 arg3){ // [port] pointer-width args + BKCollisionTriangle *collision_tris; + + collision_tris = collisionList_func_802E805C(maClanker.collisionList, maClanker.vertexList1, maClanker.position, 0, 1.0f, arg0, arg1, arg2, arg3); + if(collision_tris && func_8029453C()){ + func_80340200(maClanker.unk18, maClanker.position, 0, 1.0f, 0, collision_tris->unk0, maClanker.vertexList1, arg1); + } + return collision_tris; +} + +void __code1F70_func_80388428(f32 arg0[3], f32 arg1[3], f32 arg2, f32 arg3[3], s32 arg4, u32 arg5){ // [port] pointer-width args + func_802E9118(maClanker.collisionList, maClanker.vertexList1, maClanker.position, 0, 1.0f, arg0, arg1, arg2, arg3, arg4, arg5); +} + +void func_803884A8(f32 arg0[3], f32 arg1, f32 arg2[3], u32 arg3){ // [port] pointer-width args + func_802E9DD8(maClanker.collisionList, maClanker.vertexList1, maClanker.position, 0, 1.0f, arg0, arg1, arg2, arg3); +} + +void maClanker_setState(s32 next_state){ + s32 current_state; + if(maClanker.currentState == MACLANKER_STATE_2_LIFTING){ + sfxSource_triggerCallbackByIndex(maClanker.sfxsourceIdx); + func_8030E760(SFX_7F_HEAVYDOOR_SLAM, 0.6f, 20000); + func_8030E760(SFX_7F_HEAVYDOOR_SLAM, 0.8f, 20000); + func_8030E760(SFX_7F_HEAVYDOOR_SLAM, 0.9f, 20000); + func_8030E760(SFX_7F_HEAVYDOOR_SLAM, 1.0f, 20000); + }//L80388594 + current_state = maClanker.currentState; + maClanker.currentState = next_state; + maClanker.timeDelta = 0.0f; + if(maClanker.currentState == MACLANKER_STATE_1_IDLE_UNDERWATER){ + skeletalAnim_set(maClanker.skeletonAnim, ASSET_C3_ANIM_CLANKER_IDLE, 0.0f, 10.0f); + } + if(maClanker.currentState == MACLANKER_STATE_2_LIFTING){ + func_8030DD90(maClanker.sfxsourceIdx, 0); + sfxsource_playSfxAtVolume(maClanker.sfxsourceIdx, 1.0f); + sfxsource_setSfxId(maClanker.sfxsourceIdx, SFX_7D_ANCHOR_LIFTING); + sfxSource_setunk43_7ByIndex(maClanker.sfxsourceIdx, 3); + sfxsource_setSampleRate(maClanker.sfxsourceIdx, 27000); + sfxSource_func_8030E2C4(maClanker.sfxsourceIdx); + } + + if(maClanker.currentState == MACLANKER_STATE_3_IDLE_RAISED){ + if(current_state != MACLANKER_STATE_2_LIFTING){ + skeletalAnim_set(maClanker.skeletonAnim, ASSET_C3_ANIM_CLANKER_IDLE, 0.0f, 10.0f); + } + maClanker.position[1] = 1100.0f; + } +} + +void maClanker_spawnJiggy(void) { + jiggy_spawn(JIGGY_17_CC_CLANKER_RAISED, maClankerJiggyPosition); +} + +void maClanker_raiseClankerCutscene(void) { + func_80324E38(0, 3); + timed_setStaticCameraToNode(0, 0); + timed_setStaticCameraToNode(5.5f, 1); + timed_setStaticCameraToNode(7.0f, 2); + timed_setStaticCameraToNode(12.5f, 3); + timedFunc_set_0(13.0f, &maClanker_spawnJiggy); + timed_setStaticCameraToNode(16.0f, 1); + if (jiggyscore_isCollected(JIGGY_17_CC_CLANKER_RAISED) == FALSE) { + func_80324DBC(18.0f, VER_SELECT(ASSET_D2C_DIALOG_CLANKER_KEY_COMPLETE, 0x9FF, 0, 0), 4, NULL, NULL, NULL, 0); + } + timed_exitStaticCamera(18.0f); + func_80324E38(18.0f, 0); +} + + +void maClanker_draw(Gfx **gfx, Mtx **mtx, Vtx **vtx){ + BKVertexList *tmp_vertex_list; + BoneTransformList *bone_transform_list; + f32 player_position[3]; + f32 viewport_position[3]; + int i; + s32 tmp_s0; + f32 sp84[3]; + s32 pad80; + f32 sp74[3]; + f32 sp68[3]; + f32 sp5C[3]; + + + if(maClanker.currentState == MACLANKER_STATE_0_NOT_INITIALIZED) + return; + + viewport_getPosition_vec3f(viewport_position); + + if(viewport_position[0] < -2600.0f || 11600.0f < viewport_position[0]) + return; + + bone_transform_list = skeletalAnim_getBoneTransformList(maClanker.skeletonAnim); + boneTransformList_getBoneScale(bone_transform_list, 0x40, sp84); + for( i = 0; i < 3; i++){ + sp84[i] = sp84[i] + (1.3 - sp84[i]) * maClanker.unk8; + } + + boneTransformList_setBoneScale(bone_transform_list, 0x40, sp84); + + if(maClanker.currentState == MACLANKER_STATE_1_IDLE_UNDERWATER){ + func_8033A9A8(bone_transform_list, 0x44, D_80389C0C); + func_8033A9A8(bone_transform_list, 0x45, D_80389C0C); + func_8033A9A8(bone_transform_list, 0x46, D_80389C0C); + + func_8033A9A8(bone_transform_list, 0x47, D_80389C18); + func_8033A9A8(bone_transform_list, 0x48, D_80389C18); + func_8033A9A8(bone_transform_list, 0x49, D_80389C18); + } + + player_getPosition(player_position); + + for(i = 0; i < 2; i++){//L803888FC + vec3fArray_get_vec3f(maClanker.unk34, (i == 0) ? 0x10 : 0xf, sp74); + sp68[0] = player_position[0] - sp74[0]; + sp68[1] = player_position[1] - sp74[1]; + sp68[2] = player_position[2] - sp74[2]; + ml_vec3f_normalize(sp68); + + sp5C[0] = 0.0f; + sp5C[1] = sp68[2] * 45.0f; + sp5C[2] = -sp68[1] * 45.0f; + func_8033A9A8(bone_transform_list, (i == 0) ? 0x42 : 0x43, sp5C); + } + tmp_vertex_list = maClanker.vertexList1; + maClanker.vertexList1 = maClanker.vertexList2; + maClanker.vertexList2 = tmp_vertex_list; + + modelRender_setAppendageVisibility(1, (maClanker.currentState == MACLANKER_STATE_3_IDLE_RAISED) ? 1 : 0); + tmp_s0 = (viewport_position[0] < 100.0f)? 0 : 1; + modelRender_setAppendageVisibility(2, 1); + modelRender_setAppendageVisibility(3, 1); + modelRender_setAppendageVisibility(4, tmp_s0); + modelRender_setAppendageVisibility(5, tmp_s0); + modelRender_setAppendageVisibility(6, tmp_s0); + modelRender_setAppendageVisibility(7, tmp_s0); + modelRender_setAppendageVisibility(8, tmp_s0); + if(tmp_s0){ + tmp_s0 = (s32)(maClanker.unk4C * 3.99 + 1.0); + modelRender_setAppendageVisibility(2, tmp_s0); + modelRender_setAppendageVisibility(3, tmp_s0); + } + modelRender_setBoneTransformList(bone_transform_list); + modelRender_setRefPoints(maClanker.unk34); + modelRender_setVertexList(maClanker.vertexList1); + modelRender_setDepthMode(MODEL_RENDER_DEPTH_FULL); + modelRender_draw(gfx, mtx, maClanker.position, NULL, 1.0f, NULL, maClanker.model); + if(func_80340020(maClanker.unk18, maClanker.position, 0, 1.0f, 0, maClanker.vertexList1, player_position, player_position)){ + func_8028FAB0(player_position); + baModel_802921D4(player_position); + } +} + +void func_80388B4C(f32 arg0[3]) { // [port] pointer-width + vec3fArray_get_vec3f(maClanker.unk34, 5, arg0); +} + +void func_80388B78(f32 arg0[3], f32 arg1[3]){ + vec3fArray_get_vec3f(maClanker.unk34, 7, arg0); + vec3fArray_get_vec3f(maClanker.unk34, 8, arg1); +} + +void func_80388BBC(f32 arg0[3], f32 arg1[3]){ + vec3fArray_get_vec3f(maClanker.unk34, 9, arg0); + vec3fArray_get_vec3f(maClanker.unk34, 10, arg1); +} + +void func_80388C00(NodeProp *arg0, ActorMarker *arg1){ // [port] pointer-width + func_8031CD20(arg0, 0xb, 3); +} + +void func_80388C28(NodeProp *arg0, ActorMarker *arg1){ // [port] pointer-width + func_8031CD20(arg0, 0xb, 4); +} + +void func_80388C50(NodeProp *arg0, ActorMarker *arg1){ // [port] pointer-width + func_8031CD20(arg0, 0xb, 1); +} + +void CC_func_80388C78(NodeProp *arg0, ActorMarker *arg1){ // [port] pointer-width + func_8031CD20(arg0, 0xb, 2); +} + +int CC_func_80388CA0(void){ + return maClanker.currentState == MACLANKER_STATE_3_IDLE_RAISED; +} + +void maClanker_release(void){ + if(maClanker.currentState){ + skeletalAnim_free(maClanker.skeletonAnim); + sfxsource_freeSfxsourceByIndex(maClanker.sfxsourceIdx); + func_80340690(maClanker.unk18); + vec3fArray_free(maClanker.unk34); + if(modelbin_getVtxList(maClanker.model) != maClanker.vertexList1) + vtxList_free(maClanker.vertexList1); + if(modelbin_getVtxList(maClanker.model) != maClanker.vertexList2) + vtxList_free(maClanker.vertexList2); + assetcache_release((void *)maClanker.model); + maClanker.unk34 = NULL; + maClanker.skeletonAnim = NULL; + maClanker.unk18 = NULL; + } +} + +void maClanker_init(void){ + maClanker.currentState = MACLANKER_STATE_0_NOT_INITIALIZED; + if(gsworld_getMap() == MAP_B_CC_CLANKERS_CAVERN){ + maClanker.skeletonAnim = skeletalAnim_new(); + maClanker.sfxsourceIdx = sfxsource_createSfxsourceAndReturnIndex(); + maClanker.unk8 = 1.0f; + maClanker.unk18 = func_803406B0(); + maClanker.currentState = MACLANKER_STATE_0_NOT_INITIALIZED; + maClanker.model = assetcache_get(ASSET_88E_MODEL_CLANKER_CHAIN); + maClanker.collisionList = modelbin_getCollisionList(maClanker.model); + maClanker.unk34 = vec3fArray_new(); + maClanker.unk3C = 1.0f; + maClanker.vertexList1 = modelbin_getVtxList(maClanker.model); + maClanker.vertexList2 = vtxList_clone(maClanker.vertexList1); + maClanker.hasMetPlayer = FALSE; + maClanker.unk49 = 0; + maClanker.unk50 = 0; + maClanker.unk4C = 0.0f; + maClanker.unk54 = 1.0f; + maClanker.position[0] = 5500.0f; + maClanker.position[2] = 0.0f; + maClanker.position[1] = 0.0f; + func_80320B24(__maClanker_getClankerCollisionTris, __code1F70_func_80388428, func_803884A8); + if(!nodeProp_findPositionFromActorId(ACTOR_3B_CLANKER_DIALOG_TRIGGER, maClanker.meetDialogPosition)){ + maClanker.meetDialogPosition[0] = 0.0f; + maClanker.meetDialogPosition[1] = -1e+06f; + maClanker.meetDialogPosition[2] = 0.0f; + } + if(jiggyscore_isSpawned(JIGGY_17_CC_CLANKER_RAISED)){ + maClanker_setState(MACLANKER_STATE_3_IDLE_RAISED); + } + else{ + maClanker_setState(MACLANKER_STATE_1_IDLE_UNDERWATER); + } + } +} + +void maClanker_raiseClanker(void){ + if(maClanker.currentState == MACLANKER_STATE_1_IDLE_UNDERWATER){ + maClanker_setState(MACLANKER_STATE_2_LIFTING); + } +} + +void maClanker_playScrewNoise(s32 arg0){ + f32 sp1C[3]; + vec3fArray_get_vec3f(maClanker.unk34, 5, sp1C); + if(arg0 != 0){ + sfx_playFadeShorthandDefault(SFX_91_METALLIC_SOUND, 0.7f, 32675, sp1C, 100, 6000); + } + else{ + sfx_playFadeShorthandDefault(SFX_82_METAL_BREAK, 0.9f, 24000, sp1C, 100, 6000); + } + maClanker.unk8 = 1.0f; +} + +void maClanker_update(void){ + f32 player_position[3]; + f32 time_delta = time_getDelta(); + f32 sp64; + f32 sp60; + f32 sp54[3]; + f32 sp48[3]; + BKCollisionTriangle *tmp_v0; + f32 pad[3]; + + code13C0_checkCCChecksums(); + if(maClanker.currentState != MACLANKER_STATE_0_NOT_INITIALIZED && gsworld_getUnk0() == 2){ + // Anchor: teammate raised Clanker — play the physical raise (no cutscene). + if(maClanker.currentState == MACLANKER_STATE_1_IDLE_UNDERWATER && jiggyscore_isSpawned(JIGGY_17_CC_CLANKER_RAISED)){ + maClanker_raiseClanker(); + } + player_getPosition(player_position); + maClanker.triggerMeetDialog = (ml_vec3f_distance(player_position, maClanker.meetDialogPosition) < 200.0f); + + maClanker.timeDelta += time_delta; + sp64 = skeletalAnim_getProgress(maClanker.skeletonAnim); + skeletalAnim_update(maClanker.skeletonAnim, time_delta, 1); + sp60 = skeletalAnim_getProgress(maClanker.skeletonAnim); + if(maClanker.currentState == MACLANKER_STATE_3_IDLE_RAISED){ + vec3fArray_get_vec3f(maClanker.unk34, 5, sp54); + if(sp60 < sp64){ + sfx_playFadeShorthandDefault(SFX_7E_CREAKY_DOOR_OPENING, 0.6f, 32300, sp54, 1000, 5000); + }//L80389058 + + if(sp64 < 0.3 && 0.3 <= sp60){ + sfx_playFadeShorthandDefault(SFX_7E_CREAKY_DOOR_OPENING, 0.5f, 32300, sp54, 1000, 5000); + } + }//L8038909C + + if(maClanker.currentState == MACLANKER_STATE_2_LIFTING){ + maClanker.position[1] += 100.0f * time_delta; + } + + if(0.0f < maClanker.unk8){ + maClanker.unk8 -= time_delta / 2; + if(maClanker.unk8 <= 0.0f) + maClanker.unk8 = 0.0f; + } + + if(maClanker.currentState == MACLANKER_STATE_1_IDLE_UNDERWATER){ + if(maClanker.triggerMeetDialog && skeletalAnim_getAnimId(maClanker.skeletonAnim) != ASSET_C4_ANIM_CLANKER_BITE){ + skeletalAnim_set(maClanker.skeletonAnim, ASSET_C4_ANIM_CLANKER_BITE, 1.0f, 10.0f); + if(!maClanker.hasMetPlayer){ + gcdialog_showDialog(VER_SELECT(ASSET_D2B_DIALOG_CLANKER_MEET, 0x9FE, 0, 0), 0xE, maClanker.position, NULL, NULL, NULL); + maClanker.hasMetPlayer = TRUE; + } + }//L8038918C + + if(!maClanker.triggerMeetDialog && skeletalAnim_getAnimId(maClanker.skeletonAnim) == ASSET_C4_ANIM_CLANKER_BITE){ + skeletalAnim_set(maClanker.skeletonAnim, ASSET_C3_ANIM_CLANKER_IDLE, 1.0f, 10.0f); + } + }//L803891BC + + if(maClanker.currentState == MACLANKER_STATE_2_LIFTING){ + func_803114D0(); + if(1100.0f <= maClanker.position[1]){ + maClanker_setState(MACLANKER_STATE_3_IDLE_RAISED); + } + }//L803891F8 + + if(maClanker.currentState == MACLANKER_STATE_3_IDLE_RAISED){ + vec3fArray_get_vec3f(maClanker.unk34, 6, sp48); + if(ml_vec3f_distance(sp48, player_position) <= 130.0f && player_position[1] - sp48[1] < 50.0f){ + func_8031D04C(MAP_21_CC_WITCH_SWITCH_ROOM, WARP_CC_WITCH_SWITCH_1_TOP_ENTRANCE); + } + }//L80389260 + + if( maClanker.currentState == MACLANKER_STATE_3_IDLE_RAISED){ + tmp_v0 = func_8028EF48(); + if( tmp_v0 && !maClanker.unk49 + ){ + if(tmp_v0->flags & 2){ + func_8031CE28(0x22, 5, 180.0f); + maClanker.unk49++; + } + else if(tmp_v0->flags & 4){ + func_8031CE28(0x22, 4, 0.0f); + maClanker.unk49++; + } + } + }//L803892DC + if(ml_timer_update(&maClanker.unk3C, time_delta)){ + if(maClanker.currentState == MACLANKER_STATE_3_IDLE_RAISED){ + func_8030E9FC(SFX_D0_GRIMLET_SQUEAK, 0.5f, 0.7f, 20000, maClankerRaisedSoundPosition, 2000.0f, 4000.0f); + }else{ + func_8030EA54(SFX_D0_GRIMLET_SQUEAK, 0.5f, 0.7f, 20000, maClankerRaisedSoundPosition, 2000.0f, 4000.0f); + }//L80389384 + maClanker.unk3C = randf2(3.0f, 6.0f); + }//L803893A0 + if(maClanker.unk50 == 0){ + if(ml_timer_update(&maClanker.unk54, time_delta)) + maClanker.unk50 = 1; + } + + if(maClanker.unk50){ + maClanker.unk4C += maClanker.unk50 * ((time_delta * 30.0) / 4); + if(1.0f < maClanker.unk4C){ + maClanker.unk50 = -1; + maClanker.unk4C = 1.0f; + } + else if(maClanker.unk4C < 0.0f){ + maClanker.unk50 = 0; + maClanker.unk4C = 0.0f; + maClanker.unk54 = randf2(0.1f, 7.0f); + } + } + }//L80389490 + +} + +void maClanker_defrag(void){ + if(maClanker.unk34) + maClanker.unk34 = vec3fArray_defrag(maClanker.unk34); + + if(maClanker.skeletonAnim) + maClanker.skeletonAnim = defrag(maClanker.skeletonAnim); + + if(maClanker.unk18) + maClanker.unk18 = func_803406D4(maClanker.unk18); +} diff --git a/src/CC/ma/clankerrings.c b/src/CC/ma/clankerrings.c new file mode 100644 index 000000000..2c8657806 --- /dev/null +++ b/src/CC/ma/clankerrings.c @@ -0,0 +1,130 @@ +// BanjoDecomp: CC/ma/clankerrings.c +#include +#include "functions.h" +#include "variables.h" +#include "../CC.h" + +extern void port_ccWater_broadcastRise(int32_t map, int32_t waterId, int32_t targetDy, f32 duration); + +/* .data */ +f32 maClankerRingsJiggyPosition[3] = {0.0f, 1300.0f, -2800.0f}; + +#define RINGS_TIMER VER_SELECT(48, 40, 0, 0) // Seconds +#define RING_COUNT 9 + +/* .bss */ +struct { + u8 currentActiveRing; + u8 isMinigameActive; + f32 timer1; + f32 timer2; +} maClankerRings; + +/* .code */ +void func_80387F80(void){ + func_8034E71C((Struct73s *)func_8034C5AC(0x131), 0x190, 0.0f); // [port] cast to match decomp behavior +} + +void maClankerRings_startMinigame(void){ + item_set(ITEM_0_HOURGLASS_TIMER, RINGS_TIMER * 60 - 1); + item_set(ITEM_6_HOURGLASS, 1); + maClankerRings.isMinigameActive = 1; +} + +void maClankerRings_endMinigame(void){ + item_set(ITEM_6_HOURGLASS, 0); + maClankerRings.isMinigameActive = 0; +} + +s32 maClankerRings_isMinigameActive(void){ + if(maClankerRings.currentActiveRing > 0 && maClankerRings.currentActiveRing < 0xA){ + return maClankerRings.currentActiveRing; + } + return 0; +} + +void maClankerRings_passRing(s32 ring_num){ + if(ring_num == maClankerRings.currentActiveRing){ + if(ring_num == 1){ + maClankerRings_startMinigame(); + } + maClankerRings.currentActiveRing++; + if(maClankerRings.currentActiveRing >= RING_COUNT){ + maClankerRings_endMinigame(); + maClankerRings.timer2 = 1.0f; + } + coMusicPlayer_playMusic(COMUSIC_2B_DING_B, 28000); + } + else{//L803880BC + coMusicPlayer_playMusic(COMUSIC_2C_BUZZER, 28000); + } +} + +void maClankerRings_release(void){ + if(maClankerRings.currentActiveRing != 0){ + maClankerRings_endMinigame(); + } +} + +void maClankerRings_init(void){ + maClankerRings.currentActiveRing = 0; + if(gsworld_getMap() == MAP_22_CC_INSIDE_CLANKER){ + if(jiggyscore_isSpawned(JIGGY_1C_CC_RINGS)){ + timedFunc_set_0(0.0f, func_80387F80); + } + else{ + maClankerRings.currentActiveRing = 1; + maClankerRings.isMinigameActive = 0; + maClankerRings.timer2 = 0.0f; + maClankerRings.timer1 = 0.0f; + } + } +} + +void maClankerRings_update(void){ + f32 player_position[3]; + f32 time_delta = time_getDelta(); + Struct70s *tmp_v0; // [port] pointer-width + + if(maClankerRings.currentActiveRing != 0){ + if(jiggyscore_isSpawned(JIGGY_1C_CC_RINGS) && maClankerRings.currentActiveRing < RING_COUNT){ + maClankerRings_endMinigame(); + // func_80387F80 snaps water to risen height; VB listener suppresses it when connected (rise already animating). + if(EventSystem_Should(VB_CC_RINGS_SNAP_WATER, true)){ + func_80387F80(); + } + maClankerRings.currentActiveRing = 0; + return; + } + maClankerRings.timer1 += time_delta; + player_getPosition(player_position); + if(ml_timer_update(&maClankerRings.timer2, time_delta)){ + coMusicPlayer_playMusic(COMUSIC_2D_PUZZLE_SOLVED_FANFARE, 28000); + func_80324E38(0.0f, 3); + timed_setStaticCameraToNode(2.0f, 0); + timedJiggySpawn(2.1f, JIGGY_1C_CC_RINGS, maClankerRingsJiggyPosition); + func_80324E38(5.0f, 0); + timed_exitStaticCamera(5.0f); + tmp_v0 = func_8034C5AC(0x131); + if(tmp_v0){ + func_8034E78C((Struct73s *)tmp_v0, 0x190, 12.0f); // [port] cast matches decomp behavior + } + port_ccWater_broadcastRise(MAP_22_CC_INSIDE_CLANKER, 0x131, 0x190, 12.0f); + maClankerRings.timer1 = 0.0f; + }//L80388264 + if(!(maClankerRings.currentActiveRing < 2) && maClankerRings.isMinigameActive != 0){ + if( (player_position[0] < -1100.0f && player_position[1] < -40.0f) + || (1560.0f < player_position[0]) + || (2850.0f < player_position[2]) + || (player_position[2] < -3000.0f) + || (maClankerRings.currentActiveRing < RING_COUNT && item_empty(ITEM_6_HOURGLASS)) + ){ + maClankerRings_endMinigame(); + coMusicPlayer_playMusic(COMUSIC_3C_MINIGAME_LOSS, 28000); + maClankerRings_release(); + maClankerRings_init(); + } + }//L8038834C + }//L8038834C +} + diff --git a/src/CC/minigame_rings.c b/src/CC/minigame_rings.c deleted file mode 100644 index d5630968e..000000000 --- a/src/CC/minigame_rings.c +++ /dev/null @@ -1,127 +0,0 @@ -// BanjoDecomp: code_1B90.c -#include -#include "functions.h" -#include "variables.h" -#include "CC.h" - -extern void port_ccWater_broadcastRise(int32_t map, int32_t waterId, int32_t targetDy, f32 duration); - -/* .data */ -f32 D_80389BF0[3] = {0.0f, 1300.0f, -2800.0f}; - -/* .bss */ -struct { - u8 unk0; - u8 unk1; - f32 unk4; - f32 unk8; -} D_80389F90; - -/* .code */ -void func_80387F80(void){ - func_8034E71C((Struct73s *)func_8034C5AC(0x131), 0x190, 0.0f); -} - -void CC_func_80387FB0(void){ - item_set(ITEM_0_HOURGLASS_TIMER, 48*60 - 1); - item_set(ITEM_6_HOURGLASS, 1); - D_80389F90.unk1 = 1; -} - -void func_80387FE8(void){ - item_set(ITEM_6_HOURGLASS, 0); - D_80389F90.unk1 = 0; -} - -s32 func_80388010(void){ - if(D_80389F90.unk0 > 0 && D_80389F90.unk0 < 0xA){ - return D_80389F90.unk0; - } - return 0; -} - -void func_8038803C(s32 arg0){ - if(arg0 == D_80389F90.unk0){ - if(arg0 == 1){ - CC_func_80387FB0(); - } - D_80389F90.unk0++; - if(D_80389F90.unk0 >= 9){ - func_80387FE8(); - D_80389F90.unk8 = 1.0f; - } - coMusicPlayer_playMusic(COMUSIC_2B_DING_B, 28000); - } - else{//L803880BC - coMusicPlayer_playMusic(COMUSIC_2C_BUZZER, 28000); - } -} - -void func_803880D4(void){ - if(D_80389F90.unk0 != 0){ - func_80387FE8(); - } -} - -void func_80388104(void){ - D_80389F90.unk0 = 0; - if(gsworld_getMap() == MAP_22_CC_INSIDE_CLANKER){ - if(jiggyscore_isSpawned(JIGGY_1C_CC_RINGS)){ - timedFunc_set_0(0.0f, func_80387F80); - } - else{ - D_80389F90.unk0 = 1; - D_80389F90.unk1 = 0; - D_80389F90.unk8 = 0.0f; - D_80389F90.unk4 = 0.0f; - } - } -} - -void func_8038817C(void){ - f32 sp24[3]; - f32 sp20 = time_getDelta(); - Struct70s *tmp_v0; - - if(D_80389F90.unk0 != 0){ - if(jiggyscore_isSpawned(JIGGY_1C_CC_RINGS) && D_80389F90.unk0 < 9){ - func_80387FE8(); - // func_80387F80 snaps water to risen height; VB listener suppresses it when connected (rise already animating). - if(EventSystem_Should(VB_CC_RINGS_SNAP_WATER, true)){ - func_80387F80(); - } - D_80389F90.unk0 = 0; - return; - } - D_80389F90.unk4 += sp20; - player_getPosition(sp24); - if(ml_timer_update(&D_80389F90.unk8, sp20)){ - coMusicPlayer_playMusic(COMUSIC_2D_PUZZLE_SOLVED_FANFARE, 28000); - func_80324E38(0.0f, 3); - timed_setStaticCameraToNode(2.0f, 0); - timedJiggySpawn(2.1f, JIGGY_1C_CC_RINGS, D_80389BF0); - func_80324E38(5.0f, 0); - timed_exitStaticCamera(5.0f); - tmp_v0 = func_8034C5AC(0x131); - if(tmp_v0){ - func_8034E78C((Struct73s *)tmp_v0, 0x190, 12.0f); - } - port_ccWater_broadcastRise(MAP_22_CC_INSIDE_CLANKER, 0x131, 0x190, 12.0f); - D_80389F90.unk4 = 0.0f; - }//L80388264 - if(!(D_80389F90.unk0 < 2) && D_80389F90.unk1 != 0){ - if( (sp24[0] < -1100.0f && sp24[1] < -40.0f) - || (1560.0f < sp24[0]) - || (2850.0f < sp24[2]) - || (sp24[2] < -3000.0f) - || (D_80389F90.unk0 < 9 && item_empty(ITEM_6_HOURGLASS)) - ){ - func_80387FE8(); - coMusicPlayer_playMusic(COMUSIC_3C_MINIGAME_LOSS, 28000); - func_803880D4(); - func_80388104(); - } - }//L8038834C - }//L8038834C -} - diff --git a/src/CC/model_renderstate.c b/src/CC/model_renderstate.c index b44d296cc..921b09134 100644 --- a/src/CC/model_renderstate.c +++ b/src/CC/model_renderstate.c @@ -38,15 +38,15 @@ void func_803877B0(Struct_CC_13C0_1* arg0, void* arg1, f32 position[3], f32 rota return; if (temp_v0 == 0) { - func_8033A45C(1, 1); + modelRender_setAppendageVisibility(1, 1); } else if (temp_v0 == 1) { - func_8033A45C(1, 2); + modelRender_setAppendageVisibility(1, 2); } else if (temp_v0 == 2) { - func_8033A45C(1, 2); + modelRender_setAppendageVisibility(1, 2); rotation[2] += (arg0->unkC * 20.0f); arg4 = arg4*(1.0f - arg0->unkC); } - func_8033A45C(2, 0); + modelRender_setAppendageVisibility(2, 0); modelRender_setDepthMode(MODEL_RENDER_DEPTH_FULL); modelRender_draw(gfx, mtx, position, rotation, arg4, NULL, modeL_ptr); } @@ -109,7 +109,7 @@ void CC_func_80387A40(Struct_CC_13C0_1* arg0, Struct68s* arg1, f32 arg2) { s32 sp28; arg0->unkC += arg2; - temp_v0 = func_80388010(); + temp_v0 = maClankerRings_isMinigameActive(); if (temp_v0 == 0) { func_803878AC(arg0, arg1, 3); } else { @@ -140,7 +140,7 @@ void CC_func_80387A40(Struct_CC_13C0_1* arg0, Struct68s* arg1, f32 arg2) { sp28 = ((sp50[0]*sp44[0] + sp50[1]*sp44[1] + sp50[2]*sp44[2]) >= 0.0f) ? 1 : -1; if (sp28 == -arg0->unk8) { if (LENGTH_VEC3F(sp50) < (func_80351830(arg1) * 250.0f)) { - func_8038803C(arg0->unk0); + maClankerRings_passRing(arg0->unk0); } } arg0->unk8 = sp28; @@ -166,6 +166,18 @@ void code13C0_makeCameraFlipAndTilt(void){ } +void code13C0_checkCCChecksums(void){ +#if ANTI_TAMPER + u32 rom_data; + u32 unused; + osPiReadIo(0x504, &rom_data); + rom_data = (rom_data & 0xffff) + 0xffff5BA0; + if(rom_data){ + code13C0_makeCameraFlipAndTilt(); + } +#endif +} + void CC_func_80387D4C(void){ // [port] anti-tamper: ROM CRC check via osPiReadIo — not applicable on PC #if ANTI_TAMPER diff --git a/src/CC/platform_physics.c b/src/CC/platform_physics.c deleted file mode 100644 index 341992650..000000000 --- a/src/CC/platform_physics.c +++ /dev/null @@ -1,445 +0,0 @@ -// BanjoDecomp: code_1F70.c -#include -#include "core1/core1.h" -#include "functions.h" -#include "variables.h" - -#include "core2/modelRender.h" -#include "core2/bonetransform.h" - -extern BKCollisionTriangle *func_8028EF48(void); -extern void func_8030E9FC(enum sfx_e uid, f32 arg1, f32 arg2, u32 arg3, f32 arg4[3], f32 arg5, f32 arg6); -extern void func_8030EA54(enum sfx_e uid, f32 arg1, f32 arg2, u32 arg3, f32 arg4[3], f32 arg5, f32 arg6); -extern void func_8031CE28(s32, s32, f32); -void timed_exitStaticCamera(f32); -extern BKCollisionTriangle *collisionList_func_802E805C(BKCollisionList *, BKVertexList *, f32[3], f32[3], f32, f32[3], f32[3], f32[3], u32); -extern void func_80340200(Struct83s *, f32[3], f32[3], f32, f32[3], s16[3], BKVertexList *, f32[3]); -extern BKCollisionTriangle *func_802E9118(BKCollisionList *, BKVertexList *, f32[3], f32[3], f32, f32[3], f32[3], f32, f32[3], s32, s32); -extern BKCollisionTriangle *func_802E9DD8(BKCollisionList *, BKVertexList *, f32[3], f32 *, f32, f32[3], f32, f32[3], s32); -extern bool func_80340020(Struct83s *, f32[3], f32[3], f32, f32 *, BKVertexList *, f32[3], f32[3]); - -extern void boneTransformList_getBoneScale(BoneTransformList *, s32, f32[3]); -extern void boneTransformList_setBoneScale(BoneTransformList *, s32, f32[3]); -extern void func_8033A9A8(BoneTransformList *, s32, f32[3]); -extern void func_8033A45C(s32, s32); -extern void modelRender_setBoneTransformList(BoneTransformList *); -extern void func_8028FAB0(f32[3]); -extern void baModel_802921D4(f32[3]); - -/* .data */ -f32 D_80389C00[3] = {5700.0f, 4300.0f, 0.0f}; -f32 D_80389C0C[3] = {0.0f, 27.0f, 0.0f}; -f32 D_80389C18[3] = {0.0f, -27.0f, 0.0f}; -f32 D_80389C24[3] = {4000.0f, 3500.0f, 0.0f}; - -/* .bss */ -struct { - SkeletalAnimation *unk0; - u8 sfxsourceIdx; - //u8 pad5[0x3]; - f32 unk8; - f32 unkC[3]; - Struct83s *unk18; - BKCollisionList *unk1C; - u8 unk20; - u8 unk21; - //u8 pad22[0x2]; - BKModelBin * unk24; - f32 unk28[3]; - Vec3fArray *unk34; - f32 unk38; - f32 unk3C; - BKVertexList *unk40; - BKVertexList *unk44; - u8 unk48; - u8 unk49; - //u8 pad4A[2]; - f32 unk4C; - s32 unk50; - f32 unk54; -}D_80389FA0; - -BKCollisionTriangle *__code1F70_func_80388360(f32 arg0[3], f32 arg1[3], f32 arg2[3], u32 arg3){ - BKCollisionTriangle *out_v0; - - out_v0 = collisionList_func_802E805C(D_80389FA0.unk1C, D_80389FA0.unk40, D_80389FA0.unk28, 0, 1.0f, arg0, arg1, arg2, arg3); - if(out_v0 && func_8029453C()){ - func_80340200(D_80389FA0.unk18, D_80389FA0.unk28, 0, 1.0f, 0, out_v0->unk0, D_80389FA0.unk40, arg1); - } - return out_v0; -} - -void __code1F70_func_80388428(f32 arg0[3], f32 arg1[3], f32 arg2, f32 arg3[3], s32 arg4, u32 arg5){ - func_802E9118(D_80389FA0.unk1C, D_80389FA0.unk40, D_80389FA0.unk28, 0, 1.0f, arg0, arg1, arg2, arg3, arg4, arg5); -} - -void func_803884A8(f32 arg0[3], f32 arg1, f32 arg2[3], u32 arg3){ - func_802E9DD8(D_80389FA0.unk1C, D_80389FA0.unk40, D_80389FA0.unk28, 0, 1.0f, arg0, arg1, arg2, arg3); -} - -void func_80388518(s32 arg0){ - s32 sp24; - if(D_80389FA0.unk21 == 2){ - sfxSource_triggerCallbackByIndex(D_80389FA0.sfxsourceIdx); - func_8030E760(SFX_7F_HEAVYDOOR_SLAM, 0.6f, 20000); - func_8030E760(SFX_7F_HEAVYDOOR_SLAM, 0.8f, 20000); - func_8030E760(SFX_7F_HEAVYDOOR_SLAM, 0.9f, 20000); - func_8030E760(SFX_7F_HEAVYDOOR_SLAM, 1.0f, 20000); - }//L80388594 - sp24 = D_80389FA0.unk21; - D_80389FA0.unk21 = arg0; - D_80389FA0.unk38 = 0.0f; - if(D_80389FA0.unk21 == 1){ - skeletalAnim_set(D_80389FA0.unk0, ASSET_C3_ANIM_CLANKER_IDLE, 0.0f, 10.0f); - } - if(D_80389FA0.unk21 == 2){ - func_8030DD90(D_80389FA0.sfxsourceIdx, 0); - sfxsource_playSfxAtVolume(D_80389FA0.sfxsourceIdx, 1.0f); - sfxsource_setSfxId(D_80389FA0.sfxsourceIdx, SFX_7D_ANCHOR_LIFTING); - sfxSource_setunk43_7ByIndex(D_80389FA0.sfxsourceIdx, 3); - sfxsource_setSampleRate(D_80389FA0.sfxsourceIdx, 27000); - sfxSource_func_8030E2C4(D_80389FA0.sfxsourceIdx); - } - - if(D_80389FA0.unk21 == 3){ - if(sp24 != 2){ - skeletalAnim_set(D_80389FA0.unk0, ASSET_C3_ANIM_CLANKER_IDLE, 0.0f, 10.0f); - } - D_80389FA0.unk28[1] = 1100.0f; - } -} - -void func_80388664(void) { - jiggy_spawn(JIGGY_17_CC_CLANKER_RAISED, D_80389C00); -} - -void CC_func_8038868C(void) { - func_80324E38(0, 3); - timed_setStaticCameraToNode(0, 0); - timed_setStaticCameraToNode(5.5f, 1); - timed_setStaticCameraToNode(7.0f, 2); - timed_setStaticCameraToNode(12.5f, 3); - timedFunc_set_0(13.0f, &func_80388664); - timed_setStaticCameraToNode(16.0f, 1); - if (jiggyscore_isCollected(JIGGY_17_CC_CLANKER_RAISED) == 0) { - func_80324DBC(18.0f, 0xD2C, 4, NULL, NULL, NULL, 0); - } - timed_exitStaticCamera(18.0f); - func_80324E38(18.0f, 0); -} - - -void CC_func_80388760(Gfx **gfx, Mtx **mtx, Vtx **vtx){ - BKVertexList *tmp_v0; - BoneTransformList *s1; - f32 spA4[3]; - f32 sp98[3]; - int i; - s32 tmp_s0; - f32 sp84[3]; - s32 pad80; - f32 sp74[3]; - f32 sp68[3]; - f32 sp5C[3]; - - - if(D_80389FA0.unk21 == 0) - return; - - viewport_getPosition_vec3f(sp98); - - if(sp98[0] < -2600.0f || 11600.0f < sp98[0]) - return; - - s1 = skeletalAnim_getBoneTransformList(D_80389FA0.unk0); - boneTransformList_getBoneScale(s1, 0x40, sp84); - for( i = 0; i < 3; i++){ - sp84[i] = sp84[i] + (1.3 - sp84[i])*D_80389FA0.unk8; - } - - boneTransformList_setBoneScale(s1, 0x40, sp84); - - if(D_80389FA0.unk21 == 1){ - func_8033A9A8(s1, 0x44, D_80389C0C); - func_8033A9A8(s1, 0x45, D_80389C0C); - func_8033A9A8(s1, 0x46, D_80389C0C); - - func_8033A9A8(s1, 0x47, D_80389C18); - func_8033A9A8(s1, 0x48, D_80389C18); - func_8033A9A8(s1, 0x49, D_80389C18); - } - - player_getPosition(spA4); - - for(i = 0; i < 2; i++){//L803888FC - vec3fArray_get_vec3f(D_80389FA0.unk34, (i == 0) ? 0x10 : 0xf, sp74); - sp68[0] = spA4[0] - sp74[0]; - sp68[1] = spA4[1] - sp74[1]; - sp68[2] = spA4[2] - sp74[2]; - ml_vec3f_normalize(sp68); - - sp5C[0] = 0.0f; - sp5C[1] = sp68[2]*45.0f; - sp5C[2] = -sp68[1]*45.0f; - func_8033A9A8(s1, (i == 0)?0x42:0x43, sp5C); - } - tmp_v0 = D_80389FA0.unk40; - D_80389FA0.unk40 = D_80389FA0.unk44; - D_80389FA0.unk44 = tmp_v0; - - func_8033A45C(1, (D_80389FA0.unk21 == 3) ? 1 : 0); - tmp_s0 = (sp98[0] < 100.0f)? 0 : 1; - func_8033A45C(2, 1); - func_8033A45C(3, 1); - func_8033A45C(4, tmp_s0); - func_8033A45C(5, tmp_s0); - func_8033A45C(6, tmp_s0); - func_8033A45C(7, tmp_s0); - func_8033A45C(8, tmp_s0); - if(tmp_s0){ - tmp_s0 = (s32)(D_80389FA0.unk4C*3.99 + 1.0); - func_8033A45C(2, tmp_s0); - func_8033A45C(3, tmp_s0); - } - modelRender_setBoneTransformList(s1); - modelRender_setRefPoints(D_80389FA0.unk34); - modelRender_setVertexList(D_80389FA0.unk40); - modelRender_setDepthMode(MODEL_RENDER_DEPTH_FULL); - modelRender_draw(gfx, mtx, D_80389FA0.unk28, NULL, 1.0f, NULL, D_80389FA0.unk24); - if(func_80340020(D_80389FA0.unk18, D_80389FA0.unk28, 0, 1.0f, 0, D_80389FA0.unk40, spA4, spA4)){ - func_8028FAB0(spA4); - baModel_802921D4(spA4); - } -} - -void func_80388B4C(f32 arg0[3]) { - vec3fArray_get_vec3f(D_80389FA0.unk34, 5, arg0); -} - -void func_80388B78(f32 arg0[3], f32 arg1[3]){ - vec3fArray_get_vec3f(D_80389FA0.unk34, 7, arg0); - vec3fArray_get_vec3f(D_80389FA0.unk34, 8, arg1); -} - -void func_80388BBC(f32 arg0[3], f32 arg1[3]){ - vec3fArray_get_vec3f(D_80389FA0.unk34, 9, arg0); - vec3fArray_get_vec3f(D_80389FA0.unk34, 10, arg1); -} - -void func_80388C00(NodeProp *arg0, ActorMarker *arg1){ - func_8031CD20(arg0, 0xb, 3); -} - -void func_80388C28(NodeProp *arg0, ActorMarker *arg1){ - func_8031CD20(arg0, 0xb, 4); -} - -void func_80388C50(NodeProp *arg0, ActorMarker *arg1){ - func_8031CD20(arg0, 0xb, 1); -} - -void CC_func_80388C78(NodeProp *arg0, ActorMarker *arg1){ - func_8031CD20(arg0, 0xb, 2); -} - -int CC_func_80388CA0(void){ - return D_80389FA0.unk21 == 3; -} - -void func_80388CB4(void){ - if(D_80389FA0.unk21){ - skeletalAnim_free(D_80389FA0.unk0); - sfxsource_freeSfxsourceByIndex(D_80389FA0.sfxsourceIdx); - func_80340690(D_80389FA0.unk18); - vec3fArray_free(D_80389FA0.unk34); - if(modelbin_getVtxList(D_80389FA0.unk24) != D_80389FA0.unk40) - vtxList_free(D_80389FA0.unk40); - if(modelbin_getVtxList(D_80389FA0.unk24) != D_80389FA0.unk44) - vtxList_free(D_80389FA0.unk44); - assetcache_release((void *)D_80389FA0.unk24); - D_80389FA0.unk34 = NULL; - D_80389FA0.unk0 = NULL; - D_80389FA0.unk18 = NULL; - } -} - -void func_80388D54(void){ - D_80389FA0.unk21 = 0; - if(gsworld_getMap() == MAP_B_CC_CLANKERS_CAVERN){ - D_80389FA0.unk0 = skeletalAnim_new(); - D_80389FA0.sfxsourceIdx = sfxsource_createSfxsourceAndReturnIndex(); - D_80389FA0.unk8 = 1.0f; - D_80389FA0.unk18 = func_803406B0(); - D_80389FA0.unk21 = 0; - D_80389FA0.unk24 = assetcache_get(ASSET_88E_MODEL_CLANKER_CHAIN); - D_80389FA0.unk1C = modelbin_getCollisionList(D_80389FA0.unk24); - D_80389FA0.unk34 = vec3fArray_new(); - D_80389FA0.unk3C = 1.0f; - D_80389FA0.unk40 = modelbin_getVtxList(D_80389FA0.unk24); - D_80389FA0.unk44 = vtxList_clone(D_80389FA0.unk40); - D_80389FA0.unk48 = 0; - D_80389FA0.unk49 = 0; - D_80389FA0.unk50 = 0; - D_80389FA0.unk4C = 0.0f; - D_80389FA0.unk54 = 1.0f; - D_80389FA0.unk28[0] = 5500.0f; - D_80389FA0.unk28[2] = 0.0f; - D_80389FA0.unk28[1] = 0.0f; - func_80320B24(__code1F70_func_80388360, __code1F70_func_80388428, func_803884A8); - if(!nodeProp_findPositionFromActorId(0x3B, D_80389FA0.unkC)){ - D_80389FA0.unkC[0] = 0.0f; - D_80389FA0.unkC[1] =-1e+06f; - D_80389FA0.unkC[2] = 0.0f; - } - if(jiggyscore_isSpawned(JIGGY_17_CC_CLANKER_RAISED)){ - func_80388518(3); - } - else{ - func_80388518(1); - } - } -} - -void func_80388EA4(void){ - if(D_80389FA0.unk21 == 1){ - func_80388518(2); - } -} - -void func_80388ED4(s32 arg0){ - f32 sp1C[3]; - vec3fArray_get_vec3f(D_80389FA0.unk34, 5, sp1C); - if(arg0 != 0){ - sfx_playFadeShorthandDefault(SFX_91_METALLIC_SOUND, 0.7f, 32675, sp1C, 100, 6000); - } - else{ - sfx_playFadeShorthandDefault(SFX_82_METAL_BREAK, 0.9f, 24000, sp1C, 100, 6000); - } - D_80389FA0.unk8 = 1.0f; -} - -void CC_func_80388F4C(void){ - f32 sp6C[3]; - f32 sp68 = time_getDelta(); - f32 sp64; - f32 sp60; - f32 sp54[3]; - f32 sp48[3]; - BKCollisionTriangle *tmp_v0; - f32 pad[3]; - - CC_func_80387D4C(); - if(D_80389FA0.unk21 != 0 && gsworld_getUnk0() == 2){ - // Anchor: teammate raised Clanker — play the physical raise (no cutscene). - if(D_80389FA0.unk21 == 1 && jiggyscore_isSpawned(JIGGY_17_CC_CLANKER_RAISED)){ - func_80388EA4(); - } - player_getPosition(sp6C); - D_80389FA0.unk20 = (ml_vec3f_distance(sp6C, D_80389FA0.unkC) < 200.0f); - - D_80389FA0.unk38 += sp68; - sp64 = skeletalAnim_getProgress(D_80389FA0.unk0); - skeletalAnim_update(D_80389FA0.unk0, sp68, 1); - sp60 = skeletalAnim_getProgress(D_80389FA0.unk0); - if(D_80389FA0.unk21 == 3){ - vec3fArray_get_vec3f(D_80389FA0.unk34, 5, sp54); - if(sp60 < sp64){ - sfx_playFadeShorthandDefault(SFX_7E_CREAKY_DOOR_OPENING, 0.6f, 32300, sp54, 1000, 5000); - }//L80389058 - - if(sp64 < 0.3 && 0.3 <= sp60){ - sfx_playFadeShorthandDefault(SFX_7E_CREAKY_DOOR_OPENING, 0.5f, 32300, sp54, 1000, 5000); - } - }//L8038909C - - if(D_80389FA0.unk21 == 2){ - D_80389FA0.unk28[1] += 100.0f*sp68; - } - - if(0.0f < D_80389FA0.unk8){ - D_80389FA0.unk8 -= sp68/2; - if(D_80389FA0.unk8 <= 0.0f) - D_80389FA0.unk8 = 0.0f; - } - - if(D_80389FA0.unk21 == 1){ - if(D_80389FA0.unk20 && skeletalAnim_getAnimId(D_80389FA0.unk0) != ASSET_C4_ANIM_CLANKER_BITE){ - skeletalAnim_set(D_80389FA0.unk0, ASSET_C4_ANIM_CLANKER_BITE, 1.0f, 10.0f); - if(!D_80389FA0.unk48){ - gcdialog_showDialog(ASSET_D2B_DIALOG_CLANKER_MEET, 0xE, D_80389FA0.unk28, NULL, NULL, NULL); - D_80389FA0.unk48 = true; - } - }//L8038918C - - if(!D_80389FA0.unk20 && skeletalAnim_getAnimId(D_80389FA0.unk0) == ASSET_C4_ANIM_CLANKER_BITE){ - skeletalAnim_set(D_80389FA0.unk0, ASSET_C3_ANIM_CLANKER_IDLE, 1.0f, 10.0f); - } - }//L803891BC - - if(D_80389FA0.unk21 == 2){ - func_803114D0(); - if(1100.0f <= D_80389FA0.unk28[1]){ - func_80388518(3); - } - }//L803891F8 - - if(D_80389FA0.unk21 == 3){ - vec3fArray_get_vec3f(D_80389FA0.unk34, 6, sp48); - if(ml_vec3f_distance(sp48, sp6C) <= 130.0f && sp6C[1] - sp48[1] < 50.0f){ - func_8031D04C(MAP_21_CC_WITCH_SWITCH_ROOM, WARP_CC_WITCH_SWITCH_1_TOP_ENTRANCE); - } - }//L80389260 - - if( D_80389FA0.unk21 == 3){ - tmp_v0 = func_8028EF48(); - if( tmp_v0 && !D_80389FA0.unk49 - ){ - if(tmp_v0->flags & 2){ - func_8031CE28(0x22, 5, 180.0f); - D_80389FA0.unk49++; - } - else if(tmp_v0->flags & 4){ - func_8031CE28(0x22, 4, 0.0f); - D_80389FA0.unk49++; - } - } - }//L803892DC - if(ml_timer_update(&D_80389FA0.unk3C, sp68)){ - if(D_80389FA0.unk21 == 3){ - func_8030E9FC(SFX_D0_GRIMLET_SQUEAK, 0.5f, 0.7f, 20000, D_80389C24, 2000.0f, 4000.0f); - }else{ - func_8030EA54(SFX_D0_GRIMLET_SQUEAK, 0.5f, 0.7f, 20000, D_80389C24, 2000.0f, 4000.0f); - }//L80389384 - D_80389FA0.unk3C = randf2(3.0f, 6.0f); - }//L803893A0 - if(D_80389FA0.unk50 == 0){ - if(ml_timer_update(&D_80389FA0.unk54, sp68)) - D_80389FA0.unk50 = 1; - } - - if(D_80389FA0.unk50){ - D_80389FA0.unk4C += D_80389FA0.unk50 * ((sp68 * 30.0)/4); - if(1.0f < D_80389FA0.unk4C){ - D_80389FA0.unk50 = -1; - D_80389FA0.unk4C = 1.0f; - } - else if(D_80389FA0.unk4C < 0.0f){ - D_80389FA0.unk50 = 0; - D_80389FA0.unk4C = 0.0f; - D_80389FA0.unk54 = randf2(0.1f, 7.0f); - } - } - }//L80389490 - -} - -void func_803894A0(void){ - if(D_80389FA0.unk34) - D_80389FA0.unk34 = vec3fArray_defrag(D_80389FA0.unk34); - - if(D_80389FA0.unk0) - D_80389FA0.unk0 = defrag(D_80389FA0.unk0); - - if(D_80389FA0.unk18) - D_80389FA0.unk18 = func_803406D4(D_80389FA0.unk18); -} diff --git a/src/CCW/actor_spawninit.c b/src/CCW/actor_spawninit.c deleted file mode 100644 index 7ed064f3f..000000000 --- a/src/CCW/actor_spawninit.c +++ /dev/null @@ -1,157 +0,0 @@ -// BanjoDecomp: code_76C0.c -#include -#include "functions.h" -#include "variables.h" -#include "prop.h" -#include "actor.h" - -extern void func_802D3D54(Actor *); -extern void func_802D3D74(Actor *); -extern void func_80325F84(Actor *); - - -extern ActorInfo D_8038EB50; -extern ActorInfo D_8038EB74; -extern ActorInfo D_8038EBA0; -extern ActorInfo D_8038EBD0; -extern ActorInfo D_8038EC14; -extern ActorInfo D_8038EC70; -extern ActorInfo D_8038ECA0; -extern ActorInfo D_8038ECE8; -extern ActorInfo D_8038EE70; -extern ActorInfo D_8038F130; -extern ActorInfo chCaterpillar; -extern ActorInfo D_8038F190; -extern ActorInfo D_8038F230; -extern ActorInfo D_8038F6F0; -extern ActorInfo D_8038ED50; -extern ActorInfo D_8038ED98; -extern ActorInfo D_8038EDE0; -extern ActorInfo D_8038EE28; -extern ActorInfo D_8038ED74; -extern ActorInfo D_8038EDBC; -extern ActorInfo D_8038EE04; -extern ActorInfo D_8038EE4C; -extern ActorInfo D_8038F270; -extern ActorInfo D_8038F300; -extern ActorInfo D_8038F35C; -extern ActorInfo D_8038F380; -extern ActorInfo D_8038F3A4; -extern ActorInfo D_8038F3C8; -extern ActorInfo D_8038F3EC; -extern ActorInfo D_8038F410; -extern ActorInfo D_8038F434; -extern ActorInfo D_8038F460; -extern ActorInfo D_8038F4A8; -extern ActorInfo D_8038F4D0; -extern ActorInfo D_8038F614; -extern ActorInfo chGnawtyBoulder; -extern ActorInfo D_8038F908; -extern ActorInfo D_8038F8C0; -extern ActorInfo D_8038F720; -extern ActorInfo D_8038F744; -extern ActorInfo D_8038F768; -extern ActorInfo D_8038F78C; -extern ActorInfo chGrublinHood; -extern ActorInfo gChVacationTextTrigger; -extern ActorInfo D_8038F7D4; -extern ActorInfo D_8038F7B0; -extern ActorInfo D_8038F888; -extern ActorInfo D_8038F7F8; -extern ActorInfo D_8038F81C; -extern ActorInfo D_8038F840; -extern ActorInfo D_8038F864; - -void CCW_func_8038DB0C(Actor *this); -void func_8038DAB0(Actor *this); - -/* .data */ -ActorInfo D_8038F720 = { 0x239, 0x25F, 0x4FC, 0x1, NULL, func_802D3D54, actor_update_func_80326224, actor_drawFullDepth, 0, 0, 0.0f, 0}; -ActorInfo D_8038F744 = { 0x236, 0x260, 0x4F9, 0x1, NULL, func_802D3D54, actor_update_func_80326224, actor_drawFullDepth, 0, 0, 0.0f, 0}; -ActorInfo D_8038F768 = { 0x237, 0x261, 0x4FA, 0x1, NULL, func_802D3D54, actor_update_func_80326224, actor_drawFullDepth, 0, 0, 0.0f, 0}; -ActorInfo D_8038F78C = { 0x238, 0x262, 0x4FB, 0x1, NULL, func_802D3D54, actor_update_func_80326224, actor_drawFullDepth, 0, 0, 0.0f, 0}; -ActorInfo D_8038F7B0 = { 0x243, 0x2E6, 0x533, 0x1, NULL, func_802D3D54, actor_update_func_80326224, actor_drawFullDepth, 0, 0, 0.0f, 0}; -ActorInfo D_8038F7D4 = { 0x263, 0x2E7, 0x518, 0x1, NULL, func_8038DAB0, actor_update_func_80326224, actor_drawFullDepth, 0, 0, 0.0f, 0}; -ActorInfo D_8038F7F8 = { 0x21E, 0x233, 0x3B3, 0x1, NULL, func_802D3D74, actor_update_func_80326224, actor_drawFullDepth, 0, 0, 0.0f, 0}; -ActorInfo D_8038F81C = { 0x26B, 0x2DE, 0x531, 0x1, NULL, CCW_func_8038DB0C, actor_update_func_80326224, actor_drawFullDepth, 0, 0, 0.0f, 0}; -ActorInfo D_8038F840 = { 0x26C, 0x2DD, 0x53E, 0x1, NULL, CCW_func_8038DB0C, actor_update_func_80326224, actor_drawFullDepth, 0, 0, 0.0f, 0}; -ActorInfo D_8038F864 = { 0x26D, 0x2DC, 0x53F, 0x1, NULL, CCW_func_8038DB0C, actor_update_func_80326224, actor_drawFullDepth, 0, 0, 0.0f, 0}; -ActorInfo D_8038F888 = { 0x1CC, 0x318, 0x0, 0x0, NULL, func_80325F84, NULL, func_80325340, 0, 0, 0.0f, 0}; - - -/* .code */ -void func_8038DAB0(Actor *this){ - if(!this->initialized){ - func_802D3CE8(this); - this->initialized = true; - } - // Anchor: checked live, not just at spawn. - if (levelSpecificFlags_get(LEVEL_FLAG_38_CCW_UNKNOWN)) { - marker_despawn(this->marker); - } -} - -void CCW_func_8038DB0C(Actor *this){ - if(!this->initialized){ - func_802D3D74(this); - this->initialized = true; - this->position_x = 325.8f; - this->position_y = 600.0f; - this->position_z = 0.0f; - } -} - -void CCW_func_8038DB6C(void) -{ - spawnableActorList_add(&D_8038EB50, actor_new, ACTOR_FLAG_UNKNOWN_7); - spawnableActorList_add(&D_8038EB74, actor_new, ACTOR_FLAG_UNKNOWN_7); - spawnableActorList_add(&D_8038EBA0, actor_new, ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_8); - spawnableActorList_add(&D_8038EBD0, actor_new, ACTOR_FLAG_UNKNOWN_2 | ACTOR_FLAG_UNKNOWN_3 | ACTOR_FLAG_UNKNOWN_11 | ACTOR_FLAG_UNKNOWN_25); - spawnableActorList_add(&D_8038EC14, actor_new, ACTOR_FLAG_UNKNOWN_3 | ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_11); - spawnableActorList_add(&D_8038EC70, actor_new, ACTOR_FLAG_UNKNOWN_3 | ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_10 | ACTOR_FLAG_UNKNOWN_11 | ACTOR_FLAG_UNKNOWN_14 | ACTOR_FLAG_UNKNOWN_16 | ACTOR_FLAG_UNKNOWN_19); - spawnableActorList_add(&D_8038ECA0, actor_new, ACTOR_FLAG_UNKNOWN_3 | ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_10 | ACTOR_FLAG_UNKNOWN_11 | ACTOR_FLAG_UNKNOWN_14 | ACTOR_FLAG_UNKNOWN_19); - spawnableActorList_add(&D_8038ECE8, actor_new, ACTOR_FLAG_UNKNOWN_3 | ACTOR_FLAG_UNKNOWN_5 | ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_8 | ACTOR_FLAG_UNKNOWN_11 | ACTOR_FLAG_UNKNOWN_19); - spawnableActorList_add(&D_8038EE70, actor_new, ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_10 | ACTOR_FLAG_UNKNOWN_11); - spawnableActorList_add(&D_8038F130, actor_new, ACTOR_FLAG_UNKNOWN_1 | ACTOR_FLAG_UNKNOWN_3 | ACTOR_FLAG_UNKNOWN_5 | ACTOR_FLAG_UNKNOWN_10 | ACTOR_FLAG_UNKNOWN_11 | ACTOR_FLAG_UNKNOWN_14 | ACTOR_FLAG_UNKNOWN_19); - spawnableActorList_add(&chCaterpillar, actor_new, ACTOR_FLAG_UNKNOWN_0 | ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_11); - spawnableActorList_add(&D_8038F190, actor_new, ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_8 | ACTOR_FLAG_UNKNOWN_10 | ACTOR_FLAG_UNKNOWN_11 | ACTOR_FLAG_UNKNOWN_19); - spawnableActorList_add(&D_8038F230, actor_new, ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_8 | ACTOR_FLAG_UNKNOWN_10 | ACTOR_FLAG_UNKNOWN_11); - spawnableActorList_add(&D_8038F6F0, actor_new, ACTOR_FLAG_UNKNOWN_2 | ACTOR_FLAG_UNKNOWN_11); - spawnableActorList_add(&D_8038ED50, actor_new, ACTOR_FLAG_UNKNOWN_10); - spawnableActorList_add(&D_8038ED98, actor_new, ACTOR_FLAG_UNKNOWN_10); - spawnableActorList_add(&D_8038EDE0, actor_new, ACTOR_FLAG_UNKNOWN_10); - spawnableActorList_add(&D_8038EE28, actor_new, ACTOR_FLAG_UNKNOWN_10); - spawnableActorList_add(&D_8038ED74, actor_new, ACTOR_FLAG_NONE); - spawnableActorList_add(&D_8038EDBC, actor_new, ACTOR_FLAG_NONE); - spawnableActorList_add(&D_8038EE04, actor_new, ACTOR_FLAG_NONE); - spawnableActorList_add(&D_8038EE4C, actor_new, ACTOR_FLAG_NONE); - spawnableActorList_add(&D_8038F270, actor_new, ACTOR_FLAG_UNKNOWN_0 | ACTOR_FLAG_UNKNOWN_3 | ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_8 | ACTOR_FLAG_UNKNOWN_11); - spawnableActorList_add(&D_8038F300, actor_new, ACTOR_FLAG_UNKNOWN_0 | ACTOR_FLAG_UNKNOWN_3 | ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_8 | ACTOR_FLAG_UNKNOWN_11); - spawnableActorList_add(&D_8038F35C, actor_new, ACTOR_FLAG_UNKNOWN_0 | ACTOR_FLAG_UNKNOWN_3 | ACTOR_FLAG_UNKNOWN_8 | ACTOR_FLAG_UNKNOWN_11); - spawnableActorList_add(&D_8038F380, actor_new, ACTOR_FLAG_UNKNOWN_7); - spawnableActorList_add(&D_8038F3A4, actor_new, ACTOR_FLAG_UNKNOWN_3 | ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_11); - spawnableActorList_add(&D_8038F3C8, actor_new, ACTOR_FLAG_UNKNOWN_3 | ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_11); - spawnableActorList_add(&D_8038F3EC, actor_new, ACTOR_FLAG_UNKNOWN_7); - spawnableActorList_add(&D_8038F410, actor_new, ACTOR_FLAG_UNKNOWN_3 | ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_8 | ACTOR_FLAG_UNKNOWN_11); - spawnableActorList_add(&D_8038F434, actor_new, ACTOR_FLAG_UNKNOWN_3 | ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_11); - spawnableActorList_add(&D_8038F460, actor_new, ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_11); - spawnableActorList_add(&D_8038F4A8, actor_new, ACTOR_FLAG_UNKNOWN_1 | ACTOR_FLAG_UNKNOWN_3 | ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_8 | ACTOR_FLAG_UNKNOWN_11); - spawnableActorList_add(&D_8038F4D0, actor_new, ACTOR_FLAG_UNKNOWN_3 | ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_8 | ACTOR_FLAG_UNKNOWN_11); - spawnableActorList_add(&D_8038F614, actor_new, ACTOR_FLAG_UNKNOWN_3 | ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_8 | ACTOR_FLAG_UNKNOWN_11); - spawnableActorList_add(&chGnawtyBoulder, actor_new, ACTOR_FLAG_UNKNOWN_7); - spawnableActorList_add(&D_8038F908, actor_new, ACTOR_FLAG_UNKNOWN_3); - spawnableActorList_add(&D_8038F8C0, actor_new, ACTOR_FLAG_UNKNOWN_3); - spawnableActorList_add(&D_8038F720, actor_new, ACTOR_FLAG_NONE); - spawnableActorList_add(&D_8038F744, actor_new, ACTOR_FLAG_NONE); - spawnableActorList_add(&D_8038F768, actor_new, ACTOR_FLAG_NONE); - spawnableActorList_add(&D_8038F78C, actor_new, ACTOR_FLAG_NONE); - spawnableActorList_add(&chGrublinHood, actor_new, ACTOR_FLAG_UNKNOWN_0 | ACTOR_FLAG_UNKNOWN_5 | ACTOR_FLAG_UNKNOWN_8 | ACTOR_FLAG_UNKNOWN_16 | ACTOR_FLAG_UNKNOWN_25); - spawnableActorList_add(&gChVacationTextTrigger, actor_new, ACTOR_FLAG_NONE); - spawnableActorList_add(&D_8038F7D4, actor_new, ACTOR_FLAG_UNKNOWN_10); - spawnableActorList_add(&D_8038F7B0, actor_new, ACTOR_FLAG_UNKNOWN_10); - spawnableActorList_add(&D_8038F888, actor_new, ACTOR_FLAG_UNKNOWN_7); - spawnableActorList_add(&D_8038F7F8, actor_new, ACTOR_FLAG_UNKNOWN_10); - spawnableActorList_add(&D_8038F81C, actor_new, ACTOR_FLAG_UNKNOWN_10); - spawnableActorList_add(&D_8038F840, actor_new, ACTOR_FLAG_UNKNOWN_10); - spawnableActorList_add(&D_8038F864, actor_new, ACTOR_FLAG_UNKNOWN_10); -} diff --git a/src/CCW/bss_pad.c b/src/CCW/bss_pad.c deleted file mode 100644 index 152d079d3..000000000 --- a/src/CCW/bss_pad.c +++ /dev/null @@ -1,2 +0,0 @@ -// BanjoDecomp: bss_pad.c -char pad_CCW_8038FDD0[0x10]; diff --git a/src/CCW/ccwspawnqueue.c b/src/CCW/ccwspawnqueue.c new file mode 100644 index 000000000..3519d36f7 --- /dev/null +++ b/src/CCW/ccwspawnqueue.c @@ -0,0 +1,229 @@ +// BanjoDecomp: CCW/ccwspawnqueue.c +#include +#include "functions.h" +#include "variables.h" +#include "prop.h" +#include "actor.h" + +extern void chMMMBreakableWooden_update(Actor *); +extern void func_802D3D74(Actor *); +extern void func_80325F84(Actor *); + + +extern ActorInfo chZubbaDoorSummer; +extern ActorInfo chZubbaDoorAutumn; +extern ActorInfo chZubbaHoneyLump; +extern ActorInfo chZubba; +extern ActorInfo chZubbaDocile; +extern ActorInfo chCCWBeanstalk; +extern ActorInfo chDeadBeanstalk; +extern ActorInfo chCCWGobi; +extern ActorInfo chEyrieEgg; +extern ActorInfo chEyrieBaby; +extern ActorInfo chCaterpillar; +extern ActorInfo chEyrieAdult; +extern ActorInfo chCutsceneAdultEyrie; +extern ActorInfo chSnoreZ; +extern ActorInfo chCCWSpringSwitchDoor; +extern ActorInfo chCCWSummerSwitchDoor; +extern ActorInfo chCCWAutumnSwitchDoor; +extern ActorInfo chCCWWinterSwitchDoor; +extern ActorInfo chCCWSpringSwitch; +extern ActorInfo chCCWSummerSwitch; +extern ActorInfo chCCWAutumnSwitch; +extern ActorInfo chCCWWinterSwitch; +extern ActorInfo chNabnutSpring; +extern ActorInfo chNabnutBellyFull; +extern ActorInfo chAutumnOutdoorNabnut; +extern ActorInfo chMoundOfAcorns; +extern ActorInfo chPinkSquirrel; +extern ActorInfo chNabnutBedsheets; +extern ActorInfo chNabnutBed; +extern ActorInfo chNabnut; +extern ActorInfo chNabnutAutumnEatingAcorns; +extern ActorInfo chCarriedAcorn; +extern ActorInfo chGnawtySwimming; +extern ActorInfo chGnawtySummer; +extern ActorInfo chIndoorsGnawty; +extern ActorInfo chGnawtyBoulder; +extern ActorInfo chSnarebear; +extern ActorInfo chDeadSnarebear; +extern ActorInfo chNabnutWindowSpring; +extern ActorInfo chNabnutWindowSummer; +extern ActorInfo chNabnutWindowAutumn; +extern ActorInfo chNabnutWindowWinter; +extern ActorInfo chGrublinHood; +extern ActorInfo gChVacationTextTrigger; +extern ActorInfo chCCWWhipcrackRoomDoor; +extern ActorInfo chNabnutDoor; +extern ActorInfo D_8038F888; +extern ActorInfo chCCWMumbosHut; +extern ActorInfo chGnawtysDen; +extern ActorInfo chGnawtysBed; +extern ActorInfo chGnawtysShelves; + +void code_76C0_ccwGnawtysStuffUpdate(Actor *this); +void code_76C0_ccwWhipcrackRoomDoorUpdate(Actor *this); + +/* .data */ + +#if VERSION == VERSION_PAL +Actor* cc_pal_unk_draw(ActorMarker *, Gfx **, Mtx **, Vtx **); +#endif + +// Unused +ActorInfo chNabnutWindowSpring = { + MARKER_239_CCW_UNKNOWN_NABNUT_WINDOW, ACTOR_25F_CCW_UNKNOWN_NABNUT_WINDOW, ASSET_4FC_MODEL_CCW_UNKNOWN_NABNUT_WINDOW, + 0x1, NULL, + chMMMBreakableWooden_update, actor_update_func_80326224, actor_drawFullDepth, + 0, 0, 0.0f, 0 +}; + +// Unused +ActorInfo chNabnutWindowSummer = { + MARKER_236_CCW_UNKNOWN_NABNUT_WINDOW, ACTOR_260_CCW_UNKNOWN_NABNUT_WINDOW, ASSET_4F9_MODEL_CCW_UNKNOWN_NABNUT_WINDOW, + 0x1, NULL, + chMMMBreakableWooden_update, actor_update_func_80326224, actor_drawFullDepth, + 0, 0, 0.0f, 0 +}; + +ActorInfo chNabnutWindowAutumn = { + MARKER_237_CCW_AUTUMN_NABNUT_WINDOW, ACTOR_261_CCW_AUTUMN_NABNUT_WINDOW, ASSET_4FA_MODEL_CCW_AUTUMN_NABNUT_WINDOW, + 0x1, NULL, + chMMMBreakableWooden_update, actor_update_func_80326224, actor_drawFullDepth, + 0, 0, 0.0f, 0 +}; + +ActorInfo chNabnutWindowWinter = { + MARKER_238_CCW_WINTER_NABNUT_WINDOW, ACTOR_262_CCW_WINTER_NABNUT_WINDOW, ASSET_4FB_MODEL_CCW_WINTER_NABNUT_WINDOW, + 0x1, NULL, + chMMMBreakableWooden_update, actor_update_func_80326224, actor_drawFullDepth, + 0, 0, 0.0f, 0 +}; + +ActorInfo chNabnutDoor = { + MARKER_243_NABNUT_DOOR, ACTOR_2E6_NABNUT_DOOR, ASSET_533_MODEL_NABNUT_DOOR, + 0x1, NULL, + chMMMBreakableWooden_update, actor_update_func_80326224, actor_drawFullDepth, + 0, 0, 0.0f, 0 +}; + +ActorInfo chCCWWhipcrackRoomDoor = { + MARKER_263_CCW_WHIPCRACK_ROOM_DOOR, ACTOR_2E7_WHIPCRACK_ROOM_DOOR, ASSET_518_MODEL_CCW_WHIPCRACK_ROOM_DOOR, + 0x1, NULL, + code_76C0_ccwWhipcrackRoomDoorUpdate, actor_update_func_80326224, actor_drawFullDepth, + 0, 0, 0.0f, 0 +}; + +ActorInfo chCCWMumbosHut = { + MARKER_21E_CCW_MUMBOS_HUT, ACTOR_233_CCW_MUMBOS_HUT, ASSET_3B3_MODEL_CCW_MUMBOS_HUT, + 0x1, NULL, + func_802D3D74, actor_update_func_80326224, actor_drawFullDepth, + 0, 0, 0.0f, 0 +}; + +ActorInfo chGnawtysDen = { + MARKER_26B_GNAWTYS_DEN, ACTOR_2DE_GNAWTYS_DEN, ASSET_531_MODEL_GNAWTYS_DEN, + 0x1, NULL, + code_76C0_ccwGnawtysStuffUpdate, actor_update_func_80326224, actor_drawFullDepth, + 0, 0, 0.0f, 0 +}; + +ActorInfo chGnawtysBed = { + MARKER_26C_GNAWTYS_BED, ACTOR_2DD_GNAWTYS_BED, ASSET_53E_MODEL_GNAWTY_BED, + 0x1, NULL, + code_76C0_ccwGnawtysStuffUpdate, actor_update_func_80326224, actor_drawFullDepth, + 0, 0, 0.0f, 0 +}; + +ActorInfo chGnawtysShelves = { + MARKER_26D_GNAWTYS_SHELVES, ACTOR_2DC_GNAWTYS_SHELVES, ASSET_53F_MODEL_GNAWTY_SHELVES, + 0x1, NULL, + code_76C0_ccwGnawtysStuffUpdate, actor_update_func_80326224, actor_drawFullDepth, + 0, 0, 0.0f, 0 +}; + +ActorInfo D_8038F888 = { + MARKER_1CC_CCW_UNKNOWN, ACTOR_318_CCW_UNKNOWN, 0x0, + 0x0, NULL, + func_80325F84, NULL, func_80325340, + 0, 0, 0.0f, 0 +}; + +/* .code */ +void code_76C0_ccwWhipcrackRoomDoorUpdate(Actor *this){ + if(!this->initialized){ + func_802D3CE8(this); + this->initialized = true; + } + // Anchor: checked live, not just at spawn. + if (levelSpecificFlags_get(LEVEL_FLAG_38_CCW_UNKNOWN)) { + marker_despawn(this->marker); + } +} + +void code_76C0_ccwGnawtysStuffUpdate(Actor *this){ + if(!this->initialized){ + func_802D3D74(this); + this->initialized = true; + // Position For Gnawty's Den + this->position_x = 325.8f; + this->position_y = 600.0f; + this->position_z = 0.0f; + } +} + +void CCW_func_8038DB6C(void) +{ + spawnableActorList_add(&chZubbaDoorSummer, actor_new, ACTOR_FLAG_UNKNOWN_7); + spawnableActorList_add(&chZubbaDoorAutumn, actor_new, ACTOR_FLAG_UNKNOWN_7); + spawnableActorList_add(&chZubbaHoneyLump, actor_new, ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_8); + spawnableActorList_add(&chZubba, actor_new, ACTOR_FLAG_UNKNOWN_2 | ACTOR_FLAG_UNKNOWN_3 | ACTOR_FLAG_UNKNOWN_11 | ACTOR_FLAG_UNKNOWN_25); + spawnableActorList_add(&chZubbaDocile, actor_new, ACTOR_FLAG_UNKNOWN_3 | ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_11); + spawnableActorList_add(&chCCWBeanstalk, actor_new, ACTOR_FLAG_UNKNOWN_3 | ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_10 | ACTOR_FLAG_UNKNOWN_11 | ACTOR_FLAG_UNKNOWN_14 | ACTOR_FLAG_UNKNOWN_16 | ACTOR_FLAG_UNKNOWN_19); + spawnableActorList_add(&chDeadBeanstalk, actor_new, ACTOR_FLAG_UNKNOWN_3 | ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_10 | ACTOR_FLAG_UNKNOWN_11 | ACTOR_FLAG_UNKNOWN_14 | ACTOR_FLAG_UNKNOWN_19); + spawnableActorList_add(&chCCWGobi, actor_new, ACTOR_FLAG_UNKNOWN_3 | ACTOR_FLAG_UNKNOWN_5 | ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_8 | ACTOR_FLAG_UNKNOWN_11 | ACTOR_FLAG_UNKNOWN_19); + spawnableActorList_add(&chEyrieEgg, actor_new, ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_10 | ACTOR_FLAG_UNKNOWN_11); + spawnableActorList_add(&chEyrieBaby, actor_new, ACTOR_FLAG_UNKNOWN_1 | ACTOR_FLAG_UNKNOWN_3 | ACTOR_FLAG_UNKNOWN_5 | ACTOR_FLAG_UNKNOWN_10 | ACTOR_FLAG_UNKNOWN_11 | ACTOR_FLAG_UNKNOWN_14 | ACTOR_FLAG_UNKNOWN_19); + spawnableActorList_add(&chCaterpillar, actor_new, ACTOR_FLAG_UNKNOWN_0 | ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_11); + spawnableActorList_add(&chEyrieAdult, actor_new, ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_8 | ACTOR_FLAG_UNKNOWN_10 | ACTOR_FLAG_UNKNOWN_11 | ACTOR_FLAG_UNKNOWN_19); + spawnableActorList_add(&chCutsceneAdultEyrie, actor_new, ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_8 | ACTOR_FLAG_UNKNOWN_10 | ACTOR_FLAG_UNKNOWN_11); + spawnableActorList_add(&chSnoreZ, actor_new, ACTOR_FLAG_UNKNOWN_2 | ACTOR_FLAG_UNKNOWN_11); + spawnableActorList_add(&chCCWSpringSwitchDoor, actor_new, ACTOR_FLAG_UNKNOWN_10); + spawnableActorList_add(&chCCWSummerSwitchDoor, actor_new, ACTOR_FLAG_UNKNOWN_10); + spawnableActorList_add(&chCCWAutumnSwitchDoor, actor_new, ACTOR_FLAG_UNKNOWN_10); + spawnableActorList_add(&chCCWWinterSwitchDoor, actor_new, ACTOR_FLAG_UNKNOWN_10); + spawnableActorList_add(&chCCWSpringSwitch, actor_new, ACTOR_FLAG_NONE); + spawnableActorList_add(&chCCWSummerSwitch, actor_new, ACTOR_FLAG_NONE); + spawnableActorList_add(&chCCWAutumnSwitch, actor_new, ACTOR_FLAG_NONE); + spawnableActorList_add(&chCCWWinterSwitch, actor_new, ACTOR_FLAG_NONE); + spawnableActorList_add(&chNabnutSpring, actor_new, ACTOR_FLAG_UNKNOWN_0 | ACTOR_FLAG_UNKNOWN_3 | ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_8 | ACTOR_FLAG_UNKNOWN_11); + spawnableActorList_add(&chNabnutBellyFull, actor_new, ACTOR_FLAG_UNKNOWN_0 | ACTOR_FLAG_UNKNOWN_3 | ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_8 | ACTOR_FLAG_UNKNOWN_11); + spawnableActorList_add(&chAutumnOutdoorNabnut, actor_new, ACTOR_FLAG_UNKNOWN_0 | ACTOR_FLAG_UNKNOWN_3 | ACTOR_FLAG_UNKNOWN_8 | ACTOR_FLAG_UNKNOWN_11); + spawnableActorList_add(&chMoundOfAcorns, actor_new, ACTOR_FLAG_UNKNOWN_7); + spawnableActorList_add(&chPinkSquirrel, actor_new, ACTOR_FLAG_UNKNOWN_3 | ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_11); + spawnableActorList_add(&chNabnutBedsheets, actor_new, ACTOR_FLAG_UNKNOWN_3 | ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_11); + spawnableActorList_add(&chNabnutBed, actor_new, ACTOR_FLAG_UNKNOWN_7); + spawnableActorList_add(&chNabnut, actor_new, ACTOR_FLAG_UNKNOWN_3 | ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_8 | ACTOR_FLAG_UNKNOWN_11); + spawnableActorList_add(&chNabnutAutumnEatingAcorns, actor_new, ACTOR_FLAG_UNKNOWN_3 | ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_11); + spawnableActorList_add(&chCarriedAcorn, actor_new, ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_11); + spawnableActorList_add(&chGnawtySwimming, actor_new, ACTOR_FLAG_UNKNOWN_1 | ACTOR_FLAG_UNKNOWN_3 | ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_8 | ACTOR_FLAG_UNKNOWN_11); + spawnableActorList_add(&chGnawtySummer, actor_new, ACTOR_FLAG_UNKNOWN_3 | ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_8 | ACTOR_FLAG_UNKNOWN_11); + spawnableActorList_add(&chIndoorsGnawty, actor_new, ACTOR_FLAG_UNKNOWN_3 | ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_8 | ACTOR_FLAG_UNKNOWN_11); + spawnableActorList_add(&chGnawtyBoulder, actor_new, ACTOR_FLAG_UNKNOWN_7); + spawnableActorList_add(&chSnarebear, actor_new, ACTOR_FLAG_UNKNOWN_3); + spawnableActorList_add(&chDeadSnarebear, actor_new, ACTOR_FLAG_UNKNOWN_3); + spawnableActorList_add(&chNabnutWindowSpring, actor_new, ACTOR_FLAG_NONE); + spawnableActorList_add(&chNabnutWindowSummer, actor_new, ACTOR_FLAG_NONE); + spawnableActorList_add(&chNabnutWindowAutumn, actor_new, ACTOR_FLAG_NONE); + spawnableActorList_add(&chNabnutWindowWinter, actor_new, ACTOR_FLAG_NONE); + spawnableActorList_add(&chGrublinHood, actor_new, ACTOR_FLAG_UNKNOWN_0 | ACTOR_FLAG_UNKNOWN_5 | ACTOR_FLAG_UNKNOWN_8 | ACTOR_FLAG_UNKNOWN_16 | ACTOR_FLAG_UNKNOWN_25); + spawnableActorList_add(&gChVacationTextTrigger, actor_new, ACTOR_FLAG_NONE); + spawnableActorList_add(&chCCWWhipcrackRoomDoor, actor_new, ACTOR_FLAG_UNKNOWN_10); + spawnableActorList_add(&chNabnutDoor, actor_new, ACTOR_FLAG_UNKNOWN_10); + spawnableActorList_add(&D_8038F888, actor_new, ACTOR_FLAG_UNKNOWN_7); + spawnableActorList_add(&chCCWMumbosHut, actor_new, ACTOR_FLAG_UNKNOWN_10); + spawnableActorList_add(&chGnawtysDen, actor_new, ACTOR_FLAG_UNKNOWN_10); + spawnableActorList_add(&chGnawtysBed, actor_new, ACTOR_FLAG_UNKNOWN_10); + spawnableActorList_add(&chGnawtysShelves, actor_new, ACTOR_FLAG_UNKNOWN_10); +} diff --git a/src/CCW/ch/acorn.c b/src/CCW/ch/acorn.c index be025b938..3c7f23894 100644 --- a/src/CCW/ch/acorn.c +++ b/src/CCW/ch/acorn.c @@ -1,70 +1,84 @@ -// BanjoDecomp: code_61E0.c +// BanjoDecomp: CCW/ch/acorn.c #include #include "functions.h" #include "variables.h" #include "port/Enhancements/Retention/Retention.h" -extern ActorMarker *func_8028E86C(void); +extern ActorMarker *bacarry_getMarkerWithExtraSteps(void); extern s32 port_remoteCarry_displayUpdate(Actor *this); extern void port_anchor_onCarryThrow(s32 markerId, f32 start[3], f32 target[3]); typedef struct { - f32 unk0[3]; - f32 unkC[3]; - f32 unk18; -}ActorLocal_CCW_61E0; + f32 position[3]; + f32 unkC[3]; // some kind of distance + f32 unk18; // something time related +} ActorLocal_ChCarriedAcorn; -void func_8038C7A8(Actor *this); +void chCarriedAcorn_update(Actor *this); /* .data */ -ActorInfo D_8038F460 = { 0x1BC, 0x2A9, 0x48E, 0x0, NULL, func_8038C7A8, NULL, actor_draw, 0, 0, 0.8f, 0}; +ActorInfo chCarriedAcorn = { + MARKER_1BC_CARRIED_ACORN, ACTOR_2A9_ACORN, ASSET_48E_MODEL_ACORN, + 0x0, NULL, + chCarriedAcorn_update, NULL, actor_draw, + 0, 0, 0.8f, 0 +}; + +enum chCarriedAcorn_State_e { + CH_CARRIED_ACORN_STATE_0_NOT_INIT, + CH_CARRIED_ACORN_STATE_1_PULL_OUT, + CH_CARRIED_ACORN_STATE_2_HOLDING, + CH_CARRIED_ACORN_STATE_3_TOSS, + CH_CARRIED_ACORN_STATE_4_GIVEN_TO_NABNUT, + CH_CARRIED_ACORN_STATE_5_DESPAWN +}; /* .code */ -void CCW_func_8038C5D0(ActorMarker* marker) { +void chCarriedAcorn_sfxBoing(ActorMarker* marker) { Actor* actor = marker_getActor(marker); func_8030E878(SFX_3F2_BOING, randf2(0.95f, 1.05f), 26000, actor->position, 500.0f, 1000.0f); } -void CCW_func_8038C638(ActorMarker* marker) { +void chCarriedAcorn_sfxBanjoNoise(ActorMarker* marker) { Actor* actor = marker_getActor(marker); func_8030E878(SFX_5_BANJO_LANDING_01, randf2(0.95f, 1.05f), 22000, actor->position, 500.0f, 1000.0f); } -void CCW_func_8038C6A0(Actor *this, s32 next_state) { - ActorLocal_CCW_61E0 *local; +void chCarriedAcorn_setNextState(Actor *this, s32 next_state) { + ActorLocal_ChCarriedAcorn *local; - local = (ActorLocal_CCW_61E0 *)&this->local; - if (next_state == 1) { - skeletalAnim_set(this->unk148, 0x25B, 0.0f, 1.0f); - skeletalAnim_setCallback_1(this->unk148, 0.5f, (GenFunction_1)CCW_func_8038C5D0, (uintptr_t)this->marker); - skeletalAnim_setCallback_1(this->unk148, 0.7f, (GenFunction_1)CCW_func_8038C638, (uintptr_t)this->marker); + local = (ActorLocal_ChCarriedAcorn *)&this->local; + if (next_state == CH_CARRIED_ACORN_STATE_1_PULL_OUT) { + skeletalAnim_set(this->unk148, ASSET_25B_ANIM_ACORN_IDLE, 0.0f, 1.0f); + skeletalAnim_setCallback_1(this->unk148, 0.5f, (GenFunction_1)chCarriedAcorn_sfxBoing, (uintptr_t)this->marker); + skeletalAnim_setCallback_1(this->unk148, 0.7f, (GenFunction_1)chCarriedAcorn_sfxBanjoNoise, (uintptr_t)this->marker); } - if (next_state == 3) { - local->unk0[0] = this->position[0]; - local->unk0[1] = this->position[1]; - local->unk0[2] = this->position[2]; - func_8038BC50(local->unkC); + if (next_state == CH_CARRIED_ACORN_STATE_3_TOSS) { + local->position[0] = this->position[0]; + local->position[1] = this->position[1]; + local->position[2] = this->position[2]; + chAutumnOutsideNabnut_getPosition(local->unkC); local->unk18 = 0.0f; } - if (next_state == 4) { + if (next_state == CH_CARRIED_ACORN_STATE_4_GIVEN_TO_NABNUT) { coMusicPlayer_playMusic(COMUSIC_2B_DING_B, 28000); marker_despawn(this->marker); } - if (next_state == 5) { + if (next_state == CH_CARRIED_ACORN_STATE_5_DESPAWN) { marker_despawn(this->marker); } this->state = next_state; } -void func_8038C7A8(Actor *this) { - bool sp4C; - ActorLocal_CCW_61E0 *local; - f32 sp44; - f32 sp38[3]; +void chCarriedAcorn_update(Actor *this) { + bool player_is_carrying_acorn; + ActorLocal_ChCarriedAcorn *local; + f32 time_delta; + f32 player_position[3]; - local = (ActorLocal_CCW_61E0 *)&this->local; - sp44 = time_getDelta(); + local = (ActorLocal_ChCarriedAcorn *)&this->local; + time_delta = time_getDelta(); if (port_remoteCarry_displayUpdate(this)) { return; @@ -75,55 +89,55 @@ void func_8038C7A8(Actor *this) { return; } - sp4C = (func_8028E86C() == this->marker); - if (this->state == 0) { - if (sp4C) { - CCW_func_8038C6A0(this, 2); + player_is_carrying_acorn = (bacarry_getMarkerWithExtraSteps() == this->marker); + if (this->state == CH_CARRIED_ACORN_STATE_0_NOT_INIT) { + if (player_is_carrying_acorn) { + chCarriedAcorn_setNextState(this, CH_CARRIED_ACORN_STATE_2_HOLDING); } else { s32 acornSuppress; port_carriedSync_register(ANCHOR_COLLECTIBLE_ACORN, this->marker, (s32)this->position[0], (s32)this->position[1], (s32)this->position[2], &acornSuppress); if (acornSuppress) { - CCW_func_8038C6A0(this, 5); + chCarriedAcorn_setNextState(this, CH_CARRIED_ACORN_STATE_5_DESPAWN); return; } - CCW_func_8038C6A0(this, 1); + chCarriedAcorn_setNextState(this, CH_CARRIED_ACORN_STATE_1_PULL_OUT); } } - if (this->state == 1) { + if (this->state == CH_CARRIED_ACORN_STATE_1_PULL_OUT) { if (port_carriedSync_consumeRemoteDespawn(ANCHOR_COLLECTIBLE_ACORN, this->marker)) { - CCW_func_8038C6A0(this, 5); + chCarriedAcorn_setNextState(this, CH_CARRIED_ACORN_STATE_5_DESPAWN); return; } - player_getPosition(sp38); - if (ml_vec3f_distance(this->position, sp38) < 50.0f) { - func_8028F030(0x2A9); + player_getPosition(player_position); + if (ml_vec3f_distance(this->position, player_position) < 50.0f) { + bacarriedobj_incWithExtraSteps(ACTOR_2A9_ACORN); sfx_playFadeShorthandDefault(SFX_C5_TWINKLY_POP, 1.0f, 25000, this->position, 500, 2500); port_carriedSync_onLocalCollect(ANCHOR_COLLECTIBLE_ACORN, this->marker); - CCW_func_8038C6A0(this, 5); + chCarriedAcorn_setNextState(this, CH_CARRIED_ACORN_STATE_5_DESPAWN); } } - if (this->state == 2) { + if (this->state == CH_CARRIED_ACORN_STATE_2_HOLDING) { if (this->unk138_21) { f32 throwTarget[3]; - func_8038BC50(throwTarget); + chAutumnOutsideNabnut_getPosition(throwTarget); port_anchor_onCarryThrow(this->marker->id, this->position, throwTarget); - func_8028F010(0x2A9); + bacarriedobj_decWithExtraSteps(ACTOR_2A9_ACORN); port_carriedSync_onLocalSpend(ANCHOR_COLLECTIBLE_ACORN); - CCW_func_8038C6A0(this, 3); - } else if (!sp4C) { - func_8028F050(0x2A9); - CCW_func_8038C6A0(this, 5); + chCarriedAcorn_setNextState(this, CH_CARRIED_ACORN_STATE_3_TOSS); + } else if (!player_is_carrying_acorn) { + bacarriedobj_displayOnHudWithExtraSteps(ACTOR_2A9_ACORN); + chCarriedAcorn_setNextState(this, CH_CARRIED_ACORN_STATE_5_DESPAWN); } } - if (this->state == 3) { - local->unk18 += 3.3333333333333333 * sp44; + if (this->state == CH_CARRIED_ACORN_STATE_3_TOSS) { + local->unk18 += 3.3333333333333333 * time_delta; local->unk18 = (local->unk18 > 1.0) ? 1.0 : local->unk18; - ml_vec3f_interpolate_fast(this->position, local->unk0, local->unkC, local->unk18); + ml_vec3f_interpolate_fast(this->position, local->position, local->unkC, local->unk18); this->position[1] += 50.0f * sinf(local->unk18 * BAD_PI); if (local->unk18 == 1.0) { - CCW_func_8038C6A0(this, 4); + chCarriedAcorn_setNextState(this, CH_CARRIED_ACORN_STATE_4_GIVEN_TO_NABNUT); } } } diff --git a/src/CCW/ch/adulteyrie.c b/src/CCW/ch/adulteyrie.c new file mode 100644 index 000000000..a67ebde26 --- /dev/null +++ b/src/CCW/ch/adulteyrie.c @@ -0,0 +1,129 @@ +// BanjoDecomp: CCW/ch/adulteyrie.c +#include +#include "functions.h" +#include "variables.h" + +typedef struct { + f32 unk0; + f32 unk4; + s16 unk8; + s16 unkA; +}Struct_CCW_4530_0; + +void chEyrieAdult_setNextState(Actor *this, s32 next_state); +Actor *chEyrieAdult_draw(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx); +void chEyrieAdult_update(Actor *this); + +/* .data */ +// This is the idle Eyrie in the nest +ActorInfo chEyrieAdult = { + MARKER_1B6_EEYRIE_ADULT, ACTOR_2A3_EEYRIE_ADULT, ASSET_487_MODEL_EAGLE_ADULT, + 0x0, NULL, + chEyrieAdult_update, NULL, chEyrieAdult_draw, + 0, 0, 0.0f, 0 +}; + +Struct_CCW_4530_0 chEyrieAdultSFX[] = { + {0.15f, 0.9f, SFX_A5_EYRIE_CRY, 25000}, + {0.3f, 1.0f, SFX_A5_EYRIE_CRY, 32000}, + {0.6f, 0.8f, SFX_2_CLAW_SWIPE, 20000}, + {0.68f, 0.85f, SFX_2_CLAW_SWIPE, 23000}, + {0.75f, 0.9f, SFX_2_CLAW_SWIPE, 28000}, + {0.8f, 0.95f, SFX_2_CLAW_SWIPE, 30000}, + {0.81f, 1.0f, SFX_A5_EYRIE_CRY, 32000}, + {0.86f, 1.0f, SFX_2_CLAW_SWIPE, 31000}, + {0.93f, 1.0f, SFX_2_CLAW_SWIPE, 32000}, + 0 +}; + +enum chEyrieAdult_State_e { + CH_EERYIE_ADULT_STATE_0_NOT_INIT, + CH_EERYIE_ADULT_STATE_1_WAITING, + CH_EERYIE_ADULT_STATE_2_MEET_DIALOG, + CH_EERYIE_ADULT_STATE_3_FLIGHT_TAKE_OFF, + CH_EERYIE_ADULT_STATE_4_DESPAWN +}; + +/* .code */ +void chEyrieAdult_setMarkerToState3(ActorMarker* marker, enum asset_e text_id, s32 arg2) { + chEyrieAdult_setNextState(marker_getActor(marker), CH_EERYIE_ADULT_STATE_3_FLIGHT_TAKE_OFF); +} + +void chEyrieAdult_setNextState(Actor *this, s32 next_state) { + if (next_state == CH_EERYIE_ADULT_STATE_1_WAITING) { + skeletalAnim_set(this->unk148, ASSET_199_ANIM_EEYRIE_ADULT_UNK, 0.0f, 6.5f); + } + if (next_state == CH_EERYIE_ADULT_STATE_2_MEET_DIALOG) { + gcdialog_showDialog(VER_SELECT(ASSET_CDC_DIALOG_ADULT_EYRIE_MEET_WINTER, 0x09F1, 0, 0), VER_SELECT(0xA, 0xE, 0, 0), this->position, this->marker, chEyrieAdult_setMarkerToState3, NULL); + } + if (next_state == CH_EERYIE_ADULT_STATE_3_FLIGHT_TAKE_OFF) { + skeletalAnim_set(this->unk148, ASSET_19A_ANIM_EEYRIE_ADULT_UNK, 0.0f, 7.0f); + skeletalAnim_setBehavior(this->unk148, SKELETAL_ANIM_2_ONCE); + func_80324E38(0.0f, 3); + timed_setStaticCameraToNode(0.0f, 0); + } + if (next_state == CH_EERYIE_ADULT_STATE_4_DESPAWN) { + mapSpecificFlags_set(CCW_WINTER_SPECIFIC_FLAG_5_EEYRIE_ADULT, 1); + marker_despawn(this->marker); + } + this->state = next_state; +} + +Actor *chEyrieAdult_draw(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx){ + Actor *this; + + this = marker_getActor(marker); + if(this->state == CH_EERYIE_ADULT_STATE_0_NOT_INIT) + return this; + return actor_draw(marker, gfx, mtx, vtx); +} + +void chEyrieAdult_update(Actor *this) { + f32 player_position[3]; + f32 sp50; + f32 sp4C; + Struct_CCW_4530_0 *iPtr; + f32 sp44; + f32 sp40; + + if (!this->volatile_initialized) { + this->volatile_initialized = true; + mapSpecificFlags_set(CCW_WINTER_SPECIFIC_FLAG_5_EEYRIE_ADULT, false); + if( (!fileProgressFlag_get(FILEPROG_E8_AUTMN_EYRIE_FED) || jiggyscore_isSpawned(JIGGY_49_CCW_EYRIE)) + && !volatileFlag_get(VOLATILE_FLAG_1F_IN_CHARACTER_PARADE) + ) { + marker_despawn(this->marker); + } + else{ + chEyrieAdult_setNextState(this, CH_EERYIE_ADULT_STATE_1_WAITING); + } + return; + } + + if (this->state == CH_EERYIE_ADULT_STATE_1_WAITING) { + skeletalAnim_getProgressRange(this->unk148, &sp50, &sp4C); + if ((sp50 < 0.21) && (0.21 <= sp4C)) { + func_8030E878(0xA5, randf2(0.9f, 1.1f), 32000, this->position, 500.0f, 2500.0f); + } + + if ((sp50 < 0.56) && (0.56 <= sp4C)) { + func_8030E878(0xA5, randf2(0.9f, 1.1f), 32000, this->position, 500.0f, 2500.0f); + } + + player_getPosition(player_position); + if (ml_vec3f_distance(this->position, player_position) < 850.0f) { + chEyrieAdult_setNextState(this, CH_EERYIE_ADULT_STATE_2_MEET_DIALOG); + } + } + if (this->state == CH_EERYIE_ADULT_STATE_3_FLIGHT_TAKE_OFF) { + skeletalAnim_getProgressRange(this->unk148, &sp44, &sp40); + for(iPtr = &chEyrieAdultSFX[0]; iPtr->unk0 > 0.0f; iPtr++){ + if ((sp44 < iPtr->unk0) && (iPtr->unk0 <= sp40)) { + func_8030E878(iPtr->unk8, iPtr->unk4, iPtr->unkA, this->position, 500.0f, 2500.0f); + } + } + if (skeletalAnim_getLoopCount(this->unk148) > 0) { + chEyrieAdult_setNextState(this, CH_EERYIE_ADULT_STATE_4_DESPAWN); + } + } +} diff --git a/src/CCW/ch/beanstalk.c b/src/CCW/ch/beanstalk.c new file mode 100644 index 000000000..e7723a5fe --- /dev/null +++ b/src/CCW/ch/beanstalk.c @@ -0,0 +1,239 @@ +// BanjoDecomp: CCW/ch/beanstalk.c +#include +#include "functions.h" +#include "variables.h" + +typedef struct{ + s16 waitingAnim; + u8 waitingAnimBehavior; + u8 isInit; + s16 growingAnim; + s16 grownAnim; + s16 completeFileProgress; + s16 completeSpawnsJiggy; +}Struct_CCW_1B20_0; + +typedef struct{ + Struct_CCW_1B20_0 *unk0; +}ActorLocal_CCW_1B20; + +void chCCWBeanstalk_setNextState(Actor *this, s32 next_state); +Actor *chCCWBeanstalk_draw(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx); +void chCCWBeanstalk_update(Actor *this); + +enum chCCWBeanstalk_State_e { + CH_CCW_BEANSTALK_STATE_0_NOT_INIT, + CH_CCW_BEANSTALK_STATE_1_WAITING, + CH_CCW_BEANSTALK_STATE_2_GROWING, + CH_CCW_BEANSTALK_STATE_3_GROWN +}; + +/* .data */ +Struct_CCW_1B20_0 D_8038EC40[4] ={ + { + ASSET_173_ANIM_BEANSTALK_UNK, SKELETAL_ANIM_4_STOPPED, + 0, // Is Initialized + ASSET_173_ANIM_BEANSTALK_UNK, + ASSET_181_ANIM_BEANSTALK_UNK, + FILEPROG_E3_CCW_FLOWER_SPRING, + false + }, + { + ASSET_181_ANIM_BEANSTALK_UNK, SKELETAL_ANIM_1_LOOP, + 1, // Is Initialized + ASSET_174_ANIM_BEANSTALK_UNK, + ASSET_182_ANIM_BEANSTALK_UNK, + FILEPROG_E4_CCW_FLOWER_SUMMER, + false + }, + { + ASSET_182_ANIM_BEANSTALK_UNK, SKELETAL_ANIM_1_LOOP, + 1, // Is Initialized + ASSET_175_ANIM_BEANSTALK_UNK, + ASSET_183_ANIM_BEANSTALK_UNK, + FILEPROG_E5_CCW_FLOWER_AUTUMN, + true + }, + { + ASSET_183_ANIM_BEANSTALK_UNK, SKELETAL_ANIM_1_LOOP, + 1, // Is Initialized + 0, + 0, + 0, + false + } +}; + +// Anchor: set during a remote-water replay; skips camera/fanfare/jiggy spawn. +static s32 sFlowerRemoteGrow = 0; + +ActorInfo chCCWBeanstalk = { + MARKER_1B0_CCW_BEANSTALK, ACTOR_29D_CCW_BEANSTALK, ASSET_447_MODEL_CCW_BEANSTALK, + 0x0, NULL, + chCCWBeanstalk_update, NULL, chCCWBeanstalk_draw, + 0, 0, 1.0f, 0 +}; + +f32 chCCWBeanstalkJiggyPosition[3] = {200.0f, 2120.0f, -5570.0f}; + +/* .code */ +void chCCWBeanstalk_spawnJiggy() { + jiggy_spawn(JIGGY_4D_CCW_FLOWER, chCCWBeanstalkJiggyPosition); +} + +void chCCWBeanstalk_setNextStateByMarker(ActorMarker* marker, s32 next_state) { + chCCWBeanstalk_setNextState(marker_getActor(marker), next_state); +} + +void chCCWBeanstalk_setNextState(Actor *this, s32 next_state){ + ActorLocal_CCW_1B20 *local; + f32 phi_f22; + + local = (ActorLocal_CCW_1B20 *)&this->local; + + if (next_state == CH_CCW_BEANSTALK_STATE_1_WAITING) { + this->marker->propPtr->unk8_3 = local->unk0->isInit; + skeletalAnim_set(this->unk148, local->unk0->waitingAnim, 0.0f, 5.0f); + skeletalAnim_setBehavior(this->unk148, local->unk0->waitingAnimBehavior); + } + if (next_state == CH_CCW_BEANSTALK_STATE_2_GROWING) { + if (gsworld_getMap() == MAP_43_CCW_SPRING && !sFlowerRemoteGrow) { + coMusicPlayer_playMusic(COMUSIC_2D_PUZZLE_SOLVED_FANFARE, 28000); + } + fileProgressFlag_set(local->unk0->completeFileProgress, true); + skeletalAnim_set(this->unk148, local->unk0->growingAnim, 0.0f, 6.0f); + skeletalAnim_setBehavior(this->unk148, SKELETAL_ANIM_2_ONCE); + if (gsworld_getMap() == MAP_43_CCW_SPRING && !sFlowerRemoteGrow) { + func_80324E38(0.0f, 3); + } + if (!sFlowerRemoteGrow) { + timed_setStaticCameraToNode(0.0f, 0); + } + for( phi_f22 = 0.0f; phi_f22 <= 1.0f; phi_f22 += 0.1) { + timed_playSfx(phi_f22 * 5.7, 0x2C, phi_f22 * 0.3 + 0.7, (s32) (32000.0f - phi_f22 * 5000.0f)); + } + if (local->unk0->completeSpawnsJiggy != false) { + if (!sFlowerRemoteGrow) { + timed_setStaticCameraToNode(6.0f, 1); + timedFunc_set_0(6.1f, (GenFunction_0)chCCWBeanstalk_spawnJiggy); + } + timedFunc_set_2( + 8.0f, + (GenFunction_2)chCCWBeanstalk_setNextStateByMarker, + (uintptr_t)this->marker, + CH_CCW_BEANSTALK_STATE_3_GROWN); + } else { + if (gsworld_getMap() == MAP_43_CCW_SPRING && !sFlowerRemoteGrow) { + timed_exitStaticCamera(7.0f); + func_80324E38(7.0f, 0); + } + timedFunc_set_2( + 7.0f, + (GenFunction_2)chCCWBeanstalk_setNextStateByMarker, + (uintptr_t)this->marker, + CH_CCW_BEANSTALK_STATE_3_GROWN); + } + } + + if (next_state == CH_CCW_BEANSTALK_STATE_3_GROWN) { + this->marker->propPtr->unk8_3 = true; + skeletalAnim_set(this->unk148, local->unk0->grownAnim, 0.1f, 5.0f); + skeletalAnim_setBehavior(this->unk148, SKELETAL_ANIM_1_LOOP); + } + this->state = next_state; +} + +s32 func_80388260(ActorMarker *marker, s32 arg1){ + return marker->unk40_31 != 1; +} + +void chCCWBeanstalk_feed(ActorMarker *marker, ActorMarker *other_marker) { + coMusicPlayer_playMusic(COMUSIC_2B_DING_B, 28000); +} + +void chCCWBeanstalk_spawnBeanstalk(ActorMarker* marker, ActorMarker *other_marker) { + Actor* actor = marker_getActor(marker); + + // [port] v1.1 fix: don't allow re-planting flower in Spring after it's already been planted + if (EventSystem_Should(VB_CCW_FLOWER_REPLANT, + gsworld_getMap() == MAP_43_CCW_SPRING && actor->state == CH_CCW_BEANSTALK_STATE_1_WAITING && + !fileProgressFlag_get(FILEPROG_E3_CCW_FLOWER_SPRING))) { + chCCWBeanstalk_setNextState(actor, CH_CCW_BEANSTALK_STATE_2_GROWING); + } +} + +Actor *chCCWBeanstalk_draw(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx) { + Actor *this; + s32 sp18; + + this = marker_getActor(marker); + if ((this->state == CH_CCW_BEANSTALK_STATE_1_WAITING) + && !fileProgressFlag_get(FILEPROG_E3_CCW_FLOWER_SPRING)) + { + return func_80325340(marker, gfx, mtx, vtx); + } + + if ((skeletalAnim_getAnimId(this->unk148) == 0x175) + && (0.49 <= skeletalAnim_getProgress(this->unk148))) + { + sp18 = 1; + } else { + sp18 = 0; + } + sp18 = (skeletalAnim_getAnimId(this->unk148) == 0x183)? 1 : sp18; + modelRender_setAppendageVisibility(3, sp18); + modelRender_setAppendageVisibility(4, sp18); + return actor_draw(marker, gfx, mtx, vtx); +} + +void chCCWBeanstalk_growBeanstalk() { + Actor* actor = actorArray_findActorFromActorId(ACTOR_29D_CCW_BEANSTALK); + if (actor && actor->state == CH_CCW_BEANSTALK_STATE_1_WAITING) { + chCCWBeanstalk_setNextState(actor, CH_CCW_BEANSTALK_STATE_2_GROWING); + } +} + +bool chCCWBeanstalk_hasSpawned() { + Actor* actor = actorArray_findActorFromActorId(ACTOR_29D_CCW_BEANSTALK); + if (actor && actor->state == CH_CCW_BEANSTALK_STATE_2_GROWING) { + return true; + } + return false; +} + +void chCCWBeanstalk_update(Actor *this) { + ActorLocal_CCW_1B20 *local; + + local = (ActorLocal_CCW_1B20 *)&this->local; + if (!this->volatile_initialized) { + this->volatile_initialized = true; + func_803300C0(this->marker, (s32 (*)(ActorMarker *, ActorMarker *))func_80388260); + marker_setCollisionScripts(this->marker, NULL, chCCWBeanstalk_feed, chCCWBeanstalk_spawnBeanstalk); + actor_collisionOn(this); + if (!jiggyscore_isSpawned(JIGGY_4D_CCW_FLOWER)) { + fileProgressFlag_set(FILEPROG_E5_CCW_FLOWER_AUTUMN, false); + } + + for(local->unk0 = &D_8038EC40[0]; local->unk0 < D_8038EC40 + 3; local->unk0++){ + if(!fileProgressFlag_get(local->unk0->completeFileProgress)){ + break; + } + } + + if (!fileProgressFlag_get(FILEPROG_E3_CCW_FLOWER_SPRING) + && (gsworld_getMap() != MAP_43_CCW_SPRING)) + { + marker_despawn(this->marker); + } + else{ + chCCWBeanstalk_setNextState(this, CH_CCW_BEANSTALK_STATE_1_WAITING); + } + return; + } + + if ((this->state == CH_CCW_BEANSTALK_STATE_1_WAITING) && EventSystem_Should(VB_CCW_FLOWER_REMOTE_GROW, false, (s32)local->unk0->completeFileProgress)) { + sFlowerRemoteGrow = 1; + chCCWBeanstalk_setNextState(this, CH_CCW_BEANSTALK_STATE_2_GROWING); + sFlowerRemoteGrow = 0; + } +} diff --git a/src/CCW/ch/nabnut_summer.c b/src/CCW/ch/bellyfullnabnut.c similarity index 61% rename from src/CCW/ch/nabnut_summer.c rename to src/CCW/ch/bellyfullnabnut.c index 8388d0c15..135c17016 100644 --- a/src/CCW/ch/nabnut_summer.c +++ b/src/CCW/ch/bellyfullnabnut.c @@ -1,19 +1,19 @@ -// BanjoDecomp: code_50D0.c +// BanjoDecomp: CCW/ch/bellyfullnabnut.c #include #include "functions.h" #include "variables.h" -void func_8038B87C(Actor *this); +void chNabnutBellyFull_update(Actor *this); /* .data */ -ActorInfo D_8038F300 = { - 0x1BA, 0x2A7, 0x503, +ActorInfo chNabnutBellyFull = { + MARKER_1BA_NABNUT_FULL_BELLY, ACTOR_2A7_NABNUT_FULL_BELLY, ASSET_503_MODEL_NABNUT_BELLY_FULL, 0x0, NULL, - func_8038B87C, NULL, actor_draw, + chNabnutBellyFull_update, NULL, actor_draw, 0, 0, 2.0f, 0 }; -s32 D_8038F324[] = { +s32 chNabnutBellyFullSFX[] = { SFX_97_BLUBBER_BURPS, SFX_3E_POOP_NOISE, SFX_F6_BLUBBER_TALKING_2, @@ -23,23 +23,39 @@ s32 D_8038F324[] = { 0 }; +enum ChNabnutBellyFull_State_e { + CH_NABNUT_BELLY_FULL_STATE_1_UNK = 1 +}; + /* .code */ void func_8038B4C0(ActorMarker *marker) { Actor *this; - static s32 D_8038F340 = 0; + static s32 chNabnutBellyFullSFXIndex = 0; this = marker_getActor(marker); - func_8030E878(D_8038F324[D_8038F340], randf2(1.1f, 1.2f), (s32) randf2(31000.0f, 32000.0f), this->position, 500.0f, 2500.0f); - D_8038F340++; - if (D_8038F324[D_8038F340] == 0) { - D_8038F340 = 0; + func_8030E878( + chNabnutBellyFullSFX[chNabnutBellyFullSFXIndex], + randf2(1.1f, 1.2f), + (s32) randf2(31000.0f, 32000.0f), + this->position, + 500.0f, + 2500.0f); + chNabnutBellyFullSFXIndex++; + if (chNabnutBellyFullSFX[chNabnutBellyFullSFXIndex] == 0) { + chNabnutBellyFullSFXIndex = 0; } } void func_8038B58C(ActorMarker* marker) { Actor* actor = marker_getActor(marker); - func_8030E878(0x81, randf2(1.0f, 1.1f), (s32) randf2(31000.0f, 32000.0f), actor->position, 500.0f, 2500.0f); + func_8030E878( + SFX_81_UUU, + randf2(1.0f, 1.1f), + (s32) randf2(31000.0f, 32000.0f), + actor->position, + 500.0f, + 2500.0f); } void func_8038B610(ActorMarker* marker) { @@ -77,23 +93,23 @@ void func_8038B6DC(ActorMarker *marker) { skeletalAnim_setCallback_1(this->unk148, 0.9f, (GenFunction_1)func_8038B6DC, (uintptr_t)this->marker); } -void func_8038B814(Actor *this, s32 next_state) { - if (next_state == 1) { +void chNabnutBellyFull_setNextState(Actor *this, s32 next_state) { + if (next_state == CH_NABNUT_BELLY_FULL_STATE_1_UNK) { skeletalAnim_set(this->unk148, 0x22B, 0.2f, 11.0f); func_8038B6DC(this->marker); } this->state = next_state; } -void func_8038B87C(Actor *this) { +void chNabnutBellyFull_update(Actor *this) { if (!this->volatile_initialized) { this->volatile_initialized = true; this->has_met_before = false; - func_8038B814(this, 1); + chNabnutBellyFull_setNextState(this, CH_NABNUT_BELLY_FULL_STATE_1_UNK); } if (!this->has_met_before && func_803292E0(this)) { - this->has_met_before = true; - gcdialog_showDialog(0xCC9, 0, NULL, NULL, NULL, NULL); + this->has_met_before = TRUE; + gcdialog_showDialog(VER_SELECT(ASSET_CC9_DIALOG_NABNUT_MEET_SUMMER, 0x09DE, 0, 0), 0, NULL, NULL, NULL, NULL); } func_8028E668(this->position, 300.0f, -50.0f, 120.0f); } diff --git a/src/CCW/ch/caterpillar.c b/src/CCW/ch/caterpillar.c index fa824e537..51c8f0777 100644 --- a/src/CCW/ch/caterpillar.c +++ b/src/CCW/ch/caterpillar.c @@ -1,18 +1,18 @@ -// BanjoDecomp: code_3DA0.c +// BanjoDecomp: CCW/ch/caterpillar.c #include #include "functions.h" #include "variables.h" #include "port/Enhancements/Retention/Retention.h" -extern ActorMarker *func_8028E86C(void); +extern ActorMarker *bacarry_getMarkerWithExtraSteps(void); extern void func_8028F7D4(f32, f32); extern s32 port_remoteCarry_displayUpdate(Actor *this); extern void port_anchor_onCarryThrow(s32 markerId, f32 start[3], f32 target[3]); typedef struct { - f32 unk0[3]; - f32 unkC[3]; - f32 unk18[3]; + f32 position[3]; + f32 unkC[3]; // some kind of distance + f32 unk18[3]; // something time related f32 unk24; } ActorLocal_Caterpillar; @@ -27,41 +27,52 @@ ActorInfo chCaterpillar = { 0, 0, 1.0f, 0 }; +enum chCaterpillar_State_e { + CH_CATERPILLAR_STATE_0_NOT_INIT, + CH_CATERPILLAR_STATE_1_PULL_OUT, + CH_CATERPILLAR_STATE_2_HOLDING, + CH_CATERPILLAR_STATE_3_TOSS, + CH_CATERPILLAR_STATE_4_GIVEN_TO_EEYRIE, + CH_CATERPILLAR_STATE_5_DESPAWN +}; + /* .code */ f32 func_8038A190(Actor *this, f32 *arg1) { - f32 temp_f0; - f32 temp_f2; - - temp_f0 = mapModel_getFloorY(arg1); - temp_f2 = this->position[1]; - if (((temp_f2 + 50.0f) < temp_f0) || (temp_f0 < (temp_f2 - 50.0f))) { - return temp_f2; + f32 floor_y_position; + f32 caterpillar_y_position; + + floor_y_position = mapModel_getFloorY(arg1); + caterpillar_y_position = this->position[1]; + if (((caterpillar_y_position + 50.0f) < floor_y_position) + || (floor_y_position < (caterpillar_y_position - 50.0f))) + { + return caterpillar_y_position; } - return temp_f0; + return floor_y_position; } void chcaterpillar_setState(Actor *this, s32 next_state) { ActorLocal_Caterpillar *local = (ActorLocal_Caterpillar *)&this->local; - if (next_state == 1) { - skeletalAnim_set(this->unk148, 0x18D, 0.0f, randf2(1.9f, 2.1f)); + if (next_state == CH_CATERPILLAR_STATE_1_PULL_OUT) { + skeletalAnim_set(this->unk148, ASSET_18D_ANIM_CATERPILLAR_UNK, 0.0f, randf2(1.9f, 2.1f)); } - if (next_state == 2) { + if (next_state == CH_CATERPILLAR_STATE_2_HOLDING) { func_8028F7D4(-25.0f, 90.0f); - skeletalAnim_set(this->unk148, 0x18E, 0.2f, 2.0f); + skeletalAnim_set(this->unk148, ASSET_18E_ANIM_CATERPILLAR_IDLE, 0.2f, 2.0f); } - if (next_state == 3) { - skeletalAnim_set(this->unk148, 0x18E, 0.2f, 2.0f); + if (next_state == CH_CATERPILLAR_STATE_3_TOSS) { + skeletalAnim_set(this->unk148, ASSET_18E_ANIM_CATERPILLAR_IDLE, 0.2f, 2.0f); local->unkC[0] = this->position[0]; local->unkC[1] = this->position[1]; local->unkC[2] = this->position[2]; local->unk24 = 0.0f; } - if (next_state == 4) { + if (next_state == CH_CATERPILLAR_STATE_4_GIVEN_TO_EEYRIE) { coMusicPlayer_playMusic(COMUSIC_2B_DING_B, 28000); marker_despawn(this->marker); } - if (next_state == 5) { + if (next_state == CH_CATERPILLAR_STATE_5_DESPAWN) { actor_collisionOff(this); } this->state = next_state; @@ -69,16 +80,16 @@ void chcaterpillar_setState(Actor *this, s32 next_state) { Actor* chcaterpillar_draw(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx){ Actor *this = marker_getActor(marker); - if(this->state == 5){ + if(this->state == CH_CATERPILLAR_STATE_5_DESPAWN){ return func_80325340(marker, gfx, mtx, vtx); } return actor_draw(marker, gfx, mtx, vtx); } void chcaterpillar_update(Actor *this){ - bool sp8C; + bool player_is_carrying_caterpillar; ActorLocal_Caterpillar *local = (ActorLocal_Caterpillar *)&this->local; - f32 sp84; + f32 time_delta; enum map_e map_id; f32 sp74[3]; f32 sp70; @@ -93,23 +104,23 @@ void chcaterpillar_update(Actor *this){ return; } - sp8C = func_8028E86C() == this->marker; - sp84 = time_getDelta(); + player_is_carrying_caterpillar = bacarry_getMarkerWithExtraSteps() == this->marker; + time_delta = time_getDelta(); if(!this->volatile_initialized){ this->volatile_initialized = true; - local->unk0[0] = this->position[0]; - local->unk0[1] = this->position[1]; - local->unk0[2] = this->position[2]; - if(sp8C){ - chcaterpillar_setState(this, 2); + local->position[0] = this->position[0]; + local->position[1] = this->position[1]; + local->position[2] = this->position[2]; + if(player_is_carrying_caterpillar){ + chcaterpillar_setState(this, CH_CATERPILLAR_STATE_2_HOLDING); } else{//L8038A408 map_id = gsworld_getMap(); if ( !fileProgressFlag_get(FILEPROG_E6_SPRING_EYRIE_HATCHED) || ( map_id == MAP_45_CCW_AUTUMN && !fileProgressFlag_get(FILEPROG_E7_SUMMER_EYRIE_FED)) ) { - chcaterpillar_setState(this, 5); + chcaterpillar_setState(this, CH_CATERPILLAR_STATE_5_DESPAWN); } else { s32 wormSuppress; port_carriedSync_register(ANCHOR_COLLECTIBLE_WORM, this->marker, (s32)this->position[0], @@ -118,34 +129,34 @@ void chcaterpillar_update(Actor *this){ marker_despawn(this->marker); return; } - chcaterpillar_setState(this, 1); + chcaterpillar_setState(this, CH_CATERPILLAR_STATE_1_PULL_OUT); }//L8038A45C } }//L8038A45C - if(this->state == 1){ + if(this->state == CH_CATERPILLAR_STATE_1_PULL_OUT){ if(port_carriedSync_consumeRemoteDespawn(ANCHOR_COLLECTIBLE_WORM, this->marker)){ marker_despawn(this->marker); return; } skeletalAnim_getProgressRange(this->unk148, &sp64, &sp60); player_getPosition(sp74); - if(ml_vec3f_distance(this->position, local->unk0) < 10.0f){ + if(ml_vec3f_distance(this->position, local->position) < 10.0f){ for(i = 0; i < 10; i++){ - local->unk0[0] = randf2(-300.0f, 300.0f) + this->position_x; - local->unk0[1] = this->position_y; - local->unk0[2] = randf2(-300.0f, 300.0f) + this->position_z; - if( !(ml_vec3f_distance(local->unk0, this->position) < 50.0f) && func_80329210(this, &local->unk0)) + local->position[0] = randf2(-300.0f, 300.0f) + this->position_x; + local->position[1] = this->position_y; + local->position[2] = randf2(-300.0f, 300.0f) + this->position_z; + if( !(ml_vec3f_distance(local->position, this->position) < 50.0f) && func_80329210(this, &local->position)) break; }//L8038A544 if(i == 10){ - local->unk0[0] = this->position[0];\ - local->unk0[1] = this->position[1];\ - local->unk0[2] = this->position[2]; + local->position[0] = this->position[0];\ + local->position[1] = this->position[1];\ + local->position[2] = this->position[2]; }//L8038A564 if (i); - local->unk0[1] = func_8038A190(this, local->unk0); + local->position[1] = func_8038A190(this, local->position); }//L8038A570 if(sp64 <= 0.1 && 0.1 < sp60){ @@ -153,8 +164,8 @@ void chcaterpillar_update(Actor *this){ }//L8038A5EC if(0.65 < sp60){ - func_80258A4C(this->position, this->yaw - 90.0f, local->unk0, &sp70, &sp6C, &sp68); - this->yaw += (sp68*100.0f)*sp84; + func_80258A4C(this->position, this->yaw - 90.0f, local->position, &sp70, &sp6C, &sp68); + this->yaw += (sp68*100.0f) * time_delta; }//L8038A668 if(sp60 <= 0.4){ @@ -162,18 +173,18 @@ void chcaterpillar_update(Actor *this){ sp54[2] = 0.0f; sp54[0] = 65.0f; ml_vec3f_yaw_rotate_copy(sp54, sp54, this->yaw - 90.0f); - this->position[0] += sp84*sp54[0]; - this->position[2] += sp84*sp54[2]; + this->position[0] += time_delta * sp54[0]; + this->position[2] += time_delta * sp54[2]; if(this->marker->unk14_21){ this->position[1] = func_8038A190(this, this->position); } }//L8038A714 if(ml_vec3f_distance(this->position, sp74) < 50.0f){ - func_8028F030(ACTOR_2A2_CATERPILLAR); + bacarriedobj_incWithExtraSteps(ACTOR_2A2_CATERPILLAR); if(!volatileFlag_get(VOLATILE_FLAG_B2_HAS_COLLECTED_CATERPILLAR)){ - gcdialog_showDialog(ASSET_CC7_DIALOG_CATERPILLAR_COLLECT, 4, NULL, NULL, NULL, NULL); - volatileFlag_set(VOLATILE_FLAG_B2_HAS_COLLECTED_CATERPILLAR, true); + gcdialog_showDialog(VER_SELECT(ASSET_CC7_DIALOG_CATERPILLAR_COLLECT, 0x09DC, 0, 0), 4, NULL, NULL, NULL, NULL); + volatileFlag_set(VOLATILE_FLAG_B2_HAS_COLLECTED_CATERPILLAR, TRUE); } sfx_playFadeShorthandDefault(SFX_C5_TWINKLY_POP, 1.0f, 25000, this->position, 0x1f4, 0x9c4); port_carriedSync_onLocalCollect(ANCHOR_COLLECTIBLE_WORM, this->marker); @@ -181,31 +192,31 @@ void chcaterpillar_update(Actor *this){ } }//L8038A794 - if(this->state == 2){ + if(this->state == CH_CATERPILLAR_STATE_2_HOLDING){ if(this->unk138_21){ f32 throwTarget[3]; func_80389BD8(throwTarget); port_anchor_onCarryThrow(this->marker->id, this->position, throwTarget); - func_8028F010(ACTOR_2A2_CATERPILLAR); + bacarriedobj_decWithExtraSteps(ACTOR_2A2_CATERPILLAR); port_carriedSync_onLocalSpend(ANCHOR_COLLECTIBLE_WORM); - chcaterpillar_setState(this, 3); + chcaterpillar_setState(this, CH_CATERPILLAR_STATE_3_TOSS); } - else if(!sp8C){ - func_8028F050(ACTOR_2A2_CATERPILLAR); + else if(!player_is_carrying_caterpillar){ + bacarriedobj_displayOnHudWithExtraSteps(ACTOR_2A2_CATERPILLAR); marker_despawn(this->marker); } }//L8038A804 - if(this->state == 3){ + if(this->state == CH_CATERPILLAR_STATE_3_TOSS){ func_80389BD8(local->unk18); - local->unk24 += 3.3333333333333335*sp84; + local->unk24 += 3.3333333333333335 * time_delta; local->unk24 = (1.0 < local->unk24) ? 1.0 : local->unk24; ml_vec3f_interpolate_fast(this->position, local->unkC, local->unk18, local->unk24); - this->position[1] += 50.0f*sinf(local->unk24*3.141592654); + this->position[1] += 50.0f*sinf(local->unk24 * 3.141592654); if(1.0 == local->unk24){ - chcaterpillar_setState(this, 4); + chcaterpillar_setState(this, CH_CATERPILLAR_STATE_4_GIVEN_TO_EEYRIE); } }//L8038A8FC } diff --git a/src/CCW/ch/gobi_ccw.c b/src/CCW/ch/ccwgobi.c similarity index 55% rename from src/CCW/ch/gobi_ccw.c rename to src/CCW/ch/ccwgobi.c index 4080d3459..945a72d3e 100644 --- a/src/CCW/ch/gobi_ccw.c +++ b/src/CCW/ch/ccwgobi.c @@ -1,89 +1,110 @@ -// BanjoDecomp: code_2270.c +// BanjoDecomp: CCW/ch/ccwgobi.c #include #include "functions.h" #include "variables.h" typedef struct{ s16 map_id; - s16 unk2; - s16 unk4; - s16 unk6; -}Struct_CCW_2270_0; + s16 summerMeetDialog; + s16 summerCompleteDialog; + s16 autumnCompleteDialog; +} CH_CCW_Gobi_Dialogs; typedef struct{ - Struct_CCW_2270_0 *unk0; - SkeletalAnimation *unk4; + CH_CCW_Gobi_Dialogs *dialogs; + SkeletalAnimation *skeletal_anim; BKModelBin *spit_model; -}ActorLocal_chGobiCCW; +} ActorLocal_chGobiCCW; -void CCW_func_8038868C(Actor *this, s32 next_state); +void chCCWGobi_setState(Actor *this, s32 next_state); Actor *chGobiCCW_draw(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx); void chGobiCCW_update(Actor *this); /* .data */ -Struct_CCW_2270_0 D_8038ECD0[] = { - {MAP_44_CCW_SUMMER, 0xCDE, 0xCDF, 0x000}, - {MAP_45_CCW_AUTUMN, 0x000, 0x000, 0xCE0}, - 0 +CH_CCW_Gobi_Dialogs chCCWGobiDialogs[] = { + { + MAP_44_CCW_SUMMER, + VER_SELECT(ASSET_CDE_DIALOG_CCW_GOBI_MEET_SUMMER, 0x09F3, 0, 0), + VER_SELECT(ASSET_CDF_DIALOG_CCW_GOBI_COMPLETE_SUMMER, 0x09F4, 0, 0), + NULL + }, + { + MAP_45_CCW_AUTUMN, + NULL, + NULL, + VER_SELECT(ASSET_CE0_DIALOG_CCW_GOBI_COMPLETE_FALL, 0x09F5, 0, 0) + }, + { 0 } // [port] decomp uses NULL; first field is an integer and clang errors on -Wint-conversion }; -ActorInfo D_8038ECE8 = { +ActorInfo chCCWGobi = { MARKER_1B1_CCW_GOBI, ACTOR_29E_CCW_GOBI, ASSET_3E0_MODEL_GOBI, 0x0, NULL, chGobiCCW_update, chGobiCCW_update, chGobiCCW_draw, 0, 0, 1.0f, 0 }; +enum chccwgobi_state_e { + CH_CCW_GOBI_STATE_0_NOT_INIT, + CH_CCW_GOBI_STATE_1_WAITING, + CH_CCW_GOBI_STATE_2_SPITTING, + CH_CCW_GOBI_STATE_3_GROW_BEANSTALK, + CH_CCW_GOBI_STATE_4_DONE_SPITTING, + CH_CCW_GOBI_STATE_5_GETTING_UP, + CH_CCW_GOBI_STATE_6_RUN_AWAY, + CH_CCW_GOBI_STATE_7_DESPAWN +}; + /* .code */ -void CCW_func_80388660(ActorMarker* marker, s32 arg1) { - CCW_func_8038868C(marker_getActor(marker), arg1); +void chCCWGobi_setStateByMarker(ActorMarker* marker, s32 arg1) { + chCCWGobi_setState(marker_getActor(marker), arg1); } -void CCW_func_8038868C(Actor *this, s32 next_state) { +void chCCWGobi_setState(Actor *this, s32 next_state) { ActorLocal_chGobiCCW *local; local = (ActorLocal_chGobiCCW*)&this->local; - if (next_state == 1) { + if (next_state == CH_CCW_GOBI_STATE_1_WAITING) { skeletalAnim_set(this->unk148, ASSET_F4_ANIM_GOBI_IDLE, 0.5f, 12.0f); } - if (next_state == 2) { - if (local->unk0->unk4 != 0) { - gcdialog_showDialog(local->unk0->unk4, 4, NULL, NULL, NULL, NULL); + if (next_state == CH_CCW_GOBI_STATE_2_SPITTING) { + if (local->dialogs->summerCompleteDialog != NULL) { + gcdialog_showDialog(local->dialogs->summerCompleteDialog, 4, NULL, NULL, NULL, NULL); } skeletalAnim_set(this->unk148, ASSET_FC_ANIM_GOBI_SPITTING, 0.2f, 3.0f); skeletalAnim_setBehavior(this->unk148, SKELETAL_ANIM_2_ONCE); - skeletalAnim_set(local->unk4, ASSET_100_ANIM_GOBI_SPIT, 0.0f, 3.0f); - skeletalAnim_setBehavior(local->unk4, 2); + skeletalAnim_set(local->skeletal_anim, ASSET_100_ANIM_GOBI_SPIT, 0.0f, 3.0f); + skeletalAnim_setBehavior(local->skeletal_anim, 2); func_80324E38(0.0f, 3); timed_setStaticCameraToNode(0.0f, (gsworld_getMap() == MAP_44_CCW_SUMMER) ? 1 : 2); timed_playSfx(0.05f, SFX_84_GOBI_CRYING, 1.1f, 32000); timed_playSfx(0.8f, SFX_4B_GULPING, 0.8f, 28000); timed_playSfx(1.4f, SFX_4B_GULPING, 0.8f, 28000); timed_playSfx(2.0f, SFX_4B_GULPING, 0.8f, 28000); - timedFunc_set_2(3.2f, (GenFunction_2) CCW_func_80388660, (uintptr_t)this->marker, 3); + timedFunc_set_2(3.2f, (GenFunction_2) chCCWGobi_setStateByMarker, (uintptr_t)this->marker, 3); } - if (next_state == 3) { - func_803883F4(); + if (next_state == CH_CCW_GOBI_STATE_3_GROW_BEANSTALK) { + chCCWBeanstalk_growBeanstalk(); } - if (next_state == 4) { + if (next_state == CH_CCW_GOBI_STATE_4_DONE_SPITTING) { skeletalAnim_set(this->unk148, ASSET_176_ANIM_GOBI_YAWN, 0.5f, 4.0f); skeletalAnim_setBehavior(this->unk148, SKELETAL_ANIM_2_ONCE); timed_exitStaticCamera(0.0f); func_80324E38(0.0f, 0); } - if (next_state == 5) { - if (local->unk0->unk6 != 0) { - gcdialog_showDialog((s32) local->unk0->unk6, 4, NULL, NULL, NULL, NULL); + if (next_state == CH_CCW_GOBI_STATE_5_GETTING_UP) { + if (local->dialogs->autumnCompleteDialog != NULL) { + gcdialog_showDialog((s32) local->dialogs->autumnCompleteDialog, 4, NULL, NULL, NULL, NULL); } skeletalAnim_set(this->unk148, ASSET_FD_ANIM_GOBI2_GETTING_UP, 0.23f, 0.5f); timed_setStaticCameraToNode(0.0f, 3); } - if (next_state == 6) { + if (next_state == CH_CCW_GOBI_STATE_6_RUN_AWAY) { skeletalAnim_set(this->unk148, ASSET_F8_ANIM_GOBI_RUNNING, 0.1f, 0.71f); skeletalAnim_setBehavior(this->unk148, SKELETAL_ANIM_1_LOOP); } - if (next_state == 7) { + if (next_state == CH_CCW_GOBI_STATE_7_DESPAWN) { timed_exitStaticCamera(0.0f); func_80324E38(0.0f, 0); marker_despawn(this->marker); @@ -94,9 +115,9 @@ void CCW_func_8038868C(Actor *this, s32 next_state) { void func_8038894C(ActorMarker* marker, ActorMarker *other_marker) { Actor* actor = marker_getActor(marker); - if (actor->state == 1) { + if (actor->state == CH_CCW_GOBI_STATE_1_WAITING) { actor_collisionOff(actor); - timedFunc_set_2(0.5f, (GenFunction_2)CCW_func_80388660, (uintptr_t)actor->marker, 2); + timedFunc_set_2(0.5f, (GenFunction_2)chCCWGobi_setStateByMarker, (uintptr_t)actor->marker, 2); } } @@ -113,7 +134,7 @@ Actor *chGobiCCW_draw(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx){ sp2C[1] = this->yaw; sp2C[2] = this->roll; - modelRender_setBoneTransformList(skeletalAnim_getBoneTransformList(local->unk4)); + modelRender_setBoneTransformList(skeletalAnim_getBoneTransformList(local->skeletal_anim)); modelRender_setDepthMode(MODEL_RENDER_DEPTH_COMPARE); modelRender_draw(gfx, mtx, this->position, sp2C, 1.0f, NULL, local->spit_model); } @@ -123,13 +144,13 @@ Actor *chGobiCCW_draw(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx){ void chGobiCCW_free(Actor *this){ ActorLocal_chGobiCCW *local = (ActorLocal_chGobiCCW*)&this->local; - skeletalAnim_free(local->unk4); + skeletalAnim_free(local->skeletal_anim); assetcache_release(local->spit_model); } void chGobiCCW_update(Actor *this) { ActorLocal_chGobiCCW *local; - f32 sp48[3]; + f32 player_position[3]; f32 sp44; f32 sp40; @@ -139,54 +160,56 @@ void chGobiCCW_update(Actor *this) { this->marker->propPtr->unk8_3 = true; this->marker->actorFreeFunc = chGobiCCW_free; this->has_met_before = false; - local->unk4 = skeletalAnim_new(); + local->skeletal_anim = skeletalAnim_new(); local->spit_model = assetcache_get(ASSET_3F3_MODEL_GOBI_SPIT); marker_setCollisionScripts(this->marker, NULL, func_8038894C, NULL); if(!jiggyscore_isSpawned(JIGGY_4D_CCW_FLOWER)) { fileProgressFlag_set(FILEPROG_E5_CCW_FLOWER_AUTUMN, false); } - local->unk0 = &D_8038ECD0[0]; - while((local->unk0->map_id != 0) && (gsworld_getMap() != local->unk0->map_id)) { - local->unk0++; + local->dialogs = &chCCWGobiDialogs[0]; + while((local->dialogs->map_id != NULL) && (gsworld_getMap() != local->dialogs->map_id)) { + local->dialogs++; } if( (gsworld_getMap() == MAP_44_CCW_SUMMER) && fileProgressFlag_get(FILEPROG_E3_CCW_FLOWER_SPRING) && !fileProgressFlag_get(FILEPROG_E4_CCW_FLOWER_SUMMER)) { - CCW_func_8038868C(this, 1); + chCCWGobi_setState(this, CH_CCW_GOBI_STATE_1_WAITING); } else if( (gsworld_getMap() == MAP_45_CCW_AUTUMN) && fileProgressFlag_get(FILEPROG_E4_CCW_FLOWER_SUMMER) && !fileProgressFlag_get(FILEPROG_E5_CCW_FLOWER_AUTUMN) ) { - CCW_func_8038868C(this, 1); + chCCWGobi_setState(this, CH_CCW_GOBI_STATE_1_WAITING); } else{ marker_despawn(this->marker); } return; } - if(this->state == 1){ + if(this->state == CH_CCW_GOBI_STATE_1_WAITING){ if (!this->has_met_before) { - player_getPosition(sp48); - if (ml_vec3f_distance(this->position, sp48) < 600.0f) { - if (local->unk0->unk2 != 0) { - gcdialog_showDialog((s32) local->unk0->unk2, 4, NULL, NULL, NULL, NULL); + player_getPosition(player_position); + if (ml_vec3f_distance(this->position, player_position) < 600.0f) { + if (local->dialogs->summerMeetDialog != NULL) { + gcdialog_showDialog((s32) local->dialogs->summerMeetDialog, 4, NULL, NULL, NULL, NULL); } this->has_met_before = true; } } } - if (this->state == 2) { - skeletalAnim_update(local->unk4, time_getDelta(), 1); + if (this->state == CH_CCW_GOBI_STATE_2_SPITTING) { + skeletalAnim_update(local->skeletal_anim, time_getDelta(), 1); } - if(this->state == 3){ - if (!func_80388438()) { + if(this->state == CH_CCW_GOBI_STATE_3_GROW_BEANSTALK){ + if (!chCCWBeanstalk_hasSpawned()) { if (gsworld_getMap() == MAP_44_CCW_SUMMER) { - CCW_func_8038868C(this, 4); + chCCWGobi_setState(this, CH_CCW_GOBI_STATE_4_DONE_SPITTING); } else { - CCW_func_8038868C(this, 5); + chCCWGobi_setState(this, CH_CCW_GOBI_STATE_5_GETTING_UP); } } } - if (this->state == 4) { - if ((skeletalAnim_getAnimId(this->unk148) == ASSET_176_ANIM_GOBI_YAWN) && (skeletalAnim_getLoopCount(this->unk148) > 0)) { + if (this->state == CH_CCW_GOBI_STATE_4_DONE_SPITTING) { + if ((skeletalAnim_getAnimId(this->unk148) == ASSET_176_ANIM_GOBI_YAWN) + && (skeletalAnim_getLoopCount(this->unk148) > 0)) + { skeletalAnim_set(this->unk148, ASSET_177_ANIM_GOBI_SLEEP, 0.1f, 4.0f); skeletalAnim_setBehavior(this->unk148, SKELETAL_ANIM_1_LOOP); } @@ -202,16 +225,16 @@ void chGobiCCW_update(Actor *this) { } } - if (this->state == 5){ + if (this->state == CH_CCW_GOBI_STATE_5_GETTING_UP){ if(skeletalAnim_getLoopCount(this->unk148) > 0) { - CCW_func_8038868C(this, 6); + chCCWGobi_setState(this, CH_CCW_GOBI_STATE_6_RUN_AWAY); } } - if (this->state == 6) { + if (this->state == CH_CCW_GOBI_STATE_6_RUN_AWAY) { actor_update_func_80326224(this); if (0.99 < (f64) this->unk48) { - CCW_func_8038868C(this, 7); + chCCWGobi_setState(this, CH_CCW_GOBI_STATE_7_DESPAWN); } } } diff --git a/src/CCW/ch/cutsceneadulteyrie.c b/src/CCW/ch/cutsceneadulteyrie.c new file mode 100644 index 000000000..986470de2 --- /dev/null +++ b/src/CCW/ch/cutsceneadulteyrie.c @@ -0,0 +1,114 @@ +// BanjoDecomp: CCW/ch/cutsceneadulteyrie.c +#include +#include "functions.h" +#include "variables.h" + +typedef struct { + f32 unk0; + f32 unk4; + s16 unk8; + s16 unkA; +}Struct_CCW_4960_0; + +Actor *chCutsceneAdultEyrie_draw(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx); +void chCutsceneAdultEyrie_update(Actor *this); + +/* .data */ +// This is the flying Eyrie that poops the Jiggy +ActorInfo chCutsceneAdultEyrie = { + MARKER_1C4_CUTSCENE_ADULT_EYRIE, ACTOR_30E_CUTSCENE_ADULT_EYRIE, ASSET_487_MODEL_EAGLE_ADULT, + 0x0, NULL, + chCutsceneAdultEyrie_update, chCutsceneAdultEyrie_update, chCutsceneAdultEyrie_draw, + 0, 0, 0.0f, 0 +}; + +Struct_CCW_4960_0 chCutsceneAdultEyrieSFX[] = { + {0.5f, 0.8f, SFX_2_CLAW_SWIPE, 20000}, + 0 +}; + +enum chCutsceneAdultEyrie_State_e { + CH_CUTSCENE_ADULT_EYRIE_STATE_0_NOT_INIT, + CH_CUTSCENE_ADULT_EYRIE_STATE_1_UNK, + CH_CUTSCENE_ADULT_EYRIE_STATE_2_UNK, + CH_CUTSCENE_ADULT_EYRIE_STATE_3_UNK, + CH_CUTSCENE_ADULT_EYRIE_STATE_4_UNK +}; + +/* .code */ +void chCutsceneAdultEyrie_setNextState(Actor *this, s32 next_state) { + if (next_state == CH_CUTSCENE_ADULT_EYRIE_STATE_2_UNK) { + gcdialog_showDialog(VER_SELECT(ASSET_CDD_DIALOG_ADULT_EYRIE_COMPLETE_WINTER, 0x09F2, 0, 0), 0, NULL, NULL, NULL, NULL); + if (this->state == CH_CUTSCENE_ADULT_EYRIE_STATE_1_UNK) { + mapSpecificFlags_set(CCW_WINTER_SPECIFIC_FLAG_6_CUTSCENE_EEYRIE_ADULT, 0); + timed_setStaticCameraToNode(0.0f, 1); + } + skeletalAnim_set(this->unk148, ASSET_21D_ANIM_ADULT_EYRIE_UNK, 0.2f, 0.5f); + skeletalAnim_setBehavior(this->unk148, SKELETAL_ANIM_1_LOOP); + } + if (next_state == CH_CUTSCENE_ADULT_EYRIE_STATE_3_UNK) { + skeletalAnim_set(this->unk148, ASSET_21E_ANIM_ADULT_EYRIE_UNK, 0.2f, 2.0f); + skeletalAnim_setBehavior(this->unk148, SKELETAL_ANIM_2_ONCE); + } + if (next_state == CH_CUTSCENE_ADULT_EYRIE_STATE_4_UNK) { + timed_exitStaticCamera(0.0f); + func_80324E38(0.0f, 0); + marker_despawn(this->marker); + } + this->state = next_state; +} + +Actor *chCutsceneAdultEyrie_draw(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx){ + Actor *this; + + this = marker_getActor(marker); + if(this->state < CH_CUTSCENE_ADULT_EYRIE_STATE_2_UNK) + return this; + return actor_draw(marker, gfx, mtx, vtx); +} + +void chCutsceneAdultEyrie_update(Actor *this) { + Struct_CCW_4960_0 *iPtr; + f32 sp38; + f32 sp34; + f32 sp30; + f32 sp2C; + + if (!this->volatile_initialized) { + this->volatile_initialized = true; + chCutsceneAdultEyrie_setNextState(this, CH_CUTSCENE_ADULT_EYRIE_STATE_1_UNK); + return; + } + if (this->state == CH_CUTSCENE_ADULT_EYRIE_STATE_1_UNK){ + if(mapSpecificFlags_get(CCW_WINTER_SPECIFIC_FLAG_5_EEYRIE_ADULT)) { + mapSpecificFlags_set(CCW_WINTER_SPECIFIC_FLAG_5_EEYRIE_ADULT, false); + chCutsceneAdultEyrie_setNextState(this, CH_CUTSCENE_ADULT_EYRIE_STATE_2_UNK); + } + } + if (this->state == CH_CUTSCENE_ADULT_EYRIE_STATE_2_UNK) { + actor_update_func_80326224(this); + skeletalAnim_getProgressRange(this->unk148, &sp38, &sp34); + for(iPtr = &chCutsceneAdultEyrieSFX[0]; iPtr->unk0 > 0.0f; iPtr++){ + if ((sp38 < iPtr->unk0) && (iPtr->unk0 <= sp34)) { + func_8030E878((s32) iPtr->unk8, iPtr->unk4, iPtr->unkA, this->position, 1500.0f, 4500.0f); + } + } + if (mapSpecificFlags_get(CCW_WINTER_SPECIFIC_FLAG_6_CUTSCENE_EEYRIE_ADULT)) { + mapSpecificFlags_set(CCW_WINTER_SPECIFIC_FLAG_6_CUTSCENE_EEYRIE_ADULT, false); + chCutsceneAdultEyrie_setNextState(this, CH_CUTSCENE_ADULT_EYRIE_STATE_3_UNK); + } + if (0.99 < this->unk48) { + chCutsceneAdultEyrie_setNextState(this, CH_CUTSCENE_ADULT_EYRIE_STATE_4_UNK); + } + } + if (this->state == CH_CUTSCENE_ADULT_EYRIE_STATE_3_UNK) { + actor_update_func_80326224(this); + skeletalAnim_getProgressRange(this->unk148, &sp30, &sp2C); + if ((sp30 <= 0.5) && (sp2C >= 0.5) && !jiggyscore_isCollected(JIGGY_49_CCW_EYRIE)) { + jiggy_spawn(JIGGY_49_CCW_EYRIE, this->position); + } + if (skeletalAnim_getLoopCount(this->unk148) > 0) { + chCutsceneAdultEyrie_setNextState(this, CH_CUTSCENE_ADULT_EYRIE_STATE_2_UNK); + } + } +} diff --git a/src/CCW/ch/deadbeanstalk.c b/src/CCW/ch/deadbeanstalk.c index b98e15bf3..7f5eca32c 100644 --- a/src/CCW/ch/deadbeanstalk.c +++ b/src/CCW/ch/deadbeanstalk.c @@ -6,8 +6,14 @@ void chDeadBeanstalk_update(Actor *this); /* .data */ -ActorInfo D_8038ECA0 = { - 0x1C2, 0x30B, 0x4E3, + +enum chDeadBeanstalk_state_e { + DEAD_BEANSTALK_STATE_0_NOT_INIT, + DEAD_BEANSTALK_STATE_1_IDLE +}; + +ActorInfo chDeadBeanstalk = { + MARKER_1C2_DEAD_BEANSTALK, ACTOR_30B_DEAD_BEANSTALK, ASSET_4E3_MODEL_DEAD_BEANSTALK, 0x0, NULL, chDeadBeanstalk_update, NULL, actor_draw, 0, 0, 1.0f, 0 @@ -15,7 +21,7 @@ ActorInfo D_8038ECA0 = { /* .code */ void chDeadBeanstalk_setNextState(Actor *this, s32 next_state){ - if(next_state == 1){ + if(next_state == DEAD_BEANSTALK_STATE_1_IDLE){ skeletalAnim_set(this->unk148, 0x219, 0.0f, 1.0f); skeletalAnim_setBehavior(this->unk148, SKELETAL_ANIM_4_STOPPED); } @@ -26,7 +32,7 @@ void chDeadBeanstalk_update(Actor *this){ if(!this->volatile_initialized){ this->volatile_initialized = true; if(fileProgressFlag_get(FILEPROG_E5_CCW_FLOWER_AUTUMN)){ - chDeadBeanstalk_setNextState(this, 1); + chDeadBeanstalk_setNextState(this, DEAD_BEANSTALK_STATE_1_IDLE); } else{ marker_despawn(this->marker); diff --git a/src/CCW/ch/deadsnarebear.c b/src/CCW/ch/deadsnarebear.c new file mode 100644 index 000000000..ab6532cec --- /dev/null +++ b/src/CCW/ch/deadsnarebear.c @@ -0,0 +1,25 @@ +// BanjoDecomp: CCW/ch/deadsnarebear.c +#include +#include "functions.h" +#include "variables.h" + +void chDeadSnarebear_update(Actor *this); + + +ActorAnimationInfo chDeadSnarebearAnimations[] = { + {0x000, 0.0f}, + {ASSET_234_ANIM_DEAD_SNAREBEAR, 2.0f} +}; + +ActorInfo chDeadSnarebear = { + MARKER_251_DEAD_SNAREBEAR, ACTOR_37E_DEAD_SNAREBEAR, ASSET_506_CCW_DEAD_SNAREBEAR, + 0x1, chDeadSnarebearAnimations, + chDeadSnarebear_update, actor_update_func_80326224, actor_draw, + 0, 0, 0.0f, 0 +}; + +/* .code */ +void chDeadSnarebear_update(Actor *this){ + this->marker->propPtr->unk8_3 = true; + actor_collisionOff(this); +} diff --git a/src/CCW/ch/eyrie_baby.c b/src/CCW/ch/eyrie_baby.c deleted file mode 100644 index 721433321..000000000 --- a/src/CCW/ch/eyrie_baby.c +++ /dev/null @@ -1,314 +0,0 @@ -// BanjoDecomp: code_3310.c -#include -#include "functions.h" -#include "variables.h" -#include "port/Patches/Patches.h" - -typedef struct { - f32 unk0; - s16 unk4; - f32 unk8; - s16 unkC; -}Struct_CCW_3310_1; - -typedef struct { - s16 map_id; - s16 unk2; // enum file_progress_e - s16 unk4; // enum file_progress_e - s16 unk6; - Struct_CCW_3310_1 *unk8; - s16 unkC; - s16 unkE; - Struct_CCW_3310_1 *unk10; - s16 unk14; - // u8 pad16[2]; - Struct_CCW_3310_1 *unk18; - s16 unk1C; - // u8 pad1E[0x2]; - Struct_CCW_3310_1 *unk20; - u8 unk24; - u8 unk25; - s16 unk26; - s16 unk28; - // u8 pad2A[2]; -}Struct_CCW_3310_0; - -typedef struct { - Struct_CCW_3310_0 *unk0; - u8 unk4; - //u8 pad5[3]; - Struct_CCW_3310_1 *unk8; - s32 unkC[3]; -}ActorLocal_CCW_3310; - -Actor *func_80389B24(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx); -void CCW_func_80389BFC(Actor *this); - -/* .data */ -Struct_CCW_3310_1 D_8038EEA0[] = { - {0.11f, SFX_4A_CLUCKER_AHH, 1.1f, 25000}, - {0.22f, SFX_4A_CLUCKER_AHH, 1.1f, 25000}, - {0.34f, SFX_4A_CLUCKER_AHH, 1.1f, 25000}, - {0.55f, SFX_2_CLAW_SWIPE, 1.1f, 25000}, - {0.65f, SFX_2_CLAW_SWIPE, 1.0f, 26000}, - {0.77f, SFX_2_CLAW_SWIPE, 1.1f, 25000}, - {0.87f, SFX_2_CLAW_SWIPE, 1.0f, 24000}, - 0 -}; - -Struct_CCW_3310_1 D_8038EF20[] = { - {0.1f, SFX_80_YUMYUM_CLACK, 0.9f, 15000}, - {0.25f, SFX_4C_LIP_SMACK, 1.0f, 15000}, - {0.31f, SFX_4C_LIP_SMACK, 0.9f, 15000}, - {0.38f, SFX_4C_LIP_SMACK, 1.0f, 15000}, - {0.48f, SFX_4C_LIP_SMACK, 0.9f, 15000}, - {0.55f, SFX_97_BLUBBER_BURPS, 0.9f, 32700}, - {0.6f , SFX_2C_PULLING_NOISE, 0.7f, 25000}, - {0.73f, SFX_2C_PULLING_NOISE, 0.8f, 27000}, - {0.85f, SFX_2C_PULLING_NOISE, 0.9f, 29000}, - 0 -}; - -Struct_CCW_3310_1 D_8038EFC0[] = { - {0.2f , SFX_105_EYRIE_YAWN, 1.1f, 25000}, - {0.27f, SFX_105_EYRIE_YAWN, 1.0f, 25000}, - {0.35f, SFX_105_EYRIE_YAWN, 0.9f, 25000}, - {0.6f , SFX_106_EYRIE_LIPSMACK, 1.0f, 25000}, - {0.66f, SFX_106_EYRIE_LIPSMACK, 0.9f, 23000}, - {0.83f, SFX_1D_HITTING_AN_ENEMY_1, 0.7f, 27000}, - 0 -}; - -Struct_CCW_3310_1 D_8038F030[] = { - {0.2f , SFX_5D_BANJO_RAAOWW, 1.0f, 25000}, - {0.72f, SFX_5E_BANJO_PHEWWW, 1.0f, 25000}, - 0 -}; - -Struct_CCW_3310_1 D_8038F060[] = { - {0.95f, SFX_106_EYRIE_LIPSMACK, 1.0f, 25000}, - 0 -}; - -Struct_CCW_3310_0 D_8038F080[] = { - {MAP_43_CCW_SPRING, 0, FILEPROG_E6_SPRING_EYRIE_HATCHED, 0, NULL, 3, 0, NULL, 0x18F, D_8038EFC0, 0x190, D_8038F030, 0, 0, 0, 0}, - {MAP_44_CCW_SUMMER, FILEPROG_E6_SPRING_EYRIE_HATCHED, FILEPROG_E7_SUMMER_EYRIE_FED, 0x191, D_8038EEA0, 2, 0x192, D_8038EF20, 0x193, D_8038EFC0, 0x194, D_8038F030, 2, 5, 0x21A, 0xCD7}, - {MAP_45_CCW_AUTUMN, FILEPROG_E7_SUMMER_EYRIE_FED, FILEPROG_E8_AUTMN_EYRIE_FED, 0x195, D_8038EEA0, 2, 0x196, D_8038EF20, 0x197, D_8038EFC0, 0x198, D_8038F030, 4, 0xA, 0x21B, 0xCDA}, - 0 -}; - -ActorInfo D_8038F130 = { MARKER_1B4_EEYRIE_BABY, ACTOR_2A1_EEYRIE_BABY, ASSET_484_MODEL_EAGLE_BABY, 0x0, NULL, CCW_func_80389BFC, NULL, func_80389B24, 0, 0, 0.0f, 0}; - -/* .bss */ -f32 D_8038FDE0[3]; - -/* .code */ -void func_80389700(ActorMarker *marker, enum asset_e text_id, s32 arg2) { - timed_exitStaticCamera(0.5f); - func_80324E38(0.5f, 0); -} - -void func_80389740(ActorMarker *marker) { - Actor *this = marker_getActor(marker); - if (this->marker->unk14_21) { - __spawnQueue_add_4((GenFunction_4)spawnQueue_actor_f32, 0x30C, reinterpret_cast(s32, D_8038FDE0[0]), reinterpret_cast(s32, D_8038FDE0[1]), reinterpret_cast(s32, D_8038FDE0[2])); - } -} - -void func_80389798() { - func_8030E6D4(SFX_18C_EYRIE_MAMA); -} - -void func_803897B8(Actor *this, s32 next_state) { - ActorLocal_CCW_3310 *local; - - local = (ActorLocal_CCW_3310 *)&this->local; - local->unk8 = NULL; - if (next_state == 1) { - if (local->unk0->unk6 != 0) { - skeletalAnim_set(this->unk148, local->unk0->unk6, 0.2f, 6.0f); - skeletalAnim_setBehavior(this->unk148, SKELETAL_ANIM_1_LOOP); - } - local->unk8 = local->unk0->unk8; - } - if ((this->state == 1) && (next_state == 2)) { - fileProgressFlag_set(local->unk0->unk4, true); - } - if (next_state == 5) { - func_8028F784(1); - skeletalAnim_set(this->unk148, local->unk0->unk26, 0.2f, 2.0f); - skeletalAnim_setBehavior(this->unk148, SKELETAL_ANIM_2_ONCE); - local->unk8 = &D_8038F060[0]; - } - - if (next_state == 2) { - skeletalAnim_set(this->unk148, local->unk0->unkE, 0.2f, 8.0f); - skeletalAnim_setBehavior(this->unk148, SKELETAL_ANIM_2_ONCE); - func_80324E38(0.5f, 3); - timed_setStaticCameraToNode(0.5f, local->unk0->unk24); - timed_exitStaticCamera(16.5f); - func_80324E38(16.5f, 0); - local->unk8 = local->unk0->unk10; - } - if (next_state == 3) { - actor_collisionOff(this); - skeletalAnim_set(this->unk148, local->unk0->unk14, 0.5f, 8.5f); - skeletalAnim_setBehavior(this->unk148, SKELETAL_ANIM_2_ONCE); - if (local->unk0->map_id == MAP_43_CCW_SPRING) { - gcdialog_showDialog(0xCD6, 4, NULL, NULL, NULL, NULL); - skeletalAnim_setCallback_0(this->unk148, 0.65f, (GenFunction_0)&func_80389798); - } - if (local->unk0->map_id == MAP_44_CCW_SUMMER) { - gcdialog_showDialog(0xCD9, 4, NULL, NULL, NULL, NULL); - } - if (local->unk0->map_id == MAP_45_CCW_AUTUMN) { - gcdialog_showDialog(0xCDB, 4, NULL, NULL, NULL, NULL); - } - local->unk8 = local->unk0->unk18; - } - if (next_state == 4) { - func_8028F784(0); - skeletalAnim_set(this->unk148, local->unk0->unk1C, 0.2f, 6.0f); - skeletalAnim_setBehavior(this->unk148, SKELETAL_ANIM_1_LOOP); - skeletalAnim_setCallback_1(this->unk148, 0.2f, (GenFunction_1)func_80389740, (uintptr_t)this->marker); - skeletalAnim_setCallback_1(this->unk148, 0.3f, (GenFunction_1)func_80389740, (uintptr_t)this->marker); - skeletalAnim_setCallback_1(this->unk148, 0.4f, (GenFunction_1)func_80389740, (uintptr_t)this->marker); - skeletalAnim_setCallback_1(this->unk148, 0.72f, (GenFunction_1)func_80389740, (uintptr_t)this->marker); - skeletalAnim_setCallback_1(this->unk148, 0.82f, (GenFunction_1)func_80389740, (uintptr_t)this->marker); - skeletalAnim_setCallback_1(this->unk148, 0.92f, (GenFunction_1)func_80389740, (uintptr_t)this->marker); - local->unk8 = local->unk0->unk20; - } - this->state = next_state; -} - -Actor *func_80389B24(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx){ - Actor *this; - ActorLocal_CCW_3310 *local; - - this = marker_getActor(marker); - local = (ActorLocal_CCW_3310 *)&this->local; - if( (this->state == 0) - || ((this->state == 1) && (local->unk0->unk6 == 0)) - ) { - return this; - } - func_8033A45C(3, (this->state == 4) ? 2 : 1); - actor_draw(marker, gfx, mtx, vtx); - vec3fArray_get_vec3f(func_80329934(), 5, D_8038FDE0); - return this; -} - -void func_80389BD8(f32 dst[3]){ - dst[0] = D_8038FDE0[0]; - dst[1] = D_8038FDE0[1]; - dst[2] = D_8038FDE0[2]; -} - -void CCW_func_80389BFC(Actor *this) { - Struct_CCW_3310_1 *iPtr; - ActorLocal_CCW_3310 *local; - f32 sp5C; - f32 sp58; - f32 sp4C[3]; - - local = (ActorLocal_CCW_3310 *)&this->local; - - if (!this->volatile_initialized) { - this->volatile_initialized = true; - this->marker->propPtr->unk8_3 = true; - this->has_met_before = false; - this->position[0] = -4900.0f; - this->position[1] = 4619.0f; - this->position[2] = 0.0f; - D_8038FDE0[0] = this->position[0]; - D_8038FDE0[1] = this->position[1]; - D_8038FDE0[2] = this->position[2]; - if (this->state == 0) { - local->unk4 = (u32)port_puzzleCount_get(ANCHOR_COUNT_CCW_EYRIE_FED); - } - local->unk0 = &D_8038F080[0]; - while(local->unk0->map_id != 0 && gsworld_getMap() != local->unk0->map_id){ - local->unk0++; - } - - if ((local->unk0->unk2 != 0) && !fileProgressFlag_get(local->unk0->unk2)) { - marker_despawn(this->marker); - } else if (!fileProgressFlag_get(local->unk0->unk4)) { - func_803897B8(this, 1); - } else { - func_803897B8(this, 4); - } - - if (jiggyscore_isSpawned(JIGGY_49_CCW_EYRIE) != 0) { - marker_despawn(this->marker); - } - return; - } - - if (local->unk8) { - skeletalAnim_getProgressRange(this->unk148, &sp5C, &sp58); - for(iPtr = local->unk8; iPtr->unk0 > 0.0f; iPtr ++){ - if ((sp5C < iPtr->unk0) && (iPtr->unk0 <= sp58)) { - func_8030E878((s32) iPtr->unk4, randf2(iPtr->unk8 - 0.05, iPtr->unk8 + 0.05), iPtr->unkC, this->position, 500.0f, 2500.0f); - } - } - } - if (this->state == 1) { - player_getPosition(sp4C); - if( !this->has_met_before - && (local->unkC[2] >= 6500) - && (sp4C[2] < 6500.0f) - && (local->unk0->unk28 != 0) - ){ - this->has_met_before = true; - func_80324E38(0.0f, 3); - timed_setStaticCameraToNode(0.0f, local->unk0->unk24); - func_80324DBC(0.0f, local->unk0->unk28, 6, NULL, this->marker, func_80389700, NULL); - } - local->unkC[0] = (s32) sp4C[0]; - local->unkC[1] = (s32) sp4C[1]; - local->unkC[2] = (s32) sp4C[2]; - if (item_getCount(ITEM_22_CATERPILLAR) == 0) { - func_8028F784(0); - } - if ((local->unk0->map_id != MAP_43_CCW_SPRING) && ((this->position[0] + 500.0f) < sp4C[0])) { - player_setCarryObjectPoseInCylinder(this->position, 1110.0f, 200.0f, ACTOR_2A2_CATERPILLAR, &this); - if ((local->unk0->unkE != 0) && (carriedObj_getActorId() == ACTOR_2A2_CATERPILLAR) && (ml_vec3f_distance(this->position, sp4C) < 1010.0f) && (player_throwCarriedObject() != 0)) { - player_setThrowTargetPosition(D_8038FDE0); - if ((local->unk0->map_id == MAP_44_CCW_SUMMER) && (local->unk4 == 0)) { - gcdialog_showDialog(0xCD8, 4, NULL, NULL, NULL, NULL); - } - port_puzzleCount_add(ANCHOR_COUNT_CCW_EYRIE_FED, 1); - local->unk4 = (u32)port_puzzleCount_get(ANCHOR_COUNT_CCW_EYRIE_FED); - if (local->unk4 < local->unk0->unk25) { - func_803897B8(this, 5); - } else { - func_803897B8(this, 2); - } - } - } - // Anchor: teammate fed a worm — play the interim eat animation; final feed handled below. - if (this->state == 1) { - s32 sharedFed = port_puzzleCount_get(ANCHOR_COUNT_CCW_EYRIE_FED); - if (sharedFed > (s32)local->unk4) { - local->unk4 = (u32)sharedFed; - if ((s32)local->unk4 < (s32)local->unk0->unk25) { - func_803897B8(this, 5); - } - } - } - if (this->state == 1 && fileProgressFlag_get(local->unk0->unk4)) { - // Anchor: fed flag synced from a teammate — skip to sleep state (spring keeps its hatch cutscene). - func_803897B8(this, (local->unk0->map_id == MAP_43_CCW_SPRING) ? local->unk0->unkC : 4); - } - } - if ((this->state == 2) && (skeletalAnim_getLoopCount(this->unk148) > 0)) { - func_803897B8(this, 3); - } - if ((this->state == 3) && (skeletalAnim_getLoopCount(this->unk148) > 0)) { - func_803897B8(this, 4); - } - if ((this->state == 5) && (skeletalAnim_getLoopCount(this->unk148) > 0)) { - func_803897B8(this, 1); - } -} diff --git a/src/CCW/ch/eyrie_egg.c b/src/CCW/ch/eyrie_egg.c deleted file mode 100644 index 451c466a0..000000000 --- a/src/CCW/ch/eyrie_egg.c +++ /dev/null @@ -1,81 +0,0 @@ -// BanjoDecomp: code_3050.c -#include -#include "functions.h" -#include "variables.h" - -Actor *CCW_func_8038954C(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx); -void func_803895F4(Actor *this); - -/* .data */ -ActorInfo D_8038EE70 = { 0x1B3, 0x2A0, 0x483, 0x0, NULL, func_803895F4, NULL, CCW_func_8038954C, 0, 0, 0.0f, 0}; - -// Anchor: set while replaying a teammate's hatch; skips the camera pan. -static s32 sChEyrieEggRemote = 0; - -/* .code */ -void func_80389440(Actor *this, s32 next_state) { - void *temp_v0; - - if (next_state == 2) { - sfxsource_play(SFX_AA_BGS_EGG_BREAKING_1, 28000); - this->marker->propPtr->unk8_3 = false; - fileProgressFlag_set(FILEPROG_E6_SPRING_EYRIE_HATCHED, true); - skeletalAnim_set(this->unk148, 0x187, 0.0f, 2.0f); - skeletalAnim_setBehavior(this->unk148, SKELETAL_ANIM_2_ONCE); - if (!sChEyrieEggRemote) { - func_80324E38(0.0f, 3); - timed_setStaticCameraToNode(0.0f, 2); - timed_exitStaticCamera(8.0f); - func_80324E38(8.0f, 0); - } - } - this->state = next_state; -} - -void func_8038950C(ActorMarker* marker, ActorMarker* other_marker) { - Actor* actor = marker_getActor(marker); - if (actor->state == 1) { - func_80389440(actor, 2); - } -} - -Actor *CCW_func_8038954C(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx) { - Actor *this; - - this = marker_getActor(marker); - if (this->state == 0) - return this; - - func_8033A45C(3, (this->state < 2) ? 1 : 0); - func_8033A45C(4, (this->state < 2) ? 0 : 1); - return actor_draw(marker, gfx, mtx, vtx); -} - -void func_803895F4(Actor *this) { - f32 sp2C; - f32 sp28; - - if(!this->volatile_initialized) { - this->volatile_initialized = true; - this->marker->propPtr->unk8_3 = true; - marker_setCollisionScripts(this->marker, NULL, NULL, &func_8038950C); - func_80389440(this, 1); - if (fileProgressFlag_get(FILEPROG_E6_SPRING_EYRIE_HATCHED) || jiggyscore_isSpawned(JIGGY_49_CCW_EYRIE)) { - marker_despawn(this->marker); - } - return; - } - - if (this->state == 1 && fileProgressFlag_get(FILEPROG_E6_SPRING_EYRIE_HATCHED)) { - sChEyrieEggRemote = 1; - func_80389440(this, 2); - sChEyrieEggRemote = 0; - } - - if (this->state == 2) { - skeletalAnim_getProgressRange(this->unk148, &sp2C, &sp28); - if ((sp2C < 0.5) && (sp28 >= 0.5)) { - func_80326310(this); - } - } -} diff --git a/src/CCW/ch/eyrie_summer.c b/src/CCW/ch/eyrie_summer.c deleted file mode 100644 index 0ba4d601a..000000000 --- a/src/CCW/ch/eyrie_summer.c +++ /dev/null @@ -1,120 +0,0 @@ -// BanjoDecomp: code_4530.c -#include -#include "functions.h" -#include "variables.h" - -typedef struct { - f32 unk0; - f32 unk4; - s16 unk8; - s16 unkA; -}Struct_CCW_4530_0; - -void func_8038A950(Actor *this, s32 next_state); -Actor *func_8038AA38(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx); -void func_8038AA8C(Actor *this); - -/* .data */ -ActorInfo D_8038F190 = { - 0x1B6, 0x2A3, 0x487, - 0x0, NULL, - func_8038AA8C, NULL, func_8038AA38, - 0, 0, 0.0f, 0 -}; - -Struct_CCW_4530_0 D_8038F1B4[] = { - {0.15f, 0.9f, SFX_A5_EYRIE_CRY, 25000}, - {0.3f, 1.0f, SFX_A5_EYRIE_CRY, 32000}, - {0.6f, 0.8f, SFX_2_CLAW_SWIPE, 20000}, - {0.68f, 0.85f, SFX_2_CLAW_SWIPE, 23000}, - {0.75f, 0.9f, SFX_2_CLAW_SWIPE, 28000}, - {0.8f, 0.95f, SFX_2_CLAW_SWIPE, 30000}, - {0.81f, 1.0f, SFX_A5_EYRIE_CRY, 32000}, - {0.86f, 1.0f, SFX_2_CLAW_SWIPE, 31000}, - {0.93f, 1.0f, SFX_2_CLAW_SWIPE, 32000}, -0 -}; - -/* .code */ -void func_8038A920(ActorMarker* marker, enum asset_e text_id, s32 arg2) { - func_8038A950(marker_getActor(marker), 3); -} - -void func_8038A950(Actor *this, s32 next_state) { - if (next_state == 1) { - skeletalAnim_set(this->unk148, 0x199, 0.0f, 6.5f); - } - if (next_state == 2) { - gcdialog_showDialog(0xCDC, 0xA, this->position, this->marker, func_8038A920, NULL); - } - if (next_state == 3) { - skeletalAnim_set(this->unk148, 0x19A, 0.0f, 7.0f); - skeletalAnim_setBehavior(this->unk148, SKELETAL_ANIM_2_ONCE); - func_80324E38(0.0f, 3); - timed_setStaticCameraToNode(0.0f, 0); - } - if (next_state == 4) { - mapSpecificFlags_set(5, 1); - marker_despawn(this->marker); - } - this->state = next_state; -} - -Actor *func_8038AA38(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx){ - Actor *this; - - this = marker_getActor(marker); - if(this->state == 0) - return this; - return actor_draw(marker, gfx, mtx, vtx); -} - -void func_8038AA8C(Actor *this) { - f32 sp54[3]; - f32 sp50; - f32 sp4C; - Struct_CCW_4530_0 *iPtr; - f32 sp44; - f32 sp40; - - if (!this->volatile_initialized) { - this->volatile_initialized = true; - mapSpecificFlags_set(5, false); - if( (!fileProgressFlag_get(FILEPROG_E8_AUTMN_EYRIE_FED) || jiggyscore_isSpawned(JIGGY_49_CCW_EYRIE)) - && !volatileFlag_get(VOLATILE_FLAG_1F_IN_CHARACTER_PARADE) - ) { - marker_despawn(this->marker); - } - else{ - func_8038A950(this, 1); - } - return; - } - - if (this->state == 1) { - skeletalAnim_getProgressRange(this->unk148, &sp50, &sp4C); - if ((sp50 < 0.21) && (0.21 <= sp4C)) { - func_8030E878(0xA5, randf2(0.9f, 1.1f), 32000, this->position, 500.0f, 2500.0f); - } - - if ((sp50 < 0.56) && (0.56 <= sp4C)) { - func_8030E878(0xA5, randf2(0.9f, 1.1f), 32000, this->position, 500.0f, 2500.0f); - } - - player_getPosition(sp54); - if (ml_vec3f_distance(this->position, sp54) < 850.0f) { - func_8038A950(this, 2); - } - } - if (this->state == 3) { - skeletalAnim_getProgressRange(this->unk148, &sp44, &sp40); - for(iPtr = &D_8038F1B4[0]; iPtr->unk0 > 0.0f; iPtr++){ - if ((sp44 < iPtr->unk0) && (iPtr->unk0 <= sp40)) { - func_8030E878(iPtr->unk8, iPtr->unk4, iPtr->unkA, this->position, 500.0f, 2500.0f); - } - } - if (skeletalAnim_getLoopCount(this->unk148) > 0) { - func_8038A950(this, 4); - } - } -} diff --git a/src/CCW/ch/eyrie_winter.c b/src/CCW/ch/eyrie_winter.c deleted file mode 100644 index 13f9c2868..000000000 --- a/src/CCW/ch/eyrie_winter.c +++ /dev/null @@ -1,105 +0,0 @@ -// BanjoDecomp: code_4960.c -#include -#include "functions.h" -#include "variables.h" - -typedef struct { - f32 unk0; - f32 unk4; - s16 unk8; - s16 unkA; -}Struct_CCW_4960_0; - -Actor *func_8038AE64(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx); -void func_8038AEBC(Actor *this); - -/* .data */ -ActorInfo D_8038F230 = { - 0x1C4, 0x30E, 0x487, - 0x0, NULL, - func_8038AEBC, func_8038AEBC, func_8038AE64, - 0, 0, 0.0f, 0 -}; - -Struct_CCW_4960_0 D_8038F254[] = { - {0.5f, 0.8f, SFX_2_CLAW_SWIPE, 20000}, - 0 -}; - -/* .code */ -void func_8038AD50(Actor *this, s32 next_state) { - if (next_state == 2) { - gcdialog_showDialog(0xCDD, 0, NULL, NULL, NULL, NULL); - if (this->state == 1) { - mapSpecificFlags_set(6, 0); - timed_setStaticCameraToNode(0.0f, 1); - } - skeletalAnim_set(this->unk148, 0x21D, 0.2f, 0.5f); - skeletalAnim_setBehavior(this->unk148, SKELETAL_ANIM_1_LOOP); - } - if (next_state == 3) { - skeletalAnim_set(this->unk148, 0x21E, 0.2f, 2.0f); - skeletalAnim_setBehavior(this->unk148, SKELETAL_ANIM_2_ONCE); - } - if (next_state == 4) { - timed_exitStaticCamera(0.0f); - func_80324E38(0.0f, 0); - marker_despawn(this->marker); - } - this->state = next_state; -} - -Actor *func_8038AE64(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx){ - Actor *this; - - this = marker_getActor(marker); - if(this->state < 2) - return this; - return actor_draw(marker, gfx, mtx, vtx); -} - -void func_8038AEBC(Actor *this) { - Struct_CCW_4960_0 *iPtr; - f32 sp38; - f32 sp34; - f32 sp30; - f32 sp2C; - - if (!this->volatile_initialized) { - this->volatile_initialized = true; - func_8038AD50(this, 1); - return; - } - if (this->state == 1){ - if(mapSpecificFlags_get(5)) { - mapSpecificFlags_set(5, false); - func_8038AD50(this, 2); - } - } - if (this->state == 2) { - actor_update_func_80326224(this); - skeletalAnim_getProgressRange(this->unk148, &sp38, &sp34); - for(iPtr = &D_8038F254[0]; iPtr->unk0 > 0.0f; iPtr++){ - if ((sp38 < iPtr->unk0) && (iPtr->unk0 <= sp34)) { - func_8030E878((s32) iPtr->unk8, iPtr->unk4, iPtr->unkA, this->position, 1500.0f, 4500.0f); - } - } - if (mapSpecificFlags_get(6)) { - mapSpecificFlags_set(6, false); - func_8038AD50(this, 3); - } - if (0.99 < this->unk48) { - func_8038AD50(this, 4); - } - } - if (this->state == 3) { - actor_update_func_80326224(this); - skeletalAnim_getProgressRange(this->unk148, &sp30, &sp2C); - if ((sp30 <= 0.5) && (sp2C >= 0.5) && !jiggyscore_isCollected(JIGGY_49_CCW_EYRIE)) { - jiggy_spawn(JIGGY_49_CCW_EYRIE, this->position); - } - if (skeletalAnim_getLoopCount(this->unk148) > 0) { - func_8038AD50(this, 2); - } - } -} diff --git a/src/CCW/ch/eyrieegg.c b/src/CCW/ch/eyrieegg.c new file mode 100644 index 000000000..416e03837 --- /dev/null +++ b/src/CCW/ch/eyrieegg.c @@ -0,0 +1,94 @@ +// BanjoDecomp: CCW/ch/eyrieegg.c +#include +#include "functions.h" +#include "variables.h" + +Actor *chEyrieEgg_draw(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx); +void chEyrieEgg_update(Actor *this); + +/* .data */ +ActorInfo chEyrieEgg = { + MARKER_1B3_EAGLE_EGG, ACTOR_2A0_EAGLE_EGG, ASSET_483_MODEL_EAGLE_EGG, + 0x0, NULL, + chEyrieEgg_update, NULL, chEyrieEgg_draw, + 0, 0, 0.0f, 0 +}; + +enum chEyrieEgg_State_e { + CH_EYRIE_EGG_STATE_0_NOT_INIT, + CH_EYRIE_EGG_STATE_1_IDLE, + CH_EYRIE_EGG_STATE_2_BREAKING +}; + +// Anchor: set while replaying a teammate's hatch; skips the camera pan. +static s32 sChEyrieEggRemote = 0; + +/* .code */ +void chEyrieEgg_setNextState(Actor *this, s32 next_state) { + void *temp_v0; + + if (next_state == CH_EYRIE_EGG_STATE_2_BREAKING) { + sfxsource_play(SFX_AA_BGS_EGG_BREAKING_1, 28000); + this->marker->propPtr->unk8_3 = false; + fileProgressFlag_set(FILEPROG_E6_SPRING_EYRIE_HATCHED, true); + skeletalAnim_set(this->unk148, 0x187, 0.0f, 2.0f); + skeletalAnim_setBehavior(this->unk148, SKELETAL_ANIM_2_ONCE); + if (!sChEyrieEggRemote) { + func_80324E38(0.0f, 3); + timed_setStaticCameraToNode(0.0f, 2); + timed_exitStaticCamera(8.0f); + func_80324E38(8.0f, 0); + } + } + this->state = next_state; +} + +void chEyrieEgg_die(ActorMarker* marker, ActorMarker* other_marker) { + Actor* actor = marker_getActor(marker); + if (actor->state == CH_EYRIE_EGG_STATE_1_IDLE) { + chEyrieEgg_setNextState(actor, CH_EYRIE_EGG_STATE_2_BREAKING); + } +} + +Actor *chEyrieEgg_draw(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx) { + Actor *this; + + this = marker_getActor(marker); + if (this->state == CH_EYRIE_EGG_STATE_0_NOT_INIT) + return this; + + modelRender_setAppendageVisibility(3, (this->state < CH_EYRIE_EGG_STATE_2_BREAKING) ? 1 : 0); + modelRender_setAppendageVisibility(4, (this->state < CH_EYRIE_EGG_STATE_2_BREAKING) ? 0 : 1); + return actor_draw(marker, gfx, mtx, vtx); +} + +void chEyrieEgg_update(Actor *this) { + f32 sp2C; + f32 sp28; + + if(!this->volatile_initialized) { + this->volatile_initialized = true; + this->marker->propPtr->unk8_3 = true; + marker_setCollisionScripts(this->marker, NULL, NULL, &chEyrieEgg_die); + chEyrieEgg_setNextState(this, CH_EYRIE_EGG_STATE_1_IDLE); + if (fileProgressFlag_get(FILEPROG_E6_SPRING_EYRIE_HATCHED) + || jiggyscore_isSpawned(JIGGY_49_CCW_EYRIE)) + { + marker_despawn(this->marker); + } + return; + } + + if (this->state == CH_EYRIE_EGG_STATE_1_IDLE && fileProgressFlag_get(FILEPROG_E6_SPRING_EYRIE_HATCHED)) { + sChEyrieEggRemote = 1; + chEyrieEgg_setNextState(this, CH_EYRIE_EGG_STATE_2_BREAKING); + sChEyrieEggRemote = 0; + } + + if (this->state == CH_EYRIE_EGG_STATE_2_BREAKING) { + skeletalAnim_getProgressRange(this->unk148, &sp2C, &sp28); + if ((sp2C < 0.5) && (sp28 >= 0.5)) { + func_80326310(this); + } + } +} diff --git a/src/CCW/ch/fairy.c b/src/CCW/ch/fairy.c deleted file mode 100644 index 9c44ac9d0..000000000 --- a/src/CCW/ch/fairy.c +++ /dev/null @@ -1,129 +0,0 @@ -// BanjoDecomp: code_6620.c -#include -#include "functions.h" -#include "variables.h" - -extern ParticleEmitter *func_802EDD8C(f32[3], f32, f32); - -typedef struct{ - s16 map_id; - s16 unk2; - s16 unk4; -}Struct_CCW_6620_0; - -typedef struct{ - Struct_CCW_6620_0 *unk0; - f32 unk4[3]; -}ActorLocal_CCW_6620; - -Actor *CCW_func_8038CBF0(ActorMarker *this, Gfx **gfx, Mtx **mtx, Vtx **vtx); -void func_8038CC4C(Actor *this); - -/* .data */ -Struct_CCW_6620_0 D_8038F490[] ={ - {0x43, 0, 0xCCE}, - {0x45, 1, 0xCD1}, - {0x46, 1, 0xCD3}, - 0 -}; - -ActorInfo D_8038F4A8 = { - 0x1BD, 0x2AA, 0x48F, - 0x0, NULL, - func_8038CC4C, NULL, CCW_func_8038CBF0, - 0, 0, 2.2f, 0 -}; - -/* .code */ -void func_8038CA10(ActorMarker *marker) { - Actor *this; - ActorLocal_CCW_6620 *local; - ParticleEmitter *pCtrl; - - this = marker_getActor(marker); - local = (ActorLocal_CCW_6620 *)&this->local; - - if (this->marker->unk14_21) { - if (0.65 < (f64) randf()) { - pCtrl = func_802EDD8C(local->unk4, 0.0f, this->position[1] + 500.0f); - particleEmitter_setStartingScaleRange(pCtrl, 0.04f, 0.05f); - particleEmitter_setFinalScaleRange(pCtrl, 0.18f, 0.2f); - particleEmitter_setSpawnPositionRange(pCtrl, -10.0f, 0.0f, -10.0f, 10.0f, 20.0f, 10.0f); - particleEmitter_setParticleVelocityRange(pCtrl, 0.0f, 31.0f, 0.0f, 0.0f, 37.0f, 0.0f); - particleEmitter_emitN(pCtrl, 1); - } - } -} - -void func_8038CB40(Actor *this, s32 next_state) { - int i; - - if (next_state == 1) { - skeletalAnim_set(this->unk148, 0x289, 0.2f, 1.1f); - for(i = 0; i < 10; i++){ - skeletalAnim_setCallback_1(this->unk148, randf(), (GenFunction_1)func_8038CA10, (uintptr_t)this->marker); - } - } - this->state = next_state; -} - - -Actor *CCW_func_8038CBF0(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx) { - Actor *this; - ActorLocal_CCW_6620 *local; - - this = actor_draw(marker, gfx, mtx, vtx); - local = (ActorLocal_CCW_6620 *)&this->local; - if (this->marker->unk14_21) { - vec3fArray_get_vec3f(func_80329934(), 5, local->unk4); - } - return this; -} - -void func_8038CC4C(Actor *this) { - ActorLocal_CCW_6620 *local; - f32 sp50[3]; - f32 sp4C; - f32 sp48; - f32 sp44; - f32 sp38[3]; - - local = (ActorLocal_CCW_6620 *)&this->local; - if (!this->volatile_initialized) { - this->marker->propPtr->unk8_3 = true; - this->volatile_initialized = true; - this->has_met_before = false; - local->unk0 = &D_8038F490[0]; - while(local->unk0->map_id != 0 && gsworld_getMap() != local->unk0->map_id){ - local->unk0++; - } - func_8038CB40(this, 1); - - if (jiggyscore_isCollected(JIGGY_4B_CCW_GNAWTY)) { - levelSpecificFlags_set(LEVEL_FLAG_25_CCW_UNKNOWN, true); - } - - if ((local->unk0->unk2 != 0) && levelSpecificFlags_get(LEVEL_FLAG_25_CCW_UNKNOWN)) { - marker_despawn(this->marker); - } - - return; - } - - if (this->state == 1 && this->marker->unk14_21) { - player_getPosition(sp50); - func_80258A4C(this->position, this->yaw - 90.0f, sp50, &sp4C, &sp48, &sp44); - if (sp4C > 100.0f) { - this->yaw += 30.0f * sp44; - } - } - if (!this->has_met_before) { - player_getPosition(sp38); - if (ml_vec3f_distance(this->position, sp38) < 900.0f) { - if (local->unk0->map_id != MAP_46_CCW_WINTER || func_8028F2FC()) { - gcdialog_showDialog(local->unk0->unk4, 4, NULL, NULL, NULL, NULL); - this->has_met_before = true; - } - } - } -} diff --git a/src/CCW/ch/gnawty.c b/src/CCW/ch/gnawty.c deleted file mode 100644 index 9095dce6e..000000000 --- a/src/CCW/ch/gnawty.c +++ /dev/null @@ -1,143 +0,0 @@ -// BanjoDecomp: code_6AC0.c -#include -#include "functions.h" -#include "variables.h" - -typedef struct{ - f32 unk0; - f32 unk4; - s16 unk8; - s16 unkA; -}Struct_CCW_6AC0_0; - -void func_8038CFB4(Actor *this); - -/* .data */ -ActorInfo D_8038F4D0 = { - 0x1BE, 0x2AB, 0x48F, - 0x0, NULL, - func_8038CFB4, func_8038CFB4, actor_draw, - 0, 0, 2.2f, 0 -}; - -Struct_CCW_6AC0_0 D_8038F4F4[] = { - {0.11f, 1.0f, SFX_10_BANJO_LANDING_07, 9000}, - {0.23f, 1.0f, SFX_10_BANJO_LANDING_07, 9000}, - {0.34f, 1.0f, SFX_10_BANJO_LANDING_07, 9000}, - {0.58f, 1.0f, SFX_4D_WET_WIGGLING, 9000}, - {0.8f, 1.0f, SFX_4D_WET_WIGGLING, 9000}, - 0 -}; - -Struct_CCW_6AC0_0 D_8038F53C[] = { - {0.07f, 1.6f, SFX_56_BANJO_HUI, 32000}, - {0.17f, 1.0f, SFX_10_BANJO_LANDING_07, 9000}, - {0.22f, 1.6f, SFX_55_BANJO_HOO_2, 32000}, - {0.31f, 1.0f, SFX_10_BANJO_LANDING_07, 9000}, - {0.33f, 1.6f, SFX_54_BANJO_HOO_1, 32000}, - {0.45f, 1.0f, SFX_10_BANJO_LANDING_07, 9000}, - {0.49f, 1.7f, SFX_55_BANJO_HOO_2, 32600}, - {0.6f, 1.0f, SFX_10_BANJO_LANDING_07, 9000}, - {0.63f, 1.7f, SFX_56_BANJO_HUI, 32600}, - {0.74f, 1.0f, SFX_10_BANJO_LANDING_07, 9000}, - {0.79f, 1.6f, SFX_54_BANJO_HOO_1, 32000}, - {0.9f, 1.0f, SFX_10_BANJO_LANDING_07, 9000}, - 0 -}; - -Struct_CCW_6AC0_0 D_8038F5D8[] = { - {0.01f, 1.0f, SFX_10_BANJO_LANDING_07, 9000}, - {0.5f, 1.0f, SFX_10_BANJO_LANDING_07, 9000}, - 0 -}; - -/* .code */ -void func_8038CEB0(Actor *this, s32 next_state) { - ActorProp *temp_v0; - - if (next_state == 1) { - skeletalAnim_set(this->unk148, 0x1A6, 0.2f, 4.5f); - } - if (next_state == 2) { - this->marker->propPtr->unk8_3 = false; - skeletalAnim_set(this->unk148, 0x1A7, 0.2f, 3.0f); - skeletalAnim_setBehavior(this->unk148, SKELETAL_ANIM_2_ONCE); - gcdialog_showDialog(0xCD0, 0x24, NULL, NULL, NULL, NULL); - } - if (next_state == 3) { - skeletalAnim_set(this->unk148, 0x1A8, 0.2f, 0.5f); - skeletalAnim_setBehavior(this->unk148, SKELETAL_ANIM_1_LOOP); - } - if (next_state == 4) { - marker_despawn(this->marker); - } - this->state = next_state; -} - -void func_8038CFB4(Actor *this) { - Struct_CCW_6AC0_0 *phi_s0; - f32 sp70; - f32 sp6C; - f32 sp60[3]; - - if (!this->volatile_initialized) { - this->marker->propPtr->unk8_3 = true; - this->volatile_initialized = true; - this->has_met_before = false; - func_8038CEB0(this, 1); - if (jiggyscore_isCollected(JIGGY_4B_CCW_GNAWTY) != 0) { - levelSpecificFlags_set(LEVEL_FLAG_25_CCW_UNKNOWN, true); - } - if (levelSpecificFlags_get(LEVEL_FLAG_25_CCW_UNKNOWN) != false) { - marker_despawn(this->marker); - } - return; - } - - if (this->state == 1) { - phi_s0 = D_8038F4F4; - } else if (this->state == 2) { - phi_s0 = D_8038F53C; - } else if (this->state == 3) { - phi_s0 = D_8038F5D8; - } else{ - phi_s0 = NULL; - } - - if (phi_s0 != NULL) { - skeletalAnim_getProgressRange(this->unk148, &sp70, &sp6C); - while(phi_s0->unk0 > 0.0f){ - if (((sp70 < phi_s0->unk0) || (sp6C < sp70)) && (phi_s0->unk0 <= sp6C)) { - func_8030E878(phi_s0->unk8, randf2(phi_s0->unk4 - 0.05, phi_s0->unk4 + 0.05), randi2(phi_s0->unkA - 200, phi_s0->unkA + 100), this->position, 500.0f, 1500.0f); - } - phi_s0++; - } - } - - if (this->state == 1) { - if (!this->has_met_before) { - player_getPosition(sp60); - if (ml_vec3f_distance(this->position, sp60) < 900.0f) { - gcdialog_showDialog(0xCCF, 4, NULL, NULL, NULL, NULL); - this->has_met_before = true; - } - } - - if (levelSpecificFlags_get(LEVEL_FLAG_25_CCW_UNKNOWN) != false) { - func_8038CEB0(this, 2); - } - } - - if (this->state == 2){ - if((skeletalAnim_getLoopCount(this->unk148) > 0)) { - func_8038CEB0(this, 3); - } - } - - if (this->state == 3) { - actor_update_func_80326224(this); - if (0.99 < (f64) this->unk48) { - func_8038CEB0(this, 4); - } - } -} diff --git a/src/CCW/ch/gnawtyboulder.c b/src/CCW/ch/gnawtyboulder.c index 995a659f0..03a991b11 100644 --- a/src/CCW/ch/gnawtyboulder.c +++ b/src/CCW/ch/gnawtyboulder.c @@ -4,12 +4,20 @@ #include "variables.h" typedef struct { - f32 unk0; + f32 unk0; // time related } ActorLocal_CCW_7120; void chGnawtyBoulder_update(Actor *this); /* .data */ + +enum chGnawtyBoulder_state_e { + GNAWTY_BOULDER_STATE_0_NOT_INIT, + GNAWTY_BOULDER_STATE_1_IDLE, + GNAWTY_BOULDER_STATE_2_BREAK, + GNAWTY_BOULDER_STATE_3_DESPAWN +}; + ActorInfo chGnawtyBoulder = { 0x1BF, 0x2AC, 0x490, 0x0, NULL, @@ -18,7 +26,7 @@ ActorInfo chGnawtyBoulder = { }; /* .code */ -void CCW_func_8038D510(Actor *this) { +void chGnawtyBoulder_emitSmoke(Actor *this) { static s32 D_8038F664[3] = {0xDE, 0xA7, 0x71}; static ParticleSettingsVelocityPosition D_8038F670 = { {{ 0.0f, 50.0f, 0.0f}, { 70.0f, 100.0f, 70.0f}}, @@ -39,7 +47,7 @@ void CCW_func_8038D510(Actor *this) { particleEmitter_emitN(pCtrl, 6); } -void func_8038D5DC(Actor *this) { +void chGnawtyBoulder_emitRock(Actor *this) { static ParticleSettingsVelocityAccelerationPosition D_8038F6A0 ={ {{-100.0f, -50.0f, -100.0f}, {100.0f, 50.0f, 100.0f}}, {{ 0.0f, -800.0f, 0.0f}, { 0.0f, -800.0f, 0.0f}}, @@ -51,7 +59,7 @@ void func_8038D5DC(Actor *this) { pCtrl = partEmitMgr_newEmitter(30); particleEmitter_func_802EF9F8(pCtrl, 0.6f); particleEmitter_func_802EFA18(pCtrl, 3); - particleEmitter_setModel(pCtrl, 0x896); + particleEmitter_setModel(pCtrl, ASSET_896_MODEL_GOLD_ROCK); particleEmitter_setPosition(pCtrl, this->position); particleEmitter_setStartingScaleRange(pCtrl, 0.05f, 0.3f); particleEmitter_setAngularVelocityRange(pCtrl, @@ -68,35 +76,35 @@ void chGnawtyBoulder_setNextState(Actor *this, s32 next_state) { ActorLocal_CCW_7120 *local = (ActorLocal_CCW_7120 *)&this->local; local->unk0 = 0.0f; - if (next_state == 2) { + if (next_state == GNAWTY_BOULDER_STATE_2_BREAK) { this->marker->propPtr->unk8_3 = false; func_802BB3DC(0, 60.0f, 0.7f); - CCW_func_8038D510(this); - func_8038D5DC(this); + chGnawtyBoulder_emitSmoke(this); + chGnawtyBoulder_emitRock(this); FUNC_8030E624(SFX_9B_BOULDER_BREAKING_1, 0.3f, 15000); FUNC_8030E624(SFX_9B_BOULDER_BREAKING_1, 0.5f, 15000); FUNC_8030E624(SFX_9B_BOULDER_BREAKING_1, 0.7f, 15000); FUNC_8030E624(SFX_9B_BOULDER_BREAKING_1, 0.9f, 15000); func_80324E38(0.0f, 3); timed_setStaticCameraToNode(0.5f, 3); - timedFunc_set_2(0.5f, (GenFunction_2)levelSpecificFlags_set, LEVEL_FLAG_25_CCW_UNKNOWN, true); + timedFunc_set_2(0.5f, (GenFunction_2)levelSpecificFlags_set, LEVEL_FLAG_25_CCW_GNAWTY_JIGGY_COLLECTED, true); timed_exitStaticCamera(4.0f); func_80324E38(4.0f, 0); local->unk0 = 0.5f; marker_despawn(this->marker); } - if (next_state == 3) { + if (next_state == GNAWTY_BOULDER_STATE_3_DESPAWN) { marker_despawn(this->marker); } this->state = next_state; } -void func_8038D81C(ActorMarker* marker, ActorMarker *other_marker) { +void chGnawtyBoulder_die(ActorMarker* marker, ActorMarker *other_marker) { Actor* actor = marker_getActor(marker); - if (actor->state == 1) { + if (actor->state == GNAWTY_BOULDER_STATE_1_IDLE) { // [port] v1.1 fix: rock is indestructible in Spring (prevents sequence break) if (EventSystem_Should(VB_CCW_GNAWTY_SPRING_ROCK, gsworld_getMap() != MAP_43_CCW_SPRING)) { - chGnawtyBoulder_setNextState(actor, 2); + chGnawtyBoulder_setNextState(actor, GNAWTY_BOULDER_STATE_2_BREAK); } } } @@ -109,28 +117,30 @@ void chGnawtyBoulder_update(Actor *this) { if (!this->volatile_initialized) { this->marker->propPtr->unk8_3 = true; this->volatile_initialized = true; - marker_setCollisionScripts(this->marker, NULL, &func_8038D81C, NULL); - chGnawtyBoulder_setNextState(this, 1); + marker_setCollisionScripts(this->marker, NULL, &chGnawtyBoulder_die, NULL); + chGnawtyBoulder_setNextState(this, GNAWTY_BOULDER_STATE_1_IDLE); if (jiggyscore_isCollected(JIGGY_4B_CCW_GNAWTY) != false) { - levelSpecificFlags_set(LEVEL_FLAG_25_CCW_UNKNOWN, true); + levelSpecificFlags_set(LEVEL_FLAG_25_CCW_GNAWTY_JIGGY_COLLECTED, true); } - if ((levelSpecificFlags_get(LEVEL_FLAG_25_CCW_UNKNOWN) != false) && (gsworld_getMap() != MAP_43_CCW_SPRING)) { + if ((levelSpecificFlags_get(LEVEL_FLAG_25_CCW_GNAWTY_JIGGY_COLLECTED) != false) + && (gsworld_getMap() != MAP_43_CCW_SPRING)) + { marker_despawn(this->marker); } return; } // Anchor: teammate broke the boulder — despawn live (no break cutscene). - if (this->state == 1 - && levelSpecificFlags_get(LEVEL_FLAG_25_CCW_UNKNOWN) + if (this->state == GNAWTY_BOULDER_STATE_1_IDLE + && levelSpecificFlags_get(LEVEL_FLAG_25_CCW_GNAWTY_JIGGY_COLLECTED) && gsworld_getMap() != MAP_43_CCW_SPRING) { marker_despawn(this->marker); return; } - if(this->state == 2){ + if(this->state == GNAWTY_BOULDER_STATE_2_BREAK){ if (ml_timer_update(&local->unk0, tick) ) { - chGnawtyBoulder_setNextState(this, 3); + chGnawtyBoulder_setNextState(this, GNAWTY_BOULDER_STATE_3_DESPAWN); } } } diff --git a/src/CCW/ch/grublinhood.c b/src/CCW/ch/grublinhood.c index 2e99ab8aa..0e1ffac87 100644 --- a/src/CCW/ch/grublinhood.c +++ b/src/CCW/ch/grublinhood.c @@ -7,17 +7,9 @@ extern void func_802DABA0(ParticleEmitter *, f32[3], f32, enum asset_e); -extern void func_8033A45C(s32, s32); +extern void modelRender_setAppendageVisibility(s32, s32); extern void humanoidBaddie_ow(ActorMarker *, ActorMarker *); -enum ccw_season_e -{ - SPRING, - SUMMER, - AUTUMN, - WINTER -}; - void chgrublinhood_update(Actor *this); Actor *chgrublinhood_draw(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx); @@ -80,18 +72,18 @@ Actor *chgrublinhood_draw(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx){ this = marker_getActor(marker); local = (Humanoid_Baddies_Actor *)&this->local; - func_8033A45C(3, (local->baddieSpecific == SUMMER) ? 1 : 2); - func_8033A45C(4, (local->baddieSpecific == SUMMER) ? 1 : 2); - func_8033A45C(5, (local->baddieSpecific < AUTUMN) ? 1 : 2); - func_8033A45C(6, (local->baddieSpecific < AUTUMN) ? 1 : 2); - func_8033A45C(7, (local->baddieSpecific < AUTUMN) ? 1 : 2); - func_8033A45C(8, (local->baddieSpecific < AUTUMN) ? 1 : 2); - func_8033A45C(9, (local->baddieSpecific == SUMMER) ? 1 : 0); - func_8033A45C(10, (local->baddieSpecific < AUTUMN) ? 0 : (local->baddieSpecific == AUTUMN) ? 1 : 2); - func_8033A45C(11, (local->baddieSpecific < AUTUMN) ? 0 : (local->baddieSpecific == AUTUMN) ? 1 : 2); - func_8033A45C(12, (local->baddieSpecific == WINTER) ? 2 : 1); - func_8033A45C(13, (local->baddieSpecific == WINTER) ? 1 : 0); - func_8033A45C(14, (this->has_met_before)? false : true); + modelRender_setAppendageVisibility(3, (local->baddieSpecific == CCW_SEASON_1_SUMMER) ? 1 : 2); + modelRender_setAppendageVisibility(4, (local->baddieSpecific == CCW_SEASON_1_SUMMER) ? 1 : 2); + modelRender_setAppendageVisibility(5, (local->baddieSpecific < CCW_SEASON_2_AUTUMN) ? 1 : 2); + modelRender_setAppendageVisibility(6, (local->baddieSpecific < CCW_SEASON_2_AUTUMN) ? 1 : 2); + modelRender_setAppendageVisibility(7, (local->baddieSpecific < CCW_SEASON_2_AUTUMN) ? 1 : 2); + modelRender_setAppendageVisibility(8, (local->baddieSpecific < CCW_SEASON_2_AUTUMN) ? 1 : 2); + modelRender_setAppendageVisibility(9, (local->baddieSpecific == CCW_SEASON_1_SUMMER) ? 1 : 0); + modelRender_setAppendageVisibility(10, (local->baddieSpecific < CCW_SEASON_2_AUTUMN) ? 0 : (local->baddieSpecific == CCW_SEASON_2_AUTUMN) ? 1 : 2); + modelRender_setAppendageVisibility(11, (local->baddieSpecific < CCW_SEASON_2_AUTUMN) ? 0 : (local->baddieSpecific == CCW_SEASON_2_AUTUMN) ? 1 : 2); + modelRender_setAppendageVisibility(12, (local->baddieSpecific == CCW_SEASON_3_WINTER) ? 2 : 1); + modelRender_setAppendageVisibility(13, (local->baddieSpecific == CCW_SEASON_3_WINTER) ? 1 : 0); + modelRender_setAppendageVisibility(14, (this->has_met_before)? false : true); return actor_draw(marker, gfx, mtx, vtx); } @@ -121,14 +113,14 @@ enum ccw_season_e __get_current_season(Actor *this){ case MAP_5B_CCW_SPRING_ZUBBA_HIVE:// 8038E930 case MAP_5E_CCW_SPRING_NABNUTS_HOUSE:// 8038E930 case MAP_65_CCW_SPRING_WHIPCRACK_ROOM:// 8038E930 - return SPRING; + return CCW_SEASON_0_SPRING; case MAP_44_CCW_SUMMER:// 8038E938 case MAP_4B_CCW_SUMMER_MUMBOS_SKULL:// 8038E938 case MAP_5A_CCW_SUMMER_ZUBBA_HIVE:// 8038E938 case MAP_5F_CCW_SUMMER_NABNUTS_HOUSE:// 8038E938 case MAP_66_CCW_SUMMER_WHIPCRACK_ROOM:// 8038E938 - return SUMMER; + return CCW_SEASON_1_SUMMER; case MAP_45_CCW_AUTUMN:// 8038E940 case MAP_4C_CCW_AUTUMN_MUMBOS_SKULL:// 8038E940 @@ -136,7 +128,7 @@ enum ccw_season_e __get_current_season(Actor *this){ case MAP_60_CCW_AUTUMN_NABNUTS_HOUSE:// 8038E940 case MAP_63_CCW_AUTUMN_NABNUTS_WATER_SUPPLY:// 8038E940 case MAP_67_CCW_AUTUMN_WHIPCRACK_ROOM:// 8038E940 - return AUTUMN; + return CCW_SEASON_2_AUTUMN; case MAP_46_CCW_WINTER:// 8038E948 case MAP_4D_CCW_WINTER_MUMBOS_SKULL:// 8038E948 @@ -144,11 +136,10 @@ enum ccw_season_e __get_current_season(Actor *this){ case MAP_62_CCW_WINTER_HONEYCOMB_ROOM:// 8038E948 case MAP_64_CCW_WINTER_NABNUTS_WATER_SUPPLY:// 8038E948 case MAP_68_CCW_WINTER_WHIPCRACK_ROOM:// 8038E948 - return WINTER; + return CCW_SEASON_3_WINTER; default: - return SPRING; - + return CCW_SEASON_0_SPRING; } } diff --git a/src/CCW/ch/indoorsgnawty.c b/src/CCW/ch/indoorsgnawty.c new file mode 100644 index 000000000..dd9facb2d --- /dev/null +++ b/src/CCW/ch/indoorsgnawty.c @@ -0,0 +1,98 @@ +// BanjoDecomp: CCW/ch/indoorsgnawty.c +#include +#include "functions.h" +#include "variables.h" + +typedef struct{ + s16 map; + s16 meetBeforeJiggyDialog; + s16 meetAfterJiggyDialog; +} CH_Indoors_Gnawty_Dialogs; + +typedef struct{ + CH_Indoors_Gnawty_Dialogs *dialogs; +} ActorLocal_chIndoorsGnawty; + +void chIndoorsGnawty_update(Actor *this); +Actor *chIndoorsGnawty_draw(ActorMarker* marker, Gfx** gfx, Mtx** mtx, Vtx** vtx); + +/* .data */ +CH_Indoors_Gnawty_Dialogs chIndoorsGnawtyDialogs[] = { + { + MAP_45_CCW_AUTUMN, + VER_SELECT(ASSET_CD2_DIALOG_GNAWTY_MEET_FALL_INSIDE, 0x9E7, 0, 0), + NULL + }, + { + MAP_46_CCW_WINTER, + VER_SELECT(ASSET_CD4_DIALOG_GNAWTY_MEET_WINTER_INSIDE_JIGGY, 0x09E9, 0, 0), + VER_SELECT(ASSET_CD5_DIALOG_GNAWTY_MEET_WINTER_INSIDE_AFTER_JIGGY, 0x09EA, 0, 0) + }, + { 0 } // [port] decomp uses NULL; first field is an integer and clang errors on -Wint-conversion +}; + +ActorInfo chIndoorsGnawty = { + MARKER_1CE_INDOOR_GNAWTY, ACTOR_31A_INDOORS_GNAWTY, ASSET_48F_MODEL_GNAWTY, + 0x0, NULL, + chIndoorsGnawty_update, NULL, chIndoorsGnawty_draw, + 0, 0, 2.2f, 0 +}; + +enum chIndoorsGnawty_State_e { + CH_INDOOR_GNAWTY_STATE_0_NOT_INIT, + CH_INDOOR_GNAWTY_STATE_1_IDLE +}; + +/* .code */ +void chIndoorsGnawty_setNextState(Actor *this, s32 next_state) { + if (next_state == CH_INDOOR_GNAWTY_STATE_1_IDLE) { + skeletalAnim_set(this->unk148, ASSET_1A6_ANIM_GNAWTY_IDLE, 0.2f, 5.5f); + } + + this->state = next_state; +} + +Actor *chIndoorsGnawty_draw(ActorMarker* marker, Gfx** gfx, Mtx** mtx, Vtx** vtx) { + if (levelSpecificFlags_get(LEVEL_FLAG_25_CCW_GNAWTY_JIGGY_COLLECTED) == false) { + return func_80325340(marker, gfx, mtx, vtx); + } + + return actor_draw(marker, gfx, mtx, vtx); +} + +void chIndoorsGnawty_update(Actor *this) { + ActorLocal_chIndoorsGnawty *local; + f32 plyr_pos[3]; + + local = (ActorLocal_chIndoorsGnawty *)&this->local; + if (!this->volatile_initialized) { + this->marker->propPtr->unk8_3 = true; + this->volatile_initialized = true; + this->has_met_before = false; + local->dialogs = chIndoorsGnawtyDialogs; + while (local->dialogs->map != NULL && gsworld_getMap() != local->dialogs->map) { + local->dialogs++; + } + + chIndoorsGnawty_setNextState(this, CH_INDOOR_GNAWTY_STATE_1_IDLE); + if (jiggyscore_isCollected(JIGGY_4B_CCW_GNAWTY)) { + levelSpecificFlags_set(LEVEL_FLAG_25_CCW_GNAWTY_JIGGY_COLLECTED, true); + } + return; + } + + if(!this->has_met_before){ + player_getPosition(plyr_pos); + if (ml_vec3f_distance(this->position, plyr_pos) < 600.0f) { + if (!jiggyscore_isCollected(JIGGY_4B_CCW_GNAWTY)) { + gcdialog_showDialog(local->dialogs->meetBeforeJiggyDialog, 4, NULL, NULL, NULL, NULL); + } else { + if (local->dialogs->meetAfterJiggyDialog) { + gcdialog_showDialog(local->dialogs->meetAfterJiggyDialog, 4, NULL, NULL, NULL, NULL); + } + } + this->has_met_before = true; + } + } + +} diff --git a/src/CCW/ch/nabnut_autumn.c b/src/CCW/ch/nabnut_autumn.c deleted file mode 100644 index 3bf0931f8..000000000 --- a/src/CCW/ch/nabnut_autumn.c +++ /dev/null @@ -1,194 +0,0 @@ -// BanjoDecomp: code_5540.c -#include -#include "functions.h" -#include "variables.h" -#include "port/Patches/Patches.h" - -// Anchor: set during a remote completion replay; skips the finisher's camera/dialog. -static s32 sNabnutRemote = 0; - -typedef struct { - s32 returned_acorn_count; -}ActorLocal_CCW_5540; - -void chnabnut_setState(Actor *this, s32 next_state); -Actor *chnabnut_draw(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx); -void chnabnut_update(Actor *this); - -enum nabnut_state_e{ - NABNUT_STATE_1_SAD = 1, - NABNUT_STATE_2_WAIT, - NABNUT_STATE_3_BACKFLIP, - NABNUT_STATE_4_THANK_PLAYER, - NABNUT_STATE_5_EXIT, - NABNUT_STATE_6_DESPAWN -}; - -/* .data */ -f32 D_8038F350[3] = {0.0f, 0.0f, 0.0f}; -ActorInfo D_8038F35C = { - MARKER_1BB_NABNUT, ACTOR_2A8_NABNUT, ASSET_502_MODEL_NABNUT, - 0x0, NULL, - chnabnut_update, chnabnut_update, chnabnut_draw, - 0, 0, 1.2f, 0 -}; - -/* .code */ -void __chnabnut_setState_method(ActorMarker* marker, s32 next_state) { - chnabnut_setState(marker_getActor(marker), next_state); -} - -void chnabnut_setState(Actor *this, s32 next_state) { - - if (next_state == NABNUT_STATE_1_SAD) { - skeletalAnim_set(this->unk148, ASSET_22C_ANIM_NABNUT_CRY, 0.2f, 10.6f); - } - - if (next_state == NABNUT_STATE_2_WAIT) { - timedFunc_set_2(1.0f, (GenFunction_2)__chnabnut_setState_method, (uintptr_t)this->marker, NABNUT_STATE_3_BACKFLIP); - } - - if (next_state == NABNUT_STATE_3_BACKFLIP) { - this->marker->propPtr->unk8_3 = false; - skeletalAnim_set(this->unk148, ASSET_22D_ANIM_NABNUT_BACKFLIP, 0.2f, 3.13f); - skeletalAnim_setBehavior(this->unk148, SKELETAL_ANIM_2_ONCE); - if (!sNabnutRemote) { - func_80324E38(0.0f, 3); - timed_setStaticCameraToNode(0.0f, 0xB); - gcdialog_showDialog(0xCCC, 0x20, this->position, NULL, NULL, NULL); - } - } - - if (next_state == NABNUT_STATE_4_THANK_PLAYER) { - skeletalAnim_set(this->unk148, ASSET_22E_ANIM_NABNUT_STAND, 0.2f, 3.53f); - skeletalAnim_setBehavior(this->unk148, SKELETAL_ANIM_1_LOOP); - bundle_setYaw(this->yaw - 40.0f); - if (!jiggyscore_isSpawned(JIGGY_4A_CCW_NABNUT)) { - jiggy_spawn(JIGGY_4A_CCW_NABNUT, this->position); - } - } - - if (next_state == NABNUT_STATE_5_EXIT) { - skeletalAnim_set(this->unk148, ASSET_22F_ANIM_NABNUT_RUN, 0.2f, 0.34f); - } - - if (next_state == NABNUT_STATE_6_DESPAWN) { - if (!sNabnutRemote) { - func_80324E38(0.0f, 0); - timed_exitStaticCamera(0.0f); - } - marker_despawn(this->marker); - } - - this->state = next_state; -} - -Actor *chnabnut_draw(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx) { - Actor *this; - Actor *out; - void *sp24; - f32 temp_f2; - - this = marker_getActor(marker); - func_8033A45C(3, 0); - func_8033A45C(4, 0); - func_8033A45C(5, 1); - func_8033A45C(6, 0); - func_8033A45C(7, 1); - func_8033A45C(8, 1); - func_8033A45C(9, 0); - func_8033A45C(0xA, 1); - if (this->state == 1) { - temp_f2 = skeletalAnim_getProgress(this->unk148); - if ((0.116 <= temp_f2) && (temp_f2 <= 0.32)) { - sp24 = this->unk130; - this->unk130 = NULL; - func_8033A45C(1, 4); - out = actor_draw(marker, gfx, mtx, vtx); - out->unk130 = sp24; - return out; - } - } - return actor_draw(marker, gfx, mtx, vtx); -} - -void func_8038BC50(f32 dst[3]){ - dst[0] = D_8038F350[0]; - dst[1] = D_8038F350[1]; - dst[2] = D_8038F350[2]; -} - -void chnabnut_update(Actor *this) { - ActorLocal_CCW_5540 *local; - f32 sp30[3]; - f32 sp2C; - f32 sp28; - f32 sp24; - - local = (ActorLocal_CCW_5540 *)&this->local; - if (!this->volatile_initialized) { - this->volatile_initialized = true; - D_8038F350[0] = this->position[0]; - D_8038F350[1] = this->position[1]; - D_8038F350[2] = this->position[2]; - if (this->state == 0) { - this->has_met_before = false; - local->returned_acorn_count = port_puzzleCount_get(ANCHOR_COUNT_CCW_NABNUT_ACORNS); - sNabnutRemote = 0; - } - chnabnut_setState(this, 1); - if(jiggyscore_isSpawned(JIGGY_4A_CCW_NABNUT)) { - marker_despawn(this->marker); - } - return; - } - - if (this->state == NABNUT_STATE_1_SAD) { - player_getPosition(sp30); - if (!this->has_met_before && (ml_vec3f_distance(this->position, sp30) < 400.0f)) { - this->has_met_before = true; - gcdialog_showDialog(0xCCA, 0xE, this->position, NULL, NULL, NULL); - } - if (item_getCount(ITEM_23_ACORNS) > 0) { - func_80258A4C(this->position, this->yaw - 90.0f, sp30, &sp2C, &sp28, &sp24); - this->yaw += sp24 * 10.0f; - } - if (this->has_met_before && !gcdialog_hasCurrentTextId()) { - player_setCarryObjectPoseInCylinder(this->position, 500.0f, 200.0f, ACTOR_2A9_ACORN, &this); - if ((carriedObj_getActorId() == ACTOR_2A9_ACORN) && (ml_vec3f_distance(this->position, sp30) < 300.0f) && player_throwCarriedObject()) { - player_setThrowTargetPosition(D_8038F350); - port_puzzleCount_add(ANCHOR_COUNT_CCW_NABNUT_ACORNS, 1); - local->returned_acorn_count = port_puzzleCount_get(ANCHOR_COUNT_CCW_NABNUT_ACORNS); - if (local->returned_acorn_count >= 6) { - chnabnut_setState(this, NABNUT_STATE_2_WAIT); - } else if (item_getCount(ITEM_23_ACORNS) == 1) { - gcdialog_showDialog(0xCCB, 0x20, this->position, NULL, NULL, NULL); - } - } - } - if (this->state == NABNUT_STATE_1_SAD) { - s32 sharedReturned = port_puzzleCount_get(ANCHOR_COUNT_CCW_NABNUT_ACORNS); - if (sharedReturned > local->returned_acorn_count) { - local->returned_acorn_count = sharedReturned; - if (sharedReturned >= 6) { - sNabnutRemote = 1; - chnabnut_setState(this, NABNUT_STATE_2_WAIT); - } - } - } - } - if ((this->state == NABNUT_STATE_3_BACKFLIP) && (skeletalAnim_getLoopCount(this->unk148) > 0)) { - chnabnut_setState(this, NABNUT_STATE_4_THANK_PLAYER); - } - if ((this->state == NABNUT_STATE_4_THANK_PLAYER) && (skeletalAnim_getLoopCount(this->unk148) > 0)) { - chnabnut_setState(this, NABNUT_STATE_5_EXIT); - } - if (this->state == NABNUT_STATE_5_EXIT) { - actor_update_func_80326224(this); - func_8028FC8C(this->position); - if (0.99 < this->unk48) { - chnabnut_setState(this, NABNUT_STATE_6_DESPAWN); - } - } - func_8028E668(this->position, 300.0f, -50.0f, 120.0f); -} diff --git a/src/CCW/ch/nabnut_dialog.c b/src/CCW/ch/nabnut_dialog.c deleted file mode 100644 index 27565536b..000000000 --- a/src/CCW/ch/nabnut_dialog.c +++ /dev/null @@ -1,85 +0,0 @@ -// BanjoDecomp: code_6EC0.c -#include -#include "functions.h" -#include "variables.h" - -typedef struct{ - s16 map; - s16 unk2; - s16 unk4; -}Struct_CCW_6EC0_0; - -typedef struct{ - Struct_CCW_6EC0_0 *unk0; -}ActorLocal_CCW_6EC0; - -void func_8038D368(Actor *this); -Actor *func_8038D30C(ActorMarker* marker, Gfx** gfx, Mtx** mtx, Vtx** vtx); - -/* .data */ -Struct_CCW_6EC0_0 D_8038F600[] = { - {MAP_45_CCW_AUTUMN, 0xCD2, 0}, - {MAP_46_CCW_WINTER, 0xCD4, 0xCD5}, - 0 -}; - -ActorInfo D_8038F614 = { - 0x1CE, 0x31A, 0x48F, - 0x0, NULL, - func_8038D368, NULL, func_8038D30C, - 0, 0, 2.2f, 0 -}; - -/* .code */ -void func_8038D2B0(Actor *this, s32 next_state) { - if (next_state == 1) { - skeletalAnim_set(this->unk148, 0x1A6, 0.2f, 5.5f); - } - - this->state = next_state; -} - -Actor *func_8038D30C(ActorMarker* marker, Gfx** gfx, Mtx** mtx, Vtx** vtx) { - if (levelSpecificFlags_get(LEVEL_FLAG_25_CCW_UNKNOWN) == false) { - return func_80325340(marker, gfx, mtx, vtx); - } - - return actor_draw(marker, gfx, mtx, vtx); -} - -void func_8038D368(Actor *this) { - ActorLocal_CCW_6EC0 *local; - f32 plyr_pos[3]; - - local = (ActorLocal_CCW_6EC0 *)&this->local; - if (!this->volatile_initialized) { - this->marker->propPtr->unk8_3 = true; - this->volatile_initialized = true; - this->has_met_before = false; - local->unk0 = D_8038F600; - while (local->unk0->map != 0 && gsworld_getMap() != local->unk0->map) { - local->unk0++; - } - - func_8038D2B0(this, 1); - if (jiggyscore_isCollected(JIGGY_4B_CCW_GNAWTY)) { - levelSpecificFlags_set(LEVEL_FLAG_25_CCW_UNKNOWN, true); - } - return; - } - - if(!this->has_met_before){ - player_getPosition(plyr_pos); - if (ml_vec3f_distance(this->position, plyr_pos) < 600.0f) { - if (!jiggyscore_isCollected(JIGGY_4B_CCW_GNAWTY)) { - gcdialog_showDialog(local->unk0->unk2, 4, NULL, NULL, NULL, NULL); - } else { - if (local->unk0->unk4) { - gcdialog_showDialog(local->unk0->unk4, 4, NULL, NULL, NULL, NULL); - } - } - this->has_met_before = true; - } - } - -} diff --git a/src/CCW/ch/nabnut_spring.c b/src/CCW/ch/nabnut_spring.c deleted file mode 100644 index e502ca7ea..000000000 --- a/src/CCW/ch/nabnut_spring.c +++ /dev/null @@ -1,97 +0,0 @@ -// BanjoDecomp: code_4D00.c -#include -#include "functions.h" -#include "variables.h" - -typedef struct { - f32 unk0; -}ActorLocal_CCW_4D00; - -typedef struct { - f32 unk0; - f32 unk4; - s16 unk8; - s16 unkA; -}Struct_CCW_4D00_0; - -void func_8038B19C(Actor *this); - -/* .data */ -ActorInfo D_8038F270 = { - 0x1B9, 0x2A6, 0x502, - 0x0, NULL, - func_8038B19C, NULL, actor_draw, - 0, 0, 0.0f, 0 -}; - -Struct_CCW_4D00_0 D_8038F294[] = { - {0.12f, 1.6f, SFX_A7_WOODEN_SWOSH, 8000}, - {0.21f, 1.7f, SFX_A7_WOODEN_SWOSH, 8500}, - {0.3f , 1.6f, SFX_A7_WOODEN_SWOSH, 8000}, - {0.51f, 1.0f, SFX_4C_LIP_SMACK, 22000}, - {0.65f, 1.05f, SFX_4C_LIP_SMACK, 23000}, - {0.76f, 1.0f, SFX_4C_LIP_SMACK, 22000}, - {0.88f, 1.0f, SFX_4C_LIP_SMACK, 23000}, - 0 -}; - -/* .code */ -void func_8038B0F0(Actor *this, s32 next_state) { - ActorLocal_CCW_4D00 *local = (ActorLocal_CCW_4D00 *)&this->local; - - local->unk0 = 0.0f; - if (next_state == 1) { - skeletalAnim_swap(this->unk148, 0x1A3, 0.2f, 11.0f); - local->unk0 = randf2(3.0f, 10.0f); - } - if (next_state == 2) { - skeletalAnim_set(this->unk148, 0x1A4, 0.2f, 3.0f); - } - this->state = next_state; -} - -void func_8038B19C(Actor *this) { - ActorLocal_CCW_4D00 *local; - f32 tick; - Struct_CCW_4D00_0 *iPtr; - f32 sp50; - f32 sp4C; - - local = (ActorLocal_CCW_4D00 *)&this->local; - tick = time_getDelta(); - - if (!this->volatile_initialized) { - this->volatile_initialized = true; - this->has_met_before = false; - func_8038B0F0(this, 1); - } - - if ((this->state == 1) && ml_timer_update(&local->unk0, tick)) { - func_8038B0F0(this, 2); - } - - if (this->state == 2) { - skeletalAnim_getProgressRange(this->unk148, &sp50, &sp4C); - for(iPtr = &D_8038F294[0]; iPtr->unk0 > 0.0f; iPtr++){ - if ((sp50 < iPtr->unk0) && (iPtr->unk0 <= sp4C)) { - func_8030E878(iPtr->unk8, randf2(iPtr->unk4 - 0.05, iPtr->unk4 + 0.05), randi2(iPtr->unkA - 0x1F4, iPtr->unkA + 0x1F4), this->position, 500.0f, 2500.0f); - } - } - - if ((sp50 < 0.97) && (0.97 <= sp4C)) { - if (randf() >= 0.5) { - func_8030E878(SFX_AE_YUMYUM_TALKING, randf2(1.8f, 1.85f), randi2(19000, 21000), this->position, 500.0f, 2500.0f); - } else { - func_8030E878(SFX_4B_GULPING, randf2(1.4f, 1.45f), randi2(24000, 26000), this->position, 500.0f, 2500.0f); - } - } - if (skeletalAnim_getLoopCount(this->unk148) > 0) { - func_8038B0F0(this, 1); - } - } - if (!this->has_met_before && func_803292E0(this)) { - this->has_met_before = true; - gcdialog_showDialog(0xCC8, 0, NULL, NULL, NULL, NULL); - } - func_8028E668(this->position, 300.0f, -50.0f, 120.0f); -} diff --git a/src/CCW/ch/nabnut_winter.c b/src/CCW/ch/nabnut_winter.c deleted file mode 100644 index a1aac88c5..000000000 --- a/src/CCW/ch/nabnut_winter.c +++ /dev/null @@ -1,124 +0,0 @@ -// BanjoDecomp: code_5BF0.c -#include -#include "functions.h" -#include "variables.h" - -extern void func_8028E668(f32[3], f32, f32, f32); - -Actor *func_8038C380(ActorMarker* marker, Gfx** gfx, Mtx** mtx, Vtx** vtx); -void func_8038C41C(Actor *this); - -/* .data */ -ActorInfo D_8038F380 = { 0x1C6, 0x310, 0x501, 0x0, NULL, func_8038C41C, NULL, actor_draw, 0, 0, 0.0f, 0}; -ActorInfo D_8038F3A4 = { 0x1C7, 0x311, 0x462, 0x0, NULL, func_8038C41C, NULL, func_8038C380, 0, 0, 0.0f, 0}; -ActorInfo D_8038F3C8 = { 0x1C8, 0x312, 0x463, 0x0, NULL, func_8038C41C, NULL, actor_draw, 0, 0, 0.0f, 0}; -ActorInfo D_8038F3EC = { 0x1C9, 0x313, 0x464, 0x0, NULL, func_8038C41C, NULL, actor_draw, 0, 0, 0.0f, 0}; -ActorInfo D_8038F410 = { 0x1CA, 0x314, 0x502, 0x0, NULL, func_8038C41C, NULL, actor_draw, 0, 0, 2.0f, 0}; -ActorInfo D_8038F434 = { 0x1CB, 0x315, 0x48D, 0x0, NULL, func_8038C41C, NULL, func_8038C380, 0, 0, 0.0f, 0}; - -/* .code */ -void func_8038BFE0(ActorMarker* marker) { - Actor* sp2C = marker_getActor(marker); - func_8030E878(SFX_5D_BANJO_RAAOWW, randf2(1.0f, 1.1f), (s32)randf2(21000.0f, 22000.0f), sp2C->position, 500.0f, 2500.0f); -} - -void func_8038C064(ActorMarker* marker) { - Actor* sp2C = marker_getActor(marker); - func_8030E878(SFX_5E_BANJO_PHEWWW, randf2(1.0f, 1.1f), (s32)randf2(21000.0f, 22000.0f), sp2C->position, 500.0f, 2500.0f); -} - -void func_8038C0E8(ActorMarker* marker) { - Actor* sp24 = marker_getActor(marker); - f32 sp20 = randf2(0.9f, 1.1f); - - func_8030E878(SFX_81_UUU, sp20, (s32)randf2(10000.0f, 31000.0f), sp24->position, 500.0f, 2500.0f); -} - -void CCW_func_8038C16C(Actor *this, s32 next_state) { - Actor *other; - - if (next_state == 1) { - this->position[1] -= 300.0f; - } - - if (this->state == 1) { - this->position[1] += 300.0f; - } - - if (next_state == 2) { - if (this->marker->id == 0x1CA) { - skeletalAnim_set(this->unk148, 0x22E, 0.2f, 3.53f); - skeletalAnim_setCallback_1(this->unk148, 0.1f, (GenFunction_1)func_8038C0E8, (uintptr_t)this->marker); - } - if (this->marker->id == 0x1C7) { - skeletalAnim_set(this->unk148, 0x230, 0.2f, 4.0f); - } - if (this->marker->id == 0x1CB) { - skeletalAnim_set(this->unk148, 0x1A2, 0.2f, 4.0f); - skeletalAnim_setCallback_1(this->unk148, 0.3f, (GenFunction_1)func_8038BFE0, (uintptr_t)this->marker); - skeletalAnim_setCallback_1(this->unk148, 0.65f, (GenFunction_1)func_8038C064, (uintptr_t)this->marker); - } - if (this->marker->id == 0x1C8) { - skeletalAnim_set(this->unk148, 0x231, 0.2f, 4.0f); - } - if ((this->marker->id == 0x1C7) || (this->marker->id == 0x1CB) || (this->marker->id == 0x1C8)) { - other = actorArray_findActorFromActorId(0x313); - if (other != 0) { - this->position[0] = other->position[0]; - this->position[1] = other->position[1]; - this->position[2] = other->position[2]; - this->pitch = other->pitch; - this->yaw = other->yaw; - this->roll = other->roll; - } - } - } - this->state = next_state; -} - -Actor *func_8038C380(ActorMarker* marker, Gfx** gfx, Mtx** mtx, Vtx** vtx) { - func_8033A45C(3, 0); - func_8033A45C(4, 0); - func_8033A45C(5, 0); - func_8033A45C(6, 1); - func_8033A45C(7, 0); - func_8033A45C(8, 0); - func_8033A45C(9, 0); - func_8033A45C(0xA, 1); - return actor_draw(marker, gfx, mtx, vtx); -} - -void func_8038C41C(Actor *this) { - f32 sp2C[3]; - - if (!this->volatile_initialized) { - this->marker->propPtr->unk8_3 = true; - this->volatile_initialized = true; - this->has_met_before = false; - return; - } - - if (this->state == 0) { - if( gsworld_getMap() == MAP_60_CCW_AUTUMN_NABNUTS_HOUSE - && !jiggyscore_isSpawned(JIGGY_4A_CCW_NABNUT) - && (this->marker->id == 0x1C6 || this->marker->id == 0x1CA) - ){ - CCW_func_8038C16C(this, 1); - } else { - CCW_func_8038C16C(this, 2); - } - } - - if ((this->marker->id == 0x1CA) && (this->state != 1)) { - func_8028E668(this->position, 300.0f, -50.0f, 120.0f); - } - - if ((this->marker->id == 0x1CB) && (this->state == 2)) { - player_getPosition(sp2C); - if (!this->has_met_before && (ml_vec3f_distance(this->position, sp2C) < 400.0f)) { - this->has_met_before = true; - gcdialog_showDialog(0xCCD, 0, NULL, NULL, NULL, NULL); - } - } -} - diff --git a/src/CCW/ch/outsideautumnnabnut.c b/src/CCW/ch/outsideautumnnabnut.c new file mode 100644 index 000000000..23893dd91 --- /dev/null +++ b/src/CCW/ch/outsideautumnnabnut.c @@ -0,0 +1,226 @@ +// BanjoDecomp: CCW/ch/outsideautumnnabnut.c +#include +#include "functions.h" +#include "variables.h" +#include "port/Patches/Patches.h" + +// Anchor: set during a remote completion replay; skips the finisher's camera/dialog. +static s32 sNabnutRemote = 0; + +typedef struct { + s32 returned_acorn_count; +}ActorLocal_ChAutumnNabnutPosition; + +void chAutumnOutsideNabnut_setState(Actor *this, s32 next_state); +Actor *__chAutumnOutsideNabnut_draw(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx); +void chAutumnOutsideNabnut_update(Actor *this); + +enum chautumnoutdoornabnut_state_e{ + CH_AUTUMN_OUTDOOR_NABNUT_STATE_0_NOT_INIT, + CH_AUTUMN_OUTDOOR_NABNUT_STATE_1_SAD, + CH_AUTUMN_OUTDOOR_NABNUT_STATE_2_WAIT, + CH_AUTUMN_OUTDOOR_NABNUT_STATE_3_BACKFLIP, + CH_AUTUMN_OUTDOOR_NABNUT_STATE_4_THANK_PLAYER, + CH_AUTUMN_OUTDOOR_NABNUT_STATE_5_EXIT, + CH_AUTUMN_OUTDOOR_NABNUT_STATE_6_DESPAWN +}; + +/* .data */ +f32 chAutumnOutdoorNabnutPosition[3] = {0.0f, 0.0f, 0.0f}; // updates on init + +#define AUTUMN_NABNUT_ACORN_COUNT 6 + +ActorInfo chAutumnOutdoorNabnut = { + MARKER_1BB_NABNUT, ACTOR_2A8_NABNUT, ASSET_502_MODEL_NABNUT, + 0x0, NULL, + chAutumnOutsideNabnut_update, chAutumnOutsideNabnut_update, __chAutumnOutsideNabnut_draw, + 0, 0, 1.2f, 0 +}; + +/* .code */ +void __chAutumnOutsideNabnut_setStateMethod(ActorMarker* marker, s32 next_state) { + chAutumnOutsideNabnut_setState(marker_getActor(marker), next_state); +} + +void chAutumnOutsideNabnut_setState(Actor *this, s32 next_state) { + + if (next_state == CH_AUTUMN_OUTDOOR_NABNUT_STATE_1_SAD) { + skeletalAnim_set(this->unk148, ASSET_22C_ANIM_NABNUT_CRY, 0.2f, 10.6f); + } + + if (next_state == CH_AUTUMN_OUTDOOR_NABNUT_STATE_2_WAIT) { + timedFunc_set_2( + 1.0f, + (GenFunction_2)__chAutumnOutsideNabnut_setStateMethod, + (uintptr_t)this->marker, + CH_AUTUMN_OUTDOOR_NABNUT_STATE_3_BACKFLIP); + } + + if (next_state == CH_AUTUMN_OUTDOOR_NABNUT_STATE_3_BACKFLIP) { + this->marker->propPtr->unk8_3 = false; + skeletalAnim_set(this->unk148, ASSET_22D_ANIM_NABNUT_BACKFLIP, 0.2f, 3.13f); + skeletalAnim_setBehavior(this->unk148, SKELETAL_ANIM_2_ONCE); + if (!sNabnutRemote) { + func_80324E38(0.0f, 3); + timed_setStaticCameraToNode(0.0f, 0xB); + gcdialog_showDialog( + VER_SELECT(ASSET_CCC_DIALOG_NABNUT_ACORN_COMPLETE, 0x09E1, 0, 0), + 0x20, this->position, + NULL, NULL, NULL); + } + } + + if (next_state == CH_AUTUMN_OUTDOOR_NABNUT_STATE_4_THANK_PLAYER) { + skeletalAnim_set(this->unk148, ASSET_22E_ANIM_NABNUT_STAND, 0.2f, 3.53f); + skeletalAnim_setBehavior(this->unk148, SKELETAL_ANIM_1_LOOP); + bundle_setYaw(this->yaw - 40.0f); + if (!jiggyscore_isSpawned(JIGGY_4A_CCW_NABNUT)) { + jiggy_spawn(JIGGY_4A_CCW_NABNUT, this->position); + } + } + + if (next_state == CH_AUTUMN_OUTDOOR_NABNUT_STATE_5_EXIT) { + skeletalAnim_set(this->unk148, ASSET_22F_ANIM_NABNUT_RUN, 0.2f, 0.34f); + } + + if (next_state == CH_AUTUMN_OUTDOOR_NABNUT_STATE_6_DESPAWN) { + if (!sNabnutRemote) { + func_80324E38(0.0f, 0); + timed_exitStaticCamera(0.0f); + } + marker_despawn(this->marker); + } + + this->state = next_state; +} + +Actor *__chAutumnOutsideNabnut_draw(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx) { + Actor *this; + Actor *out; + void *sp24; + f32 temp_f2; + + this = marker_getActor(marker); + modelRender_setAppendageVisibility(3, 0); + modelRender_setAppendageVisibility(4, 0); + modelRender_setAppendageVisibility(5, 1); + modelRender_setAppendageVisibility(6, 0); + modelRender_setAppendageVisibility(7, 1); + modelRender_setAppendageVisibility(8, 1); + modelRender_setAppendageVisibility(9, 0); + modelRender_setAppendageVisibility(0xA, 1); + if (this->state == CH_AUTUMN_OUTDOOR_NABNUT_STATE_1_SAD) { + temp_f2 = skeletalAnim_getProgress(this->unk148); + if ((0.116 <= temp_f2) && (temp_f2 <= 0.32)) { + sp24 = this->unk130; + this->unk130 = NULL; + modelRender_setAppendageVisibility(1, 4); + out = actor_draw(marker, gfx, mtx, vtx); + out->unk130 = sp24; + return out; + } + } + return actor_draw(marker, gfx, mtx, vtx); +} + +void chAutumnOutsideNabnut_getPosition(f32 dst[3]){ + dst[0] = chAutumnOutdoorNabnutPosition[0]; + dst[1] = chAutumnOutdoorNabnutPosition[1]; + dst[2] = chAutumnOutdoorNabnutPosition[2]; +} + +void chAutumnOutsideNabnut_update(Actor *this) { + ActorLocal_ChAutumnNabnutPosition *local; + f32 player_position[3]; + f32 horizontal_distance; + f32 distance_in_front; + f32 side_angle_radian; + + local = (ActorLocal_ChAutumnNabnutPosition *)&this->local; + if (!this->volatile_initialized) { + this->volatile_initialized = true; + chAutumnOutdoorNabnutPosition[0] = this->position[0]; + chAutumnOutdoorNabnutPosition[1] = this->position[1]; + chAutumnOutdoorNabnutPosition[2] = this->position[2]; + if (this->state == CH_AUTUMN_OUTDOOR_NABNUT_STATE_0_NOT_INIT) { + this->has_met_before = false; + local->returned_acorn_count = port_puzzleCount_get(ANCHOR_COUNT_CCW_NABNUT_ACORNS); + sNabnutRemote = 0; + } + chAutumnOutsideNabnut_setState(this, CH_AUTUMN_OUTDOOR_NABNUT_STATE_1_SAD); + if(jiggyscore_isSpawned(JIGGY_4A_CCW_NABNUT)) { + marker_despawn(this->marker); + } + return; + } + + if (this->state == CH_AUTUMN_OUTDOOR_NABNUT_STATE_1_SAD) { + player_getPosition(player_position); + if (!this->has_met_before + && (ml_vec3f_distance(this->position, player_position) < 400.0f)) + { + this->has_met_before = true; + gcdialog_showDialog( + VER_SELECT(ASSET_CCA_DIALOG_NABNUT_MEET_FALL, 0x09DF, 0, 0), + 0xE, this->position, + NULL, NULL, NULL); + } + if (item_getCount(ITEM_23_ACORNS) > 0) { + func_80258A4C( + this->position, + this->yaw - 90.0f, + player_position, + &horizontal_distance, + &distance_in_front, + &side_angle_radian); + this->yaw += side_angle_radian * 10.0f; + } + if (this->has_met_before && !gcdialog_hasCurrentTextId()) { + player_setCarryObjectPoseInCylinder(this->position, 500.0f, 200.0f, ACTOR_2A9_ACORN, &this); + if ((carriedObj_getActorId() == ACTOR_2A9_ACORN) + && (ml_vec3f_distance(this->position, player_position) < 300.0f) + && player_throwCarriedObject()) + { + player_setThrowTargetPosition(chAutumnOutdoorNabnutPosition); + port_puzzleCount_add(ANCHOR_COUNT_CCW_NABNUT_ACORNS, 1); + local->returned_acorn_count = port_puzzleCount_get(ANCHOR_COUNT_CCW_NABNUT_ACORNS); + if (local->returned_acorn_count >= AUTUMN_NABNUT_ACORN_COUNT) { + chAutumnOutsideNabnut_setState(this, CH_AUTUMN_OUTDOOR_NABNUT_STATE_2_WAIT); + } else if (item_getCount(ITEM_23_ACORNS) == 1) { + gcdialog_showDialog( + VER_SELECT(ASSET_CCB_DIALOG_NABNUT_ACORN_CHECK, 0x09E0, 0, 0), + 0x20, this->position, + NULL, NULL, NULL); + } + } + } + if (this->state == CH_AUTUMN_OUTDOOR_NABNUT_STATE_1_SAD) { + s32 sharedReturned = port_puzzleCount_get(ANCHOR_COUNT_CCW_NABNUT_ACORNS); + if (sharedReturned > local->returned_acorn_count) { + local->returned_acorn_count = sharedReturned; + if (sharedReturned >= AUTUMN_NABNUT_ACORN_COUNT) { + sNabnutRemote = 1; + chAutumnOutsideNabnut_setState(this, CH_AUTUMN_OUTDOOR_NABNUT_STATE_2_WAIT); + } + } + } + } + if ((this->state == CH_AUTUMN_OUTDOOR_NABNUT_STATE_3_BACKFLIP) + && (skeletalAnim_getLoopCount(this->unk148) > 0)) + { + chAutumnOutsideNabnut_setState(this, CH_AUTUMN_OUTDOOR_NABNUT_STATE_4_THANK_PLAYER); + } + if ((this->state == CH_AUTUMN_OUTDOOR_NABNUT_STATE_4_THANK_PLAYER) + && (skeletalAnim_getLoopCount(this->unk148) > 0)) + { + chAutumnOutsideNabnut_setState(this, CH_AUTUMN_OUTDOOR_NABNUT_STATE_5_EXIT); + } + if (this->state == CH_AUTUMN_OUTDOOR_NABNUT_STATE_5_EXIT) { + actor_update_func_80326224(this); + func_8028FC8C(this->position); + if (0.99 < this->unk48) { + chAutumnOutsideNabnut_setState(this, CH_AUTUMN_OUTDOOR_NABNUT_STATE_6_DESPAWN); + } + } + func_8028E668(this->position, 300.0f, -50.0f, 120.0f); +} diff --git a/src/CCW/ch/seasonswitchdoors.c b/src/CCW/ch/seasonswitchdoors.c new file mode 100644 index 000000000..ac19d4047 --- /dev/null +++ b/src/CCW/ch/seasonswitchdoors.c @@ -0,0 +1,239 @@ +// BanjoDecomp: CCW/ch/seasonswitchdoors.c +#include +#include "functions.h" +#include "variables.h" + +typedef struct{ + u8 unk0; + u8 returnMapId; + u8 cameraNode; + u8 returnEntryPoint; +} CH_Season_Switch_Doors_Cutscene_Info; + +void chSeasonSwitchDoors_update(Actor *this); +void chSeasonSwitch_update(Actor *this); + +/* .data */ +CH_Season_Switch_Doors_Cutscene_Info chSeasonSwitchDoorsCutsceneInfo[] = { + {0, MAP_40_CCW_HUB, 0, 5}, + {0, MAP_43_CCW_SPRING, 1, 5}, + {0, MAP_44_CCW_SUMMER, 2, 5}, + {0, MAP_45_CCW_AUTUMN, 3, 15} +}; + +ActorAnimationInfo chSeasonSwitchAnimations[] = { + {0, 0.0f}, + {0, 0.0f}, + {0, 0.0f}, + {0, 0.0f}, + {ASSET_D4_ANIM_SWITCH_DOWN, 0.5f}, + {ASSET_D4_ANIM_SWITCH_DOWN, 100000000.0f} +}; + +ActorInfo chCCWSpringSwitchDoor = { + MARKER_133_CCW_SPRING_SEASON_DOOR, ACTOR_1E3_CCW_SPRING_SEASON_DOOR, ASSET_52E_MODEL_CCW_SEASON_DOOR, + 0x1, NULL, + chSeasonSwitchDoors_update, actor_update_func_80326224, actor_drawFullDepth, + 0, 0x4000, 0.0f, 0 +}; + +ActorInfo chCCWSpringSwitch = { + MARKER_132_CCW_SPRING_SWITCH, ACTOR_1E2_CCW_SPRING_SWITCH, ASSET_4F5_MODEL_CCW_SPRING_SWITCH, + 0x5, chSeasonSwitchAnimations, + chSeasonSwitch_update, actor_update_func_80326224, actor_draw, + 0, 0, 0.0f, 0 +}; + +ActorInfo chCCWSummerSwitchDoor = { + MARKER_131_CCW_SUMMER_SEASON_DOOR, ACTOR_16D_CCW_SUMMER_SEASON_DOOR, ASSET_52E_MODEL_CCW_SEASON_DOOR, + 0x1, NULL, + chSeasonSwitchDoors_update, actor_update_func_80326224, actor_drawFullDepth, + 0, 0x4000, 0.0f, 0 +}; + +ActorInfo chCCWSummerSwitch = { + MARKER_130_CCW_SUMMER_SWITCH, ACTOR_16C_CCW_SUMMER_SWITCH, ASSET_4F6_MODEL_CCW_SUMMER_SWITCH, + 0x5, chSeasonSwitchAnimations, + chSeasonSwitch_update, actor_update_func_80326224, actor_draw, + 0, 0, 0.0f, 0 +}; + +ActorInfo chCCWAutumnSwitchDoor = { + MARKER_12F_CCW_AUTUMN_SEASON_DOOR, ACTOR_16B_CCW_AUTUMN_SEASON_DOOR, ASSET_52E_MODEL_CCW_SEASON_DOOR, + 0x1, NULL, + chSeasonSwitchDoors_update, actor_update_func_80326224, actor_drawFullDepth, + 0, 0x4000, 0.0f, 0 +}; + +ActorInfo chCCWAutumnSwitch = { + MARKER_12E_CCW_AUTUMN_SWITCH, ACTOR_16A_CCW_AUTUMN_SWITCH, ASSET_4F7_MODEL_CCW_AUTUMN_SWITCH, + 0x5, chSeasonSwitchAnimations, + chSeasonSwitch_update, actor_update_func_80326224, actor_draw, + 0, 0, 0.0f, 0 +}; + +ActorInfo chCCWWinterSwitchDoor = { + MARKER_12D_CCW_WINTER_SEASON_DOOR, ACTOR_169_CCW_WINTER_SEASON_DOOR, ASSET_52E_MODEL_CCW_SEASON_DOOR, + 0x1, NULL, + chSeasonSwitchDoors_update, actor_update_func_80326224, actor_drawFullDepth, + 0, 0x4000, 0.0f, 0 +}; + +ActorInfo chCCWWinterSwitch = { + MARKER_12C_CCW_WINTER_SWITCH, ACTOR_168_CCW_WINTER_SWITCH, ASSET_4F8_MODEL_CCW_WINTER_SWITCH, + 0x5, chSeasonSwitchAnimations, + chSeasonSwitch_update, actor_update_func_80326224, actor_draw, + 0, 0, 0.0f, 0 +}; + +enum chCCWSeasonSwitchDoor_State_e { + CH_CCW_SEASON_SWITCH_DOOR_STATE_0_NOT_INIT, + CH_CCW_SEASON_SWITCH_DOOR_STATE_1_LOWERED, + CH_CCW_SEASON_SWITCH_DOOR_STATE_2_OPENING, + CH_CCW_SEASON_SWITCH_DOOR_STATE_3_RAISED, + CH_CCW_SEASON_SWITCH_DOOR_STATE_4_NO_COLLISION +}; + +/* .code */ +s32 chCCWSwitchAndDoor_getSeason(Actor *this){ + switch(this->marker->id){ + case MARKER_133_CCW_SPRING_SEASON_DOOR: //L80388F28 + case MARKER_132_CCW_SPRING_SWITCH: //L80388F28 + return CCW_SEASON_0_SPRING; + + case MARKER_131_CCW_SUMMER_SEASON_DOOR: //L80388F30 + case MARKER_130_CCW_SUMMER_SWITCH: //L80388F30 + return CCW_SEASON_1_SUMMER; + + case MARKER_12F_CCW_AUTUMN_SEASON_DOOR: //L80388F38 + case MARKER_12E_CCW_AUTUMN_SWITCH: //L80388F38 + return CCW_SEASON_2_AUTUMN; + + case MARKER_12D_CCW_WINTER_SEASON_DOOR: //L80388F40 + case MARKER_12C_CCW_WINTER_SWITCH: //L80388F40 + return CCW_SEASON_3_WINTER; + + default: + return CCW_SEASON_0_SPRING; + } +} + + +void chSeasonSwitch_pressed(ActorMarker *marker, ActorMarker *other_marker){ + Actor *this; + + this = marker_getActor(marker); + if ((player_movementGroup() != BSGROUP_1_INTR) && !this->unk38_0) { + this->unk38_0 = true; + actor_collisionOff(this); + subaddie_set_state_with_direction(this, CH_CCW_SEASON_SWITCH_DOOR_STATE_4_NO_COLLISION, 0.0f, 1); + actor_playAnimationOnce(this); + func_8030E6D4(SFX_90_SWITCH_PRESS); + } +} + +void chSeasonSwitch_update(Actor *this) { + + if (!this->initialized) { + this->unk138_31 = this->unk124_0 = true; + this->marker->propPtr->unk8_3 = true; + this->unk10_12 = chCCWSwitchAndDoor_getSeason(this); + this->initialized = true; + } + if (!this->volatile_initialized) { + if (fileProgressFlag_get(this->unk10_12 + FILEPROG_8B_CCW_SPRING_OPEN)) { + actor_playAnimationOnce(this); + subaddie_set_state_with_direction(this, CH_CCW_SEASON_SWITCH_DOOR_STATE_4_NO_COLLISION, 0.999f, 1); + actor_collisionOff(this); + } else { + marker_setCollisionScripts(this->marker, NULL, &chSeasonSwitch_pressed, NULL); + } + this->unk38_0 = false; + this->volatile_initialized = true; + } + // Anchor: teammate pressed this switch (flag synced) — drop it to match; unk38_0 stays false. + if( this->state != CH_CCW_SEASON_SWITCH_DOOR_STATE_4_NO_COLLISION + && fileProgressFlag_get(this->unk10_12 + FILEPROG_8B_CCW_SPRING_OPEN) + ){ + actor_playAnimationOnce(this); + subaddie_set_state_with_direction(this, CH_CCW_SEASON_SWITCH_DOOR_STATE_4_NO_COLLISION, 0.999f, 1); + actor_collisionOff(this); + } + if( (this->state == CH_CCW_SEASON_SWITCH_DOOR_STATE_4_NO_COLLISION) + && this->unk38_0 + && actor_animationIsAt(this, 0.999f) + ){ + func_802D6264( + 1.1f, + 0x40, + this->unk10_12 + 0x3C, + 0x2B, + chSeasonSwitchDoorsCutsceneInfo[this->unk10_12].returnEntryPoint, + this->unk10_12 + 0x8B); + func_80324E38(0.5f, 3); + timedFunc_set_2(1.1f, (GenFunction_2)levelSpecificFlags_set, this->unk10_12 + 7, true); + func_80324E38(5.6f, 0); + } +} + +void chSeasonSwitchDoors_doorOpening(void* marker) { + Actor* actor = marker_getActor(reinterpret_cast(ActorMarker*, marker)); + actor->unk44_31 = func_8030ED2C(SFX_3EC_CCW_DOOR_OPENING, 3); + func_8030DD90(actor->unk44_31, 0); + sfxsource_setSampleRate(actor->unk44_31, 11000); + sfxsource_playSfxAtVolume(actor->unk44_31, 0.3f); + sfxSource_func_8030E2C4(actor->unk44_31); +} + +void chSeasonSwitchDoors_doorOpened(void* marker) { + Actor* actor = marker_getActor(reinterpret_cast(ActorMarker*, marker)); + sfxSource_triggerCallbackByIndex(actor->unk44_31); + sfxsource_freeSfxsourceByIndex(actor->unk44_31); + actor->unk44_31 = 0U; + FUNC_8030E624(SFX_6C_LOCKUP_CLOSING, 1.0f, 25000); +} + +void chSeasonSwitchDoors_update(Actor *this) { + ActorProp *temp_v1; + u32 temp_v0; + u32 temp_v1_2; + + if(!this->initialized) { + this->unk58_2 = false; + this->unk10_12 = chCCWSwitchAndDoor_getSeason(this); + this->marker->propPtr->unk8_3 = true; + actor_collisionOff(this); + this->initialized = true; + } + if (!this->volatile_initialized) { + this->unk1C[0] = this->position[0]; + this->unk1C[1] = this->position[1]; + this->unk1C[2] = this->position[2]; + this->unk1C[1] += 250.0f; + + this->volatile_initialized = true; + if (fileProgressFlag_get(this->unk10_12 + FILEPROG_8B_CCW_SPRING_OPEN)) { + subaddie_set_state(this, CH_CCW_SEASON_SWITCH_DOOR_STATE_3_RAISED); + } + } + + switch (this->state) { /* irregular */ + case CH_CCW_SEASON_SWITCH_DOOR_STATE_1_LOWERED: + if (levelSpecificFlags_get(this->unk10_12 + 7)) { + timedFunc_set_1(0.05f, (GenFunction_1)chSeasonSwitchDoors_doorOpening, (uintptr_t)this->marker); + timedFunc_set_1(4.0f, (GenFunction_1)chSeasonSwitchDoors_doorOpened, (uintptr_t)this->marker); + subaddie_set_state(this, CH_CCW_SEASON_SWITCH_DOOR_STATE_2_OPENING); + } + break; + case CH_CCW_SEASON_SWITCH_DOOR_STATE_2_OPENING: + this->position[1] += 60.0f * time_getDelta(); + if (this->unk1C[1] <= this->position[1]) { + levelSpecificFlags_set(this->unk10_12 + 7, false); + subaddie_set_state(this, CH_CCW_SEASON_SWITCH_DOOR_STATE_3_RAISED); + } + break; + case CH_CCW_SEASON_SWITCH_DOOR_STATE_3_RAISED: + this->position[1] = this->unk1C[1]; + break; + } +} diff --git a/src/CCW/ch/snarebear.c b/src/CCW/ch/snarebear.c index 88af55bee..de8de25c8 100644 --- a/src/CCW/ch/snarebear.c +++ b/src/CCW/ch/snarebear.c @@ -1,24 +1,140 @@ -// BanjoDecomp: code_7BC0.c +// BanjoDecomp: CCW/ch/snarebear.c #include #include "functions.h" #include "variables.h" -void func_8038DFB0(Actor *this); +void chSnarebear_update(Actor *this); -ActorAnimationInfo D_8038F8B0[] = { - {0x000, 0.0f}, - {0x234, 2.0f} +/* .data */ +ActorAnimationInfo chSnarebearAnimations[] = { + {0x000, 0.0f}, + {ASSET_16C_ANIM_SNAREBEAR_IDLE, 2.0f}, + {ASSET_16B_ANIM_SNAREBEAR_ATTACK, 1.2f} }; -ActorInfo D_8038F8C0 = { 0x251, 0x37E, 0x506, - 0x1, D_8038F8B0, - func_8038DFB0, actor_update_func_80326224, actor_draw, +ActorInfo chSnarebear = { + MARKER_1F9_SNARE_BEAR, ACTOR_1E9_SNARE_BEAR, ASSET_440_MODEL_SNAREBEAR, + 0x1, chSnarebearAnimations, + chSnarebear_update, actor_update_func_80326224, actor_draw, 0, 0, 0.0f, 0 }; +enum chSnarebear_State_e { + CH_SNAREBEAR_STATE_0_NOT_INIT, + CH_SNAREBEAR_STATE_1_IDLE, + CH_SNAREBEAR_STATE_2_ATTACK +}; + /* .code */ -void func_8038DFB0(Actor *this){ - this->marker->propPtr->unk8_3 = true; - actor_collisionOff(this); +void chSnarebear_idle(Actor* actor) { + subaddie_set_state_with_direction(actor, CH_SNAREBEAR_STATE_1_IDLE, 0.001f, 1); + actor->unk38_31 = randi2(0, 0); +} + +void chSnarebear_attack(Actor* actor) { + subaddie_set_state_with_direction(actor, CH_SNAREBEAR_STATE_2_ATTACK, 0.001f, 1); +} + +void func_8038E060(BoneTransformList *bone_transform_list, ActorMarker *marker){ + Actor *this; + f32 sp28[3]; + s32 pad24; + f32 sp18[4]; // quaternion: func_80345C78 writes 4 floats + + this = marker_getActor(marker); + if(bone_transform_list){ + sp28[0] = 0.0f; + sp28[1] = this->unk1C[0]; + sp28[2] = 0.0f; + + + func_80345C78(sp18, sp28); + func_8033A8F0(bone_transform_list, 1, sp18); + modelRender_setBoneTransformList(bone_transform_list); + } +} + +void chSnarebear_update(Actor *this) { + f32 player_position[3]; + f32 horizontal_distance; + f32 distance_in_front; + f32 side_angle_radian; + f32 time_delta; + + time_delta = time_getDelta(); + + if(!subaddie_playerIsWithinSphere(this, 3000)) return; + + if (!this->volatile_initialized) { + this->volatile_initialized = true; + func_8028746C(this->anctrl, (GenFunction_2)func_8038E060); + func_8028748C(this->anctrl, (uintptr_t)this->marker); + this->marker->propPtr->unk8_3 = true; + this->unk1C[0] = 0.0f; + this->unk38_31 = 0; + } + + if (player_getTransformation() == TRANSFORM_6_BEE) { + actor_collisionOff(this); + } else { + actor_collisionOn(this); + player_getPosition(player_position); + func_80258A4C( + this->position, + this->yaw - 90.0f, + player_position, + &horizontal_distance, + &distance_in_front, + &side_angle_radian); + if( (horizontal_distance < 1050.0f) + && (side_angle_radian > -1.0f) + && (side_angle_radian < 1.0f) + ) { + func_80258A4C( + this->position, + this->unk1C[0] + (this->yaw - 90.0f), + player_position, + &horizontal_distance, + &distance_in_front, + &side_angle_radian); + this->unk1C[0] += side_angle_radian * 160.0f * time_delta; + } else { + if (this->unk1C[0] > 0.0f) { + this->unk1C[0] -= (30.0f * time_delta); + this->unk1C[0] = (this->unk1C[0] < 0.0f) ? 0.0f : this->unk1C[0]; + + } else if (this->unk1C[0] < 0.0f) { + this->unk1C[0] += (30.0f * time_delta); + this->unk1C[0] = (this->unk1C[0] > 0.0f) ? 0.0f : this->unk1C[0]; + } + } + } + switch (this->state) { + case CH_SNAREBEAR_STATE_1_IDLE: + if (this->unk38_31 != 0) { + this->unk38_31--; + break; + } + if( subaddie_playerIsWithinSphereAndActive(this, 680) + && (this->unk38_31 == 0) + && (player_getTransformation() == TRANSFORM_1_BANJO) + ) { + chSnarebear_attack(this); + } + break; + + case CH_SNAREBEAR_STATE_2_ATTACK: + if (actor_animationIsAt(this, 0.999f)) { + chSnarebear_idle(this); + break; + } + if( actor_animationIsAt(this, 0.18f) + || actor_animationIsAt(this, 0.47f) + || actor_animationIsAt(this, 0.78f) + ) { + sfx_playFadeShorthandDefault(SFX_80_YUMYUM_CLACK, 1.0f, 32000, this->position, 1500, 3000); + } + break; + } } diff --git a/src/CCW/ch/snore.c b/src/CCW/ch/snore.c index f4159827c..74a08c8fb 100644 --- a/src/CCW/ch/snore.c +++ b/src/CCW/ch/snore.c @@ -6,15 +6,27 @@ void chSnoreZ_update(Actor *this); /* .data */ -ActorInfo D_8038F6F0 = { 0x1C3, 0x30C, 0x4E4, 0x0, NULL, chSnoreZ_update, NULL, actor_draw, 0, 0, 0.0f, 0}; + +enum chSnoreZ_state_e { + SNORE_Z_STATE_0_NOT_INIT, + SNORE_Z_STATE_1_SPAWN_IN, + SNORE_Z_STATE_2_FADE_AWAY +}; + +ActorInfo chSnoreZ = { + MARKER_1C3_SNORE_Z, ACTOR_30C_SNORE_Z, ASSET_4E4_MODEL_SNORE_Z, + 0x0, NULL, + chSnoreZ_update, NULL, actor_draw, + 0, 0, 0.0f, 0 +}; /* .code */ void chSnoreZ_setNextState(Actor *this, s32 next_state) { - if (next_state == 1) { - skeletalAnim_set(this->unk148, 0x21C, 0.0f, 6.0f); + if (next_state == SNORE_Z_STATE_1_SPAWN_IN) { + skeletalAnim_set(this->unk148, ASSET_21C_ANIM_SNORE_Z, 0.0f, 6.0f); skeletalAnim_setBehavior(this->unk148, SKELETAL_ANIM_2_ONCE); } - if (next_state == 2) { + if (next_state == SNORE_Z_STATE_2_FADE_AWAY) { func_80326310(this); } this->state = next_state; @@ -27,15 +39,15 @@ void chSnoreZ_update(Actor *this) { if (!this->volatile_initialized) { this->volatile_initialized = true; - this->depth_mode = 2; + this->depth_mode = MODEL_RENDER_DEPTH_COMPARE; this->marker->unk40_22 = true; - chSnoreZ_setNextState(this, 1); + chSnoreZ_setNextState(this, SNORE_Z_STATE_1_SPAWN_IN); } - if (this->state == 1) { + if (this->state == SNORE_Z_STATE_1_SPAWN_IN) { this = this; skeletalAnim_getProgressRange(this->unk148, &sp24, &sp20); if ((sp24 < 0.25f) && (sp20 >= 0.25f)) { - chSnoreZ_setNextState(this, 2); + chSnoreZ_setNextState(this, SNORE_Z_STATE_2_FADE_AWAY); } } } diff --git a/src/CCW/ch/springnabnut.c b/src/CCW/ch/springnabnut.c new file mode 100644 index 000000000..82023570c --- /dev/null +++ b/src/CCW/ch/springnabnut.c @@ -0,0 +1,110 @@ +// BanjoDecomp: CCW/ch/springnabnut.c +#include +#include "functions.h" +#include "variables.h" + +typedef struct { + f32 currSFXProgress; +}ActorLocal_CCW_4D00; + +typedef struct { + f32 sfxProgress; + f32 volume; + s16 sfxId; + s16 sampleRate; +} CH_NABNUT_SPRING_SFX; + +void chNabnutSpring_update(Actor *this); + +/* .data */ + +ActorInfo chNabnutSpring = { + MARKER_1B9_NABNUT_SPRING, ACTOR_2A6_NABNUT_SPRING, ASSET_502_MODEL_NABNUT, + 0x0, NULL, + chNabnutSpring_update, NULL, actor_draw, + 0, 0, 0.0f, 0 +}; + +CH_NABNUT_SPRING_SFX chNabnutSpringSfx[] = { + {0.12f, 1.6f, SFX_A7_WOODEN_SWOSH, 8000}, + {0.21f, 1.7f, SFX_A7_WOODEN_SWOSH, 8500}, + {0.3f , 1.6f, SFX_A7_WOODEN_SWOSH, 8000}, + {0.51f, 1.0f, SFX_4C_LIP_SMACK, 22000}, + {0.65f, 1.05f, SFX_4C_LIP_SMACK, 23000}, + {0.76f, 1.0f, SFX_4C_LIP_SMACK, 22000}, + {0.88f, 1.0f, SFX_4C_LIP_SMACK, 23000}, + 0 +}; + +enum chNabnutSpring_State_e { + CH_NABNUT_SPRING_STATE_0_NOT_INIT, + CH_NABNUT_SPRING_STATE_1_LOOKING_AROUND, + CH_NABNUT_SPRING_STATE_2_EATING +}; + +/* .code */ +void chNabnutSpring_setState(Actor *this, s32 next_state) { + ActorLocal_CCW_4D00 *local = (ActorLocal_CCW_4D00 *)&this->local; + + local->currSFXProgress = 0.0f; + if (next_state == CH_NABNUT_SPRING_STATE_1_LOOKING_AROUND) { + skeletalAnim_swap(this->unk148, ASSET_1A3_ANIM_NABNUT_SPRING_LOOKING_AROUND, 0.2f, 11.0f); + local->currSFXProgress = randf2(3.0f, 10.0f); + } + if (next_state == CH_NABNUT_SPRING_STATE_2_EATING) { + skeletalAnim_set(this->unk148, ASSET_1A4_ANIM_NABNUT_SPRING_EATING, 0.2f, 3.0f); + } + this->state = next_state; +} + +void chNabnutSpring_update(Actor *this) { + ActorLocal_CCW_4D00 *local; + f32 tick; + CH_NABNUT_SPRING_SFX *iPtr; + f32 prev_progress; + f32 curr_progress; + + local = (ActorLocal_CCW_4D00 *)&this->local; + tick = time_getDelta(); + + if (!this->volatile_initialized) { + this->volatile_initialized = true; + this->has_met_before = false; + chNabnutSpring_setState(this, CH_NABNUT_SPRING_STATE_1_LOOKING_AROUND); + } + + if ((this->state == CH_NABNUT_SPRING_STATE_1_LOOKING_AROUND) && ml_timer_update(&local->currSFXProgress, tick)) { + chNabnutSpring_setState(this, CH_NABNUT_SPRING_STATE_2_EATING); + } + + if (this->state == CH_NABNUT_SPRING_STATE_2_EATING) { + skeletalAnim_getProgressRange(this->unk148, &prev_progress, &curr_progress); + for(iPtr = &chNabnutSpringSfx[0]; iPtr->sfxProgress > 0.0f; iPtr++){ + if ((prev_progress < iPtr->sfxProgress) && (iPtr->sfxProgress <= curr_progress)) { + func_8030E878( + iPtr->sfxId, + randf2(iPtr->volume - 0.05, iPtr->volume + 0.05), + randi2(iPtr->sampleRate - 500, iPtr->sampleRate + 500), + this->position, + 500.0f, + 2500.0f); + } + } + + if ((prev_progress < 0.97) && (0.97 <= curr_progress)) { + if (randf() >= 0.5) { + func_8030E878(SFX_AE_YUMYUM_TALKING, randf2(1.8f, 1.85f), randi2(19000, 21000), this->position, 500.0f, 2500.0f); + } else { + func_8030E878(SFX_4B_GULPING, randf2(1.4f, 1.45f), randi2(24000, 26000), this->position, 500.0f, 2500.0f); + } + } + if (skeletalAnim_getLoopCount(this->unk148) > 0) { + chNabnutSpring_setState(this, CH_NABNUT_SPRING_STATE_1_LOOKING_AROUND); + } + } + if (!this->has_met_before && func_803292E0(this)) { + this->has_met_before = TRUE; + gcdialog_showDialog(VER_SELECT(ASSET_CC8_DIALOG_NABNUT_MEET_SPRING, 0x09DD, 0, 0), 0, NULL, NULL, NULL, NULL); + } + func_8028E668(this->position, 300.0f, -50.0f, 120.0f); +} diff --git a/src/CCW/ch/summeroutsidegnawty.c b/src/CCW/ch/summeroutsidegnawty.c new file mode 100644 index 000000000..4ebb00d9c --- /dev/null +++ b/src/CCW/ch/summeroutsidegnawty.c @@ -0,0 +1,160 @@ +// BanjoDecomp: CCW/ch/summeroutsidegnawty.c +#include +#include "functions.h" +#include "variables.h" + +typedef struct{ + f32 sfxProgress; + f32 volume; + s16 sfxId; + s16 sampleRate; +} CH_Gnawty_Summer_SFX; + +void chGnawtySummer_update(Actor *this); + +/* .data */ + +ActorInfo chGnawtySummer = { + MARKER_1BE_GNAWTY_SUMMER, ACTOR_2AB_GNAWTY_SUMMER, ASSET_48F_MODEL_GNAWTY, + 0x0, NULL, + chGnawtySummer_update, chGnawtySummer_update, actor_draw, + 0, 0, 2.2f, 0 +}; + +CH_Gnawty_Summer_SFX chGnawtySummerIdleSfx[] = { + {0.11f, 1.0f, SFX_10_BANJO_LANDING_07, 9000}, + {0.23f, 1.0f, SFX_10_BANJO_LANDING_07, 9000}, + {0.34f, 1.0f, SFX_10_BANJO_LANDING_07, 9000}, + {0.58f, 1.0f, SFX_4D_WET_WIGGLING, 9000}, + {0.8f, 1.0f, SFX_4D_WET_WIGGLING, 9000}, + 0 +}; + +CH_Gnawty_Summer_SFX chGnawtySummerCheeringSfx[] = { + {0.07f, 1.6f, SFX_56_BANJO_HUI, 32000}, + {0.17f, 1.0f, SFX_10_BANJO_LANDING_07, 9000}, + {0.22f, 1.6f, SFX_55_BANJO_HOO_2, 32000}, + {0.31f, 1.0f, SFX_10_BANJO_LANDING_07, 9000}, + {0.33f, 1.6f, SFX_54_BANJO_HOO_1, 32000}, + {0.45f, 1.0f, SFX_10_BANJO_LANDING_07, 9000}, + {0.49f, 1.7f, SFX_55_BANJO_HOO_2, 32600}, + {0.6f, 1.0f, SFX_10_BANJO_LANDING_07, 9000}, + {0.63f, 1.7f, SFX_56_BANJO_HUI, 32600}, + {0.74f, 1.0f, SFX_10_BANJO_LANDING_07, 9000}, + {0.79f, 1.6f, SFX_54_BANJO_HOO_1, 32000}, + {0.9f, 1.0f, SFX_10_BANJO_LANDING_07, 9000}, + 0 +}; + +CH_Gnawty_Summer_SFX chGnawtySummerRunningSfx[] = { + {0.01f, 1.0f, SFX_10_BANJO_LANDING_07, 9000}, + {0.5f, 1.0f, SFX_10_BANJO_LANDING_07, 9000}, + 0 +}; + +enum chGnawtySummer_State_e { + CH_GNAWTY_SUMMER_STATE_0_NOT_INIT, + CH_GNAWTY_SUMMER_STATE_1_IDLE, + CH_GNAWTY_SUMMER_STATE_2_CHEERING, + CH_GNAWTY_SUMMER_STATE_3_RUNNING, + CH_GNAWTY_SUMMER_STATE_4_DESPAWN +}; + +/* .code */ +void chGnawtySummer_setState(Actor *this, s32 next_state) { + ActorProp *temp_v0; + + if (next_state == CH_GNAWTY_SUMMER_STATE_1_IDLE) { + skeletalAnim_set(this->unk148, ASSET_1A6_ANIM_GNAWTY_IDLE, 0.2f, 4.5f); + } + if (next_state == CH_GNAWTY_SUMMER_STATE_2_CHEERING) { + this->marker->propPtr->unk8_3 = false; + skeletalAnim_set(this->unk148, ASSET_1A7_ANIM_GNAWTY_CHEERING, 0.2f, 3.0f); + skeletalAnim_setBehavior(this->unk148, SKELETAL_ANIM_2_ONCE); + gcdialog_showDialog(VER_SELECT(ASSET_CD0_DIALOG_GNAWTY_COMPLETE_SUMMER, 0x9E5, 0, 0), 0x24, NULL, NULL, NULL, NULL); + } + if (next_state == CH_GNAWTY_SUMMER_STATE_3_RUNNING) { + skeletalAnim_set(this->unk148, ASSET_1A8_ANIM_GNAWTY_RUNNING, 0.2f, 0.5f); + skeletalAnim_setBehavior(this->unk148, SKELETAL_ANIM_1_LOOP); + } + if (next_state == CH_GNAWTY_SUMMER_STATE_4_DESPAWN) { + marker_despawn(this->marker); + } + this->state = next_state; +} + +void chGnawtySummer_update(Actor *this) { + CH_Gnawty_Summer_SFX *sfx_list; + f32 prev_progress; + f32 curr_progress; + f32 player_position[3]; + + if (!this->volatile_initialized) { + this->marker->propPtr->unk8_3 = true; + this->volatile_initialized = true; + this->has_met_before = false; + chGnawtySummer_setState(this, CH_GNAWTY_SUMMER_STATE_1_IDLE); + if (jiggyscore_isCollected(JIGGY_4B_CCW_GNAWTY) != false) { + levelSpecificFlags_set(LEVEL_FLAG_25_CCW_GNAWTY_JIGGY_COLLECTED, true); + } + if (levelSpecificFlags_get(LEVEL_FLAG_25_CCW_GNAWTY_JIGGY_COLLECTED) != false) { + marker_despawn(this->marker); + } + return; + } + + if (this->state == CH_GNAWTY_SUMMER_STATE_1_IDLE) { + sfx_list = chGnawtySummerIdleSfx; + } else if (this->state == CH_GNAWTY_SUMMER_STATE_2_CHEERING) { + sfx_list = chGnawtySummerCheeringSfx; + } else if (this->state == CH_GNAWTY_SUMMER_STATE_3_RUNNING) { + sfx_list = chGnawtySummerRunningSfx; + } else{ + sfx_list = NULL; + } + + if (sfx_list != NULL) { + skeletalAnim_getProgressRange(this->unk148, &prev_progress, &curr_progress); + while(sfx_list->sfxProgress > 0.0f){ + if (((prev_progress < sfx_list->sfxProgress) || (curr_progress < prev_progress)) + && (sfx_list->sfxProgress <= curr_progress)) + { + func_8030E878( + sfx_list->sfxId, + randf2(sfx_list->volume - 0.05, sfx_list->volume + 0.05), + randi2(sfx_list->sampleRate - 200, sfx_list->sampleRate + 100), + this->position, + 500.0f, + 1500.0f); + } + sfx_list++; + } + } + + if (this->state == CH_GNAWTY_SUMMER_STATE_1_IDLE) { + if (!this->has_met_before) { + player_getPosition(player_position); + if (ml_vec3f_distance(this->position, player_position) < 900.0f) { + gcdialog_showDialog(VER_SELECT(ASSET_CCF_DIALOG_GNAWTY_MEET_SUMMER, 0x9E4, 0, 0), 4, NULL, NULL, NULL, NULL); + this->has_met_before = TRUE; + } + } + + if (levelSpecificFlags_get(LEVEL_FLAG_25_CCW_GNAWTY_JIGGY_COLLECTED) != false) { + chGnawtySummer_setState(this, CH_GNAWTY_SUMMER_STATE_2_CHEERING); + } + } + + if (this->state == CH_GNAWTY_SUMMER_STATE_2_CHEERING){ + if((skeletalAnim_getLoopCount(this->unk148) > 0)) { + chGnawtySummer_setState(this, CH_GNAWTY_SUMMER_STATE_3_RUNNING); + } + } + + if (this->state == CH_GNAWTY_SUMMER_STATE_3_RUNNING) { + actor_update_func_80326224(this); + if (0.99 < (f64) this->unk48) { + chGnawtySummer_setState(this, CH_GNAWTY_SUMMER_STATE_4_DESPAWN); + } + } +} diff --git a/src/CCW/ch/swimminggnawty.c b/src/CCW/ch/swimminggnawty.c new file mode 100644 index 000000000..2976ce50e --- /dev/null +++ b/src/CCW/ch/swimminggnawty.c @@ -0,0 +1,140 @@ +// BanjoDecomp: CCW/ch/swimminggnawty.c +#include +#include "functions.h" +#include "variables.h" + +extern ParticleEmitter *func_802EDD8C(f32[3], f32, f32); + +typedef struct{ + s16 map_id; + s16 despawnIfJiggyCollected; + s16 dialog; +} CH_GNAWTY_SWIMMING_DIALOG; + +typedef struct{ + CH_GNAWTY_SWIMMING_DIALOG *dialog; + f32 unk4[3]; +} ActorLocal_CCW_6620; + +Actor *chGnawtySwimming_draw(ActorMarker *this, Gfx **gfx, Mtx **mtx, Vtx **vtx); +void chGnawtySwimming_update(Actor *this); + +/* .data */ +CH_GNAWTY_SWIMMING_DIALOG chGnawtySwimmingDialogs[] ={ + {MAP_43_CCW_SPRING, FALSE, VER_SELECT(ASSET_CCE_DIALOG_GNAWTY_MEET_SPRING, 0x09E3, 0, 0)}, + {MAP_45_CCW_AUTUMN, TRUE, VER_SELECT(ASSET_CD1_DIALOG_GNAWTY_MEET_FALL_OUTSIDE, 0x09E6, 0, 0)}, + {MAP_46_CCW_WINTER, TRUE, VER_SELECT(ASSET_CD3_DIALOG_GNAWTY_MEET_WINTER_OUTSIDE, 0x09E8, 0, 0)}, + { 0 } // [port] decomp uses NULL; first field is an integer and clang errors on -Wint-conversion +}; + +enum chGnawtySwimming_State_e { + CH_GNAWTY_SWIMMING_STATE_0_NOT_INIT, + CH_GNAWTY_SWIMMING_STATE_1_SWIMMING +}; + +ActorInfo chGnawtySwimming = { + MARKER_1BD_GNAWTY_SWIMMING, ACTOR_2AA_GNAWTY_SWIMMING, ASSET_48F_MODEL_GNAWTY, + 0x0, NULL, + chGnawtySwimming_update, NULL, chGnawtySwimming_draw, + 0, 0, 2.2f, 0 +}; + +/* .code */ +void chGnawtySwimming_emitParticles(ActorMarker *marker) { + Actor *this; + ActorLocal_CCW_6620 *local; + ParticleEmitter *pCtrl; + + this = marker_getActor(marker); + local = (ActorLocal_CCW_6620 *)&this->local; + + if (this->marker->unk14_21) { + if (0.65 < (f64) randf()) { + pCtrl = func_802EDD8C(local->unk4, 0.0f, this->position[1] + 500.0f); + particleEmitter_setStartingScaleRange(pCtrl, 0.04f, 0.05f); + particleEmitter_setFinalScaleRange(pCtrl, 0.18f, 0.2f); + particleEmitter_setSpawnPositionRange(pCtrl, -10.0f, 0.0f, -10.0f, 10.0f, 20.0f, 10.0f); + particleEmitter_setParticleVelocityRange(pCtrl, 0.0f, 31.0f, 0.0f, 0.0f, 37.0f, 0.0f); + particleEmitter_emitN(pCtrl, 1); + } + } +} + +void chGnawtySwimming_setState(Actor *this, s32 next_state) { + int i; + + if (next_state == CH_GNAWTY_SWIMMING_STATE_1_SWIMMING) { + skeletalAnim_set(this->unk148, 0x289, 0.2f, 1.1f); + for(i = 0; i < 10; i++){ + skeletalAnim_setCallback_1(this->unk148, randf(), (GenFunction_1)chGnawtySwimming_emitParticles, (uintptr_t)this->marker); + } + } + this->state = next_state; +} + + +Actor *chGnawtySwimming_draw(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx) { + Actor *this; + ActorLocal_CCW_6620 *local; + + this = actor_draw(marker, gfx, mtx, vtx); + local = (ActorLocal_CCW_6620 *)&this->local; + if (this->marker->unk14_21) { + vec3fArray_get_vec3f(func_80329934(), 5, local->unk4); + } + return this; +} + +void chGnawtySwimming_update(Actor *this) { + ActorLocal_CCW_6620 *local; + f32 player_pos_1[3]; + f32 horizontal_distance; + f32 distance_in_front; + f32 side_angle_radian; + f32 player_pos_2[3]; + + local = (ActorLocal_CCW_6620 *)&this->local; + if (!this->volatile_initialized) { + this->marker->propPtr->unk8_3 = true; + this->volatile_initialized = true; + this->has_met_before = false; + local->dialog = &chGnawtySwimmingDialogs[0]; + while(local->dialog->map_id != 0 && gsworld_getMap() != local->dialog->map_id){ + local->dialog++; + } + chGnawtySwimming_setState(this, CH_GNAWTY_SWIMMING_STATE_1_SWIMMING); + + if (jiggyscore_isCollected(JIGGY_4B_CCW_GNAWTY)) { + levelSpecificFlags_set(LEVEL_FLAG_25_CCW_GNAWTY_JIGGY_COLLECTED, true); + } + + if ((local->dialog->despawnIfJiggyCollected != false) + && levelSpecificFlags_get(LEVEL_FLAG_25_CCW_GNAWTY_JIGGY_COLLECTED)) + { + marker_despawn(this->marker); + } + + return; + } + + if (this->state == CH_GNAWTY_SWIMMING_STATE_1_SWIMMING && this->marker->unk14_21) { + player_getPosition(player_pos_1); + func_80258A4C( + this->position, this->yaw - 90.0f, player_pos_1, + &horizontal_distance, &distance_in_front, &side_angle_radian); + if (horizontal_distance > 100.0f) { + this->yaw += 30.0f * side_angle_radian; + } + } + if (!this->has_met_before) { + player_getPosition(player_pos_2); + if (ml_vec3f_distance(this->position, player_pos_2) < 900.0f) { + if (local->dialog->map_id != MAP_46_CCW_WINTER + || func_8028F2FC()) + { + gcdialog_showDialog(local->dialog->dialog, 4, NULL, NULL, NULL, NULL); + this->has_met_before = true; + } + } + } +} diff --git a/src/CCW/ch/vacationtexttrigger.c b/src/CCW/ch/vacationtexttrigger.c index 474616d49..dbf39717e 100644 --- a/src/CCW/ch/vacationtexttrigger.c +++ b/src/CCW/ch/vacationtexttrigger.c @@ -39,7 +39,7 @@ void chVacationTextTrigger_update(Actor* this) { // Start dialog if player is within trigger if (__playerIsWithinTrigger(0, -107, 188) != 0) { - gcdialog_showDialog(0xDA9, 4, NULL, NULL, NULL, NULL); + gcdialog_showDialog(VER_SELECT(ASSET_DA9_DIALOG_MUMBO_CCW_VACATION, 0x0A27, 0, 0), 4, NULL, NULL, NULL, NULL); volatileFlag_set(VOLATILE_FLAG_13_HAS_TRIGGERED_MUMBO_VACATION_TEXT, 1); } } diff --git a/src/CCW/ch/zubba.c b/src/CCW/ch/zubba.c deleted file mode 100644 index d3367f084..000000000 --- a/src/CCW/ch/zubba.c +++ /dev/null @@ -1,216 +0,0 @@ -// BanjoDecomp: code_950.c -#include -#include "functions.h" -#include "variables.h" - -extern void func_8030DBFC(u8, f32, f32, f32); - -typedef struct{ - u8 sfxsourceIdx; - //u8 pad1[3]; - ActorMarker *unk4; - f32 unk8[3]; - f32 unk14; - f32 unk18; -}ActorLocal_CCW_950; - -void chwasp_update(Actor *this); - -/* .data */ -ActorInfo D_8038EBD0 = { MARKER_1AE_ZUBBA, ACTOR_29B_ZUBBA, ASSET_446_MODEL_ZUBBA, 0x0, NULL, chwasp_update, NULL, actor_draw, 0, 0, 1.0f, 0}; - -/* .code */ -void chwasp_setState(Actor *this, s32 next_state) { - ActorLocal_CCW_950 *local; - f32 sp50[3]; - f32 sp44[3]; - - local = (ActorLocal_CCW_950 *)&this->local; - local->unk18 = 0.0f; - if (next_state == 1) { - local->unk18 = 800.0f; - skeletalAnim_set(this->unk148, ASSET_16F_ANIM_ZUBBA_FLY_MOVE, 0.0f, 0.65f); - } - if (next_state == 2) { - skeletalAnim_set(this->unk148, ASSET_170_ANIM_ZUBBA_FLY_IDLE, 0.1f, 0.65f); - player_getPosition(sp50); - sp50[1] += 50.0f; - local->unk8[0] = sp50[0] - this->position[0]; - local->unk8[1] = sp50[1] - this->position[1]; - local->unk8[2] = sp50[2] - this->position[2]; - ml_vec3f_normalize(local->unk8); - if ((local->unk8[0] == 0.0f) && (local->unk8[1] == 0.0f) && (local->unk8[2] == 0.0f)) { - local->unk8[1] = -1.0f; - } - } - if (next_state == 3) { - sfx_playFadeShorthandDefault(SFX_1F_HITTING_AN_ENEMY_3, 1.2f, 32200, this->position, 500, 3000); - func_80324D54(randf2(0.1f, 0.4f), 0x3FC, randf2(0.95f, 1.1f), 32000, this->position, 500.0f, 3000.0f); - actor_collisionOff(this); - } - if (next_state == 4) { - skeletalAnim_set(this->unk148, ASSET_171_ANIM_ZUBBA_DIE, 0.1f, 0.2f); - sfx_playFadeShorthandDefault(SFX_1F_HITTING_AN_ENEMY_3, 1.2f, 32200, this->position, 500, 3000); - func_80324D54(0.1f, 0x66, randf2(1.6f, 1.7f), 32000, this->position, 500.0f, 3000.0f); - func_803867C8(local->unk4); - actor_collisionOff(this); - player_getPosition(sp44); - sp44[1] += 50.0f; - local->unk8[0] = this->position[0] - sp44[0]; - local->unk8[1] = this->position[1] - sp44[1]; - local->unk8[2] = this->position[2] - sp44[2]; - ml_vec3f_normalize(local->unk8); - if ((local->unk8[0] == 0.0f) && (local->unk8[1] == 0.0f) && (local->unk8[2] == 0.0f)) { - local->unk8[1] = -1.0f; - } - } - if (next_state == 5) { - func_8030E878(SFX_A_BANJO_LANDING_05, randf2(0.85f, 0.95f), 18000, this->position, 500.0f, 3000.0f); - skeletalAnim_set(this->unk148, ASSET_172_ANIM_ZUBBA_LAND, 0.0f, 1.0f); - skeletalAnim_setBehavior(this->unk148, SKELETAL_ANIM_2_ONCE); - } - if (next_state == 6) { - marker_despawn(this->marker); - } - if (next_state == 7) { - func_80386814(local->unk4); - marker_despawn(this->marker); - } - this->state = next_state; -} - - -void func_80387124(ActorMarker* marker, ActorMarker *other_marker) { - chwasp_setState(marker_getActor(marker), 3); -} - -void CCW_func_80387150(ActorMarker* marker, ActorMarker *other_marker) { - chwasp_setState(marker_getActor(marker), 4); -} - -void func_8038717C(Actor *this){ - ActorLocal_CCW_950 *local; - - local = (ActorLocal_CCW_950 *)&this->local; - sfxsource_freeSfxsourceByIndex(local->sfxsourceIdx); -} - -void chwasp_update(Actor *this) { - ActorLocal_CCW_950 *local; - f32 sp68; - Actor *other; - s32 sp60; - s32 sp5C; - f32 sp50[3]; - f32 sp4C; - f32 sp48; - f32 sp44; - f32 temp_f0; - f32 pad; - - - sp68 = time_getDelta(); - local = (ActorLocal_CCW_950 *)&this->local; - if (!this->volatile_initialized) { - this->volatile_initialized = true; - this->marker->actorFreeFunc = func_8038717C; - local->sfxsourceIdx = sfxsource_createSfxsourceAndReturnIndex(); - local->unk4 = 0; - local->unk14 = 1000.0f; - sfxsource_setSfxId(local->sfxsourceIdx, 0x3FA); - sfxSource_setunk43_7ByIndex(local->sfxsourceIdx, 2); - sfxsource_playSfxAtVolume(local->sfxsourceIdx, 0.9f); - sfxsource_setSampleRate(local->sfxsourceIdx, 0); - marker_setCollisionScripts(this->marker, func_80387124, NULL, CCW_func_80387150); - chwasp_setState(this, 1); - return; - } - if(local->unk4 == NULL) { - other = actorArray_findActorFromActorId(0x299); - if (other == NULL) { - marker_despawn(this->marker); - return; - } - local->unk4 = other->marker; - func_80386840(local->unk4, &sp60, &sp5C); - local->unk14 = (((f32)sp60 /(f32)sp5C) * 1000.0f) + 1000.0f; - } - - if (this->state == 1) { - temp_f0 = this->position[1]; - this->position[0] += 0.1 * sp68; - this->position[1] += local->unk18 * sp68; - if ((temp_f0 < 0.0f) && (this->position[1] >= 0.0f)) { - func_8030E878(SFX_A_BANJO_LANDING_05, randf2(1.0f, 1.1f), 18000, this->position, 500.0f, 3000.0f); - } - player_getPosition(sp50); - func_80258A4C(this->position, this->yaw - 90.0f, sp50, &sp4C, &sp48, &sp44); - this->yaw += 360.0f * sp44 * sp68; - if (this->position[1] > 150.0f) { - local->unk18 -= 2000.0f * sp68; - if (local->unk18 < 0.0f) { - chwasp_setState(this, 2); - } - } - } - - if (this->state == 2) { - if (local->unk18 < local->unk14) { - local->unk18 += (4.0f * local->unk14 * sp68); - } - this->position[0] += local->unk8[0] * local->unk18 * sp68; - this->position[1] += local->unk8[1] * local->unk18 * sp68; - this->position[2] += local->unk8[2] * local->unk18 * sp68; - if( (this->position[0] < -1500.0f) || (1500.0f < this->position[0]) - || (this->position[1] < -100.0f) || (1300.0f < this->position[1]) - || (this->position[2] < -1200.0f) || (this->position[2] > 2000.0f) - ){ - chwasp_setState(this, 7); - } - } - - if (this->state == 3) { - this->position[1] += local->unk18 * sp68; - if (local->unk18 < local->unk14) { - local->unk18 += 2000.0f * sp68; - } - - if( (this->position[0] < -1500.0f) || (1500.0f < this->position[0]) - || (this->position[1] < -100.0f) || (1300.0f < this->position[1]) - || (this->position[2] < -1200.0f) || (this->position[2] > 2000.0f) - ) { - chwasp_setState(this, 7); - } - } - - if (this->state == 4) { - this->position[0] += local->unk8[0] * 1000.0f * sp68; - this->position[1] -= local->unk18 * sp68; - this->position[2] += local->unk8[2] * 1000.0f * sp68; - if (local->unk18 < local->unk14) { - local->unk18 += (1000.0f * sp68); - } - if (this->position[1] <= 0.0f) { - this->position[1] = 0.0f; - chwasp_setState(this, 5); - } - } - - if (this->state == 5) { - this->position[1] -= 300.0f * sp68; - if (this->position[1] < -200.0f) { - chwasp_setState(this, 6); - } - } - - if(this->state); - if (this->state == 2) { - func_8030DBFC(local->sfxsourceIdx, 1.0f, 1.1f, 0.05f); - } else { - func_8030DBFC(local->sfxsourceIdx, 0.8f, 0.9f, 0.05f); - } - sfxsource_set_fade_distances(local->sfxsourceIdx, 500.0f, 1500.0f); - sfxsource_set_position(local->sfxsourceIdx, this->position); - sfxSource_func_8030E2C4(local->sfxsourceIdx); - sfxsource_setSampleRate(local->sfxsourceIdx, (s32) ((local->unk18 / local->unk14) * 10000.0f)); -} diff --git a/src/CCW/ch/zubba_hive_npc.c b/src/CCW/ch/zubba_hive_npc.c deleted file mode 100644 index 30c3a34ac..000000000 --- a/src/CCW/ch/zubba_hive_npc.c +++ /dev/null @@ -1,133 +0,0 @@ -// BanjoDecomp: code_14B0.c -#include "functions.h" -#include "variables.h" -#include - -#include - -extern void func_8030DBFC(u8, f32, f32, f32); -extern void sfxsource_setSampleRate(u8, s32); - -typedef struct{ - s16 unk0; - u8 unk2; - u8 unk3; - s16 unk4; -}Struct_CCW_14B0_0; - -typedef struct { - u8 sfxsourceIdx; - // u8 pad1[3]; - Struct_CCW_14B0_0 *unk4; - f32 unk8; - f32 unkC[3]; - f32 unk18[3]; -}ActorLocal_CCW_14B0; - -void CCW_func_80387A40(Actor *this); - -/* .data */ -Struct_CCW_14B0_0 D_8038EC00[] = { - {MAP_5B_CCW_SPRING_ZUBBA_HIVE, 0x7, 0x4C, 0xCE1}, - {MAP_5C_CCW_AUTUMN_ZUBBA_HIVE, 0x8, 0x00, 0xCE5}, - 0 -}; - -ActorInfo D_8038EC14 = { 0x1AF, 0x29C, 0x446, 0x0, NULL, CCW_func_80387A40, NULL, actor_draw, 0, 0, 1.0f, 0}; - -/* .code */ -void func_803878A0(Actor *this, s32 next_state) { - ActorLocal_CCW_14B0 *local = (ActorLocal_CCW_14B0 *)&this->local; - int i; - - if (next_state == 1) { - if (skeletalAnim_getAnimId(this->unk148) != 0x16F) { - skeletalAnim_set(this->unk148, 0x16F, 0.1f, 0.65f); - } - for(i = 0; i < 10; i++){ - local->unkC[0] = randf2(-500.0f, 500.0f); - local->unkC[1] = randf2(400.0f, 900.0f); - local->unkC[2] = randf2(-400.0f, 700.0f); - if(ml_vec3f_distance(this->position, local->unkC) > 800.0f) - break; - } - local->unk8 = randf2(500.0f, 1000.0f); - } - this->state = next_state; -} - -void CCW_func_80387A20(Actor *this){ - ActorLocal_CCW_14B0 *local = (ActorLocal_CCW_14B0 *)&this->local; - sfxsource_freeSfxsourceByIndex(local->sfxsourceIdx); -} - -void CCW_func_80387A40(Actor *this) { - ActorLocal_CCW_14B0 *local; - f32 sp68; - f32 sp5C[3]; - f32 sp58; - f32 sp54; - f32 sp50; - f32 sp44[3]; - - local = (ActorLocal_CCW_14B0 *)&this->local; - sp68 = time_getDelta(); - if (!this->volatile_initialized) { - this->volatile_initialized = true; - this->marker->actorFreeFunc = CCW_func_80387A20; - local->unk4 = &D_8038EC00[0]; - while((local->unk4->unk0 != 0) && (gsworld_getMap() != local->unk4->unk0)) { - local->unk4++; - } - local->sfxsourceIdx = sfxsource_createSfxsourceAndReturnIndex(); - local->unk18[0] = local->unk18[1] = local->unk18[2] = 0.0f; - sfxsource_setSfxId(local->sfxsourceIdx, 0x3FA); - sfxSource_setunk43_7ByIndex(local->sfxsourceIdx, 2); - sfxsource_playSfxAtVolume(local->sfxsourceIdx, 0.9f); - sfxsource_setSampleRate(local->sfxsourceIdx, 0); - func_803878A0(this, 1); - return; - } - - if (this->state == 1) { - sp5C[0] = local->unkC[0] - this->position[0]; - sp5C[1] = local->unkC[1] - this->position[1]; - sp5C[2] = local->unkC[2] - this->position[2]; - if (ml_vec3f_distance(this->position, local->unkC) < 500.0f) { - ml_vec3f_set_length(sp5C, local->unk8 * 8.0f); - } else { - ml_vec3f_set_length(sp5C, local->unk8 * 2); - } - this->position[0] += (local->unk18[0] * sp68) + (sp5C[0] * sp68 * sp68); - this->position[1] += (local->unk18[1] * sp68) + (sp5C[1] * sp68 * sp68); - this->position[2] += (local->unk18[2] * sp68) + (sp5C[2] * sp68 * sp68); - local->unk18[0] += sp5C[0] * sp68; - local->unk18[1] += sp5C[1] * sp68; - local->unk18[2] += sp5C[2] * sp68; - if (local->unk8 < LENGTH_VEC3F(local->unk18)) { - ml_vec3f_set_length(local->unk18, local->unk8); - } - func_80258A4C(this->position, this->yaw - 90.0f, local->unkC, &sp58, &sp54, &sp50); - this->yaw += 140.0f * sp50 * sp68; - if (ml_vec3f_distance(this->position, local->unkC) < 100.0f) { - func_803878A0(this, 1); - } - } - - if(this->position[0]); - - func_8030DBFC(local->sfxsourceIdx, 0.8f, 0.9f, 0.05f); - sfxsource_set_fade_distances(local->sfxsourceIdx, 500.0f, 1500.0f); - sfxsource_set_position(local->sfxsourceIdx, this->position); - sfxSource_func_8030E2C4(local->sfxsourceIdx); - sfxsource_setSampleRate(local->sfxsourceIdx, 2000.0f + 8000.0f*(LENGTH_VEC3F(local->unk18)/ local->unk8)); - if (!mapSpecificFlags_get(local->unk4->unk2)) { - player_getPosition(sp44); - if (sp44[2] > -600.0f) { - if (!local->unk4->unk3 || !jiggyscore_isCollected(local->unk4->unk3) ) { - gcdialog_showDialog(local->unk4->unk4, 4, NULL, NULL, NULL, NULL); - mapSpecificFlags_set(local->unk4->unk2, true); - } - } - } -} diff --git a/src/CCW/ch/zubbadoor.c b/src/CCW/ch/zubbadoor.c index 3ec863763..b8f6d1a26 100644 --- a/src/CCW/ch/zubbadoor.c +++ b/src/CCW/ch/zubbadoor.c @@ -3,14 +3,31 @@ #include "functions.h" #include "variables.h" -void func_803864B8(Actor *this); +void chZubbaDoor_update(Actor *this); -ActorInfo D_8038EB50 = { 0x1AC, 0x298, 0x444, 0x0, NULL, func_803864B8, NULL, actor_draw, 0, 0, 0.0f, 0}; -ActorInfo D_8038EB74 = { 0x1AC, 0x29A, 0x445, 0x0, NULL, func_803864B8, NULL, actor_draw, 0, 0, 0.0f, 0}; +ActorInfo chZubbaDoorSummer = { + MARKER_1AC_ZUBBA_DOOR, ACTOR_298_ZUBBA_DOOR_SUMMER, ASSET_444_MODEL_CCW_ZUBBA_DOOR, + 0x0, NULL, + chZubbaDoor_update, NULL, actor_draw, + 0, 0, 0.0f, 0 +}; + +ActorInfo chZubbaDoorAutumn = { + MARKER_1AC_ZUBBA_DOOR, ACTOR_29A_ZUBBA_DOOR_AUTUMN, ASSET_445_MODEL_CCW_ZUBBA_DOOR, + 0x0, NULL, + chZubbaDoor_update, NULL, actor_draw, + 0, 0, 0.0f, 0 +}; + +enum chZubbaDoor_State_e { + CH_ZUBBA_DOOR_STATE_0_NOT_INIT, + CH_ZUBBA_DOOR_STATE_1_IDLE, + CH_ZUBBA_DOOR_STATE_2_DESPAWN +}; /* .code */ -void CCW_func_803863F0(Actor *this, s32 next_state){ - if(next_state == 2){ +void chZubbaDoor_setState(Actor *this, s32 next_state){ + if(next_state == CH_ZUBBA_DOOR_STATE_2_DESPAWN){ sfx_playFadeShorthandDefault(SFX_2F_ORANGE_SPLAT, 1.0f, 32000, this->position, 500, 3000); levelSpecificFlags_set(LEVEL_FLAG_10_CCW_BREAK_ZUBBA_DOOR, true); marker_despawn(this->marker); @@ -20,17 +37,19 @@ void CCW_func_803863F0(Actor *this, s32 next_state){ void chZubbaDoor_die(ActorMarker* marker, ActorMarker *arg1) { Actor* actor = marker_getActor(marker); - if (actor->state == 1 && gsworld_getMap() == MAP_44_CCW_SUMMER) { - CCW_func_803863F0(actor, 2); + if (actor->state == CH_ZUBBA_DOOR_STATE_1_IDLE + && gsworld_getMap() == MAP_44_CCW_SUMMER) + { + chZubbaDoor_setState(actor, CH_ZUBBA_DOOR_STATE_2_DESPAWN); } } -void func_803864B8(Actor *this){ +void chZubbaDoor_update(Actor *this){ if(!this->volatile_initialized){ this->volatile_initialized = true; this->marker->propPtr->unk8_3 = true; marker_setCollisionScripts(this->marker, NULL, NULL, chZubbaDoor_die); - CCW_func_803863F0(this, 1); + chZubbaDoor_setState(this, CH_ZUBBA_DOOR_STATE_1_IDLE); if (levelSpecificFlags_get(LEVEL_FLAG_10_CCW_BREAK_ZUBBA_DOOR)) { marker_despawn(this->marker); diff --git a/src/CCW/ch/zubbahoneylump.c b/src/CCW/ch/zubbahoneylump.c new file mode 100644 index 000000000..e9180e887 --- /dev/null +++ b/src/CCW/ch/zubbahoneylump.c @@ -0,0 +1,244 @@ +// BanjoDecomp: CCW/ch/zubbahoneylump.c +#include +#include "core1/core1.h" +#include "functions.h" +#include "variables.h" + + + +typedef struct{ + ActorMarker *jiggyMarker; + s32 spawnedZubbaCount; + s32 zubbasDefeated; + f32 unkC; // time related +}ActorLocal_CCW_160; + +void chZubbaFight_setState(Actor *this, s32 next_state); +void chZubbaFight_update(Actor *this); + +/* .data */ +ActorInfo chZubbaHoneyLump = { + MARKER_1AD_ZUBBA_HONEY_LUMP, ACTOR_299_ZUBBA_HONEY_LUMP, ASSET_443_MODEL_ZUBBA_HONEY_LUMP, + 0x0, NULL, + chZubbaFight_update, NULL, actor_draw, + 0, 0, 0.0f, 0 +}; + +enum chZubbaFight_State_e { + CH_ZUBBA_FIGHT_STATE_0_NOT_INIT, + CH_ZUBBA_FIGHT_STATE_1_IDLE, + CH_ZUBBA_FIGHT_STATE_2_DIALOG, + CH_ZUBBA_FIGHT_STATE_3_FIGHT, + CH_ZUBBA_FIGHT_STATE_4_FIGHT_COMPLETE +}; + +#define NUM_OF_ZUBBAS_TO_DEFEAT 10 + +/* .code */ +void chZubbaFight_jiggy(ActorMarker *marker){ + Actor *this; + ActorLocal_CCW_160 *local; + + + this = marker_getActor(marker); + local = (ActorLocal_CCW_160 *)&this->local; + this->unk124_11 = 2; + this->alpha_124_19 = 0xFF; + if (local->jiggyMarker != NULL) { + actor_collisionOn(marker_getActor(local->jiggyMarker)); + } + coMusicPlayer_playMusic(COMUSIC_3D_JIGGY_SPAWN, 28000); +} + +void chZubbaFight_startFightDialog(ActorMarker* marker, enum asset_e text_id, s32 arg2) { + chZubbaFight_setState(marker_getActor(marker), CH_ZUBBA_FIGHT_STATE_3_FIGHT); +} + +void chZubbaFight_setState(Actor *this, s32 next_state) { + ActorLocal_CCW_160 *local; + + local = (ActorLocal_CCW_160 *)&this->local; + local->unkC = 0.0f; + if (next_state == CH_ZUBBA_FIGHT_STATE_2_DIALOG) { + if (!volatileFlag_getAndSet(VOLATILE_FLAG_B5, 1)) { + gcdialog_showDialog( + VER_SELECT(ASSET_CE2_DIALOG_ZUBBA_MEET_SUMMER, 0x09F7, 0, 0), 4, NULL, this->marker, chZubbaFight_startFightDialog, NULL); + } else { + gcdialog_showDialog(VER_SELECT(ASSET_CE3_DIALOG_ZUBBA_RETURN, 0x09F8, 0, 0), 4, NULL, NULL, NULL, NULL); + chZubbaFight_setState(this, CH_ZUBBA_FIGHT_STATE_3_FIGHT); + return; + } + } + + if (next_state == CH_ZUBBA_FIGHT_STATE_3_FIGHT) { + local->unkC = 0.1f; + func_8025A58C(0, 4000); + coMusicPlayer_playMusic(COMUSIC_4B_CCW_ZUBBA_FIGHT, 30000); + } + + if (next_state == CH_ZUBBA_FIGHT_STATE_4_FIGHT_COMPLETE) { + if (volatileFlag_get(VOLATILE_FLAG_2_FF_IN_MINIGAME)) { + item_set(ITEM_6_HOURGLASS, false); + volatileFlag_set(VOLATILE_FLAG_3, 0); + volatileFlag_set(VOLATILE_FLAG_5_FF_MINIGAME_WON, 1); + } else { + gcdialog_showDialog(VER_SELECT(ASSET_CE4_DIALOG_ZUBBA_COMPLETE, 0x09F9, 0, 0), 4, NULL, NULL, NULL, NULL); + func_8025A58C(-1, 400); + comusic_8025AB44(COMUSIC_4B_CCW_ZUBBA_FIGHT, 0, 400); + func_8025AABC(COMUSIC_4B_CCW_ZUBBA_FIGHT); + coMusicPlayer_playMusic(COMUSIC_2D_PUZZLE_SOLVED_FANFARE, 28000); + func_80324E38(0.0f, 3); + timed_setStaticCameraToNode(2.0f, 4); + timedFunc_set_1(2.0f, (GenFunction_1)chZubbaFight_jiggy, (uintptr_t)this->marker); + timed_exitStaticCamera(4.0f); + func_80324E38(4.0f, 0); + } + } + this->state = next_state; +} + +void chZubbaFight_zubbaKilled(ActorMarker *marker){ + Actor *this; + ActorLocal_CCW_160 *local; + + this = marker_getActor(marker); + local = (ActorLocal_CCW_160 *)&this->local; + local->zubbasDefeated++; + local->spawnedZubbaCount--; + if(local->zubbasDefeated == NUM_OF_ZUBBAS_TO_DEFEAT){ + chZubbaFight_setState(this, CH_ZUBBA_FIGHT_STATE_4_FIGHT_COMPLETE); + } +} + +void chZubbaFight_zubbaDisappear(ActorMarker *marker){ + Actor *this; + ActorLocal_CCW_160 *local; + + this = marker_getActor(marker); + local = (ActorLocal_CCW_160 *)&this->local; + local->spawnedZubbaCount--; +} + +void chZubbaFight_zubbaScore(ActorMarker *marker, s32 *score, s32 *total){ + Actor *this; + ActorLocal_CCW_160 *local; + + this = marker_getActor(marker); + local = (ActorLocal_CCW_160 *)&this->local; + + *score = local->zubbasDefeated; + *total = NUM_OF_ZUBBAS_TO_DEFEAT; +} + +void chZubbaFight_update(Actor *this) { + ActorLocal_CCW_160 *local; + f32 time_delta; + Actor *jiggy_actor; + f32 sp78[3]; + f32 sp6C[3]; + s32 pad68; + f32 player_position_1[3]; + s32 phi_s0; + f32 sp4C[3]; + f32 player_position_2[3]; + s32 phi_v0; + f32 tmp; + + time_delta = time_getDelta(); + local = (ActorLocal_CCW_160 *)&this->local; + if(!this->volatile_initialized) { + this->volatile_initialized = true; + this->marker->propPtr->unk8_3 = true; + local->jiggyMarker = (ActorMarker *)(uintptr_t)1; // [port] full pointer-width sentinel write + local->spawnedZubbaCount = 0; + local->zubbasDefeated = 0; + local->unkC = 0.0f; + if (volatileFlag_get(VOLATILE_FLAG_2_FF_IN_MINIGAME)) { + this->position_y -= 300.0f; + } + chZubbaFight_setState(this, CH_ZUBBA_FIGHT_STATE_1_IDLE); + return; + } + if ((uintptr_t)local->jiggyMarker == 1) { + jiggy_actor = actorArray_findActorFromActorId(ACTOR_46_JIGGY); + if(volatileFlag_get(VOLATILE_FLAG_2_FF_IN_MINIGAME)) { + local->jiggyMarker = NULL; + if (jiggy_actor != NULL) { + actor_collisionOff(jiggy_actor); + jiggy_actor->position[1] -= 300.0f; + } + } else if (jiggy_actor != NULL) { + local->jiggyMarker = jiggy_actor->marker; + actor_collisionOff(jiggy_actor); + if (jiggyscore_isCollected(JIGGY_4C_CCW_ZUBBAS) != 0) { + marker_despawn(local->jiggyMarker); + marker_despawn(this->marker); + } + } else { + marker_despawn(this->marker); + } + return; + } + + if (local->jiggyMarker != NULL) { + jiggy_actor = marker_getActor(local->jiggyMarker); + viewport_getPosition_vec3f(sp78); + sp6C[0] = this->position[0] - sp78[0]; + sp6C[1] = this->position[1] - sp78[1]; + sp6C[2] = this->position[2] - sp78[2]; + sp6C[1] = 0.0f; + ml_vec3f_set_length(sp6C, 20.0f); + jiggy_actor->position[0] = this->position[0] + sp6C[0]; + jiggy_actor->position[1] = this->position[1] + sp6C[1]; + jiggy_actor->position[2] = this->position[2] + sp6C[2]; + } + if (ml_timer_update(&local->unkC, time_delta)) { + if ((local->spawnedZubbaCount < 3) && ((local->zubbasDefeated + local->spawnedZubbaCount) < 10)) { + player_getPosition(player_position_1); + for(phi_s0 = 0; phi_s0 < 20; phi_s0++){ + sp4C[0] = randf2(-500.0f, 500.0f); + sp4C[1] = -100.0f; + sp4C[2] = randf2(-500.0f, 900.0f); + + if(ml_vec3f_distance(this->position, sp4C) < 400.0f) + continue; + + tmp = ml_vec3f_distance(player_position_1, sp4C); + phi_v0 = (phi_s0 < 0xA) ? 500 : 200; + if(tmp < (f32) phi_v0) + continue; + + if(viewport_isPointOutsideFrustum_3f(sp4C[0], 0.0f, sp4C[2])) + break; + + } + __spawnQueue_add_4((GenFunction_4)spawnQueue_actor_f32, ACTOR_29B_ZUBBA, reinterpret_cast(s32, sp4C[0]), reinterpret_cast(s32, sp4C[1]), reinterpret_cast(s32, sp4C[2])); + local->spawnedZubbaCount++; + } + local->unkC = randf2(0.5 - ((local->zubbasDefeated / 10) * 0.4), 1.0 - ((local->zubbasDefeated / 10) * 0.8)); + } + if (this->state == CH_ZUBBA_FIGHT_STATE_1_IDLE) { + if (volatileFlag_get(VOLATILE_FLAG_2_FF_IN_MINIGAME) + && volatileFlag_get(VOLATILE_FLAG_3)) + { + item_set(ITEM_6_HOURGLASS, 1); + item_set(ITEM_0_HOURGLASS_TIMER, VER_SELECT(1800, 1500, 1, 1) - 1); + chZubbaFight_setState(this, CH_ZUBBA_FIGHT_STATE_3_FIGHT); + } else if ((local->jiggyMarker != NULL) && (gsworld_getMap() == MAP_5A_CCW_SUMMER_ZUBBA_HIVE)) { + player_getPosition(player_position_2); + if ((ml_vec3f_distance(this->position, player_position_2) < 300.0f) + && (player_getTransformation() == TRANSFORM_1_BANJO)) + { + chZubbaFight_setState(this, CH_ZUBBA_FIGHT_STATE_2_DIALOG); + } + } + } + if ((this->state == CH_ZUBBA_FIGHT_STATE_3_FIGHT) + && volatileFlag_get(VOLATILE_FLAG_2_FF_IN_MINIGAME) + && item_empty(ITEM_0_HOURGLASS_TIMER)) + { + item_set(ITEM_6_HOURGLASS, 0); + volatileFlag_set(VOLATILE_FLAG_3, 0); + volatileFlag_set(VOLATILE_FLAG_5_FF_MINIGAME_WON, 0); + } +} diff --git a/src/CCW/checksums.c b/src/CCW/checksums.c new file mode 100644 index 000000000..11836811f --- /dev/null +++ b/src/CCW/checksums.c @@ -0,0 +1,7 @@ +// BanjoDecomp: CCW/checksums.c +#include +#include "checksums.h" + +// !! THIS FILE MUST BE LINKED FIRST FOR THIS OVERLAY !! + +/* bss */ struct overlay_checksums_s gChecksumsCCW; diff --git a/src/CCW/eyrie_baby.c b/src/CCW/eyrie_baby.c new file mode 100644 index 000000000..50c384f8e --- /dev/null +++ b/src/CCW/eyrie_baby.c @@ -0,0 +1,382 @@ +// BanjoDecomp: code_3310.c +#include +#include "functions.h" +#include "variables.h" +#include "port/Patches/Patches.h" + +typedef struct { + f32 unk0; + s16 unk4; + f32 unk8; + s16 unkC; +} Eyrie_Baby_SFX; + +typedef struct { + s16 map_id; + s16 requiredFileProgress; + s16 unlocksFileProgress; + s16 waitingAnimation; + Eyrie_Baby_SFX *waitingSFX; + s16 nextStateWhenComplete; // Probably only used for Spring + s16 yawningAnimation; + Eyrie_Baby_SFX *yawnSFX; + s16 goingToSleepAnimation; + // u8 pad16[2]; + Eyrie_Baby_SFX *goingToSleepSFX; + s16 sleepingAnimation; + // u8 pad1E[0x2]; + Eyrie_Baby_SFX *sleepingSFX; + u8 cameraNode; + u8 caterpillarRequirement; + s16 eatingAnimation; + s16 meetDialog; + // u8 pad2A[2]; +} Eyrie_Baby_Dialog; + +typedef struct { + Eyrie_Baby_Dialog *progression; + u8 eatenCount; + //u8 pad5[3]; + Eyrie_Baby_SFX *sfx; + s32 unkC[3]; // something about player position? +} ActorLocal_CCW_3310; + +Actor *chEyrieBaby_draw(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx); +void chEyrieBaby_update(Actor *this); + +/* .data */ +enum cheyriebaby_state_e { + CH_EYRIE_BABY_STATE_0_NOT_HATCHED, + CH_EYRIE_BABY_STATE_1_IDLE, + CH_EYRIE_BABY_STATE_2_YAWNING, + CH_EYRIE_BABY_STATE_3_GOING_TO_SLEEP, + CH_EYRIE_BABY_STATE_4_SLEEPING, + CH_EYRIE_BABY_STATE_5_EATING_CATERPILLARS +}; + +Eyrie_Baby_SFX chEyrieBabyWaitingSFX[] = { + {0.11f, SFX_4A_CLUCKER_AHH, 1.1f, 25000}, + {0.22f, SFX_4A_CLUCKER_AHH, 1.1f, 25000}, + {0.34f, SFX_4A_CLUCKER_AHH, 1.1f, 25000}, + {0.55f, SFX_2_CLAW_SWIPE, 1.1f, 25000}, + {0.65f, SFX_2_CLAW_SWIPE, 1.0f, 26000}, + {0.77f, SFX_2_CLAW_SWIPE, 1.1f, 25000}, + {0.87f, SFX_2_CLAW_SWIPE, 1.0f, 24000}, + 0 +}; + +Eyrie_Baby_SFX chEyrieBabyYawnSFX[] = { + {0.1f, SFX_80_YUMYUM_CLACK, 0.9f, 15000}, + {0.25f, SFX_4C_LIP_SMACK, 1.0f, 15000}, + {0.31f, SFX_4C_LIP_SMACK, 0.9f, 15000}, + {0.38f, SFX_4C_LIP_SMACK, 1.0f, 15000}, + {0.48f, SFX_4C_LIP_SMACK, 0.9f, 15000}, + {0.55f, SFX_97_BLUBBER_BURPS, 0.9f, 32700}, + {0.6f , SFX_2C_PULLING_NOISE, 0.7f, 25000}, + {0.73f, SFX_2C_PULLING_NOISE, 0.8f, 27000}, + {0.85f, SFX_2C_PULLING_NOISE, 0.9f, 29000}, + 0 +}; + +Eyrie_Baby_SFX chEyrieBabyGoingToSleepSFX[] = { + {0.2f , SFX_105_EYRIE_YAWN, 1.1f, 25000}, + {0.27f, SFX_105_EYRIE_YAWN, 1.0f, 25000}, + {0.35f, SFX_105_EYRIE_YAWN, 0.9f, 25000}, + {0.6f , SFX_106_EYRIE_LIPSMACK, 1.0f, 25000}, + {0.66f, SFX_106_EYRIE_LIPSMACK, 0.9f, 23000}, + {0.83f, SFX_1D_HITTING_AN_ENEMY_1, 0.7f, 27000}, + 0 +}; + +Eyrie_Baby_SFX chEyrieBabySleepingSFX[] = { + {0.2f , SFX_5D_BANJO_RAAOWW, 1.0f, 25000}, + {0.72f, SFX_5E_BANJO_PHEWWW, 1.0f, 25000}, + 0 +}; + +Eyrie_Baby_SFX chEyrieBabyEatingSFX[] = { + {0.95f, SFX_106_EYRIE_LIPSMACK, 1.0f, 25000}, + 0 +}; + +Eyrie_Baby_Dialog chEyrieBabyProgression[] = { + { + MAP_43_CCW_SPRING, // Map + 0, FILEPROG_E6_SPRING_EYRIE_HATCHED, // File Progress + 0, NULL, // Waiting + CH_EYRIE_BABY_STATE_3_GOING_TO_SLEEP, // Unk + 0, NULL, // Yawning + 0x18F, chEyrieBabyGoingToSleepSFX, // Going To Sleep + 0x190, chEyrieBabySleepingSFX, // Sleeping + 0, // Camera Node + 0, // Caterpillar Requirement + 0, // Eating Animation + 0 // Meet Dialog + }, + { + MAP_44_CCW_SUMMER, // Map + FILEPROG_E6_SPRING_EYRIE_HATCHED, FILEPROG_E7_SUMMER_EYRIE_FED, // File Progress + 0x191, chEyrieBabyWaitingSFX, // Waiting + CH_EYRIE_BABY_STATE_2_YAWNING, // Unk + 0x192, chEyrieBabyYawnSFX, // Yawning + 0x193, chEyrieBabyGoingToSleepSFX, // Going To Sleep + 0x194, chEyrieBabySleepingSFX, // Sleeping + 2, // Camera Node + 5, // Caterpillar Requirement + 0x21A, // Eating Animation + VER_SELECT(ASSET_CD7_DIALOG_BABY_EYRIE_MEET_SUMMER, 0x09EC, 0, 0) // Meet Dialog + }, + { + MAP_45_CCW_AUTUMN, // Map + FILEPROG_E7_SUMMER_EYRIE_FED, FILEPROG_E8_AUTMN_EYRIE_FED, // File Progress + 0x195, chEyrieBabyWaitingSFX, // Waiting + CH_EYRIE_BABY_STATE_2_YAWNING, // Unk + 0x196, chEyrieBabyYawnSFX, // Yawning + 0x197, chEyrieBabyGoingToSleepSFX, // Going To Sleep + 0x198, chEyrieBabySleepingSFX, // Sleeping + 4, // Camera Node + 10, // Caterpillar Requirement + 0x21B, // Eating Animation + VER_SELECT(ASSET_CDA_DIALOG_BABY_EYRIE_MEET_FALL, 0x09EF, 0, 0) // Meet Dialog + }, + { 0 } // [port] decomp uses NULL; first field is an integer and clang errors on -Wint-conversion +}; + +ActorInfo chEyrieBaby = { + MARKER_1B4_EEYRIE_BABY, ACTOR_2A1_EEYRIE_BABY, ASSET_484_MODEL_EAGLE_BABY, + 0x0, NULL, + chEyrieBaby_update, NULL, chEyrieBaby_draw, + 0, 0, 0.0f, 0 +}; + +/* .bss */ +f32 chEyrieBabyThrowPosition[3]; + +/* .code */ +void func_80389700(ActorMarker *marker, enum asset_e text_id, s32 arg2) { + timed_exitStaticCamera(0.5f); + func_80324E38(0.5f, 0); +} + +void func_80389740(ActorMarker *marker) { + Actor *this = marker_getActor(marker); + if (this->marker->unk14_21) { + __spawnQueue_add_4((GenFunction_4)spawnQueue_actor_f32, 0x30C, reinterpret_cast(s32, chEyrieBabyThrowPosition[0]), reinterpret_cast(s32, chEyrieBabyThrowPosition[1]), reinterpret_cast(s32, chEyrieBabyThrowPosition[2])); + } +} + +void chEyrieBaby_saysMama() { + func_8030E6D4(SFX_18C_EYRIE_MAMA); +} + +void chEyrieBaby_setState(Actor *this, s32 next_state) { + ActorLocal_CCW_3310 *local; + + local = (ActorLocal_CCW_3310 *)&this->local; + local->sfx = NULL; + if (next_state == CH_EYRIE_BABY_STATE_1_IDLE) { + if (local->progression->waitingAnimation != NULL) { + skeletalAnim_set(this->unk148, local->progression->waitingAnimation, 0.2f, 6.0f); + skeletalAnim_setBehavior(this->unk148, SKELETAL_ANIM_1_LOOP); + } + local->sfx = local->progression->waitingSFX; + } + if ((this->state == CH_EYRIE_BABY_STATE_1_IDLE) + && (next_state == CH_EYRIE_BABY_STATE_2_YAWNING)) { + fileProgressFlag_set(local->progression->unlocksFileProgress, true); + } + if (next_state == CH_EYRIE_BABY_STATE_5_EATING_CATERPILLARS) { + func_8028F784(1); + skeletalAnim_set(this->unk148, local->progression->eatingAnimation, 0.2f, 2.0f); + skeletalAnim_setBehavior(this->unk148, SKELETAL_ANIM_2_ONCE); + local->sfx = &chEyrieBabyEatingSFX[0]; + } + + if (next_state == CH_EYRIE_BABY_STATE_2_YAWNING) { + skeletalAnim_set(this->unk148, local->progression->yawningAnimation, 0.2f, 8.0f); + skeletalAnim_setBehavior(this->unk148, SKELETAL_ANIM_2_ONCE); + func_80324E38(0.5f, 3); + timed_setStaticCameraToNode(0.5f, local->progression->cameraNode); + timed_exitStaticCamera(16.5f); + func_80324E38(16.5f, 0); + local->sfx = local->progression->yawnSFX; + } + if (next_state == CH_EYRIE_BABY_STATE_3_GOING_TO_SLEEP) { + actor_collisionOff(this); + skeletalAnim_set(this->unk148, local->progression->goingToSleepAnimation, 0.5f, 8.5f); + skeletalAnim_setBehavior(this->unk148, SKELETAL_ANIM_2_ONCE); + if (local->progression->map_id == MAP_43_CCW_SPRING) { + gcdialog_showDialog(VER_SELECT(ASSET_CD6_DIALOG_BABY_EYRIE_HATCH, 0x09EB, 0, 0), 4, NULL, NULL, NULL, NULL); + skeletalAnim_setCallback_0(this->unk148, 0.65f, &chEyrieBaby_saysMama); + } + if (local->progression->map_id == MAP_44_CCW_SUMMER) { + gcdialog_showDialog(VER_SELECT(ASSET_CD9_DIALOG_BABY_EYRIE_COMPLETE_SUMMER, 0x09EE, 0, 0), 4, NULL, NULL, NULL, NULL); + } + if (local->progression->map_id == MAP_45_CCW_AUTUMN) { + gcdialog_showDialog(VER_SELECT(ASSET_CDB_DIALOG_BABY_EYRIE_COMPLETE_FALL, 0x09F0, 0, 0), 4, NULL, NULL, NULL, NULL); + } + local->sfx = local->progression->goingToSleepSFX; + } + if (next_state == CH_EYRIE_BABY_STATE_4_SLEEPING) { + func_8028F784(0); + skeletalAnim_set(this->unk148, local->progression->sleepingAnimation, 0.2f, 6.0f); + skeletalAnim_setBehavior(this->unk148, SKELETAL_ANIM_1_LOOP); + skeletalAnim_setCallback_1(this->unk148, 0.2f, (GenFunction_1)func_80389740, (uintptr_t)this->marker); + skeletalAnim_setCallback_1(this->unk148, 0.3f, (GenFunction_1)func_80389740, (uintptr_t)this->marker); + skeletalAnim_setCallback_1(this->unk148, 0.4f, (GenFunction_1)func_80389740, (uintptr_t)this->marker); + skeletalAnim_setCallback_1(this->unk148, 0.72f, (GenFunction_1)func_80389740, (uintptr_t)this->marker); + skeletalAnim_setCallback_1(this->unk148, 0.82f, (GenFunction_1)func_80389740, (uintptr_t)this->marker); + skeletalAnim_setCallback_1(this->unk148, 0.92f, (GenFunction_1)func_80389740, (uintptr_t)this->marker); + local->sfx = local->progression->sleepingSFX; + } + this->state = next_state; +} + +Actor *chEyrieBaby_draw(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx){ + Actor *this; + ActorLocal_CCW_3310 *local; + + this = marker_getActor(marker); + local = (ActorLocal_CCW_3310 *)&this->local; + if( (this->state == CH_EYRIE_BABY_STATE_0_NOT_HATCHED) + || ((this->state == CH_EYRIE_BABY_STATE_1_IDLE) + && (local->progression->waitingAnimation == NULL)) + ) { + return this; + } + modelRender_setAppendageVisibility(3, (this->state == CH_EYRIE_BABY_STATE_4_SLEEPING) ? 2 : 1); + actor_draw(marker, gfx, mtx, vtx); + vec3fArray_get_vec3f(func_80329934(), 5, chEyrieBabyThrowPosition); + return this; +} + +void func_80389BD8(f32 dst[3]){ + dst[0] = chEyrieBabyThrowPosition[0]; + dst[1] = chEyrieBabyThrowPosition[1]; + dst[2] = chEyrieBabyThrowPosition[2]; +} + +void chEyrieBaby_update(Actor *this) { + Eyrie_Baby_SFX *iPtr; + ActorLocal_CCW_3310 *local; + f32 sp5C; + f32 sp58; + f32 player_position[3]; + + local = (ActorLocal_CCW_3310 *)&this->local; + + if (!this->volatile_initialized) { + this->volatile_initialized = true; + this->marker->propPtr->unk8_3 = true; + this->has_met_before = false; + this->position[0] = -4900.0f; + this->position[1] = 4619.0f; + this->position[2] = 0.0f; + chEyrieBabyThrowPosition[0] = this->position[0]; + chEyrieBabyThrowPosition[1] = this->position[1]; + chEyrieBabyThrowPosition[2] = this->position[2]; + if (this->state == CH_EYRIE_BABY_STATE_0_NOT_HATCHED) { + local->eatenCount = (u32)port_puzzleCount_get(ANCHOR_COUNT_CCW_EYRIE_FED); + } + local->progression = &chEyrieBabyProgression[0]; + while(local->progression->map_id != NULL && gsworld_getMap() != local->progression->map_id){ + local->progression++; + } + + if ((local->progression->requiredFileProgress != NULL) + && !fileProgressFlag_get(local->progression->requiredFileProgress)) + { + marker_despawn(this->marker); + } else if (!fileProgressFlag_get(local->progression->unlocksFileProgress)) { + chEyrieBaby_setState(this, CH_EYRIE_BABY_STATE_1_IDLE); + } else { + chEyrieBaby_setState(this, CH_EYRIE_BABY_STATE_4_SLEEPING); + } + + if (jiggyscore_isSpawned(JIGGY_49_CCW_EYRIE) != false) { + marker_despawn(this->marker); + } + return; + } + + if (local->sfx) { + skeletalAnim_getProgressRange(this->unk148, &sp5C, &sp58); + for(iPtr = local->sfx; iPtr->unk0 > 0.0f; iPtr ++){ + if ((sp5C < iPtr->unk0) && (iPtr->unk0 <= sp58)) { + func_8030E878((s32) iPtr->unk4, randf2(iPtr->unk8 - 0.05, iPtr->unk8 + 0.05), iPtr->unkC, this->position, 500.0f, 2500.0f); + } + } + } + if (this->state == CH_EYRIE_BABY_STATE_1_IDLE) { + player_getPosition(player_position); + if( !this->has_met_before + && (local->unkC[2] >= 6500) + && (player_position[2] < 6500.0f) + && (local->progression->meetDialog != NULL) + ){ + this->has_met_before = true; + func_80324E38(0.0f, 3); + timed_setStaticCameraToNode(0.0f, local->progression->cameraNode); + func_80324DBC(0.0f, local->progression->meetDialog, 6, NULL, this->marker, func_80389700, NULL); + } + local->unkC[0] = (s32) player_position[0]; + local->unkC[1] = (s32) player_position[1]; + local->unkC[2] = (s32) player_position[2]; + if (item_getCount(ITEM_22_CATERPILLAR) == 0) { + func_8028F784(0); + } + if ((local->progression->map_id != MAP_43_CCW_SPRING) + && ((this->position[0] + 500.0f) < player_position[0])) + { + player_setCarryObjectPoseInCylinder(this->position, 1110.0f, 200.0f, ACTOR_2A2_CATERPILLAR, &this); + if ((local->progression->yawningAnimation != NULL) + && (carriedObj_getActorId() == ACTOR_2A2_CATERPILLAR) + && (ml_vec3f_distance(this->position, player_position) < 1010.0f) + && (player_throwCarriedObject() != 0)) + { + player_setThrowTargetPosition(chEyrieBabyThrowPosition); + if ((local->progression->map_id == MAP_44_CCW_SUMMER) + && (local->eatenCount == 0)) + { + gcdialog_showDialog(VER_SELECT(ASSET_CD8_DIALOG_BABY_EYRIE_CHECK_SUMMER, 0x09ED, 0, 0), 4, NULL, NULL, NULL, NULL); + } + port_puzzleCount_add(ANCHOR_COUNT_CCW_EYRIE_FED, 1); + local->eatenCount = (u32)port_puzzleCount_get(ANCHOR_COUNT_CCW_EYRIE_FED); + if (local->eatenCount < local->progression->caterpillarRequirement) { + chEyrieBaby_setState(this, CH_EYRIE_BABY_STATE_5_EATING_CATERPILLARS); + } else { + chEyrieBaby_setState(this, CH_EYRIE_BABY_STATE_2_YAWNING); + } + } + } + // Anchor: teammate fed a worm — play the interim eat animation; final feed handled below. + if (this->state == CH_EYRIE_BABY_STATE_1_IDLE) { + s32 sharedFed = port_puzzleCount_get(ANCHOR_COUNT_CCW_EYRIE_FED); + if (sharedFed > (s32)local->eatenCount) { + local->eatenCount = (u32)sharedFed; + if ((s32)local->eatenCount < (s32)local->progression->caterpillarRequirement) { + chEyrieBaby_setState(this, CH_EYRIE_BABY_STATE_5_EATING_CATERPILLARS); + } + } + } + if (this->state == CH_EYRIE_BABY_STATE_1_IDLE && fileProgressFlag_get(local->progression->unlocksFileProgress)) { + // Anchor: fed flag synced from a teammate — skip to sleep state (spring keeps its hatch cutscene). + chEyrieBaby_setState(this, (local->progression->map_id == MAP_43_CCW_SPRING) ? local->progression->nextStateWhenComplete : CH_EYRIE_BABY_STATE_4_SLEEPING); + } + } + if ((this->state == CH_EYRIE_BABY_STATE_2_YAWNING) + && (skeletalAnim_getLoopCount(this->unk148) > 0)) + { + chEyrieBaby_setState(this, CH_EYRIE_BABY_STATE_3_GOING_TO_SLEEP); + } + if ((this->state == CH_EYRIE_BABY_STATE_3_GOING_TO_SLEEP) + && (skeletalAnim_getLoopCount(this->unk148) > 0)) + { + chEyrieBaby_setState(this, CH_EYRIE_BABY_STATE_4_SLEEPING); + } + if ((this->state == CH_EYRIE_BABY_STATE_5_EATING_CATERPILLARS) + && (skeletalAnim_getLoopCount(this->unk148) > 0)) + { + chEyrieBaby_setState(this, CH_EYRIE_BABY_STATE_1_IDLE); + } +} diff --git a/src/CCW/flower.c b/src/CCW/flower.c deleted file mode 100644 index 15c8c394e..000000000 --- a/src/CCW/flower.c +++ /dev/null @@ -1,184 +0,0 @@ -// BanjoDecomp: code_1B20.c -#include -#include "functions.h" -#include "variables.h" - -typedef struct{ - s16 unk0; - u8 unk2; - u8 unk3; - s16 unk4; - s16 unk6; - s16 unk8; // enum file_progress_e - s16 unkA; -}Struct_CCW_1B20_0; - -typedef struct{ - Struct_CCW_1B20_0 *unk0; -}ActorLocal_CCW_1B20; - -void func_80387F64(Actor *this, s32 next_state); -Actor *CCW_func_803882F4(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx); -void func_80388478(Actor *this); - -/* .data */ -Struct_CCW_1B20_0 D_8038EC40[4] ={ - {0x173, 4, 0, 0x173, 0x181, 0xE3, 0}, - {0x181, 1, 1, 0x174, 0x182, 0xE4, 0}, - {0x182, 1, 1, 0x175, 0x183, 0xE5, 1}, - {0x183, 1, 1, 0x000, 0x000, 0x00, 0} -}; - -// Anchor: set during a remote-water replay; skips camera/fanfare/jiggy spawn. -static s32 sFlowerRemoteGrow = 0; - -ActorInfo D_8038EC70 = { 0x1B0, 0x29D, 0x447, 0x0, NULL, func_80388478, NULL, CCW_func_803882F4, 0, 0, 1.0f, 0}; -f32 D_8038EC94[3] = {200.0f, 2120.0f, -5570.0f}; - -/* .code */ -void func_80387F10() { - jiggy_spawn(JIGGY_4D_CCW_FLOWER, D_8038EC94); -} - -void func_80387F38(ActorMarker* marker, s32 arg1) { - func_80387F64(marker_getActor(marker), arg1); -} - -void func_80387F64(Actor *this, s32 next_state){ - ActorLocal_CCW_1B20 *local; - f32 phi_f22; - - local = (ActorLocal_CCW_1B20 *)&this->local; - - if (next_state == 1) { - this->marker->propPtr->unk8_3 = local->unk0->unk3; - skeletalAnim_set(this->unk148, local->unk0->unk0, 0.0f, 5.0f); - skeletalAnim_setBehavior(this->unk148, local->unk0->unk2); - } - if (next_state == 2) { - if (gsworld_getMap() == MAP_43_CCW_SPRING && !sFlowerRemoteGrow) { - coMusicPlayer_playMusic(COMUSIC_2D_PUZZLE_SOLVED_FANFARE, 28000); - } - fileProgressFlag_set(local->unk0->unk8, true); - skeletalAnim_set(this->unk148, local->unk0->unk4, 0.0f, 6.0f); - skeletalAnim_setBehavior(this->unk148, SKELETAL_ANIM_2_ONCE); - if (gsworld_getMap() == MAP_43_CCW_SPRING && !sFlowerRemoteGrow) { - func_80324E38(0.0f, 3); - } - if (!sFlowerRemoteGrow) { - timed_setStaticCameraToNode(0.0f, 0); - } - for( phi_f22 = 0.0f; phi_f22 <= 1.0f; phi_f22 += 0.1) { - timed_playSfx(phi_f22 * 5.7, 0x2C, phi_f22 * 0.3 + 0.7, (s32) (32000.0f - phi_f22 * 5000.0f)); - } - if (local->unk0->unkA != 0) { - if (!sFlowerRemoteGrow) { - timed_setStaticCameraToNode(6.0f, 1); - timedFunc_set_0(6.1f, (GenFunction_0)func_80387F10); - } - timedFunc_set_2(8.0f, (GenFunction_2)func_80387F38, (uintptr_t)this->marker, 3); - } else { - if (gsworld_getMap() == MAP_43_CCW_SPRING && !sFlowerRemoteGrow) { - timed_exitStaticCamera(7.0f); - func_80324E38(7.0f, 0); - } - timedFunc_set_2(7.0f, (GenFunction_2)func_80387F38, (uintptr_t)this->marker, 3); - } - } - - if (next_state == 3) { - this->marker->propPtr->unk8_3 = true; - skeletalAnim_set(this->unk148, local->unk0->unk6, 0.1f, 5.0f); - skeletalAnim_setBehavior(this->unk148, SKELETAL_ANIM_1_LOOP); - } - this->state = next_state; -} - -s32 func_80388260(ActorMarker *marker, s32 arg1){ - return marker->unk40_31 != 1; -} - -void CCW_func_80388278(ActorMarker *marker, ActorMarker *other_marker) { - coMusicPlayer_playMusic(COMUSIC_2B_DING_B, 28000); -} - -void func_803882A4(ActorMarker* marker, ActorMarker *other_marker) { - Actor* actor = marker_getActor(marker); - - // [port] v1.1 fix: don't allow re-planting flower in Spring after it's already been planted - if (EventSystem_Should(VB_CCW_FLOWER_REPLANT, - gsworld_getMap() == MAP_43_CCW_SPRING && actor->state == 1 && - !fileProgressFlag_get(FILEPROG_E3_CCW_FLOWER_SPRING))) { - func_80387F64(actor, 2); - } -} - -Actor *CCW_func_803882F4(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx) { - Actor *this; - s32 sp18; - - this = marker_getActor(marker); - if ((this->state == 1) && !fileProgressFlag_get(FILEPROG_E3_CCW_FLOWER_SPRING)) { - return func_80325340(marker, gfx, mtx, vtx); - } - - if ((skeletalAnim_getAnimId(this->unk148) == 0x175) && (0.49 <= skeletalAnim_getProgress(this->unk148))) { - sp18 = 1; - } else { - sp18 = 0; - } - sp18 = (skeletalAnim_getAnimId(this->unk148) == 0x183)? 1 : sp18; - func_8033A45C(3, sp18); - func_8033A45C(4, sp18); - return actor_draw(marker, gfx, mtx, vtx); -} - -void func_803883F4() { - Actor* actor = actorArray_findActorFromActorId(0x29D); - if (actor && actor->state == 1) { - func_80387F64(actor, 2); - } -} - -bool func_80388438() { - Actor* actor = actorArray_findActorFromActorId(0x29D); - if (actor && actor->state == 2) { - return true; - } - return false; -} - -void func_80388478(Actor *this) { - ActorLocal_CCW_1B20 *local; - - local = (ActorLocal_CCW_1B20 *)&this->local; - if (!this->volatile_initialized) { - this->volatile_initialized = true; - func_803300C0(this->marker, (s32 (*)(ActorMarker *, ActorMarker *))func_80388260); - marker_setCollisionScripts(this->marker, NULL, CCW_func_80388278, func_803882A4); - actor_collisionOn(this); - if (!jiggyscore_isSpawned(JIGGY_4D_CCW_FLOWER)) { - fileProgressFlag_set(FILEPROG_E5_CCW_FLOWER_AUTUMN, false); - } - - for(local->unk0 = &D_8038EC40[0]; local->unk0 < D_8038EC40 + 3; local->unk0++){ - if(!fileProgressFlag_get(local->unk0->unk8)){ - break; - } - } - - if (!fileProgressFlag_get(FILEPROG_E3_CCW_FLOWER_SPRING) && (gsworld_getMap() != MAP_43_CCW_SPRING)) { - marker_despawn(this->marker); - } - else{ - func_80387F64(this, 1); - } - return; - } - - if ((this->state == 1) && EventSystem_Should(VB_CCW_FLOWER_REMOTE_GROW, false, (s32)local->unk0->unk8)) { - sFlowerRemoteGrow = 1; - func_80387F64(this, 2); - sFlowerRemoteGrow = 0; - } -} diff --git a/src/CCW/minigame_zubba.c b/src/CCW/minigame_zubba.c deleted file mode 100644 index a1b71edc1..000000000 --- a/src/CCW/minigame_zubba.c +++ /dev/null @@ -1,221 +0,0 @@ -// BanjoDecomp: code_160.c -#include -#include "core1/core1.h" -#include "functions.h" -#include "variables.h" - - - -typedef struct{ - ActorMarker *unk0; - s32 unk4; - s32 unk8; - f32 unkC; -}ActorLocal_CCW_160; - -void func_803865F4(Actor *this, s32 next_state); -void func_8038687C(Actor *this); - -/* .data */ -ActorInfo D_8038EBA0 = { 0x1AD, 0x299, 0x443, 0x0, NULL, func_8038687C, NULL, actor_draw, 0, 0, 0.0f, 0}; - -/* .code */ -void CCW_func_80386550(ActorMarker *marker){ - Actor *this; - ActorLocal_CCW_160 *local; - - - this = marker_getActor(marker); - local = (ActorLocal_CCW_160 *)&this->local; - this->unk124_11 = 2; - this->alpha_124_19 = 0xFF; - if (local->unk0 != NULL) { - actor_collisionOn(marker_getActor(local->unk0)); - } - coMusicPlayer_playMusic(COMUSIC_3D_JIGGY_SPAWN, 28000); -} - -void func_803865C4(ActorMarker* marker, enum asset_e text_id, s32 arg2) { - func_803865F4(marker_getActor(marker), 3); -} - -void func_803865F4(Actor *this, s32 next_state) { - ActorLocal_CCW_160 *local; - - local = (ActorLocal_CCW_160 *)&this->local; - local->unkC = 0.0f; - if (next_state == 2) { - if (!volatileFlag_getAndSet(VOLATILE_FLAG_B5, 1)) { - gcdialog_showDialog(0xCE2, 4, NULL, this->marker, func_803865C4, NULL); - } else { - gcdialog_showDialog(0xCE3, 4, NULL, NULL, NULL, NULL); - func_803865F4(this, 3); - return; - } - } - - if (next_state == 3) { - local->unkC = 0.1f; - func_8025A58C(0, 4000); - coMusicPlayer_playMusic(COMUSIC_4B_CCW_ZUBBA_FIGHT, 30000); - } - - if (next_state == 4) { - if (volatileFlag_get(VOLATILE_FLAG_2_FF_IN_MINIGAME)) { - item_set(ITEM_6_HOURGLASS, false); - volatileFlag_set(VOLATILE_FLAG_3, 0); - volatileFlag_set(VOLATILE_FLAG_5_FF_MINIGAME_WON, 1); - } else { - gcdialog_showDialog(0xCE4, 4, NULL, NULL, NULL, NULL); - func_8025A58C(-1, 400); - comusic_8025AB44(COMUSIC_4B_CCW_ZUBBA_FIGHT, 0, 400); - func_8025AABC(COMUSIC_4B_CCW_ZUBBA_FIGHT); - coMusicPlayer_playMusic(COMUSIC_2D_PUZZLE_SOLVED_FANFARE, 28000); - func_80324E38(0.0f, 3); - timed_setStaticCameraToNode(2.0f, 4); - timedFunc_set_1(2.0f, (GenFunction_1)CCW_func_80386550, (uintptr_t)this->marker); - timed_exitStaticCamera(4.0f); - func_80324E38(4.0f, 0); - } - } - this->state = next_state; -} - -void func_803867C8(ActorMarker *marker){ - Actor *this; - ActorLocal_CCW_160 *local; - - this = marker_getActor(marker); - local = (ActorLocal_CCW_160 *)&this->local; - local->unk8++; - local->unk4--; - if(local->unk8 == 10){ - func_803865F4(this, 4); - } -} - -void func_80386814(ActorMarker *marker){ - Actor *this; - ActorLocal_CCW_160 *local; - - this = marker_getActor(marker); - local = (ActorLocal_CCW_160 *)&this->local; - local->unk4--; -} - -void func_80386840(ActorMarker *marker, s32 *score, s32 *total){ - Actor *this; - ActorLocal_CCW_160 *local; - - this = marker_getActor(marker); - local = (ActorLocal_CCW_160 *)&this->local; - - *score = local->unk8; - *total = 10; -} - -void func_8038687C(Actor *this) { - ActorLocal_CCW_160 *local; - f32 sp88; - Actor *other; - f32 sp78[3]; - f32 sp6C[3]; - s32 pad68; - f32 sp5C[3]; - s32 phi_s0; - f32 sp4C[3]; - f32 sp40[3]; - s32 phi_v0; - f32 tmp; - - sp88 = time_getDelta(); - local = (ActorLocal_CCW_160 *)&this->local; - if(!this->volatile_initialized) { - this->volatile_initialized = true; - this->marker->propPtr->unk8_3 = true; - reinterpret_cast(s32, local->unk0) = 1; - local->unk4 = 0; - local->unk8 = 0; - local->unkC = 0.0f; - if (volatileFlag_get(VOLATILE_FLAG_2_FF_IN_MINIGAME)) { - this->position_y -= 300.0f; - } - func_803865F4(this, 1); - return; - } - if ((uintptr_t)local->unk0 == 1) { - other = actorArray_findActorFromActorId(0x46); - if(volatileFlag_get(VOLATILE_FLAG_2_FF_IN_MINIGAME)) { - local->unk0 = NULL; - if (other != NULL) { - actor_collisionOff(other); - other->position[1] -= 300.0f; - } - } else if (other != NULL) { - local->unk0 = other->marker; - actor_collisionOff(other); - if (jiggyscore_isCollected(JIGGY_4C_CCW_ZUBBAS) != 0) { - marker_despawn(local->unk0); - marker_despawn(this->marker); - } - } else { - marker_despawn(this->marker); - } - return; - } - - if (local->unk0 != NULL) { - other = marker_getActor(local->unk0); - viewport_getPosition_vec3f(sp78); - sp6C[0] = this->position[0] - sp78[0]; - sp6C[1] = this->position[1] - sp78[1]; - sp6C[2] = this->position[2] - sp78[2]; - sp6C[1] = 0.0f; - ml_vec3f_set_length(sp6C, 20.0f); - other->position[0] = this->position[0] + sp6C[0]; - other->position[1] = this->position[1] + sp6C[1]; - other->position[2] = this->position[2] + sp6C[2]; - } - if (ml_timer_update(&local->unkC, sp88)) { - if ((local->unk4 < 3) && ((local->unk8 + local->unk4) < 10)) { - player_getPosition(sp5C); - for(phi_s0 = 0; phi_s0 < 20; phi_s0++){ - sp4C[0] = randf2(-500.0f, 500.0f); - sp4C[1] = -100.0f; - sp4C[2] = randf2(-500.0f, 900.0f); - - if(ml_vec3f_distance(this->position, sp4C) < 400.0f) - continue; - - tmp = ml_vec3f_distance(sp5C, sp4C); - phi_v0 = (phi_s0 < 0xA) ? 500 : 200; - if(tmp < (f32) phi_v0) - continue; - - if(viewport_isPointOutsideFrustum_3f(sp4C[0], 0.0f, sp4C[2])) - break; - - } - __spawnQueue_add_4((GenFunction_4)spawnQueue_actor_f32, 0x29B, reinterpret_cast(s32, sp4C[0]), reinterpret_cast(s32, sp4C[1]), reinterpret_cast(s32, sp4C[2])); - local->unk4++; - } - local->unkC = randf2(0.5 - ((local->unk8 / 10) * 0.4), 1.0 - ((local->unk8 / 10) * 0.8)); - } - if (this->state == 1) { - if (volatileFlag_get(VOLATILE_FLAG_2_FF_IN_MINIGAME) && volatileFlag_get(VOLATILE_FLAG_3)) { - item_set(ITEM_6_HOURGLASS, 1); - item_set(ITEM_0_HOURGLASS_TIMER, 1800 - 1); - func_803865F4(this, 3); - } else if ((local->unk0 != NULL) && (gsworld_getMap() == MAP_5A_CCW_SUMMER_ZUBBA_HIVE)) { - player_getPosition(sp40); - if ((ml_vec3f_distance(this->position, sp40) < 300.0f) && (player_getTransformation() == TRANSFORM_1_BANJO)) { - func_803865F4(this, 2); - } - } - } - if ((this->state == 3) && volatileFlag_get(VOLATILE_FLAG_2_FF_IN_MINIGAME) && item_empty(ITEM_0_HOURGLASS_TIMER)) { - item_set(ITEM_6_HOURGLASS, 0); - volatileFlag_set(VOLATILE_FLAG_3, 0); - volatileFlag_set(VOLATILE_FLAG_5_FF_MINIGAME_WON, 0); - } -} diff --git a/src/CCW/nabnut_winter.c b/src/CCW/nabnut_winter.c new file mode 100644 index 000000000..13589719b --- /dev/null +++ b/src/CCW/nabnut_winter.c @@ -0,0 +1,174 @@ +// BanjoDecomp: code_5BF0.c +#include +#include "functions.h" +#include "variables.h" + +extern void func_8028E668(f32[3], f32, f32, f32); + +Actor *func_8038C380(ActorMarker* marker, Gfx** gfx, Mtx** mtx, Vtx** vtx); +void func_8038C41C(Actor *this); + +/* .data */ + +ActorInfo chMoundOfAcorns = { + MARKER_1C6_MOUND_OF_ACORNS, ACTOR_310_NABNUT_HOUSE_PILE_OF_ACORNS, ASSET_501_MODEL_MOUND_OF_ACORNS, + 0x0, NULL, + func_8038C41C, NULL, actor_draw, + 0, 0, 0.0f, 0 +}; + +ActorInfo chPinkSquirrel = { + MARKER_1C7_PINK_SQUIRREL, ACTOR_311_PINK_SQUIRREL, ASSET_462_MODEL_PINK_SQUIRREL, + 0x0, NULL, + func_8038C41C, NULL, func_8038C380, + 0, 0, 0.0f, 0 +}; + +ActorInfo chNabnutBedsheets = { + MARKER_1C8_NABNUT_BEDSHEETS, ACTOR_312_NABNUT_BEDSHEETS, ASSET_463_MODEL_NABNUT_BEDSHEETS, + 0x0, NULL, + func_8038C41C, NULL, actor_draw, + 0, 0, 0.0f, 0 +}; + +ActorInfo chNabnutBed = { + MARKER_1C9_NABNUT_BED, ACTOR_313_NABNUT_BED, ASSET_464_MODEL_NABNUT_BED, + 0x0, NULL, + func_8038C41C, NULL, actor_draw, + 0, 0, 0.0f, 0 +}; + +ActorInfo chNabnut = { + MARKER_1CA_NABNUT, ACTOR_314_NABNUT_IN_AUTUMN_HOUSE, ASSET_502_MODEL_NABNUT, + 0x0, NULL, + func_8038C41C, NULL, actor_draw, + 0, 0, 2.0f, 0 +}; + +ActorInfo chNabnutAutumnEatingAcorns = { + MARKER_1CB_NABNUT_EATING_ACORNS, ACTOR_315_NABNUT_EATING_ACORNS, ASSET_48D_MODEL_NABNUT_EATING_ACORNS, + 0x0, NULL, func_8038C41C, + NULL, func_8038C380, + 0, 0, 0.0f, 0 +}; + +enum code_5BF0_state_e { + CODE_5BF0_STATE_0_NOT_INIT, + CODE_5BF0_STATE_1_CCW_AUTUMN_AFTER_ACORN_JIGGY, + CODE_5BF0_STATE_2_CCW_WINTER_OR_NO_ACORN_JIGGY +}; + +/* .code */ +void func_8038BFE0(ActorMarker* marker) { + Actor* sp2C = marker_getActor(marker); + func_8030E878(SFX_5D_BANJO_RAAOWW, randf2(1.0f, 1.1f), (s32)randf2(21000.0f, 22000.0f), sp2C->position, 500.0f, 2500.0f); +} + +void func_8038C064(ActorMarker* marker) { + Actor* sp2C = marker_getActor(marker); + func_8030E878(SFX_5E_BANJO_PHEWWW, randf2(1.0f, 1.1f), (s32)randf2(21000.0f, 22000.0f), sp2C->position, 500.0f, 2500.0f); +} + +void func_8038C0E8(ActorMarker* marker) { + Actor* sp24 = marker_getActor(marker); + f32 sp20 = randf2(0.9f, 1.1f); + + func_8030E878(SFX_81_UUU, sp20, (s32)randf2(10000.0f, 31000.0f), sp24->position, 500.0f, 2500.0f); +} + +void code_5BF0_setState(Actor *this, s32 next_state) { + Actor *other; + + if (next_state == CODE_5BF0_STATE_1_CCW_AUTUMN_AFTER_ACORN_JIGGY) { + this->position[1] -= 300.0f; + } + + if (this->state == CODE_5BF0_STATE_1_CCW_AUTUMN_AFTER_ACORN_JIGGY) { + this->position[1] += 300.0f; + } + + if (next_state == CODE_5BF0_STATE_2_CCW_WINTER_OR_NO_ACORN_JIGGY) { + if (this->marker->id == MARKER_1CA_NABNUT) { + skeletalAnim_set(this->unk148, ASSET_22E_ANIM_NABNUT_STAND, 0.2f, 3.53f); + skeletalAnim_setCallback_1(this->unk148, 0.1f, (GenFunction_1)func_8038C0E8, (uintptr_t)this->marker); + } + if (this->marker->id == MARKER_1C7_PINK_SQUIRREL) { + skeletalAnim_set(this->unk148, ASSET_230_ANIM_PINK_SQUIRREL_UNK, 0.2f, 4.0f); + } + if (this->marker->id == MARKER_1CB_NABNUT_EATING_ACORNS) { + skeletalAnim_set(this->unk148, ASSET_1A2_ANIM_NABNUT_SLEEP, 0.2f, 4.0f); + skeletalAnim_setCallback_1(this->unk148, 0.3f, (GenFunction_1)func_8038BFE0, (uintptr_t)this->marker); + skeletalAnim_setCallback_1(this->unk148, 0.65f, (GenFunction_1)func_8038C064, (uintptr_t)this->marker); + } + if (this->marker->id == MARKER_1C8_NABNUT_BEDSHEETS) { + skeletalAnim_set(this->unk148, ASSET_231_ANIM_NABNUT_BEDSHEETS_UNK, 0.2f, 4.0f); + } + if ((this->marker->id == MARKER_1C7_PINK_SQUIRREL) + || (this->marker->id == MARKER_1CB_NABNUT_EATING_ACORNS) + || (this->marker->id == MARKER_1C8_NABNUT_BEDSHEETS)) + { + other = actorArray_findActorFromActorId(ACTOR_313_NABNUT_BED); + if (other != 0) { + this->position[0] = other->position[0]; + this->position[1] = other->position[1]; + this->position[2] = other->position[2]; + this->pitch = other->pitch; + this->yaw = other->yaw; + this->roll = other->roll; + } + } + } + this->state = next_state; +} + +Actor *func_8038C380(ActorMarker* marker, Gfx** gfx, Mtx** mtx, Vtx** vtx) { + modelRender_setAppendageVisibility(3, 0); + modelRender_setAppendageVisibility(4, 0); + modelRender_setAppendageVisibility(5, 0); + modelRender_setAppendageVisibility(6, 1); + modelRender_setAppendageVisibility(7, 0); + modelRender_setAppendageVisibility(8, 0); + modelRender_setAppendageVisibility(9, 0); + modelRender_setAppendageVisibility(0xA, 1); + return actor_draw(marker, gfx, mtx, vtx); +} + +void func_8038C41C(Actor *this) { + f32 player_position[3]; + + if (!this->volatile_initialized) { + this->marker->propPtr->unk8_3 = true; + this->volatile_initialized = true; + this->has_met_before = false; + return; + } + + if (this->state == CODE_5BF0_STATE_0_NOT_INIT) { + if( gsworld_getMap() == MAP_60_CCW_AUTUMN_NABNUTS_HOUSE + && !jiggyscore_isSpawned(JIGGY_4A_CCW_NABNUT) + && (this->marker->id == MARKER_1C6_MOUND_OF_ACORNS + || this->marker->id == MARKER_1CA_NABNUT) + ){ + code_5BF0_setState(this, CODE_5BF0_STATE_1_CCW_AUTUMN_AFTER_ACORN_JIGGY); + } else { + code_5BF0_setState(this, CODE_5BF0_STATE_2_CCW_WINTER_OR_NO_ACORN_JIGGY); + } + } + + if ((this->marker->id == MARKER_1CA_NABNUT) + && (this->state != CODE_5BF0_STATE_1_CCW_AUTUMN_AFTER_ACORN_JIGGY)) + { + func_8028E668(this->position, 300.0f, -50.0f, 120.0f); + } + + if ((this->marker->id == MARKER_1CB_NABNUT_EATING_ACORNS) + && (this->state == CODE_5BF0_STATE_2_CCW_WINTER_OR_NO_ACORN_JIGGY)) + { + player_getPosition(player_position); + if (!this->has_met_before && (ml_vec3f_distance(this->position, player_position) < 400.0f)) { + this->has_met_before = TRUE; + gcdialog_showDialog(VER_SELECT(ASSET_CCD_DIALOG_NABNUT_MEET_WINTER, 0x09E2, 0, 0), 0, NULL, NULL, NULL, NULL); + } + } +} + diff --git a/src/CCW/seasonal_switch.c b/src/CCW/seasonal_switch.c deleted file mode 100644 index 18b7b48d5..000000000 --- a/src/CCW/seasonal_switch.c +++ /dev/null @@ -1,179 +0,0 @@ -// BanjoDecomp: code_2B00.c -#include -#include "functions.h" -#include "variables.h" - -typedef struct{ - u8 unk0; - u8 unk1; - u8 unk2; - u8 unk3; -}Struct_CCW_2B00_0; - -void func_80389268(Actor *this); -void func_80388FD4(Actor *this); - -/* .data */ -Struct_CCW_2B00_0 D_8038ED10[] = { - {0, 0x40, 0, 5}, - {0, 0x43, 1, 5}, - {0, 0x44, 2, 5}, - {0, 0x45, 3, 15} -}; - -ActorAnimationInfo D_8038ED20[] = { - {0, 0.0f}, - {0, 0.0f}, - {0, 0.0f}, - {0, 0.0f}, - {ASSET_D4_ANIM_SWITCH_DOWN, 0.5f}, - {ASSET_D4_ANIM_SWITCH_DOWN, 100000000.0f} -}; - -ActorInfo D_8038ED50 = { 0x133, 0x1E3, 0x52E, 0x1, NULL, func_80389268, actor_update_func_80326224, actor_drawFullDepth, 0, 0x4000, 0.0f, 0}; -ActorInfo D_8038ED74 = { 0x132, 0x1E2, 0x4F5, 0x5, D_8038ED20, func_80388FD4, actor_update_func_80326224, actor_draw, 0, 0, 0.0f, 0}; -ActorInfo D_8038ED98 = { 0x131, 0x16D, 0x52E, 0x1, NULL, func_80389268, actor_update_func_80326224, actor_drawFullDepth, 0, 0x4000, 0.0f, 0}; -ActorInfo D_8038EDBC = { 0x130, 0x16C, 0x4F6, 0x5, D_8038ED20, func_80388FD4, actor_update_func_80326224, actor_draw, 0, 0, 0.0f, 0}; -ActorInfo D_8038EDE0 = { 0x12F, 0x16B, 0x52E, 0x1, NULL, func_80389268, actor_update_func_80326224, actor_drawFullDepth, 0, 0x4000, 0.0f, 0}; -ActorInfo D_8038EE04 = { 0x12E, 0x16A, 0x4F7, 0x5, D_8038ED20, func_80388FD4, actor_update_func_80326224, actor_draw, 0, 0, 0.0f, 0}; -ActorInfo D_8038EE28 = { 0x12D, 0x169, 0x52E, 0x1, NULL, func_80389268, actor_update_func_80326224, actor_drawFullDepth, 0, 0x4000, 0.0f, 0}; -ActorInfo D_8038EE4C = { 0x12C, 0x168, 0x4F8, 0x5, D_8038ED20, func_80388FD4, actor_update_func_80326224, actor_draw, 0, 0, 0.0f, 0}; - -/* .code */ -s32 func_80388EF0(Actor *this){ - switch(this->marker->id){ - case 0x133: //L80388F28 - case 0x132: //L80388F28 - return 0; - - case 0x131: //L80388F30 - case 0x130: //L80388F30 - return 1; - - case 0x12F: //L80388F38 - case 0x12E: //L80388F38 - return 2; - - case 0x12D: //L80388F40 - case 0x12C: //L80388F40 - return 3; - - default: - return 0; - } -} - - -void func_80388F50(ActorMarker *marker, ActorMarker *other_marker){ - Actor *this; - - this = marker_getActor(marker); - if ((player_movementGroup() != BSGROUP_1_INTR) && !this->unk38_0) { - this->unk38_0 = true; - actor_collisionOff(this); - subaddie_set_state_with_direction(this, 4, 0.0f, 1); - actor_playAnimationOnce(this); - func_8030E6D4(SFX_90_SWITCH_PRESS); - } -} - -void func_80388FD4(Actor *this) { - - if (!this->initialized) { - this->unk138_31 = this->unk124_0 = true; - this->marker->propPtr->unk8_3 = true; - this->unk10_12 = func_80388EF0(this); - this->initialized = true; - } - if (!this->volatile_initialized) { - if (fileProgressFlag_get(this->unk10_12 + FILEPROG_8B_CCW_SPRING_OPEN)) { - actor_playAnimationOnce(this); - subaddie_set_state_with_direction(this, 4, 0.999f, 1); - actor_collisionOff(this); - } else { - marker_setCollisionScripts(this->marker, NULL, &func_80388F50, NULL); - } - this->unk38_0 = false; - this->volatile_initialized = true; - } - // Anchor: teammate pressed this switch (flag synced) — drop it to match; unk38_0 stays false. - if( this->state != 4 - && fileProgressFlag_get(this->unk10_12 + FILEPROG_8B_CCW_SPRING_OPEN) - ){ - actor_playAnimationOnce(this); - subaddie_set_state_with_direction(this, 4, 0.999f, 1); - actor_collisionOff(this); - } - if( (this->state == 4) - && this->unk38_0 - && actor_animationIsAt(this, 0.999f) - ){ - func_802D6264(1.1f, 0x40, this->unk10_12 + 0x3C, 0x2B, D_8038ED10[this->unk10_12].unk3, this->unk10_12 + 0x8B); - func_80324E38(0.5f, 3); - timedFunc_set_2(1.1f, (GenFunction_2)levelSpecificFlags_set, this->unk10_12 + 7, true); - func_80324E38(5.6f, 0); - } -} - -void func_803891B0(void* marker) { - Actor* actor = marker_getActor(reinterpret_cast(ActorMarker*, marker)); - actor->unk44_31 = func_8030ED2C(SFX_3EC_CCW_DOOR_OPENING, 3); - func_8030DD90(actor->unk44_31, 0); - sfxsource_setSampleRate(actor->unk44_31, 0x2AF8); - sfxsource_playSfxAtVolume(actor->unk44_31, 0.3f); - sfxSource_func_8030E2C4(actor->unk44_31); -} - -void func_8038921C(void* marker) { - Actor* actor = marker_getActor(reinterpret_cast(ActorMarker*, marker)); - sfxSource_triggerCallbackByIndex(actor->unk44_31); - sfxsource_freeSfxsourceByIndex(actor->unk44_31); - actor->unk44_31 = 0U; - FUNC_8030E624(SFX_6C_LOCKUP_CLOSING, 1.0f, 25000); -} - -void func_80389268(Actor *this) { - ActorProp *temp_v1; - u32 temp_v0; - u32 temp_v1_2; - - if(!this->initialized) { - this->unk58_2 = false; - this->unk10_12 = func_80388EF0(this); - this->marker->propPtr->unk8_3 = true; - actor_collisionOff(this); - this->initialized = true; - } - if (!this->volatile_initialized) { - this->unk1C[0] = this->position[0]; - this->unk1C[1] = this->position[1]; - this->unk1C[2] = this->position[2]; - this->unk1C[1] += 250.0f; - - this->volatile_initialized = true; - if (fileProgressFlag_get(this->unk10_12 + FILEPROG_8B_CCW_SPRING_OPEN)) { - subaddie_set_state(this, 3); - } - } - - - switch (this->state) { /* irregular */ - case 1: - if (levelSpecificFlags_get(this->unk10_12 + 7)) { - timedFunc_set_1(0.05f, (GenFunction_1)func_803891B0, (uintptr_t)this->marker); - timedFunc_set_1(4.0f, (GenFunction_1)func_8038921C, (uintptr_t)this->marker); - subaddie_set_state(this, 2); - } - break; - case 2: - this->position[1] += 60.0f * time_getDelta(); - if (this->unk1C[1] <= this->position[1]) { - levelSpecificFlags_set(this->unk10_12 + 7, false); - subaddie_set_state(this, 3); - } - break; - case 3: - this->position[1] = this->unk1C[1]; - break; - } -} diff --git a/src/CCW/snarebear_proximity.c b/src/CCW/snarebear_proximity.c deleted file mode 100644 index 1090a0529..000000000 --- a/src/CCW/snarebear_proximity.c +++ /dev/null @@ -1,122 +0,0 @@ -// BanjoDecomp: code_7BF0.c -#include -#include "functions.h" -#include "variables.h" - - -void func_8038E0C8(Actor *this); - -/* .data */ -ActorAnimationInfo D_8038F8F0[] = { - {0x000, 0.0f}, - {0x16C, 2.0f}, - {0x16B, 1.2f} -}; - -ActorInfo D_8038F908 = { - MARKER_1F9_SNARE_BEAR, ACTOR_1E9_SNARE_BEAR, ASSET_440_MODEL_SNAREBEAR, - 0x1, D_8038F8F0, - func_8038E0C8, actor_update_func_80326224, actor_draw, - 0, 0, 0.0f, 0 -}; - -/* .code */ -void func_8038DFE0(Actor* actor) { - subaddie_set_state_with_direction(actor, 1, 0.001f, 1); - actor->unk38_31 = randi2(0, 0); -} - -void CCW_func_8038E034(Actor* actor) { - subaddie_set_state_with_direction(actor, 2, 0.001f, 1); -} - -void func_8038E060(BoneTransformList *arg0, ActorMarker *marker){ - Actor *this; - f32 sp28[3]; - s32 pad24; - f32 sp18[4]; // quaternion: func_80345C78 writes 4 floats - - this = marker_getActor(marker); - if(arg0){ - sp28[0] = 0.0f; - sp28[1] = this->unk1C[0]; - sp28[2] = 0.0f; - - - func_80345C78(sp18, sp28); - func_8033A8F0(arg0, 1, sp18); - modelRender_setBoneTransformList(arg0); - } -} - -void func_8038E0C8(Actor *this) { - f32 sp44[3]; - f32 sp40; - f32 sp3C; - f32 sp38; - f32 sp34; - - sp34 = time_getDelta(); - - if(!subaddie_playerIsWithinSphere(this, 3000)) return; - - if (!this->volatile_initialized) { - this->volatile_initialized = true; - func_8028746C(this->anctrl, (GenFunction_2)func_8038E060); - func_8028748C(this->anctrl, (uintptr_t)this->marker); - this->marker->propPtr->unk8_3 = true; - this->unk1C[0] = 0.0f; - this->unk38_31 = 0; - } - - if (player_getTransformation() == TRANSFORM_6_BEE) { - actor_collisionOff(this); - } else { - actor_collisionOn(this); - player_getPosition(sp44); - func_80258A4C(this->position, this->yaw - 90.0f, sp44, &sp40, &sp3C, &sp38); - if( (sp40 < 1050.0f) - && (sp38 > -1.0f) - && (sp38 < 1.0f) - ) { - func_80258A4C(this->position, this->unk1C[0] + (this->yaw - 90.0f), sp44, &sp40, &sp3C, &sp38); - this->unk1C[0] += sp38 * 160.0f * sp34; - } else { - if (this->unk1C[0] > 0.0f) { - this->unk1C[0] -= (30.0f * sp34); - this->unk1C[0] = (this->unk1C[0] < 0.0f) ? 0.0f : this->unk1C[0]; - - } else if (this->unk1C[0] < 0.0f) { - this->unk1C[0] += (30.0f * sp34); - this->unk1C[0] = (this->unk1C[0] > 0.0f) ? 0.0f : this->unk1C[0]; - } - } - } - switch (this->state) { - case 1: - if (this->unk38_31 != 0) { - this->unk38_31--; - break; - } - if( subaddie_playerIsWithinSphereAndActive(this, 0x2A8) - && (this->unk38_31 == 0) - && (player_getTransformation() == TRANSFORM_1_BANJO) - ) { - CCW_func_8038E034(this); - } - break; - - case 2: - if (actor_animationIsAt(this, 0.999f)) { - func_8038DFE0(this); - break; - } - if( actor_animationIsAt(this, 0.18f) - || actor_animationIsAt(this, 0.47f) - || actor_animationIsAt(this, 0.78f) - ) { - sfx_playFadeShorthandDefault(SFX_80_YUMYUM_CLACK, 1.0f, 32000, this->position, 1500, 3000); - } - break; - } -} diff --git a/src/CCW/zubba.c b/src/CCW/zubba.c new file mode 100644 index 000000000..bb9095edc --- /dev/null +++ b/src/CCW/zubba.c @@ -0,0 +1,240 @@ +// BanjoDecomp: code_950.c +#include +#include "functions.h" +#include "variables.h" + +extern void func_8030DBFC(u8, f32, f32, f32); + +typedef struct{ + u8 sfxsourceIdx; + //u8 pad1[3]; + ActorMarker *honeyLumpMarker; + f32 distanceToPlayer[3]; + f32 unk14; + f32 unk18; // time related +}ActorLocal_CCW_950; + +void chZubba_update(Actor *this); + +/* .data */ +ActorInfo chZubba = { + MARKER_1AE_ZUBBA, ACTOR_29B_ZUBBA, ASSET_446_MODEL_ZUBBA, + 0x0, NULL, + chZubba_update, NULL, actor_draw, + 0, 0, 1.0f, 0 +}; + +enum chzubba_state_e { + CH_ZUBBA_STATE_0_NOT_INIT, + CH_ZUBBA_STATE_1_NON_AGRO_FLYING, + CH_ZUBBA_STATE_2_ATTACK, + CH_ZUBBA_STATE_3_HIT_PLAYER, + CH_ZUBBA_STATE_4_DIE, + CH_ZUBBA_STATE_5_SPLAT, + CH_ZUBBA_STATE_6_DIE_DESPAWN, + CH_ZUBBA_STATE_7_FIGHT_COMPLETE_DESPAWN +}; + +/* .code */ +void chZubba_setState(Actor *this, s32 next_state) { + ActorLocal_CCW_950 *local; + f32 player_position_1[3]; + f32 player_position_2[3]; + + local = (ActorLocal_CCW_950 *)&this->local; + local->unk18 = 0.0f; + if (next_state == CH_ZUBBA_STATE_1_NON_AGRO_FLYING) { + local->unk18 = 800.0f; + skeletalAnim_set(this->unk148, ASSET_16F_ANIM_ZUBBA_FLY_MOVE, 0.0f, 0.65f); + } + if (next_state == CH_ZUBBA_STATE_2_ATTACK) { + skeletalAnim_set(this->unk148, ASSET_170_ANIM_ZUBBA_FLY_IDLE, 0.1f, 0.65f); + player_getPosition(player_position_1); + player_position_1[1] += 50.0f; + local->distanceToPlayer[0] = player_position_1[0] - this->position[0]; + local->distanceToPlayer[1] = player_position_1[1] - this->position[1]; + local->distanceToPlayer[2] = player_position_1[2] - this->position[2]; + ml_vec3f_normalize(local->distanceToPlayer); + if ((local->distanceToPlayer[0] == 0.0f) + && (local->distanceToPlayer[1] == 0.0f) + && (local->distanceToPlayer[2] == 0.0f)) + { + local->distanceToPlayer[1] = -1.0f; + } + } + if (next_state == CH_ZUBBA_STATE_3_HIT_PLAYER) { + sfx_playFadeShorthandDefault(SFX_1F_HITTING_AN_ENEMY_3, 1.2f, 32200, this->position, 500, 3000); + func_80324D54(randf2(0.1f, 0.4f), SFX_3FC_ZUBBA_UNK, randf2(0.95f, 1.1f), 32000, this->position, 500.0f, 3000.0f); + actor_collisionOff(this); + } + if (next_state == CH_ZUBBA_STATE_4_DIE) { + skeletalAnim_set(this->unk148, ASSET_171_ANIM_ZUBBA_DIE, 0.1f, 0.2f); + sfx_playFadeShorthandDefault(SFX_1F_HITTING_AN_ENEMY_3, 1.2f, 32200, this->position, 500, 3000); + func_80324D54(0.1f, 0x66, randf2(1.6f, 1.7f), 32000, this->position, 500.0f, 3000.0f); + chZubbaFight_zubbaKilled(local->honeyLumpMarker); + actor_collisionOff(this); + player_getPosition(player_position_2); + player_position_2[1] += 50.0f; + local->distanceToPlayer[0] = this->position[0] - player_position_2[0]; + local->distanceToPlayer[1] = this->position[1] - player_position_2[1]; + local->distanceToPlayer[2] = this->position[2] - player_position_2[2]; + ml_vec3f_normalize(local->distanceToPlayer); + if ((local->distanceToPlayer[0] == 0.0f) + && (local->distanceToPlayer[1] == 0.0f) + && (local->distanceToPlayer[2] == 0.0f)) + { + local->distanceToPlayer[1] = -1.0f; + } + } + if (next_state == CH_ZUBBA_STATE_5_SPLAT) { + func_8030E878(SFX_A_BANJO_LANDING_05, randf2(0.85f, 0.95f), 18000, this->position, 500.0f, 3000.0f); + skeletalAnim_set(this->unk148, ASSET_172_ANIM_ZUBBA_LAND, 0.0f, 1.0f); + skeletalAnim_setBehavior(this->unk148, SKELETAL_ANIM_2_ONCE); + } + if (next_state == CH_ZUBBA_STATE_6_DIE_DESPAWN) { + marker_despawn(this->marker); + } + if (next_state == CH_ZUBBA_STATE_7_FIGHT_COMPLETE_DESPAWN) { + chZubbaFight_zubbaDisappear(local->honeyLumpMarker); + marker_despawn(this->marker); + } + this->state = next_state; +} + + +void chZubba_hitPlayer(ActorMarker* marker, ActorMarker *other_marker) { + chZubba_setState(marker_getActor(marker), CH_ZUBBA_STATE_3_HIT_PLAYER); +} + +void chZubba_die(ActorMarker* marker, ActorMarker *other_marker) { + chZubba_setState(marker_getActor(marker), CH_ZUBBA_STATE_4_DIE); +} + +void chZubba_freeSfx(Actor *this){ + ActorLocal_CCW_950 *local; + + local = (ActorLocal_CCW_950 *)&this->local; + sfxsource_freeSfxsourceByIndex(local->sfxsourceIdx); +} + +void chZubba_update(Actor *this) { + ActorLocal_CCW_950 *local; + f32 time_delta; + Actor *honey_lump_actor; + s32 zubbas_defeated; + s32 zubbas_to_defeat; + f32 player_position[3]; + f32 horizontal_distance; + f32 distance_in_front; + f32 side_angle_radian; + f32 temp_f0; + f32 pad; + + + time_delta = time_getDelta(); + local = (ActorLocal_CCW_950 *)&this->local; + if (!this->volatile_initialized) { + this->volatile_initialized = true; + this->marker->actorFreeFunc = chZubba_freeSfx; + local->sfxsourceIdx = sfxsource_createSfxsourceAndReturnIndex(); + local->honeyLumpMarker = 0; + local->unk14 = 1000.0f; + sfxsource_setSfxId(local->sfxsourceIdx, SFX_3FA_HONEYCOMB_TALKING); + sfxSource_setunk43_7ByIndex(local->sfxsourceIdx, 2); + sfxsource_playSfxAtVolume(local->sfxsourceIdx, 0.9f); + sfxsource_setSampleRate(local->sfxsourceIdx, 0); + marker_setCollisionScripts(this->marker, chZubba_hitPlayer, NULL, chZubba_die); + chZubba_setState(this, CH_ZUBBA_STATE_1_NON_AGRO_FLYING); + return; + } + if(local->honeyLumpMarker == NULL) { + honey_lump_actor = actorArray_findActorFromActorId(ACTOR_299_ZUBBA_HONEY_LUMP); + if (honey_lump_actor == NULL) { + marker_despawn(this->marker); + return; + } + local->honeyLumpMarker = honey_lump_actor->marker; + chZubbaFight_zubbaScore(local->honeyLumpMarker, &zubbas_defeated, &zubbas_to_defeat); + local->unk14 = (((f32)zubbas_defeated /(f32)zubbas_to_defeat) * 1000.0f) + 1000.0f; + } + + if (this->state == CH_ZUBBA_STATE_1_NON_AGRO_FLYING) { + temp_f0 = this->position[1]; + this->position[0] += 0.1 * time_delta; + this->position[1] += local->unk18 * time_delta; + if ((temp_f0 < 0.0f) && (this->position[1] >= 0.0f)) { + func_8030E878(SFX_A_BANJO_LANDING_05, randf2(1.0f, 1.1f), 18000, this->position, 500.0f, 3000.0f); + } + player_getPosition(player_position); + func_80258A4C( + this->position, this->yaw - 90.0f, player_position, + &horizontal_distance, &distance_in_front, &side_angle_radian); + this->yaw += 360.0f * side_angle_radian * time_delta; + if (this->position[1] > 150.0f) { + local->unk18 -= 2000.0f * time_delta; + if (local->unk18 < 0.0f) { + chZubba_setState(this, CH_ZUBBA_STATE_2_ATTACK); + } + } + } + + if (this->state == CH_ZUBBA_STATE_2_ATTACK) { + if (local->unk18 < local->unk14) { + local->unk18 += (4.0f * local->unk14 * time_delta); + } + this->position[0] += local->distanceToPlayer[0] * local->unk18 * time_delta; + this->position[1] += local->distanceToPlayer[1] * local->unk18 * time_delta; + this->position[2] += local->distanceToPlayer[2] * local->unk18 * time_delta; + if( (this->position[0] < -1500.0f) || (1500.0f < this->position[0]) + || (this->position[1] < -100.0f) || (1300.0f < this->position[1]) + || (this->position[2] < -1200.0f) || (this->position[2] > 2000.0f) + ){ + chZubba_setState(this, CH_ZUBBA_STATE_7_FIGHT_COMPLETE_DESPAWN); + } + } + + if (this->state == CH_ZUBBA_STATE_3_HIT_PLAYER) { + this->position[1] += local->unk18 * time_delta; + if (local->unk18 < local->unk14) { + local->unk18 += 2000.0f * time_delta; + } + + if( (this->position[0] < -1500.0f) || (1500.0f < this->position[0]) + || (this->position[1] < -100.0f) || (1300.0f < this->position[1]) + || (this->position[2] < -1200.0f) || (this->position[2] > 2000.0f) + ) { + chZubba_setState(this, CH_ZUBBA_STATE_7_FIGHT_COMPLETE_DESPAWN); + } + } + + if (this->state == CH_ZUBBA_STATE_4_DIE) { + this->position[0] += local->distanceToPlayer[0] * 1000.0f * time_delta; + this->position[1] -= local->unk18 * time_delta; + this->position[2] += local->distanceToPlayer[2] * 1000.0f * time_delta; + if (local->unk18 < local->unk14) { + local->unk18 += (1000.0f * time_delta); + } + if (this->position[1] <= 0.0f) { + this->position[1] = 0.0f; + chZubba_setState(this, CH_ZUBBA_STATE_5_SPLAT); + } + } + + if (this->state == CH_ZUBBA_STATE_5_SPLAT) { + this->position[1] -= 300.0f * time_delta; + if (this->position[1] < -200.0f) { + chZubba_setState(this, CH_ZUBBA_STATE_6_DIE_DESPAWN); + } + } + + if(this->state); + if (this->state == CH_ZUBBA_STATE_2_ATTACK) { + func_8030DBFC(local->sfxsourceIdx, 1.0f, 1.1f, 0.05f); + } else { + func_8030DBFC(local->sfxsourceIdx, 0.8f, 0.9f, 0.05f); + } + sfxsource_set_fade_distances(local->sfxsourceIdx, 500.0f, 1500.0f); + sfxsource_set_position(local->sfxsourceIdx, this->position); + sfxSource_func_8030E2C4(local->sfxsourceIdx); + sfxsource_setSampleRate(local->sfxsourceIdx, (s32) ((local->unk18 / local->unk14) * 10000.0f)); +} diff --git a/src/CCW/zubba_hive_npc.c b/src/CCW/zubba_hive_npc.c new file mode 100644 index 000000000..499b1abb7 --- /dev/null +++ b/src/CCW/zubba_hive_npc.c @@ -0,0 +1,157 @@ +// BanjoDecomp: code_14B0.c +#include "functions.h" +#include "variables.h" +#include + +#include + +extern void func_8030DBFC(u8, f32, f32, f32); +extern void sfxsource_setSampleRate(u8, s32); + +typedef struct{ + s16 map; + u8 mapFlag; + u8 jiggyId; + s16 textId; +} Zubba_Docile_Dialog; + +typedef struct { + u8 sfxsourceIdx; + // u8 pad1[3]; + Zubba_Docile_Dialog *dialog; + f32 unk8; // random value? + f32 targetPosition[3]; + f32 unk18[3]; // some kind of position? +} ActorLocal_ZubbaDocile; + +void chZubbaDocile_update(Actor *this); + +/* .data */ +Zubba_Docile_Dialog chZubbaDocileDialog[] = { + { + MAP_5B_CCW_SPRING_ZUBBA_HIVE, + CCW_ZUBBA_SPECIFIC_FLAG_7_SPRING_DIALOG, + JIGGY_4C_CCW_ZUBBAS, + VER_SELECT(ASSET_CE1_DIALOG_ZUBBA_MEET_SPRING, 0x09F6, 0, 0) + }, + { + MAP_5C_CCW_AUTUMN_ZUBBA_HIVE, + CCW_ZUBBA_SPECIFIC_FLAG_8_AUTUMN_DIALOG, + NULL, + VER_SELECT(ASSET_CE5_DIALOG_ZUBBA_MEET_FALL, 0x09FA, 0, 0) + }, + { 0 } // [port] decomp uses NULL; first field is an integer and clang errors on -Wint-conversion +}; + +ActorInfo chZubbaDocile = { + MARKER_1AF_ZUBBA_DOCILE, ACTOR_29C_ZUBBA_DOCILE, ASSET_446_MODEL_ZUBBA, + 0x0, NULL, + chZubbaDocile_update, NULL, actor_draw, + 0, 0, 1.0f, 0 +}; + +enum chzubbadocile_state_e { + CH_ZUBBA_DOCILE_STATE_0_NOT_INIT, + CH_ZUBBA_DOCILE_STATE_1_DOCILE +}; + +/* .code */ +void chZubbaDocile_setState(Actor *this, s32 next_state) { + ActorLocal_ZubbaDocile *local = (ActorLocal_ZubbaDocile *)&this->local; + int i; + + if (next_state == CH_ZUBBA_DOCILE_STATE_1_DOCILE) { + if (skeletalAnim_getAnimId(this->unk148) != ASSET_16F_ANIM_ZUBBA_FLY_MOVE) { + skeletalAnim_set(this->unk148, ASSET_16F_ANIM_ZUBBA_FLY_MOVE, 0.1f, 0.65f); + } + for(i = 0; i < 10; i++){ + local->targetPosition[0] = randf2(-500.0f, 500.0f); + local->targetPosition[1] = randf2(400.0f, 900.0f); + local->targetPosition[2] = randf2(-400.0f, 700.0f); + if(ml_vec3f_distance(this->position, local->targetPosition) > 800.0f) + break; + } + local->unk8 = randf2(500.0f, 1000.0f); + } + this->state = next_state; +} + +void chZubbaDocile_free(Actor *this){ + ActorLocal_ZubbaDocile *local = (ActorLocal_ZubbaDocile *)&this->local; + sfxsource_freeSfxsourceByIndex(local->sfxsourceIdx); +} + +void chZubbaDocile_update(Actor *this) { + ActorLocal_ZubbaDocile *local; + f32 time_delta; + f32 distance[3]; + f32 horizontal_distance; + f32 distance_in_front; + f32 side_angle_radian; + f32 player_position[3]; + + local = (ActorLocal_ZubbaDocile *)&this->local; + time_delta = time_getDelta(); + if (!this->volatile_initialized) { + this->volatile_initialized = true; + this->marker->actorFreeFunc = chZubbaDocile_free; + local->dialog = &chZubbaDocileDialog[0]; + while((local->dialog->map != NULL) && (gsworld_getMap() != local->dialog->map)) { + local->dialog++; + } + local->sfxsourceIdx = sfxsource_createSfxsourceAndReturnIndex(); + local->unk18[0] = local->unk18[1] = local->unk18[2] = 0.0f; + sfxsource_setSfxId(local->sfxsourceIdx, SFX_3FA_HONEYCOMB_TALKING); + sfxSource_setunk43_7ByIndex(local->sfxsourceIdx, 2); + sfxsource_playSfxAtVolume(local->sfxsourceIdx, 0.9f); + sfxsource_setSampleRate(local->sfxsourceIdx, 0); + chZubbaDocile_setState(this, CH_ZUBBA_DOCILE_STATE_1_DOCILE); + return; + } + + if (this->state == CH_ZUBBA_DOCILE_STATE_1_DOCILE) { + distance[0] = local->targetPosition[0] - this->position[0]; + distance[1] = local->targetPosition[1] - this->position[1]; + distance[2] = local->targetPosition[2] - this->position[2]; + if (ml_vec3f_distance(this->position, local->targetPosition) < 500.0f) { + ml_vec3f_set_length(distance, local->unk8 * 8.0f); + } else { + ml_vec3f_set_length(distance, local->unk8 * 2); + } + this->position[0] += (local->unk18[0] * time_delta) + (distance[0] * time_delta * time_delta); + this->position[1] += (local->unk18[1] * time_delta) + (distance[1] * time_delta * time_delta); + this->position[2] += (local->unk18[2] * time_delta) + (distance[2] * time_delta * time_delta); + local->unk18[0] += distance[0] * time_delta; + local->unk18[1] += distance[1] * time_delta; + local->unk18[2] += distance[2] * time_delta; + if (local->unk8 < LENGTH_VEC3F(local->unk18)) { + ml_vec3f_set_length(local->unk18, local->unk8); + } + func_80258A4C( + this->position, this->yaw - 90.0f, local->targetPosition, + &horizontal_distance, &distance_in_front, &side_angle_radian); + this->yaw += 140.0f * side_angle_radian * time_delta; + if (ml_vec3f_distance(this->position, local->targetPosition) < 100.0f) { + chZubbaDocile_setState(this, CH_ZUBBA_DOCILE_STATE_1_DOCILE); + } + } + + if(this->position[0]); + + func_8030DBFC(local->sfxsourceIdx, 0.8f, 0.9f, 0.05f); + sfxsource_set_fade_distances(local->sfxsourceIdx, 500.0f, 1500.0f); + sfxsource_set_position(local->sfxsourceIdx, this->position); + sfxSource_func_8030E2C4(local->sfxsourceIdx); + sfxsource_setSampleRate(local->sfxsourceIdx, 2000.0f + 8000.0f * (LENGTH_VEC3F(local->unk18) / local->unk8)); + if (!mapSpecificFlags_get(local->dialog->mapFlag)) { + player_getPosition(player_position); + if (player_position[2] > -600.0f) { + if (!local->dialog->jiggyId + || !jiggyscore_isCollected(local->dialog->jiggyId)) + { + gcdialog_showDialog(local->dialog->textId, 4, NULL, NULL, NULL, NULL); + mapSpecificFlags_set(local->dialog->mapFlag, true); + } + } + } +} diff --git a/src/FP/bss_pad.c b/src/FP/bss_pad.c deleted file mode 100644 index d073ba296..000000000 --- a/src/FP/bss_pad.c +++ /dev/null @@ -1,2 +0,0 @@ -// BanjoDecomp: bss_pad.c -char pad_FP_80392F10[0x10]; diff --git a/src/FP/ch/bearcub.c b/src/FP/ch/bearcub.c index 553c070e8..00b474eaf 100644 --- a/src/FP/ch/bearcub.c +++ b/src/FP/ch/bearcub.c @@ -78,7 +78,7 @@ void func_8038A1F0(Actor **this_ptr, enum marker_e carried_obj_marker_id, enum a return; } - if (bacarry_get_markerId() != carried_obj_marker_id) { + if (bacarry_getMarkerId() != carried_obj_marker_id) { return; } @@ -102,7 +102,7 @@ void func_8038A274(Actor *this){ } void func_8038A318(ActorMarker *caller, enum asset_e text_id, s32 arg1){ - if(text_id == 0xc19){ + if(text_id == VER_SELECT(ASSET_C19_DIALOG_BOGGY_KIDS_PRESENT_RECEIVED_3, 0x993, 0, 0)){ gcStaticCamera_activate(0x25); jiggy_spawn(JIGGY_2E_FP_PRESENTS, FP_D_80391E74); coMusicPlayer_playMusic(COMUSIC_2D_PUZZLE_SOLVED_FANFARE, 32000); @@ -177,9 +177,9 @@ void func_8038A384(Actor *this){ } sp34 = levelSpecificFlags_get(LEVEL_FLAG_11_FP_UNKNOWN) + levelSpecificFlags_get(LEVEL_FLAG_12_FP_UNKNOWN) + levelSpecificFlags_get(LEVEL_FLAG_13_FP_UNKNOWN); - sp38 = (sp34 == 1) ? ASSET_C17_DIALOG_BOGGY_KIDS_PRESENT_RECEIVED_1 - : (sp34 == 2) ? ASSET_C18_DIALOG_BOGGY_KIDS_PRESENT_RECEIVED_2 - : ASSET_C19_DIALOG_BOGGY_KIDS_PRESENT_RECEIVED_3; + sp38 = (sp34 == 1) ? VER_SELECT(ASSET_C17_DIALOG_BOGGY_KIDS_PRESENT_RECEIVED_1, 0x991, 0, 0) + : (sp34 == 2) ? VER_SELECT(ASSET_C18_DIALOG_BOGGY_KIDS_PRESENT_RECEIVED_2, 0x992, 0, 0) + : VER_SELECT(ASSET_C19_DIALOG_BOGGY_KIDS_PRESENT_RECEIVED_3, 0x993, 0, 0); this->yaw_ideal = (f32)subaddie_getYawToPlayer(this); subaddie_turnToYaw(this, 2.0f); @@ -193,8 +193,8 @@ void func_8038A384(Actor *this){ && !jiggyscore_isCollected(JIGGY_2C_FP_BOGGY_3) && !jiggyscore_isSpawned(JIGGY_2C_FP_BOGGY_3) ){ - if (gcdialog_showDialog(ASSET_C1A_DIALOG_BOGGY_KIDS_MEET, 0x2a, NULL, NULL, NULL, NULL)) { - levelSpecificFlags_set(LEVEL_FLAG_19_FP_UNKNOWN, true); + if (gcdialog_showDialog(VER_SELECT(ASSET_C1A_DIALOG_BOGGY_KIDS_MEET, 0x994, 0, 0), 0x2a, NULL, NULL, NULL, NULL)) { + levelSpecificFlags_set(LEVEL_FLAG_19_FP_UNKNOWN, TRUE); } } } @@ -216,7 +216,7 @@ void func_8038A384(Actor *this){ } if(levelSpecificFlags_get(D_80391E80[sp3C].unk0)){ subaddie_set_state_with_direction(this, 2, 0.001f, 1); - if (sp38 == ASSET_C19_DIALOG_BOGGY_KIDS_PRESENT_RECEIVED_3) { + if (sp38 == VER_SELECT(ASSET_C19_DIALOG_BOGGY_KIDS_PRESENT_RECEIVED_3, 0x993, 0, 0)) { gcdialog_showDialog(sp38, 0x2f, this->position, this->marker, func_8038A318, NULL); } else { diff --git a/src/FP/ch/boggy1.c b/src/FP/ch/boggy1.c index 7c8ff2353..9e2b5b0ff 100644 --- a/src/FP/ch/boggy1.c +++ b/src/FP/ch/boggy1.c @@ -38,8 +38,8 @@ Actor *func_803875E0(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx){ if(!this->unk38_31 || this->state == 5) return this; - func_8033A45C(1, 0); - func_8033A45C(3, 1); + modelRender_setAppendageVisibility(1, 0); + modelRender_setAppendageVisibility(3, 1); this = actor_draw(marker, gfx, mtx, vtx); if(marker->unk14_21){ vec3fArray_get_vec3f(func_80329934(), 5, this->velocity); @@ -86,8 +86,8 @@ void func_803877A8(ActorMarker *caller, enum asset_e text_id, s32 arg2){ void func_80387828(ActorMarker *caller, enum asset_e text_id, s32 arg2){ Actor *this = marker_getActor(caller); - if (text_id == 0xc00) { - gcdialog_showDialog(ASSET_C2B_DIALOG_BOGGY_SAVED_2, 0xf, NULL, this->marker, NULL, func_803877A8); + if (text_id == VER_SELECT(ASSET_C00_DIALOG_BOGGY_SAVED, 0x97A, 0, 0)) { + gcdialog_showDialog(VER_SELECT(ASSET_C2B_DIALOG_BOGGY_SAVED_2, 0x9A5, 0, 0), 0xf, NULL, this->marker, NULL, func_803877A8); } } @@ -143,14 +143,14 @@ void func_8038794C(Actor *this){ if(mapSpecificFlags_get(0x1)){ func_8028F94C(1, this->position); timed_setStaticCameraToNode(0.0f, 0x12); - func_80324DBC(1.0f, 0xc00, 0xe, NULL, this->marker, func_80387828, func_803877A8); + func_80324DBC(1.0f, VER_SELECT(ASSET_C00_DIALOG_BOGGY_SAVED, 0x97A, 0, 0), 0xe, NULL, this->marker, func_80387828, func_803877A8); func_803876A4(this); break; }//L80387B38 if(!this->has_met_before && subaddie_playerIsWithinSphereAndActive(this, 0x1f4)){ if(!player_movementGroup() || player_movementGroup() == BSGROUP_8_TROT){ - if (gcdialog_showDialog(ASSET_BFF_DIALOG_BOGGY_MEET, 0x2a, this->position, NULL, NULL, NULL)) { + if (gcdialog_showDialog(VER_SELECT(ASSET_BFF_DIALOG_BOGGY_MEET, 0x979, 0, 0), 0x2a, this->position, NULL, NULL, NULL)) { for (i = 0; i < 5; i++) { timedFunc_set_1(D_80391BEC[i], (GenFunction_1) func_8038787C, (uintptr_t)this->marker); } diff --git a/src/FP/ch/boggy2.c b/src/FP/ch/boggy2.c index 4b8110cd3..776954a99 100644 --- a/src/FP/ch/boggy2.c +++ b/src/FP/ch/boggy2.c @@ -64,8 +64,8 @@ Actor *func_80388740(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx){ ActorLocal_FP_2350 * local = (ActorLocal_FP_2350 *) &this->local; f32 sp2C[3]; - func_8033A45C(1, 1); - func_8033A45C(3, 1); + modelRender_setAppendageVisibility(1, 1); + modelRender_setAppendageVisibility(3, 1); this = actor_draw(marker, gfx, mtx, vtx); if(this->volatile_initialized && marker->unk14_21){ if( this->state == 4 @@ -96,20 +96,20 @@ void FP_func_803888E4(Actor *this){ static f32 D_80391D18[3] = {1463.0f, 635.0f, 5193.0f}; subaddie_set_state_with_direction(this, 0xC, 0.0001f, 1); if(!jiggyscore_isSpawned(JIGGY_30_FP_BOGGY_2)){ - if(mapSpecificFlags_get(5)){ - func_80324DBC(0.1f, 0xc06, 0x2a, D_80391D18, this->marker, func_80388D70, NULL); + if(mapSpecificFlags_get(FP_SPECIFIC_FLAG_5_WALRUS_RACE_FAILED)){ + func_80324DBC(0.1f, VER_SELECT(ASSET_C06_DIALOG_BOGGY_SLED_WALRUS_SECOND_START, 0x980, 0, 0), 0x2a, D_80391D18, this->marker, func_80388D70, NULL); } else{//L80388964 - func_80324DBC(0.1f, 0xc03, 0x2a, D_80391D18, this->marker, func_80388D70, NULL); + func_80324DBC(0.1f, VER_SELECT(ASSET_C03_DIALOG_BOGGY_SLED_WALRUS_START, 0x97D, 0, 0), 0x2a, D_80391D18, this->marker, func_80388D70, NULL); } } else{//L803889A0 func_8028F490(D_80391D0C); - if(mapSpecificFlags_get(6)){ - func_80324DBC(0.1f, 0xc29, 0x2a, D_80391D18, this->marker, func_80388D70, NULL); + if(mapSpecificFlags_get(FP_SPECIFIC_FLAG_6_BANJO_RACE_FAILED)){ + func_80324DBC(0.1f, VER_SELECT(ASSET_C29_DIALOG_BOGGY_SLED_BEAR_SECOND_START, 0x9A3, 0, 0), 0x2a, D_80391D18, this->marker, func_80388D70, NULL); } else{ - func_80324DBC(0.1f, 0xc28, 0x2a, D_80391D18, this->marker, func_80388D70, NULL); + func_80324DBC(0.1f, VER_SELECT(ASSET_C28_DIALOG_BOGGY_SLED_BEAR_START, 0x9A2, 0, 0), 0x2a, D_80391D18, this->marker, func_80388D70, NULL); } }//L80388A30 mapSpecificFlags_set(5, true); @@ -126,11 +126,11 @@ void func_80388A50(Actor *this){ void func_80388A94(Actor *this){ func_80388A50(this); - if(mapSpecificFlags_get(6)){ - gcdialog_showDialog(ASSET_C0A_DIALOG_BOGGY_SLED_BEAR_MISS_RETRY, 0xe, this->position, this->marker, func_80388D70, NULL); + if(mapSpecificFlags_get(FP_SPECIFIC_FLAG_6_BANJO_RACE_FAILED)){ + gcdialog_showDialog(VER_SELECT(ASSET_C0A_DIALOG_BOGGY_SLED_BEAR_MISS_RETRY, 0x984, 0, 0), 0xe, this->position, this->marker, func_80388D70, NULL); } else{ - gcdialog_showDialog(ASSET_C09_DIALOG_BOGGY_SLED_BEAR_ANSWER_TO_START, 0xe, this->position, this->marker, func_80388D70, NULL); + gcdialog_showDialog(VER_SELECT(ASSET_C09_DIALOG_BOGGY_SLED_BEAR_ANSWER_TO_START, 0x983, 0, 0), 0xe, this->position, this->marker, func_80388D70, NULL); } } @@ -138,17 +138,17 @@ void func_80388B18(Actor *this, u8 arg1){ if(arg1 == true){ if(player_getTransformation() == TRANSFORM_4_WALRUS){ func_80388A50(this); - if(mapSpecificFlags_get(5)){ - gcdialog_showDialog(ASSET_C05_DIALOG_BOGGY_SLED_WALRUS_MISS_RETRY, 0xf, this->position, this->marker, func_80388D70, NULL); + if(mapSpecificFlags_get(FP_SPECIFIC_FLAG_5_WALRUS_RACE_FAILED)){ + gcdialog_showDialog(VER_SELECT(ASSET_C05_DIALOG_BOGGY_SLED_WALRUS_MISS_RETRY, 0x97F, 0, 0), 0xf, this->position, this->marker, func_80388D70, NULL); } else{ - gcdialog_showDialog(ASSET_C02_DIALOG_BOGGY_SLED_WALRUS_MEET, 0xf, this->position, this->marker, func_80388D70, NULL); + gcdialog_showDialog(VER_SELECT(ASSET_C02_DIALOG_BOGGY_SLED_WALRUS_MEET, 0x97C, 0, 0), 0xf, this->position, this->marker, func_80388D70, NULL); } } else{//L80388BB8 if(!volatileFlag_get(VOLATILE_FLAG_B3)){ - if(gcdialog_showDialog(ASSET_C01_DIALOG_BOGGY_SLED_BEAR_DENY, 0xe, this->position, this->marker, func_80388D70, NULL)){ - volatileFlag_set(VOLATILE_FLAG_B3, true); + if(gcdialog_showDialog(VER_SELECT(ASSET_C01_DIALOG_BOGGY_SLED_BEAR_DENY, 0x97B, 0, 0), 0xe, this->position, this->marker, func_80388D70, NULL)){ + volatileFlag_set(VOLATILE_FLAG_B3, TRUE); func_80388A50(this); } } @@ -157,8 +157,8 @@ void func_80388B18(Actor *this, u8 arg1){ else{//L80388C08 if(player_getTransformation() == TRANSFORM_4_WALRUS){ if(!volatileFlag_get(VOLATILE_FLAG_B4)){ - if(gcdialog_showDialog(ASSET_C08_DIALOG_BOGGY_SLED_WALRUS_COMPLETE_RETRY, 0xe, this->position, this->marker, func_80388D70, NULL)){ - volatileFlag_set(VOLATILE_FLAG_B4, true); + if(gcdialog_showDialog(VER_SELECT(ASSET_C08_DIALOG_BOGGY_SLED_WALRUS_COMPLETE_RETRY, 0x982, 0, 0), 0xe, this->position, this->marker, func_80388D70, NULL)){ + volatileFlag_set(VOLATILE_FLAG_B4, TRUE); func_80388A50(this); } } @@ -198,10 +198,10 @@ void func_80388D70(ActorMarker *caller, enum asset_e text_id, s32 arg2){ timed_exitStaticCamera(0.0f); switch(text_id){ - case 0xc03: - case 0xc06: - case 0xc28: - case 0xc29://L80388DC4 + case VER_SELECT(ASSET_C03_DIALOG_BOGGY_SLED_WALRUS_START, 0x97D, 0, 0): + case VER_SELECT(ASSET_C06_DIALOG_BOGGY_SLED_WALRUS_SECOND_START, 0x980, 0, 0): + case VER_SELECT(ASSET_C28_DIALOG_BOGGY_SLED_BEAR_START, 0x9A2, 0, 0): + case VER_SELECT(ASSET_C29_DIALOG_BOGGY_SLED_BEAR_SECOND_START, 0x9A3, 0, 0)://L80388DC4 coMusicPlayer_playMusic(COMUSIC_3A_FP_BOGGY_RACE, 25000); func_8025A58C(0, 4000); core1_ce60_incOrDecCounter(false); @@ -392,7 +392,7 @@ void func_803895E0(void){ : cubeList_findNodePropByActorIdAndPosition_s32(D_80391DB8[i].unk0, D_80391DAC); nodeprop_getPosition(s0, sp64); - f20 = (f32)nodeprop_getYaw(s0); + f20 = (f32)nodeProp_getYaw(s0); f8 = (f32)nodeprop_getScale(s0); f22 = f8*0.01; actor = actor_spawnWithYaw_f32(D_80391DB8[i].actor_id, sp64, (s32)f20); @@ -474,7 +474,7 @@ void func_803896FC(Actor *this){ } else if( subaddie_playerIsWithinSphereAndActive(this, 0x1C2) && player_movementGroup() == BSGROUP_0_NONE - && func_8028F20C() + && player_isStableWithExtraSteps() && func_8028EFC8() && sp3C[FACE_BUTTON(BUTTON_B)] == 1 && !gcdialog_hasCurrentTextId() @@ -483,13 +483,13 @@ void func_803896FC(Actor *this){ && player_getTransformation() != TRANSFORM_4_WALRUS && volatileFlag_get(VOLATILE_FLAG_B3) ){ - gcdialog_showDialog(ASSET_C01_DIALOG_BOGGY_SLED_BEAR_DENY, 0xf, this->position, this->marker, func_80388D70, NULL); + gcdialog_showDialog(VER_SELECT(ASSET_C01_DIALOG_BOGGY_SLED_BEAR_DENY, 0x97B, 0, 0), 0xf, this->position, this->marker, func_80388D70, NULL); } else if( local->unk19 == 2){ if( player_getTransformation() == TRANSFORM_4_WALRUS && volatileFlag_get(VOLATILE_FLAG_B4) ){ - gcdialog_showDialog(ASSET_C08_DIALOG_BOGGY_SLED_WALRUS_COMPLETE_RETRY, 0xf, this->position, this->marker, func_80388D70, NULL); + gcdialog_showDialog(VER_SELECT(ASSET_C08_DIALOG_BOGGY_SLED_WALRUS_COMPLETE_RETRY, 0x982, 0, 0), 0xf, this->position, this->marker, func_80388D70, NULL); } else if( player_getTransformation() != TRANSFORM_4_WALRUS){ func_80388A94(this); diff --git a/src/FP/ch/boggy3.c b/src/FP/ch/boggy3.c index a1e42df6a..b36a7b1c3 100644 --- a/src/FP/ch/boggy3.c +++ b/src/FP/ch/boggy3.c @@ -27,11 +27,11 @@ Actor *func_80390290(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx){ if(this->unk38_31) return this; - if(gcdialog_getCurrentTextId() == 0xC1F || gcdialog_getCurrentTextId() == 0xC1E){ + if(gcdialog_getCurrentTextId() == VER_SELECT(ASSET_C1F_DIALOG_BOGGY_IGLOO_2, 0x999, 0, 0) || gcdialog_getCurrentTextId() == VER_SELECT(ASSET_C1E_DIALOG_BOGGY_IGLOO_1, 0x998, 0, 0)){ sp18 = 1; } - func_8033A45C(1, 0); - func_8033A45C(3, sp18); + modelRender_setAppendageVisibility(1, 0); + modelRender_setAppendageVisibility(3, sp18); return actor_draw(marker, gfx, mtx, vtx); } @@ -78,15 +78,15 @@ void func_80390388(Actor *this){ && (player_movementGroup() == BSGROUP_0_NONE || player_movementGroup() == BSGROUP_8_TROT) ){ if(0.0f == this->unk1C[0] && func_80390334()){ - if(gcdialog_showDialog(ASSET_C1F_DIALOG_BOGGY_IGLOO_2, 0xb, this->position, NULL, NULL, NULL)){ - this->has_met_before = true; + if(gcdialog_showDialog(VER_SELECT(ASSET_C1F_DIALOG_BOGGY_IGLOO_2, 0x999, 0, 0), 0xb, this->position, NULL, NULL, NULL)){ + this->has_met_before = TRUE; this->unk1C[0] = 1.0f; } } else{ if( !this->has_met_before ){ - if(gcdialog_showDialog(ASSET_C1E_DIALOG_BOGGY_IGLOO_1, 0x2b, this->position, NULL, NULL, NULL)){ - this->has_met_before = true; + if(gcdialog_showDialog(VER_SELECT(ASSET_C1E_DIALOG_BOGGY_IGLOO_1, 0x998, 0, 0), 0x2b, this->position, NULL, NULL, NULL)){ + this->has_met_before = TRUE; } } } diff --git a/src/FP/mapstate/slalomctrl.c b/src/FP/ch/boggyraceflag1.c similarity index 94% rename from src/FP/mapstate/slalomctrl.c rename to src/FP/ch/boggyraceflag1.c index 559186760..12be9720e 100644 --- a/src/FP/mapstate/slalomctrl.c +++ b/src/FP/ch/boggyraceflag1.c @@ -1,4 +1,4 @@ -// BanjoDecomp: code_19E0.c +// BanjoDecomp: FP/ch/boggyraceflag1.c #include #include "functions.h" #include "variables.h" @@ -34,9 +34,9 @@ Actor *func_80387DD0(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx){ if(this->velocity[0] == 0.0f || 0.0f != this->velocity[1]) return this; - func_8033A45C(2, this->velocity[0] == 1.0f ? 1 : 0); - func_8033A45C(3, this->velocity[0] == 3.0f ? 1 : 0); - func_8033A45C(4, this->velocity[0] == 2.0f ? 1 : 0); + modelRender_setAppendageVisibility(2, this->velocity[0] == 1.0f ? 1 : 0); + modelRender_setAppendageVisibility(3, this->velocity[0] == 3.0f ? 1 : 0); + modelRender_setAppendageVisibility(4, this->velocity[0] == 2.0f ? 1 : 0); return actor_draw(marker, gfx, mtx, vtx); } diff --git a/src/FP/mapstate/slalom2ctrl.c b/src/FP/ch/boggyraceflag2.c similarity index 89% rename from src/FP/mapstate/slalom2ctrl.c rename to src/FP/ch/boggyraceflag2.c index 2c768c47d..795d3d2ab 100644 --- a/src/FP/mapstate/slalom2ctrl.c +++ b/src/FP/ch/boggyraceflag2.c @@ -1,4 +1,4 @@ -// BanjoDecomp: code_1FF0.c +// BanjoDecomp: FP/ch/boggyraceflag2.c #include #include "functions.h" #include "variables.h" @@ -29,9 +29,9 @@ Actor *func_803883E0(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx){ if(this->velocity[0] == 0.0f || 0.0f != this->velocity[1]) return this; - func_8033A45C(2, this->velocity[0] == 1.0f ? 1 : 0); - func_8033A45C(3, this->velocity[0] == 3.0f ? 1 : 0); - func_8033A45C(4, this->velocity[0] == 2.0f ? 1 : 0); + modelRender_setAppendageVisibility(2, this->velocity[0] == 1.0f ? 1 : 0); + modelRender_setAppendageVisibility(3, this->velocity[0] == 3.0f ? 1 : 0); + modelRender_setAppendageVisibility(4, this->velocity[0] == 2.0f ? 1 : 0); return actor_draw(marker, gfx, mtx, vtx); } diff --git a/src/FP/ch/cavewozza.c b/src/FP/ch/cavewozza.c index b41f13246..d61c7dfe6 100644 --- a/src/FP/ch/cavewozza.c +++ b/src/FP/ch/cavewozza.c @@ -70,15 +70,15 @@ void chCaveWozza_update(Actor *this){ if (subaddie_playerIsWithinSphereAndActive(this, 350)) { if (player_getTransformation() == TRANSFORM_4_WALRUS) { if (!levelSpecificFlags_get(LEVEL_FLAG_31_FP_WOZZA_WALRUS_TALKED)) { - if (gcdialog_showDialog(ASSET_C27_DIALOG_WOZZA_CAVE_MEET_AS_WALRUS, 0x23, NULL, NULL, NULL, NULL)) { - levelSpecificFlags_set(LEVEL_FLAG_31_FP_WOZZA_WALRUS_TALKED, true); + if (gcdialog_showDialog(VER_SELECT(ASSET_C27_DIALOG_WOZZA_CAVE_MEET_AS_WALRUS, 0x9A1, 0, 0), 0x23, NULL, NULL, NULL, NULL)) { + levelSpecificFlags_set(LEVEL_FLAG_31_FP_WOZZA_WALRUS_TALKED, TRUE); } } } else { - if (!levelSpecificFlags_get(LEVEL_FLAG_31_FP_WOZZA_WALRUS_TALKED)) { - if (gcdialog_showDialog(ASSET_C26_DIALOG_WOZZA_CAVE_MEET_AS_BEAR, 0x23, NULL, NULL, NULL, NULL)) { - levelSpecificFlags_set(LEVEL_FLAG_31_FP_WOZZA_WALRUS_TALKED, true); + if (!levelSpecificFlags_get(LEVEL_FLAG_32_FP_WOZZA_BEAR_TALKED)) { + if (gcdialog_showDialog(VER_SELECT(ASSET_C26_DIALOG_WOZZA_CAVE_MEET_AS_BEAR, 0x9A0, 0, 0), 0x23, NULL, NULL, NULL, NULL)) { + levelSpecificFlags_set(LEVEL_FLAG_32_FP_WOZZA_BEAR_TALKED, TRUE); } } } diff --git a/src/FP/ch/racesled.c b/src/FP/ch/racesled.c index 083626892..7bff52d2f 100644 --- a/src/FP/ch/racesled.c +++ b/src/FP/ch/racesled.c @@ -56,7 +56,7 @@ void __chRaceSled_touch(ActorMarker *this_marker, ActorMarker *other_marker){ if(this->state == 2){ player_getPosition(plyr_pos); if( this->position_y + 20.0f < plyr_pos[1] - && func_8028F20C() + && player_isStableWithExtraSteps() && player_getTransformation() == TRANSFORM_4_WALRUS && func_8028F68C(BS_INTR_27_WALRUS_SLED, this->marker) ){ diff --git a/src/FP/ch/snowmanbutton.c b/src/FP/ch/snowmanbutton.c index 3e2f8612a..2f536cf12 100644 --- a/src/FP/ch/snowmanbutton.c +++ b/src/FP/ch/snowmanbutton.c @@ -42,8 +42,8 @@ s32 D_80391B44[3] = {225, 225, 245}; /* .code */ Actor *func_80386B80(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx){ Actor *this = marker_getActor(marker); - func_8033A45C(1, this->state == 3); - func_8033A45C(2, modelRender_func_8033A0F0(1) ^ 1); + modelRender_setAppendageVisibility(1, this->state == 3); + modelRender_setAppendageVisibility(2, modelRender_func_8033A0F0(1) ^ 1); return actor_draw(marker, gfx, mtx, vtx); } diff --git a/src/FP/ch/twinkly.c b/src/FP/ch/twinkly.c index d5fbd1238..ebdb1e130 100644 --- a/src/FP/ch/twinkly.c +++ b/src/FP/ch/twinkly.c @@ -85,8 +85,8 @@ Actor *func_8038C0B0(ActorMarker *marker, f32 arg1[3], f32 arg2, f32 arg3[3], s3 Actor *chTwinkly_draw(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx){ Actor *this = marker_getActor(marker); - func_8033A45C(2, this->unk38_31); - func_8033A45C(1, modelRender_func_8033A0F0(2) ^ 1); + modelRender_setAppendageVisibility(2, this->unk38_31); + modelRender_setAppendageVisibility(1, modelRender_func_8033A0F0(2) ^ 1); return actor_draw(marker, gfx, mtx, vtx); } @@ -337,11 +337,11 @@ void chTwinkly_update(Actor *this){ if(this->unk1C[1] <= this->position_y){ this->position_y = this->unk1C[1]; if(!fileProgressFlag_get(FILEPROG_82_MET_TWINKLIES)){ - gcdialog_showDialog(0xc12, 0x2a, this->position, this->marker, chTwinkly_setUpMinigame, NULL); - fileProgressFlag_set(FILEPROG_82_MET_TWINKLIES, true); + gcdialog_showDialog(VER_SELECT(ASSET_C12_DIALOG_TWINKLIE_MINIGAME_START, 0x98C, 0, 0), 0x2a, this->position, this->marker, chTwinkly_setUpMinigame, NULL); + fileProgressFlag_set(FILEPROG_82_MET_TWINKLIES, TRUE); } else{ - gcdialog_showDialog(0xc25, 0x2b, this->position, this->marker, chTwinkly_setUpMinigame, NULL); + gcdialog_showDialog(VER_SELECT(ASSET_C25_DIALOG_TWINKLIE_MINIGAME_RETRY, 0x99F, 0, 0), 0x2b, this->position, this->marker, chTwinkly_setUpMinigame, NULL); } subaddie_set_state(this, 5); this->pitch -= 3.0f; diff --git a/src/FP/ch/twinklybox.c b/src/FP/ch/twinklybox.c index a63d7f123..dc801194c 100644 --- a/src/FP/ch/twinklybox.c +++ b/src/FP/ch/twinklybox.c @@ -180,7 +180,7 @@ void chTwinklyBox_destroyBox(ActorMarker *marker){ chTwinklyBox_destroyBoxDust(this->position, 12, ASSET_700_SPRITE_DUST); this->velocity[1] = 0.0f; sfx_playFadeShorthandDefault(SFX_30_MAGIC_POOF, 1.0f, 32000, this->position, 1000, 3500); - gcdialog_showDialog(0xc13, 0, NULL, NULL, NULL, NULL); + gcdialog_showDialog(VER_SELECT(ASSET_C13_DIALOG_TWINKLIE_MINIGAME_COMPLETE, 0x98D, 0, 0), 0, NULL, NULL, NULL, NULL); } void chTwinklyBox_openBox(Actor *this){ @@ -372,8 +372,8 @@ void chTwinklyBox_update(Actor *this){ func_8028F784(0); subaddie_set_state_with_direction(this, 4, 0.999f, 1); actor_playAnimationOnce(this); - item_set(ITEM_0_HOURGLASS_TIMER, 80*60 - 1); - item_set(ITEM_6_HOURGLASS, true); + item_set(ITEM_0_HOURGLASS_TIMER, 80*FRAMERATE - 1); + item_set(ITEM_6_HOURGLASS, TRUE); this->unk38_31 = 0xA; item_set(ITEM_24_TWINKLY_SCORE, this->unk38_31); __spawnQueue_add_1((GenFunction_1)chTwinklyBox_spawnSecondAndThirdMuncher, (uintptr_t)this->marker); diff --git a/src/FP/ch/twinklymuncher.c b/src/FP/ch/twinklymuncher.c index e35bf10db..1f80cfac3 100644 --- a/src/FP/ch/twinklymuncher.c +++ b/src/FP/ch/twinklymuncher.c @@ -128,7 +128,7 @@ void chTwinklyMuncher_update(Actor *this){ if(this->actorTypeSpecificField == 1 && !fileProgressFlag_get(FILEPROG_13_COMPLETED_TWINKLIES_MINIGAME)){ if(this->state != 6 && this->state != 7 && 0.0f == this->velocity[0]){ timed_setStaticCameraToNode(0.5f, 0xd); - gcdialog_showDialog(ASSET_C15_DIALOG_TWINKLIE_MINIGAME_MISS, 0x2b, this->position, this->marker, chTwinklyMuncher_failMinigameExit, NULL); + gcdialog_showDialog(VER_SELECT(ASSET_C15_DIALOG_TWINKLIE_MINIGAME_MISS, 0x98F, 0, 0), 0x2b, this->position, this->marker, chTwinklyMuncher_failMinigameExit, NULL); this->velocity[0] = 1.0f; subaddie_set_state_with_direction(this, 6, 0.03f, 1); actor_loopAnimation(this); @@ -202,8 +202,8 @@ void chTwinklyMuncher_update(Actor *this){ sfx_playFadeShorthandDefault(SFX_27_JINJO_HI, 1.6f, 32000, this->position, 1250, 2500); func_80324D54(0.35f, SFX_110_TWINKLY_DEATH, 1.0f, 32000, this->position, 1250.0f, 2500.0f); marker_despawn(sp38->marker); - if( !mapSpecificFlags_get(0xa) && gcdialog_showDialog(0xc16, 0, NULL, NULL, NULL, NULL)){ - mapSpecificFlags_set(0xa, true); + if( !mapSpecificFlags_get(FP_SPECIFIC_FLAG_A_FIRST_TWINKLY_EATEN) && gcdialog_showDialog(VER_SELECT(ASSET_C16_DIALOG_TWINKLIE_MINIGAME_EATEN, 0x990, 0, 0), 0, NULL, NULL, NULL, NULL)){ + mapSpecificFlags_set(FP_SPECIFIC_FLAG_A_FIRST_TWINKLY_EATEN, TRUE); } } }//L8038E620 diff --git a/src/FP/ch/wozza.c b/src/FP/ch/wozza.c index fefe57902..69dc4fb98 100644 --- a/src/FP/ch/wozza.c +++ b/src/FP/ch/wozza.c @@ -70,11 +70,11 @@ void chWozza_enterCaveFinal(Actor *this){ void chWozza_textCallback(ActorMarker *caller, enum asset_e text_id, s32 arg2){ Actor *this = marker_getActor(caller); switch(text_id){ - case 0xC1B: + case VER_SELECT(ASSET_C1B_DIALOG_WOZZA_MEET_AS_BEAR, 0x995, 0, 0): timed_exitStaticCamera(0.0f); break; - case 0xC1C: + case VER_SELECT(ASSET_C1C_DIALOG_WOZZA_MEET_AS_WALRUS, 0x996, 0, 0): timed_exitStaticCamera(0.0f); chWozza_enterCaveFinal(this); break; @@ -107,8 +107,8 @@ void chWozza_firstContact(Actor *this){ subaddie_set_state(this, 2); actor_loopAnimation(this); timed_setStaticCameraToNode(0.0f, 0x2e); - func_80324DBC(0.0f, 0xc1b, 0x2a, this->position, this->marker, chWozza_textCallback, NULL); - timedFunc_set_1(2.5f, (GenFunction_1)chWozza_delayedRetreatToCave, (uintptr_t)this->marker); + func_80324DBC(0.0f, VER_SELECT(ASSET_C1B_DIALOG_WOZZA_MEET_AS_BEAR, 0x995, 0, 0), 0x2a, this->position, this->marker, chWozza_textCallback, NULL); + timedFunc_set_1(2.5f, (GenFunction_1)chWozza_delayedRetreatToCave, reinterpret_cast(uintptr_t, this->marker)); } else{ chWozza_retreatToCave(this); @@ -274,8 +274,8 @@ void chWozza_update(Actor *this){ chWozza_checkForPlayer(this); if(!local->unk30){ - if(gcdialog_showDialog(0xc1d, 0x20, NULL, NULL, NULL, NULL)){ - local->unk30 = true; + if(gcdialog_showDialog(VER_SELECT(ASSET_C1D_DIALOG_WOZZA_RETURN, 0x997, 0, 0), 0x20, NULL, NULL, NULL, NULL)){ + local->unk30 = TRUE; } } break; @@ -301,7 +301,7 @@ void chWozza_update(Actor *this){ } if(subaddie_playerIsWithinSphereAndActive(this, 500) && !this->has_met_before){ - if(gcdialog_showDialog(0xc1c, 0xAA, this->position, this->marker, chWozza_textCallback, chWozza_checkCompletion)){ + if(gcdialog_showDialog(VER_SELECT(ASSET_C1C_DIALOG_WOZZA_MEET_AS_WALRUS, 0x996, 0, 0), 0xAA, this->position, this->marker, chWozza_textCallback, chWozza_checkCompletion)){ timed_setStaticCameraToNode(0.0f, 0x2E); this->has_met_before = true; } diff --git a/src/FP/ch/xmastree.c b/src/FP/ch/xmastree.c index 58c66189d..f753e3c73 100644 --- a/src/FP/ch/xmastree.c +++ b/src/FP/ch/xmastree.c @@ -20,12 +20,12 @@ ActorInfo chXmasTree = { /* .code */ Actor *chXmasTree_draw(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx){ Actor *this = marker_getActor(marker); - func_8033A45C(5, this->unk38_31); - func_8033A45C(6, fileProgressFlag_get(FILEPROG_13_COMPLETED_TWINKLIES_MINIGAME) && !modelRender_func_8033A0F0(5)); + modelRender_setAppendageVisibility(5, this->unk38_31); + modelRender_setAppendageVisibility(6, fileProgressFlag_get(FILEPROG_13_COMPLETED_TWINKLIES_MINIGAME) && !modelRender_func_8033A0F0(5)); return actor_draw(marker, gfx, mtx, vtx); } -void __chXmasTree_free(Actor *this){ +void chXmasTree_free(Actor *this){ u8 tmp_a0; item_set(ITEM_6_HOURGLASS, false); @@ -36,30 +36,30 @@ void __chXmasTree_free(Actor *this){ } } -void __chXmasTree_80386EF4(Actor *this, int arg1){ +void chXmasTree_setState(Actor *this, int arg1){ this->unk38_31 = arg1; mapSpecificFlags_set(0, this->unk38_31); } -void __chXmasTree_80386F3C(void){ +void chXmasTree_swapCameraToIce(void){ levelSpecificFlags_set(LEVEL_FLAG_29_FP_XMAS_TREE_COMPLETE, true); musicKeepsPlaying(); volatileFlag_set(VOLATILE_FLAG_E, 1); transitionToMap(MAP_53_FP_CHRISTMAS_TREE, WARP_FP_CHRISTMAS_TREE_1_ENTRANCE, 0); } -void __chXmasTree_80386F84(Actor * this){ +void chXmasTree_setLightsOn(Actor * this){ subaddie_set_state(this, 2); - __chXmasTree_80386EF4(this, 0); + chXmasTree_setState(this, 0); } -void __chXmasTree_spawnSwitch(void){ +void chXmasTree_spawnSwitch(void){ static s32 chXmasTree_switch_spawn_position[3] = {-0x1220, 0x6A, 0x1945}; actor_spawnWithYaw_s32(ACTOR_338_XMAS_TREE_SWITCH, &chXmasTree_switch_spawn_position, 350); } -void __chXmasTree_spawnStar(void *marker){ +void chXmasTree_spawnStar(void *marker){ Actor *this = marker_getActor(reinterpret_cast(ActorMarker *, marker)); Actor *child = spawn_child_actor(0x339, &this); s32 pad; @@ -68,22 +68,22 @@ void __chXmasTree_spawnStar(void *marker){ child->position_z += 25.0f; } -void __chXmasTree_80387038(Actor *this){ +void chXmasTree_lightsDeactivatedSounds(Actor *this){ if(func_8030E3FC(this->unk44_31)) sfxSource_triggerCallbackByIndex(this->unk44_31); sfxsource_playSfxAtVolume(this->unk44_31, randf2(0.9f, 1.1f)); sfxSource_func_8030E2C4(this->unk44_31); } -void __chXmasTree_8038709C(Actor *this){ +void chXmasTree_setLightsOff(Actor *this){ if(this->state == 5){ if(!mapSpecificFlags_get(0)) - __chXmasTree_80387038(this); + chXmasTree_lightsDeactivatedSounds(this); return; } if(mapSpecificFlags_get(0) && !func_8030E3FC(this->unk44_31)) - __chXmasTree_80387038(this); + chXmasTree_lightsDeactivatedSounds(this); } void chXmasTree_update(Actor *this){ @@ -94,17 +94,17 @@ void chXmasTree_update(Actor *this){ this->volatile_initialized = true; this->marker->propPtr->unk8_3 = true; this->marker->collidable = false; - marker_setFreeMethod(this->marker, __chXmasTree_free); + marker_setFreeMethod(this->marker, chXmasTree_free); if(this->unk44_31 == 0){ this->unk44_31 = sfxsource_createSfxsourceAndReturnIndex(); sfxsource_setSfxId(this->unk44_31, SFX_415_XMAS_LIGHTS_FLICKERING); sfxSource_setunk43_7ByIndex(this->unk44_31, 3); sfxsource_setSampleRate(this->unk44_31, 28000); } - __spawnQueue_add_0(__chXmasTree_spawnSwitch); - __spawnQueue_add_1((GenFunction_1)__chXmasTree_spawnStar, (uintptr_t)this->marker); + __spawnQueue_add_0(chXmasTree_spawnSwitch); + __spawnQueue_add_1((GenFunction_1)chXmasTree_spawnStar, (uintptr_t)this->marker); if(fileProgressFlag_get(FILEPROG_13_COMPLETED_TWINKLIES_MINIGAME)){ - __chXmasTree_80386F84(this); + chXmasTree_setLightsOn(this); mapSpecificFlags_set(2, false); } } @@ -122,15 +122,15 @@ void chXmasTree_update(Actor *this){ } if (jiggyscore_isCollected(JIGGY_2F_FP_XMAS_TREE) || levelSpecificFlags_get(LEVEL_FLAG_29_FP_XMAS_TREE_COMPLETE)) { - __chXmasTree_80386EF4(this, 1); + chXmasTree_setState(this, 1); return; } switch(this->state){ case 1: // L80387268 - __chXmasTree_80386EF4(this, 0); + chXmasTree_setState(this, 0); if(fileProgressFlag_get(FILEPROG_13_COMPLETED_TWINKLIES_MINIGAME)){ - __chXmasTree_80386F84(this); + chXmasTree_setLightsOn(this); } break; @@ -141,21 +141,21 @@ void chXmasTree_update(Actor *this){ this->lifetime_value = 2.0f; coMusicPlayer_playMusic(COMUSIC_61_XMAS_TREE_LIGHTS_UP, 28000); gcStaticCamera_activate(0x1A); - gcdialog_showDialog(0xC14, 0, NULL, NULL, NULL, NULL); + gcdialog_showDialog(VER_SELECT(ASSET_C14_DIALOG_TWINKLIE_MINIGAME_LIGHT_TREE, 0x98E, 0, 0), 0, NULL, NULL, NULL, NULL); break; case 3: // L803872F0 if(0.0 <= this->lifetime_value){ if( 1.8 < this->lifetime_value){ - __chXmasTree_80386EF4(this, 0); + chXmasTree_setState(this, 0); } else if(this->lifetime_value < 0.2){//L80387340 - __chXmasTree_80386EF4(this, 1); + chXmasTree_setState(this, 1); } else{ if(randf() < 0.2){ - __chXmasTree_80386EF4(this, this->unk38_31 ^ 1); - __chXmasTree_8038709C(this); + chXmasTree_setState(this, this->unk38_31 ^ 1); + chXmasTree_setLightsOff(this); } }//L803873AC this->lifetime_value -= sp2C; @@ -163,9 +163,9 @@ void chXmasTree_update(Actor *this){ else{//L803873BC if(func_802BB270()){ subaddie_set_state(this, 4); - __chXmasTree_80386EF4(this, 1); - item_set(ITEM_0_HOURGLASS_TIMER, 3600 - 1); - item_set(ITEM_6_HOURGLASS, true); + chXmasTree_setState(this, 1); + item_set(ITEM_0_HOURGLASS_TIMER, VER_SELECT(3600, 3000, 0, 0) - 1); + item_set(ITEM_6_HOURGLASS, TRUE); } } @@ -174,7 +174,7 @@ void chXmasTree_update(Actor *this){ case 4: // L80387400 if(mapSpecificFlags_get(3)){ subaddie_set_state(this, 6); - __chXmasTree_80386EF4(this, 1); + chXmasTree_setState(this, 1); item_set(ITEM_6_HOURGLASS, false); tmp_a0 = this->unk44_31; if(tmp_a0){ @@ -182,7 +182,7 @@ void chXmasTree_update(Actor *this){ this->unk44_31 = 0; } func_80324E38(0.0f, 3); - timedFunc_set_0(0.5f, __chXmasTree_80386F3C); + timedFunc_set_0(0.5f, chXmasTree_swapCameraToIce); } else{//L80387470 if(item_empty(ITEM_6_HOURGLASS)){ @@ -203,21 +203,21 @@ void chXmasTree_update(Actor *this){ case 5: // L803874EC if(0.0 <= this->lifetime_value){ if( 1.8 < this->lifetime_value){ - __chXmasTree_80386EF4(this, 1); + chXmasTree_setState(this, 1); } else if(this->lifetime_value < 0.2){ - __chXmasTree_80386EF4(this, 0); + chXmasTree_setState(this, 0); } else{ if(randf() < 0.2){ - __chXmasTree_80386EF4(this, this->unk38_31 ^ 1); - __chXmasTree_8038709C(this); + chXmasTree_setState(this, this->unk38_31 ^ 1); + chXmasTree_setLightsOff(this); } } this->lifetime_value -= sp2C; } else{ - __chXmasTree_80386F84(this); + chXmasTree_setLightsOn(this); } break; } diff --git a/src/FP/ch/xmastreestar.c b/src/FP/ch/xmastreestar.c index a9cc9cddf..a9b001885 100644 --- a/src/FP/ch/xmastreestar.c +++ b/src/FP/ch/xmastreestar.c @@ -27,8 +27,8 @@ f32 D_803935D0[3]; /* .code */ Actor *chXmasTreeStar_draw(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx){ - func_8033A45C( 2, mapSpecificFlags_get(0)); - func_8033A45C( 1, mapSpecificFlags_get(0) ^ 1); + modelRender_setAppendageVisibility( 2, mapSpecificFlags_get(0)); + modelRender_setAppendageVisibility( 1, mapSpecificFlags_get(0) ^ 1); return actor_draw(marker, gfx, mtx, vtx); } diff --git a/src/FP/ch/xmastreeswitch.c b/src/FP/ch/xmastreeswitch.c index 066f0a56e..1bb552b91 100644 --- a/src/FP/ch/xmastreeswitch.c +++ b/src/FP/ch/xmastreeswitch.c @@ -22,8 +22,8 @@ ActorInfo D_80392420 = { 0x206, 0x338, 0x486, /* .code */ Actor *chXmasTreeSwitch_draw(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx){ - func_8033A45C(1, 0); - func_8033A45C(2, 1); + modelRender_setAppendageVisibility(1, 0); + modelRender_setAppendageVisibility(2, 1); return actor_draw(marker, gfx, mtx, vtx); } diff --git a/src/FP/checksums.c b/src/FP/checksums.c new file mode 100644 index 000000000..b56783710 --- /dev/null +++ b/src/FP/checksums.c @@ -0,0 +1,7 @@ +// BanjoDecomp: FP/checksums.c +#include +#include "checksums.h" + +// !! THIS FILE MUST BE LINKED FIRST FOR THIS OVERLAY !! + +/* bss */ struct overlay_checksums_s gChecksumsFP; diff --git a/src/FP/actor_spawninit.c b/src/FP/fpspawnqueue.c similarity index 99% rename from src/FP/actor_spawninit.c rename to src/FP/fpspawnqueue.c index 119c2a794..bf98e1dec 100644 --- a/src/FP/actor_spawninit.c +++ b/src/FP/fpspawnqueue.c @@ -1,4 +1,4 @@ -// BanjoDecomp: code_ABD0.c +// BanjoDecomp: FP/fpspawnqueue.c #include #include "core1/core1.h" #include "functions.h" @@ -213,7 +213,7 @@ void func_80391744(Actor *this, Actor* other){ f32 tmp_f0; sp24 = nodeprop_findByActorIdAndActorPosition(0x22A, this); - tmp_f0 = (f32)nodeprop_getYaw(sp24); + tmp_f0 = (f32)nodeProp_getYaw(sp24); other->yaw = tmp_f0; this->yaw = tmp_f0; ml_vec3f_yaw_rotate_copy(sp28, sp34, tmp_f0); diff --git a/src/FP/mapstate/slalom.c b/src/FP/ma/slalom.c similarity index 91% rename from src/FP/mapstate/slalom.c rename to src/FP/ma/slalom.c index 4f82d9f85..fc25a098d 100644 --- a/src/FP/mapstate/slalom.c +++ b/src/FP/ma/slalom.c @@ -250,23 +250,23 @@ void maSlalom_dialogCallback(ActorMarker *caller, enum asset_e text_id, s32 arg2 } switch(text_id){ - case 0xc04: //8038B318 + case VER_SELECT(ASSET_C04_DIALOG_BOGGY_SLED_WALRUS_MISS, 0x97E, 0, 0): //8038B318 __maSlalom_loseDialogCallback(); break; - case 0xc07: //8038B328 + case VER_SELECT(ASSET_C07_DIALOG_BOGGY_SLED_WALRUS_COMPLETE, 0x981, 0, 0): //8038B328 __maSlalom_winDialogCallback(JIGGY_30_FP_BOGGY_2); break; - case 0xc0b: //8038B338 + case VER_SELECT(ASSET_C0B_DIALOG_BOGGY_SLED_BEAR_MISS, 0x985, 0, 0): //8038B338 __maSlalom_loseDialogCallback(); break; - case 0xc0d: //8038B348 + case VER_SELECT(ASSET_C0D_DIALOG_BOGGY_SLED_BEAR_COMPLETE, 0x987, 0, 0): //8038B348 __maSlalom_winDialogCallback(JIGGY_2C_FP_BOGGY_3); break; - case 0xc10: //8038B358 + case VER_SELECT(ASSET_C10_DIALOG_BOGGY_SLED_EITHER_GIVE_UP, 0x98A, 0, 0): //8038B358 func_8038ABDC(); code_7060_setVoidOutLocation(gsworld_getMap(), 0x11); func_8028F66C(BS_INTR_2A); @@ -300,12 +300,12 @@ void maSlalom_lose(void){ if(!jiggyscore_isCollected(JIGGY_30_FP_BOGGY_2)){ timed_setStaticCameraToNode(0.0f, 1); timed_playSfx(1.0f, SFX_8C_BOGGY_WAHEY, 1.0f, 32000); - func_80324DBC(2.0f, 0xC04, 0x2b, pntBoggy->position, NULL, maSlalom_dialogCallback, NULL); + func_80324DBC(2.0f, VER_SELECT(ASSET_C04_DIALOG_BOGGY_SLED_WALRUS_MISS, 0x97E, 0, 0), 0x2b, pntBoggy->position, NULL, maSlalom_dialogCallback, NULL); }//L8038B4E0 else{ timed_setStaticCameraToNode(0.0f, 1); timed_playSfx(1.0f, SFX_8C_BOGGY_WAHEY, 1.0f, 32000); - func_80324DBC(2.0f, 0xC0b, 0x2b, pntBoggy->position, NULL, maSlalom_dialogCallback, NULL); + func_80324DBC(2.0f, VER_SELECT(ASSET_C0B_DIALOG_BOGGY_SLED_BEAR_MISS, 0x985, 0, 0), 0x2b, pntBoggy->position, NULL, maSlalom_dialogCallback, NULL); } } @@ -359,10 +359,10 @@ void maSlalom_update(void){ pntBoggy->unk38_31 = 2; timed_playSfx(1.0f, SFX_8D_BOGGY_OHWW, 1.0f, 32000); if(jiggyscore_isCollected(JIGGY_30_FP_BOGGY_2) || jiggyscore_isSpawned(JIGGY_30_FP_BOGGY_2)){ - func_80324DBC(2.0f, 0xc0d, 0x2a, pntBoggy->position, NULL, maSlalom_dialogCallback, NULL); + func_80324DBC(2.0f, VER_SELECT(ASSET_C0D_DIALOG_BOGGY_SLED_BEAR_COMPLETE, 0x987, 0, 0), 0x2a, pntBoggy->position, NULL, maSlalom_dialogCallback, NULL); } else{ - func_80324DBC(2.0f, 0xc07, 0x22, pntBoggy->position, NULL, maSlalom_dialogCallback, NULL); + func_80324DBC(2.0f, VER_SELECT(ASSET_C07_DIALOG_BOGGY_SLED_WALRUS_COMPLETE, 0x981, 0, 0), 0x22, pntBoggy->position, NULL, maSlalom_dialogCallback, NULL); } Me.state = MA_SLALOM_STATE_4_LOSE; break; @@ -539,7 +539,7 @@ void maSlalom_setBoggyGate(s32 gate_num){ FP_func_8038AB60(0); if(!player_isDead()){ func_8028F918(2); - gcdialog_showDialog(0xc10, 0x20, NULL, NULL, maSlalom_dialogCallback, NULL); + gcdialog_showDialog(VER_SELECT(ASSET_C10_DIALOG_BOGGY_SLED_EITHER_GIVE_UP, 0x98A, 0, 0), 0x20, NULL, NULL, maSlalom_dialogCallback, NULL); }//L8038BD40 Me.state = MA_SLALOM_STATE_4_LOSE; break; @@ -547,7 +547,7 @@ void maSlalom_setBoggyGate(s32 gate_num){ case 3: if(!Me.hasBeenThreeBehind && !player_isDead()){ Me.hasBeenThreeBehind = 1; - gcdialog_showDialog(0xc0f, 0x20, NULL, NULL, NULL, NULL); + gcdialog_showDialog(VER_SELECT(ASSET_C0F_DIALOG_BOGGY_SLED_EITHER_TAUNT_2, 0x989, 0, 0), 0x20, NULL, NULL, NULL, NULL); }//L8038BD94 func_8025AEA0(0x3a, 0x411aa); break; @@ -555,7 +555,7 @@ void maSlalom_setBoggyGate(s32 gate_num){ case 2: if(!Me.hasBeenTwoBehind && !player_isDead()){ Me.hasBeenTwoBehind = 1; - gcdialog_showDialog(0xc0e, 0x20, NULL, NULL, NULL, NULL); + gcdialog_showDialog(VER_SELECT(ASSET_C0E_DIALOG_BOGGY_SLED_EITHER_TAUNT_1, 0x988, 0, 0), 0x20, NULL, NULL, NULL, NULL); }//L8038BDF0 func_8025AEA0(0x3a, 0x493e0); break; diff --git a/src/FP/mapstate/snowbutton.c b/src/FP/ma/snowbutton.c similarity index 100% rename from src/FP/mapstate/snowbutton.c rename to src/FP/ma/snowbutton.c diff --git a/src/FP/mapstate/snowy.c b/src/FP/ma/snowy.c similarity index 100% rename from src/FP/mapstate/snowy.c rename to src/FP/ma/snowy.c diff --git a/src/FP/ch/wozza_fire.c b/src/FP/wozza_fire.c similarity index 100% rename from src/FP/ch/wozza_fire.c rename to src/FP/wozza_fire.c diff --git a/src/GV/bss_pad.c b/src/GV/bss_pad.c deleted file mode 100644 index 4d37dc71d..000000000 --- a/src/GV/bss_pad.c +++ /dev/null @@ -1,2 +0,0 @@ -// BanjoDecomp: bss_pad.c -char pad_GV_D_80391A20[0x10]; diff --git a/src/GV/ch/cactus.c b/src/GV/cactus.c similarity index 100% rename from src/GV/ch/cactus.c rename to src/GV/cactus.c diff --git a/src/GV/ch/carpet1.c b/src/GV/carpet1.c similarity index 100% rename from src/GV/ch/carpet1.c rename to src/GV/carpet1.c diff --git a/src/GV/ch/carpet2.c b/src/GV/carpet2.c similarity index 93% rename from src/GV/ch/carpet2.c rename to src/GV/carpet2.c index fe8a39cb9..6634a0bfc 100644 --- a/src/GV/ch/carpet2.c +++ b/src/GV/carpet2.c @@ -74,7 +74,7 @@ void func_8038D47C(Actor *this){ player_getPosition(sp3C); if(player_movementGroup() == BSGROUP_0_NONE){ if( ml_vec3f_distance(sp3C, this->unk1C) < 100.0f || ml_vec3f_distance(sp3C, this->velocity) < 100.0f){ - if(gcdialog_showDialog(ASSET_A7B_DIALOG_JINXY_MEET, 0, NULL, NULL, NULL, NULL)){ + if(gcdialog_showDialog(VER_SELECT(ASSET_A7B_DIALOG_JINXY_MEET, 0x937, 0, 0), 0, NULL, NULL, NULL, NULL)){ mapSpecificFlags_set(0x14, 1); } } @@ -105,8 +105,8 @@ void func_8038D47C(Actor *this){ } if( actor_animationIsAt(this, 0.99f) ){ if(--this->unk38_31 == 0){ - gcdialog_showDialog(ASSET_A7C_DIALOG_JINXY_ONE_EGG, 4, NULL, NULL, NULL, NULL); - mapSpecificFlags_set(0x14, true); + gcdialog_showDialog(VER_SELECT(ASSET_A7C_DIALOG_JINXY_ONE_EGG, 0x938, 0, 0), 4, NULL, NULL, NULL, NULL); + mapSpecificFlags_set(0x14, TRUE); subaddie_set_state_forward(this, 1); } } diff --git a/src/GV/ch/ancientone.c b/src/GV/ch/ancientone.c index 96ada5f56..59ddf6117 100644 --- a/src/GV/ch/ancientone.c +++ b/src/GV/ch/ancientone.c @@ -1,4 +1,4 @@ -// BanjoDecomp: CH/ancientone.c +// BanjoDecomp: GV/ch/ancientone.c #include #include "functions.h" #include "variables.h" @@ -96,7 +96,7 @@ void func_803867F4(void){ void func_80386850(ActorMarker *caller_marker, enum asset_e text_id, s32 arg2){ Actor *caller = marker_getActor(caller_marker); - if(text_id == 0xA80){ + if(text_id == VER_SELECT(0xA80, 0x93C, 0, 0)){ subaddie_set_state_with_direction(caller, 2, 0.0f, 1); actor_playAnimationOnce(caller); coMusicPlayer_playMusic(COMUSIC_2D_PUZZLE_SOLVED_FANFARE, 0x7fff); @@ -173,16 +173,16 @@ void chAncientOne_update(Actor *this){ mapSpecificFlags_set(sp38, true); if(sp38== 0xB){ if(!jiggyscore_isCollected(JIGGY_46_GV_ANCIENT_ONES)){ - gcdialog_showDialog(ASSET_A80_DIALOG_ANCIENT_ONES_DONE, 0xE, NULL, this->marker, func_80386850, NULL); + gcdialog_showDialog(VER_SELECT(ASSET_A80_DIALOG_ANCIENT_ONES_DONE, 0x93C, 0, 0), 0xE, NULL, this->marker, func_80386850, NULL); } else{ - func_80386850(this->marker, 0xA80, -1); + func_80386850(this->marker, VER_SELECT(ASSET_A80_DIALOG_ANCIENT_ONES_DONE, 0x93C, 0, 0), -1); } }//L80386B98 else { if(sp38== 7){ if(!jiggyscore_isCollected(JIGGY_46_GV_ANCIENT_ONES)){ - gcdialog_showDialog(ASSET_A7F_DIALOG_ANCIENT_ONES_MEET, 0x4, NULL, NULL, NULL, NULL); + gcdialog_showDialog(VER_SELECT(ASSET_A7F_DIALOG_ANCIENT_ONES_MEET, 0x93B, 0, 0), 0x4, NULL, NULL, NULL, NULL); } } @@ -248,8 +248,8 @@ Actor *chAncientOne_draw(ActorMarker *this_marker, Gfx **gfx, Mtx **mtx, Vtx **v s32 tmp_v0; sp58 = (this->state == 3) ? 0 : 1; - func_8033A45C(3, sp58); - func_8033A45C(4, sp58); + modelRender_setAppendageVisibility(3, sp58); + modelRender_setAppendageVisibility(4, sp58); actor_draw(this_marker, gfx, mtx, vtx); if( !this->initialized && this_marker->unk14_21){ vec3fArray_get_vec3i(func_80329934(), 5, sp4C); diff --git a/src/GV/ch/buriedpyramid.c b/src/GV/ch/buriedpyramid.c index d342ff3f5..0d2634c79 100644 --- a/src/GV/ch/buriedpyramid.c +++ b/src/GV/ch/buriedpyramid.c @@ -1,4 +1,4 @@ -// BanjoDecomp: CH/buriedpyramid.c +// BanjoDecomp: GV/ch/buriedpyramid.c #include #include "functions.h" #include "variables.h" diff --git a/src/GV/ch/egg_pot.c b/src/GV/ch/eggpot.c similarity index 95% rename from src/GV/ch/egg_pot.c rename to src/GV/ch/eggpot.c index 32ff46425..05cc9baea 100644 --- a/src/GV/ch/egg_pot.c +++ b/src/GV/ch/eggpot.c @@ -1,4 +1,4 @@ -// BanjoDecomp: code_3AA0.c +// BanjoDecomp: GV/ch/eggpot.c #include #include "functions.h" #include "variables.h" diff --git a/src/GV/ch/gobi1.c b/src/GV/ch/gobi1.c index 8c8ddc4ff..fdcb99009 100644 --- a/src/GV/ch/gobi1.c +++ b/src/GV/ch/gobi1.c @@ -1,4 +1,4 @@ -// BanjoDecomp: CH/gobi1.c +// BanjoDecomp: GV/ch/gobi1.c #include #include "functions.h" #include "variables.h" @@ -159,7 +159,7 @@ void chGobi1_update(Actor *this){ timed_playSfx(1.0f, SFX_84_GOBI_CRYING, 1.1f, 30000); timed_playSfx(2.0f, SFX_84_GOBI_CRYING, 1.3f, 30000); timed_playSfx(2.5f, SFX_74_WALKING_NOISE_5, 0.5f, 30000); - func_80324DBC(3.0f, ASSET_A74_DIALOG_GOBI_HELPED, 0x2a, this->position, NULL, NULL, NULL); + func_80324DBC(3.0f, VER_SELECT(ASSET_A74_DIALOG_GOBI_HELPED, 0x930, 0, 0), 0x2a, this->position, NULL, NULL, NULL); timed_playSfx(5.0f, SFX_2E_BIGBUTT_RUNNING, 1.0f, 20000); timed_playSfx(5.6f, SFX_2E_BIGBUTT_RUNNING, 1.0f, 20000); timed_playSfx(6.5f, SFX_2E_BIGBUTT_RUNNING, 1.0f, 20000); @@ -181,7 +181,7 @@ void chGobi1_update(Actor *this){ && subaddie_playerIsWithinSphereAndActive(this, 250) && !subaddie_playerIsWithinSphereAndActive(this, 80) && func_8028F2A0() - && gcdialog_showDialog(0xa73, 0, NULL, NULL, NULL, NULL) + && gcdialog_showDialog(VER_SELECT(0xa73, 0x92F, 0, 0), 0, NULL, NULL, NULL, NULL) ){ this->has_met_before = true; } diff --git a/src/GV/ch/gobi2.c b/src/GV/ch/gobi2.c index 4f72f936c..ad0fc87a5 100644 --- a/src/GV/ch/gobi2.c +++ b/src/GV/ch/gobi2.c @@ -1,4 +1,4 @@ -// BanjoDecomp: CH/gobi2.c +// BanjoDecomp: GV/ch/gobi2.c #include #include "functions.h" #include "variables.h" @@ -86,7 +86,7 @@ void chGobi2_setState(Actor *this, s32 next_state){ timed_playSfx(0.8f, SFX_4B_GULPING, 0.8f, 28000); timed_playSfx(1.4f, SFX_4B_GULPING, 0.8f, 28000); timed_playSfx(2.0f, SFX_4B_GULPING, 0.8f, 28000); - func_80324DBC(3.0f, ASSET_A72_DIALOG_TRUNKER_HELPED, 0x2A, D_80390CEC, this->marker, func_80387A2C, NULL); + func_80324DBC(3.0f, VER_SELECT(ASSET_A72_DIALOG_TRUNKER_HELPED, 0x92E, 0, 0), 0x2A, D_80390CEC, this->marker, func_80387A2C, NULL); }//L80387C94 if(next_state == 4){ @@ -204,8 +204,8 @@ void chGobi2_update(Actor *this){ if(!this->has_met_before){ if(subaddie_playerIsWithinSphereAndActive(this, 0xFA) && !subaddie_playerIsWithinSphereAndActive(this, 0x50)){ if(func_8028F2A0()){ - if(gcdialog_showDialog(ASSET_A75_DIALOG_GOBI2_MEET, 0, this->position, NULL, NULL, NULL)) - this->has_met_before = true; + if(gcdialog_showDialog(VER_SELECT(ASSET_A75_DIALOG_GOBI2_MEET, 0x931, 0, 0), 0, this->position, NULL, NULL, NULL)) + this->has_met_before = TRUE; } } } diff --git a/src/GV/ch/gobi3.c b/src/GV/ch/gobi3.c index 98ab87eda..1552e5897 100644 --- a/src/GV/ch/gobi3.c +++ b/src/GV/ch/gobi3.c @@ -1,4 +1,4 @@ -// BanjoDecomp: CH/gobi3.c +// BanjoDecomp: GV/ch/gobi3.c #include "functions.h" #include "variables.h" #include @@ -75,7 +75,7 @@ void chGobi3_setState(Actor *this, s32 next_state){ if(next_state == 5){ skeletalAnim_set(this->unk148, 0xd9, 0.5f, 4.0f); - gcdialog_showDialog(ASSET_A77_DIALOG_GOBI3_DONE, 0xe, this->position, this->marker, __chGobi3_runaway, NULL); + gcdialog_showDialog(VER_SELECT(ASSET_A77_DIALOG_GOBI3_DONE, 0x933, 0, 0), 0xe, this->position, this->marker, __chGobi3_runaway, NULL); } if(next_state == 4){ diff --git a/src/GV/ch/gobirock.c b/src/GV/ch/gobirock.c index 9875f57a3..29caebd52 100644 --- a/src/GV/ch/gobirock.c +++ b/src/GV/ch/gobirock.c @@ -1,4 +1,4 @@ -// BanjoDecomp: CH/gobirock.c +// BanjoDecomp: GV/ch/gobirock.c #include #include "functions.h" #include "variables.h" diff --git a/src/GV/ch/gobirope.c b/src/GV/ch/gobirope.c index 1c2b5cb71..e934d1f1d 100644 --- a/src/GV/ch/gobirope.c +++ b/src/GV/ch/gobirope.c @@ -1,4 +1,4 @@ -// BanjoDecomp: CH/gobirope.c +// BanjoDecomp: GV/ch/gobirope.c #include #include "functions.h" #include "variables.h" diff --git a/src/GV/ch/grabba.c b/src/GV/ch/grabba.c index 7f04ea682..c1886224b 100644 --- a/src/GV/ch/grabba.c +++ b/src/GV/ch/grabba.c @@ -1,4 +1,4 @@ -// BanjoDecomp: code_5570.c +// BanjoDecomp: GV/ch/grabba.c #include #include "functions.h" #include "variables.h" @@ -64,7 +64,7 @@ void func_8038BA08(Actor *this){ if(player_movementGroup() == BSGROUP_6_TURBO_TALON_TRAINERS) player_stateTimer_set(STATE_TIMER_3_TURBO_TALON, 0.0f); - gcdialog_showDialog(ASSET_A79_DIALOG_GRABBA_DEFEAT, 0xf, this->position, this->marker, func_8038B988, NULL); + gcdialog_showDialog(VER_SELECT(ASSET_A79_DIALOG_GRABBA_DEFEAT, 0x935, 0, 0), 0xf, this->position, this->marker, func_8038B988, NULL); comusic_8025AB44(COMUSIC_57_TURBO_TRAINERS, 7000, 700); } @@ -246,8 +246,8 @@ void chGrabba_update(Actor *this){ } else{ if(!this->has_met_before){ - if(gcdialog_showDialog(ASSET_A78_DIALOG_GRABBA_MEET, 0, NULL, NULL, NULL, NULL)){ - this->has_met_before = true; + if(gcdialog_showDialog(VER_SELECT(ASSET_A78_DIALOG_GRABBA_MEET, 0x934, 0, 0), 0, NULL, NULL, NULL, NULL)){ + this->has_met_before = TRUE; } } } @@ -277,8 +277,8 @@ void chGrabba_update(Actor *this){ } if(!this->unk138_23){ - if(gcdialog_showDialog(ASSET_A7A_DIALOG_GRABBA_TOO_FAST, 0, NULL, NULL, NULL, NULL)){ - this->unk138_23 = true; + if(gcdialog_showDialog(VER_SELECT(ASSET_A7A_DIALOG_GRABBA_TOO_FAST, 0x936, 0, 0), 0, NULL, NULL, NULL, NULL)){ + this->unk138_23 = TRUE; } } } diff --git a/src/GV/ch/histup.c b/src/GV/ch/histup.c index 4ca545240..34e9cda79 100644 --- a/src/GV/ch/histup.c +++ b/src/GV/ch/histup.c @@ -1,4 +1,4 @@ -// BanjoDecomp: CH/histup.c +// BanjoDecomp: GV/ch/histup.c #include #include "functions.h" #include "variables.h" @@ -28,10 +28,10 @@ ActorInfo D_80391318 = { MARKER_AA_HISTUP, ACTOR_11C_HISTUP, ASSET_3DE_MODEL_HIS /* .bss */ extern struct { - s32 unk0; + s32 eggCount; s32 unk4; s32 unk8; -}GV_D_80391AB0; +} rubeeEggPot; /* .code */ int func_8038D920(Actor *this, f32 arg1){ @@ -76,19 +76,19 @@ void GV_func_8038DB0C(Actor *this){ } void func_8038DB4C(s32 arg0){ - GV_D_80391AB0.unk0 = arg0; + rubeeEggPot.eggCount = arg0; } void func_8038DB58(s32 arg0){ - GV_D_80391AB0.unk4 = arg0; + rubeeEggPot.unk4 = arg0; } s32 func_8038DB64(void){ - return GV_D_80391AB0.unk4; + return rubeeEggPot.unk4; } void func_8038DB70(void){ - GV_D_80391AB0.unk4++; + rubeeEggPot.unk4++; } @@ -115,7 +115,7 @@ void func_8038DBDC(Actor *this){ actor_collisionOff(this); subaddie_set_state_with_direction(this, 1, 0.99f, 0); anctrl_setPlaybackType(this->anctrl, ANIMCTRL_STOPPED); - GV_D_80391AB0.unk8 = 0; + rubeeEggPot.unk8 = 0; func_8038DB4C(0); this->unk1C[0] = 0.0f; }//L8038DC90 @@ -135,7 +135,7 @@ void func_8038DBDC(Actor *this){ case 2: //8038DD3C if(!(func_8038E178() < 5)){ func_8038DB88(this); - if(GV_D_80391AB0.unk8){ + if(rubeeEggPot.unk8){ subaddie_set_state_with_direction(this, 3, 0.99f, 0); anctrl_setPlaybackType(this->anctrl, ANIMCTRL_STOPPED); this->unk1C[0] = 0.0f; @@ -197,7 +197,7 @@ void func_8038DBDC(Actor *this){ anctrl_setDuration(this->anctrl, 1.6f); func_80386608(); func_8038DB4C(0); - GV_D_80391AB0.unk8 = false; + rubeeEggPot.unk8 = FALSE; func_8025A58C(-1, 0x190); func_8025A7DC(COMUSIC_27_GV_RUBEES_SONG); if(!this->unk44_31){ diff --git a/src/GV/ch/jinxy.c b/src/GV/ch/jinxy.c deleted file mode 100644 index 949f52e6a..000000000 --- a/src/GV/ch/jinxy.c +++ /dev/null @@ -1,158 +0,0 @@ -// BanjoDecomp: code_3D90.c -#include -#include "functions.h" -#include "variables.h" - -extern f32 mapModel_getFloorY(f32[3]); - -void func_8038A314(Actor *this); -void func_8038A31C(Actor *this); -Actor *func_8038A180(ActorMarker *this_marker, Gfx **gfx, Mtx **mtx, Vtx **vtx); - -/* .data */ -ActorAnimationInfo D_80390FA0[] = { - {0, 0.0f}, - {ASSET_C9_ANIM_MAGIC_CARPET, 2.0f}, - {ASSET_C9_ANIM_MAGIC_CARPET, 2.0f}, - {ASSET_C9_ANIM_MAGIC_CARPET, 2.0f}, - {ASSET_C9_ANIM_MAGIC_CARPET, 2.0f}, - {ASSET_C9_ANIM_MAGIC_CARPET, 2.0f}, -}; -ActorInfo D_80390FD0 = { MARKER_B0_MAGIC_CARPET_2, ACTOR_123_MAGIC_CARPET_2, ASSET_3DC_MODEL_MAGIC_CARPET, - 0x1, D_80390FA0, - func_8038A314, func_8038A31C, func_8038A180, - 0, 0, 0.0f, 0 -}; -u8 D_80390FF4[6] = {0,0,0,1,1,1}; - -/* .code */ -Actor *func_8038A180(ActorMarker *this_marker, Gfx **gfx, Mtx **mtx, Vtx **vtx){ - Actor * this = marker_getActor(this_marker); - - if(this->unk1C[0] != 0.0f){ - this = actor_draw(this_marker, gfx, mtx, vtx); - - if( this->unk54 == 0.0f - && this->unk48 != this->unk1C[1] - && this_marker->unk14_21 - && subaddie_playerIsWithinSphereAndActive(this, 3000) - ){ - commonParticle_add(this->marker, 6, func_80329904); - commonParticle_new(0xc, this->marker->unk14_21); - } - } - return this; -} - - -f32 func_8038A264(Actor *shadow, Actor* this){ - if(this && shadow){ - return ml_map_f(this->position_y - shadow->position_y, 0.0f, 2200.0f, 1.0f, 0.35f); - } - else{ - return 0.0; - } -} - -void func_8038A2C0(void *this_marker){ - Actor *this = marker_getActor(reinterpret_cast(ActorMarker *, this_marker)); - Actor *shadow = spawn_child_actor(ACTOR_122_MAGIC_CARPET_SHADOW, &this); - s32 pad; - - suSetSpriteScale(shadow, this->scale); - this->partnerActor = shadow->marker; -} - -void func_8038A314(Actor *this){} - -void func_8038A31C(Actor *this){ - Actor *sp24; - if(!this->volatile_initialized){ - this->volatile_initialized = true; - actor_collisionOff(this); - __spawnQueue_add_1((GenFunction_1)func_8038A2C0, (uintptr_t)this->marker); - this->velocity[0] = 0.0f; - } - - if(this->partnerActor) - sp24 = subaddie_getLinkedActor(this); - - this->unk1C[1] = this->unk48; - ; - - switch(code7FF0_getMagicCarpetState(this, 3)) - { - case 1: //L8038A3C0 - func_80343DEC(this); - this->marker->propPtr->unk8_3 = true; - this->unk1C[0] = 1.0; - this->alpha_124_19 = 0xff; - if(this->unk54 != 0.0f){ - subaddie_set_state_with_direction(this, 2, 0.02f, 1); - anctrl_setPlaybackType(this->anctrl, ANIMCTRL_STOPPED); - } - break; - case 2: //L8038A440 - this->marker->propPtr->unk8_3 = true; - this->unk1C[0] = 1.0; - if(45.0f <= this->velocity[0]){ - subaddie_set_state_with_direction(this, 3, 0.02f, 1); - this->velocity[0] = 0.0f; - } - else{ - if(D_80390FF4[((s32)this->velocity[0])%6] == 0){ - this->alpha_124_19 -= 0x55; - } - else{ - this->alpha_124_19 += 0x55; - } - this->velocity[0] += 1.0f; - } - break; - case 3: //L8038A534 - func_80343DEC(this); - this->marker->propPtr->unk8_3 = false; - this->unk1C[0] = 0.0; - this->alpha_124_19 = 0; - if(this->unk54 == 0.0f){ - subaddie_set_state_with_direction(this, 4, 0.02f, 1); - } - break; - - case 4: //L8038A5A4 - this->marker->propPtr->unk8_3 = true; - this->unk1C[0] = 1.0; - if(45.0f <= this->velocity[0]){ - subaddie_set_state_with_direction(this, 1, 0.02f, 1); - anctrl_setPlaybackType(this->anctrl, ANIMCTRL_LOOP); - this->velocity[0] = 0.0f; - } - else{ - if(D_80390FF4[5 - ((s32)this->velocity[0])%6 ] != 0){ - this->alpha_124_19 += 0x55; - } - else{ - this->alpha_124_19 -= 0x55; - } - this->velocity[0] += 1.0f; - } - - break; - }//L8038A6A4 - this->unk124_11 = 0x3; - this->pitch = 0.0f; - if(this->partnerActor && sp24 && this->partnerActor->id == MARKER_AF_MAGIC_CARPET_SHADOW){ - sp24->position_x = this->position_x; - sp24->position_y = mapModel_getFloorY(this->position) + 60.0f; - sp24->position_z = this->position_z; - sp24->unk1C[0] = func_8038A264(sp24, this); - sp24->yaw = this->yaw; - sp24->velocity[0] = 1.0; - sp24->velocity[1] = this->alpha_124_19; - if (0.0f != this->unk1C[0]) - sp24->unk1C[2] = 1.0; - else - sp24->unk1C[2] = 0.0f; - - }//L8038A780 -} diff --git a/src/GV/mazectrl.c b/src/GV/ch/mazectrl.c similarity index 90% rename from src/GV/mazectrl.c rename to src/GV/ch/mazectrl.c index ffc5b2848..142e298a0 100644 --- a/src/GV/mazectrl.c +++ b/src/GV/ch/mazectrl.c @@ -1,4 +1,4 @@ -// BanjoDecomp: CH/mazectrl.c +// BanjoDecomp: GV/ch/mazectrl.c #include #include "functions.h" #include "variables.h" @@ -67,8 +67,8 @@ void __chMazeCtrl_setState(Actor *this, s32 next_state){ if(next_state == 2){ func_8025A58C(0, 4000); coMusicPlayer_playMusic(COMUSIC_26_GV_SANDYBUTT_DANGER, 30000); - item_set(ITEM_0_HOURGLASS_TIMER, 0xdd3); - item_set(ITEM_6_HOURGLASS, true); + item_set(ITEM_0_HOURGLASS_TIMER, VER_SELECT(0xdd3, 0xb85, 0, 0)); + item_set(ITEM_6_HOURGLASS, TRUE); func_8038F520(1.0f); FUNC_8030E624(SFX_3F6_RUBBING, 0.8f, 25000); FUNC_8030E624(SFX_3F6_RUBBING, 0.7f, 25000); @@ -86,8 +86,8 @@ void __chMazeCtrl_setState(Actor *this, s32 next_state){ } if (!levelSpecificFlags_get(LEVEL_FLAG_16_GV_UNKNOWN)) { - gcdialog_showDialog(ASSET_A82_DIALOG_SANDYBUTT_START_MAZE, 4, NULL, NULL, NULL, NULL); - levelSpecificFlags_set(LEVEL_FLAG_16_GV_UNKNOWN, true); + gcdialog_showDialog(VER_SELECT(ASSET_A82_DIALOG_SANDYBUTT_START_MAZE, 0x93E, 0, 0), 4, NULL, NULL, NULL, NULL); + levelSpecificFlags_set(LEVEL_FLAG_16_GV_UNKNOWN, TRUE); } }//L8038F794 @@ -136,8 +136,8 @@ void __chMazeCtrl_setState(Actor *this, s32 next_state){ coMusicPlayer_playMusic(COMUSIC_2D_PUZZLE_SOLVED_FANFARE, 0x7fff); if(!levelSpecificFlags_get(LEVEL_FLAG_17_GV_UNKNOWN)){ - gcdialog_showDialog(ASSET_A83_DIALOG_SANDYBUTT_DONE, 4, NULL, NULL, NULL, NULL); - levelSpecificFlags_set(LEVEL_FLAG_17_GV_UNKNOWN, true); + gcdialog_showDialog(VER_SELECT(ASSET_A83_DIALOG_SANDYBUTT_DONE, 0x93F, 0, 0), 4, NULL, NULL, NULL, NULL); + levelSpecificFlags_set(LEVEL_FLAG_17_GV_UNKNOWN, TRUE); } } @@ -179,7 +179,7 @@ void chMazeCtrl_update(Actor *this){ if (!levelSpecificFlags_get(LEVEL_FLAG_15_GV_UNKNOWN) && ml_timer_update(&local->unk8, sp34) - && gcdialog_showDialog(ASSET_A81_DIALOG_SANDYBUTT_ENTER, 0, NULL, NULL, NULL, NULL) + && gcdialog_showDialog(VER_SELECT(ASSET_A81_DIALOG_SANDYBUTT_ENTER, 0x93D, 0, 0), 0, NULL, NULL, NULL, NULL) ) { levelSpecificFlags_set(LEVEL_FLAG_15_GV_UNKNOWN, true); } diff --git a/src/GV/ch/mummum.c b/src/GV/ch/mummum.c index 53c9a69ab..dbc6ad01b 100644 --- a/src/GV/ch/mummum.c +++ b/src/GV/ch/mummum.c @@ -1,4 +1,4 @@ -// BanjoDecomp: (core2 origin, not from GV overlay) +// BanjoDecomp: core2/ch/mummum.c #include #include "functions.h" #include "variables.h" diff --git a/src/GV/ch/sarcophagus.c b/src/GV/ch/sarcophagus.c index 260ffb7b4..bc20521ce 100644 --- a/src/GV/ch/sarcophagus.c +++ b/src/GV/ch/sarcophagus.c @@ -1,4 +1,4 @@ -// BanjoDecomp: CH/sarcophagus.c +// BanjoDecomp: GV/ch/sarcophagus.c #include #include "functions.h" #include "variables.h" diff --git a/src/GV/ch/slappa.c b/src/GV/ch/slappa.c index e1423e092..5d8f275ce 100644 --- a/src/GV/ch/slappa.c +++ b/src/GV/ch/slappa.c @@ -1,4 +1,4 @@ -// BanjoDecomp: code_4740.c +// BanjoDecomp: GV/ch/slappa.c #include #include "functions.h" #include "variables.h" diff --git a/src/GV/ch/toots.c b/src/GV/ch/toots.c index bf84aa0dd..edeb96f8e 100644 --- a/src/GV/ch/toots.c +++ b/src/GV/ch/toots.c @@ -1,4 +1,4 @@ -// BanjoDecomp: CH/toots.c +// BanjoDecomp: GV/ch/toots.c #include #include "functions.h" #include "variables.h" diff --git a/src/GV/ch/trunker.c b/src/GV/ch/trunker.c index d4a4b4958..93e013092 100644 --- a/src/GV/ch/trunker.c +++ b/src/GV/ch/trunker.c @@ -1,4 +1,4 @@ -// BanjoDecomp: CH/trunker.c +// BanjoDecomp: GV/ch/trunker.c #include #include "functions.h" #include "variables.h" @@ -75,8 +75,8 @@ void chTrunker_update(Actor *this){ && !subaddie_playerIsWithinSphereAndActive(this, 80) && func_8028F2A0() ){ - gcdialog_showDialog(ASSET_A71_DIALOG_TRUNKER_MEET, 0xe, this->position, NULL, NULL, NULL); - this->has_met_before = true; + gcdialog_showDialog(VER_SELECT(ASSET_A71_DIALOG_TRUNKER_MEET, 0x92D, 0, 0), 0xe, this->position, NULL, NULL, NULL); + this->has_met_before = TRUE; }//L80389254 if(this->state == 1 && mapSpecificFlags_get(0xC)){ diff --git a/src/GV/checksums.c b/src/GV/checksums.c new file mode 100644 index 000000000..a89de711c --- /dev/null +++ b/src/GV/checksums.c @@ -0,0 +1,7 @@ +// BanjoDecomp: GV/checksums.c +#include +#include "checksums.h" + +// !! THIS FILE MUST BE LINKED FIRST FOR THIS OVERLAY !! + +/* bss */ struct overlay_checksums_s gChecksumsGV; diff --git a/src/GV/crc.c b/src/GV/crc.c index 22cff99bb..8ace3ef7a 100644 --- a/src/GV/crc.c +++ b/src/GV/crc.c @@ -1,4 +1,4 @@ -// BanjoDecomp: code_3B10.c +// BanjoDecomp: GV/crc.c #include #include "functions.h" #include "variables.h" @@ -7,11 +7,9 @@ extern void player_stateTimer_set(s32, f32); extern f32 player_stateTimer_get(enum state_timer_e); -/* .data */ -//TODO Implement CRC calculation in Makefile(?) -u32 D_80390F30 = 0x00274530; //GV.code CRC1 -u32 D_80390F34 = 0xAA18BBF3; //GV.code CRC2 -u32 D_80390F38 = 0x0003031C; //GV.data CRC1 (with this value = 0) +s32 D_80390F30 = VER_SELECT(0x00274530, 0x002764CA, 0, 0); // GV_TEXT_CRC1 +s32 D_80390F34 = VER_SELECT(0xAA18BBF3, 0xFB1E80F4, 0, 0); // GV_TEXT_CRC2 +s32 D_80390F38 = VER_SELECT(0x0003031C, 0x00031973, 0, 0); // GV_DATA_CRC1 /* .code */ diff --git a/src/GV/gv_helpers.c b/src/GV/gv_helpers.c index fed404bb2..0c40a25a4 100644 --- a/src/GV/gv_helpers.c +++ b/src/GV/gv_helpers.c @@ -4,25 +4,25 @@ #include "variables.h" struct { - s32 unk0; + s32 eggCount; s32 unk4; s32 unk8; -}GV_D_80391AB0; +} rubeeEggPot; /* .code */ -void func_8038E140(void){ - GV_D_80391AB0.unk0++; +void rubeeEggPot_addedEggToPot(void){ + rubeeEggPot.eggCount++; coMusicPlayer_playMusic(COMUSIC_2B_DING_B, 26000); } s32 func_8038E178(void){ - return GV_D_80391AB0.unk0; + return rubeeEggPot.eggCount; } -s32 func_8038E184(void){ +s32 rubeeEggPot_getEggGoal(void){ return 5; } void func_8038E18C(void){ - GV_D_80391AB0.unk8 = true; + rubeeEggPot.unk8 = TRUE; } diff --git a/src/GV/actor_spawninit.c b/src/GV/gvspawnqueue.c similarity index 89% rename from src/GV/actor_spawninit.c rename to src/GV/gvspawnqueue.c index 75cbb7665..0b01ec333 100644 --- a/src/GV/actor_spawninit.c +++ b/src/GV/gvspawnqueue.c @@ -1,4 +1,4 @@ -// BanjoDecomp: code_7FF0.c +// BanjoDecomp: GV/gvspawnqueue.c #include #include "core1/core1.h" #include "functions.h" @@ -10,7 +10,7 @@ #include "port/Patches/Patches.h" extern void core1_7090_initSfxSource(s32, s32, s32, f32); -extern void func_802D3D54(Actor *this); +extern void chMMMBreakableWooden_update(Actor *this); extern void func_802D3D74(Actor *this); extern Actor *func_80325F2C(ActorMarker *this_marker, Gfx **gfx, Mtx **mtx, Vtx **vtx); extern void func_8032BC3C(Actor *, f32); @@ -24,20 +24,20 @@ extern ActorInfo chGobiRock; extern ActorInfo chGobi2; extern ActorInfo chGobi3; extern ActorInfo chTrunker; -extern ActorInfo GV_D_80390DD0; +extern ActorInfo chMagicCarpetShadow; extern ActorInfo chSarcophagus; extern ActorInfo chSNSSarcophagus; -extern ActorInfo D_80390ED0; +extern ActorInfo chRubee; extern ActorInfo D_80390F00; -extern ActorInfo D_80390FD0; +extern ActorInfo chMagicCarpet2; extern ActorInfo D_80391010; extern ActorInfo chSlappa; extern ActorInfo chGrabba; extern ActorInfo D_803911C0; -extern ActorInfo D_803911F4; -extern ActorInfo D_80391218; -extern ActorInfo D_8039123C; -extern ActorInfo D_80391260; +extern ActorInfo chJinxyHeadSandybutt1; +extern ActorInfo chJinxyHeadSandybutt2; +extern ActorInfo chJinxyHeadSandybutt3; +extern ActorInfo chSandybuttEggToll; extern ActorInfo D_80391318; extern ActorInfo D_80391358; extern ActorInfo D_803912B8; @@ -111,13 +111,13 @@ ActorInfo D_80391494 = { MARKER_23C_GV_SNS_SWITCH, ACTOR_245_GV_SNS_SWITCH, ASSE ActorInfo D_803914B8 = { MARKER_EB_GV_BANJO_DOOR, ACTOR_6D_GV_BANJO_DOOR, ASSET_3D8_MODEL_GV_BANJO_DOOR, 0x1, 0x0, - func_802D3D54, func_8038E460, func_80325F2C, + chMMMBreakableWooden_update, func_8038E460, func_80325F2C, 0, 0, 0.0f, 0 }; ActorInfo D_803914DC = { MARKER_ED_GV_SUN_DOOR, ACTOR_140_GV_SUN_DOOR, ASSET_3FF_MODEL_GV_SUN_DOOR, 0x1, 0x0, - func_802D3D54, func_8038E4DC, func_80325F2C, + chMMMBreakableWooden_update, func_8038E4DC, func_80325F2C, 0, 0, 0.0f, 0 }; @@ -192,7 +192,7 @@ void func_8038E460(Actor *this){//banjo_door mapSpecificFlags_set(2, true); if(EventSystem_Should(VB_DOOR_OPEN_CAMERA, true, GV_DOOR_CAM_JINXY)){ func_8028F918(0); - func_80324DBC(4.0f, ASSET_A7D_DIALOG_JINXY_HELPED, 4, NULL, NULL, NULL, NULL); + func_80324DBC(4.0f, VER_SELECT(ASSET_A7D_DIALOG_JINXY_HELPED, 0x939, 0, 0), 4, NULL, NULL, NULL, NULL); } } } @@ -252,7 +252,7 @@ void func_8038E648(Actor *this){ s32 pyramidTimer = 25; CALL_EVENT(OnWaterPyramidTimer, &pyramidTimer); // [port] may extend timer this->unk38_31 = pyramidTimer * 24; // [port] door duration derived from HUD timer (vanilla ratio 600:25) - func_802D68F0(pyramidTimer); + code_4C020_setHourglassTimer(pyramidTimer); item_set(ITEM_6_HOURGLASS, 1); } break; @@ -262,7 +262,7 @@ void func_8038E648(Actor *this){ if(90.0f <= this->pitch){ subaddie_set_state(this, 7); this->pitch = 90.0f; - gcsfx_playAtSampleRate(SFX_7F_HEAVYDOOR_SLAM); + gcsfx_play(SFX_7F_HEAVYDOOR_SLAM); core1_7090_freeSfxSource(0); } break; @@ -280,10 +280,10 @@ void func_8038E648(Actor *this){ if(this->pitch <= 0.0f){ subaddie_set_state(this, 1); this->pitch = 0.0f; - gcsfx_playAtSampleRate(SFX_7F_HEAVYDOOR_SLAM); + gcsfx_play(SFX_7F_HEAVYDOOR_SLAM); mapSpecificFlags_set(5, false); core1_7090_freeSfxSource(0); - volatileFlag_setAndTriggerDialog_0(VOLATILE_FLAG_AC_GV_TRAPDOOR_MISSED); + progressDialog_setAndTriggerDialog_0(VOLATILE_FLAG_AC_GV_TRAPDOOR_MISSED); } break; }//L8038E904: @@ -335,7 +335,7 @@ void func_8038E97C(Actor *this){ if(this->unk38_31 == 0){ subaddie_set_state(this, 1); core1_7090_freeSfxSource(1); - gcsfx_playAtSampleRate(SFX_7F_HEAVYDOOR_SLAM); + gcsfx_play(SFX_7F_HEAVYDOOR_SLAM); } } @@ -362,7 +362,7 @@ void chKazooieDoor_update(Actor *this){ this->position_z -= 1.3319999999999999; if(this->unk1C[1] <= this->position_y){ subaddie_set_state(this, 7); - gcsfx_playAtSampleRate(SFX_7F_HEAVYDOOR_SLAM); + gcsfx_play(SFX_7F_HEAVYDOOR_SLAM); core1_7090_freeSfxSource(1); this->unk38_31 = 450; } @@ -382,7 +382,7 @@ void chKazooieDoor_update(Actor *this){ if(this->position_y <= this->unk1C[0]){ this->position_y = this->unk1C[0]; subaddie_set_state(this, 1); - gcsfx_playAtSampleRate(SFX_7F_HEAVYDOOR_SLAM); + gcsfx_play(SFX_7F_HEAVYDOOR_SLAM); core1_7090_freeSfxSource(1); mapSpecificFlags_set(6, false); } @@ -399,7 +399,7 @@ void chSunSwitch_update(Actor *this){ && func_802BB270() ){ this->velocity_x = 1.0f; - func_802D68F0(10); + code_4C020_setHourglassTimer(10); item_set(ITEM_6_HOURGLASS, 1); }//L8038EDC8 @@ -444,7 +444,7 @@ void chKazooieTarget_update(Actor *this){ && func_802BB270() ){ this->velocity_x = 1.0f; - func_802D68F0(0x15); + code_4C020_setHourglassTimer(0x15); item_set(ITEM_6_HOURGLASS, 1); }//L8038EDC8 @@ -496,20 +496,20 @@ void GV_func_8038F154(void) spawnableActorList_add(&chGobi2, actor_new, ACTOR_FLAG_UNKNOWN_3 | ACTOR_FLAG_UNKNOWN_5 | ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_8 | ACTOR_FLAG_UNKNOWN_10 | ACTOR_FLAG_UNKNOWN_11); spawnableActorList_add(&chGobi3, actor_new, ACTOR_FLAG_UNKNOWN_3 | ACTOR_FLAG_UNKNOWN_5 | ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_8 | ACTOR_FLAG_UNKNOWN_11); spawnableActorList_add(&chTrunker, actor_new, ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_8 | ACTOR_FLAG_UNKNOWN_10 | ACTOR_FLAG_UNKNOWN_11); - spawnableActorList_add(&GV_D_80390DD0, actor_new, ACTOR_FLAG_UNKNOWN_2 | ACTOR_FLAG_UNKNOWN_14); + spawnableActorList_add(&chMagicCarpetShadow, actor_new, ACTOR_FLAG_UNKNOWN_2 | ACTOR_FLAG_UNKNOWN_14); spawnableActorList_add(&chSarcophagus, actor_new, ACTOR_FLAG_UNKNOWN_3 | ACTOR_FLAG_UNKNOWN_6 | ACTOR_FLAG_UNKNOWN_10); spawnableActorList_add(&chSNSSarcophagus, actor_new, ACTOR_FLAG_UNKNOWN_3 | ACTOR_FLAG_UNKNOWN_6); - spawnableActorList_add(&D_80390ED0, actor_new, ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_8); + spawnableActorList_add(&chRubee, actor_new, ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_8); spawnableActorList_add(&D_80390F00, actor_new, ACTOR_FLAG_UNKNOWN_7); - spawnableActorList_add(&D_80390FD0, actor_new, ACTOR_FLAG_UNKNOWN_3 | ACTOR_FLAG_UNKNOWN_6 | ACTOR_FLAG_UNKNOWN_14); + spawnableActorList_add(&chMagicCarpet2, actor_new, ACTOR_FLAG_UNKNOWN_3 | ACTOR_FLAG_UNKNOWN_6 | ACTOR_FLAG_UNKNOWN_14); spawnableActorList_add(&D_80391010, actor_new, ACTOR_FLAG_UNKNOWN_3 | ACTOR_FLAG_UNKNOWN_6 | ACTOR_FLAG_UNKNOWN_14); spawnableActorList_add(&chSlappa, actor_new, ACTOR_FLAG_UNKNOWN_0 | ACTOR_FLAG_UNKNOWN_3 | ACTOR_FLAG_UNKNOWN_5 | ACTOR_FLAG_UNKNOWN_6 | ACTOR_FLAG_UNKNOWN_16); spawnableActorList_add(&chGrabba, actor_new, ACTOR_FLAG_UNKNOWN_3 | ACTOR_FLAG_UNKNOWN_6); spawnableActorList_add(&D_803911C0, actor_new, ACTOR_FLAG_UNKNOWN_3); - spawnableActorList_add(&D_803911F4, actor_new, ACTOR_FLAG_UNKNOWN_3 | ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_8 | ACTOR_FLAG_UNKNOWN_11 | ACTOR_FLAG_UNKNOWN_19); - spawnableActorList_add(&D_80391218, actor_new, ACTOR_FLAG_UNKNOWN_3 | ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_8 | ACTOR_FLAG_UNKNOWN_11 | ACTOR_FLAG_UNKNOWN_19); - spawnableActorList_add(&D_8039123C, actor_new, ACTOR_FLAG_UNKNOWN_3 | ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_8 | ACTOR_FLAG_UNKNOWN_11 | ACTOR_FLAG_UNKNOWN_19); - spawnableActorList_add(&D_80391260, actor_new, ACTOR_FLAG_UNKNOWN_7); + spawnableActorList_add(&chJinxyHeadSandybutt1, actor_new, ACTOR_FLAG_UNKNOWN_3 | ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_8 | ACTOR_FLAG_UNKNOWN_11 | ACTOR_FLAG_UNKNOWN_19); + spawnableActorList_add(&chJinxyHeadSandybutt2, actor_new, ACTOR_FLAG_UNKNOWN_3 | ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_8 | ACTOR_FLAG_UNKNOWN_11 | ACTOR_FLAG_UNKNOWN_19); + spawnableActorList_add(&chJinxyHeadSandybutt3, actor_new, ACTOR_FLAG_UNKNOWN_3 | ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_8 | ACTOR_FLAG_UNKNOWN_11 | ACTOR_FLAG_UNKNOWN_19); + spawnableActorList_add(&chSandybuttEggToll, actor_new, ACTOR_FLAG_UNKNOWN_7); spawnableActorList_add(&D_80391318, actor_new, ACTOR_FLAG_UNKNOWN_1 | ACTOR_FLAG_UNKNOWN_3 | ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_8 | ACTOR_FLAG_UNKNOWN_9 | ACTOR_FLAG_UNKNOWN_10); spawnableActorList_add(&D_80391358, actor_new, ACTOR_FLAG_UNKNOWN_3 | ACTOR_FLAG_UNKNOWN_4 | ACTOR_FLAG_UNKNOWN_8 | ACTOR_FLAG_UNKNOWN_10); // Big Jinxy Head ? spawnableActorList_add(&D_803912B8, actor_new, ACTOR_FLAG_UNKNOWN_8 | ACTOR_FLAG_UNKNOWN_10); diff --git a/src/GV/ch/handshadow.c b/src/GV/handshadow.c similarity index 100% rename from src/GV/ch/handshadow.c rename to src/GV/handshadow.c diff --git a/src/GV/ch/jinxy_head.c b/src/GV/jinxy_head.c similarity index 100% rename from src/GV/ch/jinxy_head.c rename to src/GV/jinxy_head.c diff --git a/src/GV/magiccarpet2.c b/src/GV/magiccarpet2.c new file mode 100644 index 000000000..bbe7a21b2 --- /dev/null +++ b/src/GV/magiccarpet2.c @@ -0,0 +1,171 @@ +// BanjoDecomp: GV/magiccarpet2.c +#include +#include "functions.h" +#include "variables.h" + +extern f32 mapModel_getFloorY(f32[3]); + +// [port] func_80329904 is declared in functions.h with its real signature. +// void func_80329904(ActorMarker *, s32, void *); + +void chmagiccarpet2_emptyupdate(Actor *this); +void chmagiccarpet2_update(Actor *this); +Actor *chmagiccarpet2_draw(ActorMarker *this_marker, Gfx **gfx, Mtx **mtx, Vtx **vtx); + +/* .data */ +ActorAnimationInfo chMagicCarpet2Animations[] = { + {0, 0.0f}, + {ASSET_C9_ANIM_MAGIC_CARPET, 2.0f}, + {ASSET_C9_ANIM_MAGIC_CARPET, 2.0f}, + {ASSET_C9_ANIM_MAGIC_CARPET, 2.0f}, + {ASSET_C9_ANIM_MAGIC_CARPET, 2.0f}, + {ASSET_C9_ANIM_MAGIC_CARPET, 2.0f}, +}; + +ActorInfo chMagicCarpet2 = { + MARKER_B0_MAGIC_CARPET_2, ACTOR_123_MAGIC_CARPET_2, ASSET_3DC_MODEL_MAGIC_CARPET, + 0x1, chMagicCarpet2Animations, + chmagiccarpet2_emptyupdate, chmagiccarpet2_update, chmagiccarpet2_draw, + 0, 0, 0.0f, 0 +}; + +u8 D_80390FF4[6] = {0, 0, 0, 1, 1, 1}; + +enum chmagicarpet2_state_e { + CHMAGICCARPET2_STATE_0_NOT_INIT, + CHMAGICCARPET2_STATE_1_UNK, + CHMAGICCARPET2_STATE_2_UNK, + CHMAGICCARPET2_STATE_3_UNK, + CHMAGICCARPET2_STATE_4_UNK +}; + +/* .code */ +Actor *chmagiccarpet2_draw(ActorMarker *this_marker, Gfx **gfx, Mtx **mtx, Vtx **vtx){ + Actor * this = marker_getActor(this_marker); + + if(this->unk1C[0] != 0.0f){ + this = actor_draw(this_marker, gfx, mtx, vtx); + + if( this->unk54 == 0.0f + && this->unk48 != this->unk1C[1] + && this_marker->unk14_21 + && subaddie_playerIsWithinSphereAndActive(this, 3000) + ){ + commonParticle_add(this->marker, 6, func_80329904); + commonParticle_new(0xc, this->marker->unk14_21); + } + } + return this; +} + + +f32 func_8038A264(Actor *shadow, Actor* this){ + if(this && shadow){ + return ml_map_f(this->position_y - shadow->position_y, 0.0f, 2200.0f, 1.0f, 0.35f); + } + else{ + return 0.0; + } +} + +void func_8038A2C0(void *this_marker){ + Actor *this = marker_getActor(reinterpret_cast(ActorMarker *, this_marker)); + Actor *shadow = spawn_child_actor(ACTOR_122_MAGIC_CARPET_SHADOW, &this); + s32 pad; + + suSetSpriteScale(shadow, this->scale); + this->partnerActor = shadow->marker; +} + +void chmagiccarpet2_emptyupdate(Actor *this){} + +void chmagiccarpet2_update(Actor *this){ + Actor *sp24; + + if(!this->volatile_initialized){ + this->volatile_initialized = TRUE; + actor_collisionOff(this); + __spawnQueue_add_1((GenFunction_1)func_8038A2C0, reinterpret_cast(uintptr_t, this->marker)); + this->velocity[0] = 0.0f; + } + + if(this->partnerActor) + sp24 = subaddie_getLinkedActor(this); + + this->unk1C[1] = this->unk48; + + switch(code7FF0_getMagicCarpetState(this, CHMAGICCARPET2_STATE_3_UNK)) + { + case CHMAGICCARPET2_STATE_1_UNK: //L8038A3C0 + func_80343DEC(this); + this->marker->propPtr->unk8_3 = TRUE; + this->unk1C[0] = 1.0; + this->alpha_124_19 = 0xff; + if(this->unk54 != 0.0f){ + subaddie_set_state_with_direction(this, 2, 0.02f, 1); + anctrl_setPlaybackType(this->anctrl, ANIMCTRL_STOPPED); + } + break; + case CHMAGICCARPET2_STATE_2_UNK: //L8038A440 + this->marker->propPtr->unk8_3 = TRUE; + this->unk1C[0] = 1.0; + if(45.0f <= this->velocity[0]){ + subaddie_set_state_with_direction(this, 3, 0.02f, 1); + this->velocity[0] = 0.0f; + } + else{ + if(D_80390FF4[((s32)this->velocity[0]) % 6] == 0){ + this->alpha_124_19 -= 0x55; + } + else{ + this->alpha_124_19 += 0x55; + } + this->velocity[0] += 1.0f; + } + break; + case CHMAGICCARPET2_STATE_3_UNK: //L8038A534 + func_80343DEC(this); + this->marker->propPtr->unk8_3 = FALSE; + this->unk1C[0] = 0.0; + this->alpha_124_19 = 0; + if(this->unk54 == 0.0f){ + subaddie_set_state_with_direction(this, 4, 0.02f, 1); + } + break; + + case CHMAGICCARPET2_STATE_4_UNK: //L8038A5A4 + this->marker->propPtr->unk8_3 = TRUE; + this->unk1C[0] = 1.0; + if(45.0f <= this->velocity[0]){ + subaddie_set_state_with_direction(this, 1, 0.02f, 1); + anctrl_setPlaybackType(this->anctrl, ANIMCTRL_LOOP); + this->velocity[0] = 0.0f; + } + else { + if(D_80390FF4[5 - ((s32)this->velocity[0])%6 ] != 0){ + this->alpha_124_19 += 0x55; + } + else{ + this->alpha_124_19 -= 0x55; + } + this->velocity[0] += 1.0f; + } + break; + }//L8038A6A4 + this->unk124_11 = 0x3; + this->pitch = 0.0f; + if(this->partnerActor && sp24 && this->partnerActor->id == MARKER_AF_MAGIC_CARPET_SHADOW){ + sp24->position_x = this->position_x; + sp24->position_y = mapModel_getFloorY(this->position) + 60.0f; + sp24->position_z = this->position_z; + sp24->unk1C[0] = func_8038A264(sp24, this); + sp24->yaw = this->yaw; + sp24->velocity[0] = 1.0; + sp24->velocity[1] = this->alpha_124_19; + if (0.0f != this->unk1C[0]) + sp24->unk1C[2] = 1.0; + else + sp24->unk1C[2] = 0.0f; + + }//L8038A780 +} diff --git a/src/GV/ch/carpet_shadow.c b/src/GV/magiccarpetshadow.c similarity index 61% rename from src/GV/ch/carpet_shadow.c rename to src/GV/magiccarpetshadow.c index b3fc76eb2..68429daac 100644 --- a/src/GV/ch/carpet_shadow.c +++ b/src/GV/magiccarpetshadow.c @@ -1,25 +1,26 @@ -// BanjoDecomp: code_2EE0.c +// BanjoDecomp: GV/magiccarpetshadow.c #include #include "functions.h" #include "variables.h" -void func_8038938C(Actor *this); -Actor *func_803892D0(ActorMarker *this_marker, Gfx **gfx, Mtx **mtx, Vtx **vtx); +void chMagicCarpetShadow_update(Actor *this); +Actor *chMagicCarpetShadow_draw(ActorMarker *this_marker, Gfx **gfx, Mtx **mtx, Vtx **vtx); /* .data */ -extern ActorAnimationInfo D_80390DC0[]={ +extern ActorAnimationInfo chMagicCarpetShadowAnimations[] = { {0, 0.0f}, {ASSET_F1_ANIM_MAGIC_CARPET, 2.0f} }; -extern ActorInfo GV_D_80390DD0 = { MARKER_AF_MAGIC_CARPET_SHADOW, ACTOR_122_MAGIC_CARPET_SHADOW, ASSET_3E7_MODEL_MAGIC_CARPET_SHADOW, - 0x1, D_80390DC0, - func_8038938C, actor_update_func_80326224, func_803892D0, +extern ActorInfo chMagicCarpetShadow = { + MARKER_AF_MAGIC_CARPET_SHADOW, ACTOR_122_MAGIC_CARPET_SHADOW, ASSET_3E7_MODEL_MAGIC_CARPET_SHADOW, + 0x1, chMagicCarpetShadowAnimations, + chMagicCarpetShadow_update, actor_update_func_80326224, chMagicCarpetShadow_draw, 2500, 0, 0.0f, 0 }; /* .code */ -Actor *func_803892D0(ActorMarker *this_marker, Gfx **gfx, Mtx **mtx, Vtx **vtx){ +Actor *chMagicCarpetShadow_draw(ActorMarker *this_marker, Gfx **gfx, Mtx **mtx, Vtx **vtx){ f32 rotation[3]; f32 position[3]; Actor *this; @@ -36,7 +37,7 @@ Actor *func_803892D0(ActorMarker *this_marker, Gfx **gfx, Mtx **mtx, Vtx **vtx){ return this; } -void func_8038938C(Actor *this){ +void chMagicCarpetShadow_update(Actor *this){ if(!this->initialized){ this->initialized = true; this->unk124_11 = 3; diff --git a/src/GV/matchinggame.c b/src/GV/matchinggame.c index fea1e578d..dc36b94f5 100644 --- a/src/GV/matchinggame.c +++ b/src/GV/matchinggame.c @@ -71,9 +71,9 @@ void __matchingGame_setState(s32 next_state){ if(next_state == 2){ item_set(ITEM_6_HOURGLASS, 1); if(volatileFlag_get(VOLATILE_FLAG_2_FF_IN_MINIGAME)) - item_set(ITEM_0_HOURGLASS_TIMER, 4499); + item_set(ITEM_0_HOURGLASS_TIMER, VER_SELECT(4499, 0xea5, 0, 0)); else - item_set(ITEM_0_HOURGLASS_TIMER, 5999); + item_set(ITEM_0_HOURGLASS_TIMER, VER_SELECT(5999, 0x1387, 0, 0)); } if(matchingGame.state == 2){ item_set(ITEM_6_HOURGLASS, 0); @@ -157,7 +157,7 @@ void gv_matchingGame_update(void){ } if(matchingGame.tile_a == NULL || matchingGame.tile_b == NULL){ - if( player_getActiveHitbox(0) == HITBOX_1_BEAK_BUSTER && func_8028F20C()){ + if( player_getActiveHitbox(0) == HITBOX_1_BEAK_BUSTER && player_isStableWithExtraSteps()){ player_getPosition(player_position); sp4C = model_func_8033F3E8(mapModel_getModel(0), player_position, 0x190, 0x1a0); if(sp4C){ diff --git a/src/GV/pyramid_raise.c b/src/GV/pyramid_raise.c index cc644b3c8..c92504b67 100644 --- a/src/GV/pyramid_raise.c +++ b/src/GV/pyramid_raise.c @@ -17,32 +17,49 @@ typedef struct { f32 unk24; }ActorLocal_GV_6370; -void func_8038C8A0(Actor *this, s32 next_state); -void func_8038CC98(Actor *this); -Actor *func_8038CC40(ActorMarker *this_marker, Gfx **gfx, Mtx **mtx, Vtx **vtx); +void chJinxyHeadSandybutt_setState(Actor *this, s32 next_state); +void chJinxyHeadSandybutt_update(Actor *this); +Actor *chJinxyHeadSandybutt_draw(ActorMarker *this_marker, Gfx **gfx, Mtx **mtx, Vtx **vtx); /* .data */ -u8 D_803911F0[3] = {0, 1, 2}; -ActorInfo D_803911F4 = { 0xBB, 0x285, 0x3E6, +u8 chJinxyHeadSandybuttIndices[3] = {0, 1, 2}; + +// Jinxy Head 2 +ActorInfo chJinxyHeadSandybutt1 = { + MARKER_BB_JINXY_HEAD_SANDYBUTT, ACTOR_285_JINXY_HEAD_SANDYBUTT_1, ASSET_3E6_JINXY_HEAD_KING_SANDYBUTT, 0, NULL, - func_8038CC98, actor_update_func_80326224, func_8038CC40, + chJinxyHeadSandybutt_update, actor_update_func_80326224, chJinxyHeadSandybutt_draw, 0, 0, 0.0f, 0 }; -ActorInfo D_80391218 = { 0xBB, 0x286, 0x3E6, +ActorInfo chJinxyHeadSandybutt2 = { + MARKER_BB_JINXY_HEAD_SANDYBUTT, ACTOR_286_JINXY_HEAD_SANDYBUTT_2, ASSET_3E6_JINXY_HEAD_KING_SANDYBUTT, 0, NULL, - func_8038CC98, actor_update_func_80326224, func_8038CC40, + chJinxyHeadSandybutt_update, actor_update_func_80326224, chJinxyHeadSandybutt_draw, 0, 0, 0.0f, 0 }; -ActorInfo D_8039123C = { 0xBB, 0x287, 0x3E6, +ActorInfo chJinxyHeadSandybutt3 = { + MARKER_BB_JINXY_HEAD_SANDYBUTT, ACTOR_287_JINXY_HEAD_SANDYBUTT_3, ASSET_3E6_JINXY_HEAD_KING_SANDYBUTT, 0, NULL, - func_8038CC98, actor_update_func_80326224, func_8038CC40, + chJinxyHeadSandybutt_update, actor_update_func_80326224, chJinxyHeadSandybutt_draw, 0, 0, 0.0f, 0 }; +enum chjinxyheadsandybutt_state_e { + CHJINXYHEADSANDYBUTT_STATE_0_NOT_INIT, + CHJINXYHEADSANDYBUTT_STATE_1_UNK, + CHJINXYHEADSANDYBUTT_STATE_2_UNK, + CHJINXYHEADSANDYBUTT_STATE_3_UNK, + CHJINXYHEADSANDYBUTT_STATE_4_UNK, + CHJINXYHEADSANDYBUTT_STATE_5_UNK, + CHJINXYHEADSANDYBUTT_STATE_6_FED, + CHJINXYHEADSANDYBUTT_STATE_7_GO_AWAY, + CHJINXYHEADSANDYBUTT_STATE_8_COMPLETED +}; + /* .code */ -void func_8038C760(Actor *this, s32 arg1){ +void chJinxyHeadSandybutt_raisePyramid(Actor *this, s32 arg1){ ActorLocal_GV_6370 *local = (ActorLocal_GV_6370 *)&this->local; chBuriedPyramid_setRaisedAmount(local->unk14, arg1); FUNC_8030E624(SFX_3F6_RUBBING, 0.7f, 28000); @@ -63,21 +80,26 @@ void func_8038C760(Actor *this, s32 arg1){ } } -void func_8038C880(Actor *this){ - func_8038C8A0(this, 0); +void chJinxyHeadSandybutt_free(Actor *this){ + chJinxyHeadSandybutt_setState(this, CHJINXYHEADSANDYBUTT_STATE_0_NOT_INIT); } -void func_8038C8A0(Actor *this, s32 next_state){ +void chJinxyHeadSandybutt_setState(Actor *this, s32 next_state){ ActorLocal_GV_6370 *local = (ActorLocal_GV_6370 *)&this->local; local->unk0 = 0; local->unk24 = 0.0f; - this->marker->propPtr->unk8_3 = (next_state == 1) ? false : true; - this->marker->collidable = (next_state == 1) ? false : true; - if(this->state == 4 || this->state == 5) + this->marker->propPtr->unk8_3 = (next_state == CHJINXYHEADSANDYBUTT_STATE_1_UNK) ? FALSE : TRUE; + this->marker->collidable = (next_state == CHJINXYHEADSANDYBUTT_STATE_1_UNK) ? FALSE : TRUE; + if(this->state == CHJINXYHEADSANDYBUTT_STATE_4_UNK + || this->state == CHJINXYHEADSANDYBUTT_STATE_5_UNK) + { sfxsource_freeSfxsourceByIndex(local->sfxsourceIdx); + } - if(next_state == 4 || next_state == 5){ + if(next_state == CHJINXYHEADSANDYBUTT_STATE_4_UNK + || next_state == CHJINXYHEADSANDYBUTT_STATE_5_UNK) + { local->sfxsourceIdx = sfxsource_createSfxsourceAndReturnIndex(); sfxsource_setSfxId(local->sfxsourceIdx, SFX_3EC_CCW_DOOR_OPENING); sfxSource_setunk43_7ByIndex(local->sfxsourceIdx, 3); @@ -86,7 +108,7 @@ void func_8038C8A0(Actor *this, s32 next_state){ sfxSource_func_8030E2C4(local->sfxsourceIdx); }//L8038C9B8 - if(next_state == 2){ + if(next_state == CHJINXYHEADSANDYBUTT_STATE_2_UNK){ skeletalAnim_set(this->unk148, ASSET_F0_ANIM_MINI_SHPYNX_EATING, 1.0f, 3.0f); skeletalAnim_setProgress(this->unk148, 0.27f); skeletalAnim_setBehavior(this->unk148, SKELETAL_ANIM_4_STOPPED); @@ -100,28 +122,31 @@ void func_8038C8A0(Actor *this, s32 next_state){ } }//L8038CA6C - if(next_state == 3){ + if(next_state == CHJINXYHEADSANDYBUTT_STATE_3_UNK){ local->unk24 = 3.0f; skeletalAnim_set(this->unk148, ASSET_F0_ANIM_MINI_SHPYNX_EATING, 1.0f, 3.0f); skeletalAnim_setProgress(this->unk148, 0.27f); skeletalAnim_setBehavior(this->unk148, SKELETAL_ANIM_4_STOPPED); }//L8038CAB4 - if(this->state == 3){ + if(this->state == CHJINXYHEADSANDYBUTT_STATE_3_UNK){ skeletalAnim_set(this->unk148, ASSET_F0_ANIM_MINI_SHPYNX_EATING, 0.5f, 3.0f); skeletalAnim_setProgress(this->unk148, 0.99f); skeletalAnim_setBehavior(this->unk148, SKELETAL_ANIM_2_ONCE); - if(next_state == 4 || next_state == 5) + if(next_state == CHJINXYHEADSANDYBUTT_STATE_4_UNK + || next_state == CHJINXYHEADSANDYBUTT_STATE_5_UNK) + { sfx_playFadeShorthandDefault(SFX_DE_WOOD_SQUEAK, 1.0f, 32675, this->position, 500, 1500); + } }//L8038CB20 - if(next_state == 6){ + if(next_state == CHJINXYHEADSANDYBUTT_STATE_6_FED){ func_80324E38(0.0f, 3); skeletalAnim_set(this->unk148, ASSET_F0_ANIM_MINI_SHPYNX_EATING, 0.0f, 3.0f); coMusicPlayer_playMusic(COMUSIC_2B_DING_B, 28000); } - if(next_state == 7){ + if(next_state == CHJINXYHEADSANDYBUTT_STATE_7_GO_AWAY){ local->unkC = 0.0f; local->unk18[0] = this->position_x; local->unk18[1] = this->position_y; @@ -130,26 +155,26 @@ void func_8038C8A0(Actor *this, s32 next_state){ FUNC_8030E624(SFX_3F6_RUBBING, 0.8f, 30000); } - if(next_state == 8){ - if(this->state == 7){ + if(next_state == CHJINXYHEADSANDYBUTT_STATE_8_COMPLETED){ + if(this->state == CHJINXYHEADSANDYBUTT_STATE_7_GO_AWAY){ baMotor_80250D94(0.8f, 0.7f, 3.0f); - func_8038C760(this, *local->unk8 + 1); + chJinxyHeadSandybutt_raisePyramid(this, *local->unk8 + 1); } marker_despawn(this->marker); } this->state = next_state; } -Actor *func_8038CC40(ActorMarker *this_marker, Gfx **gfx, Mtx **mtx, Vtx **vtx){ +Actor *chJinxyHeadSandybutt_draw(ActorMarker *this_marker, Gfx **gfx, Mtx **mtx, Vtx **vtx){ Actor *this = marker_getActor(this_marker); - if(this->state == 1) return this; + if(this->state == CHJINXYHEADSANDYBUTT_STATE_1_UNK) return this; return actor_draw(this_marker, gfx, mtx, vtx); } -void func_8038CC98(Actor *this){ +void chJinxyHeadSandybutt_update(Actor *this){ ActorLocal_GV_6370 *local = (ActorLocal_GV_6370 *)&this->local; - f32 sp80 = time_getDelta(); - s32 sp7C; + f32 time_delta = time_getDelta(); + s32 pyramid_file_progress; f32 pad70; f32 sp6C[3]; f32 f12; @@ -159,24 +184,24 @@ void func_8038CC98(Actor *this){ f32 sp48[3]; if(!this->volatile_initialized){ - sp7C = fileProgressFlag_getN(FILEPROG_F8_KING_SANDYBUTT_PYRAMID_STATE, 2); - this->volatile_initialized = true; - this->marker->actorFreeFunc = func_8038C880; - local->unk8 = &D_803911F0[this->modelCacheIndex - 0x285]; + pyramid_file_progress = fileProgressFlag_getN(FILEPROG_F8_KING_SANDYBUTT_PYRAMID_STATE, 2); + this->volatile_initialized = TRUE; + this->marker->actorFreeFunc = chJinxyHeadSandybutt_free; + local->unk8 = &chJinxyHeadSandybuttIndices[this->modelCacheIndex - 0x285]; local->unk10 = 0; local->unk14 = 0; local->unkC = 0.0f; local->unk18[0] = this->position_x; local->unk18[1] = this->position_y; local->unk18[2] = this->position_z; - if(*local->unk8 < sp7C){ - func_8038C8A0(this, 8); + if(*local->unk8 < pyramid_file_progress){ + chJinxyHeadSandybutt_setState(this, CHJINXYHEADSANDYBUTT_STATE_8_COMPLETED); } - else if(sp7C == *local->unk8){ - func_8038C8A0(this, 2); + else if(pyramid_file_progress == *local->unk8){ + chJinxyHeadSandybutt_setState(this, CHJINXYHEADSANDYBUTT_STATE_2_UNK); } else{ - func_8038C8A0(this, 1); + chJinxyHeadSandybutt_setState(this, CHJINXYHEADSANDYBUTT_STATE_1_UNK); } return; } @@ -185,22 +210,22 @@ void func_8038CC98(Actor *this){ local->unk14 = actorArray_findActorFromActorId(ACTOR_31D_SANDYBUTT_PYRAMID)->marker; } - if(this->state != 8 && fileProgressFlag_getN(FILEPROG_F8_KING_SANDYBUTT_PYRAMID_STATE, 2) > *local->unk8){ - func_8038C8A0(this, 8); + if(this->state != CHJINXYHEADSANDYBUTT_STATE_8_COMPLETED && fileProgressFlag_getN(FILEPROG_F8_KING_SANDYBUTT_PYRAMID_STATE, 2) > *local->unk8){ + chJinxyHeadSandybutt_setState(this, CHJINXYHEADSANDYBUTT_STATE_8_COMPLETED); return; } - if(this->state == 1){ + if(this->state == CHJINXYHEADSANDYBUTT_STATE_1_UNK){ if(fileProgressFlag_getN(FILEPROG_F8_KING_SANDYBUTT_PYRAMID_STATE, 2) == *local->unk8){ - func_8038C8A0(this, 2); + chJinxyHeadSandybutt_setState(this, CHJINXYHEADSANDYBUTT_STATE_2_UNK); } } - if(this->state == 2){ - local->unkC += 0.5*sp80; + if(this->state == CHJINXYHEADSANDYBUTT_STATE_2_UNK){ + local->unkC += 0.5 * time_delta; if(1.0f <= local->unkC){ local->unkC = 1.0f; - func_8038C8A0(this, 3); + chJinxyHeadSandybutt_setState(this, CHJINXYHEADSANDYBUTT_STATE_3_UNK); } sp6C[0] = 0.0f; sp6C[1] = 0.0f; @@ -211,26 +236,28 @@ void func_8038CC98(Actor *this){ this->position_z = local->unk18[2] + sp6C[2]; }//L8038CECC - if(this->state == 3){ + if(this->state == CHJINXYHEADSANDYBUTT_STATE_3_UNK){ if(0.0f < local->unk24){ - local->unk24 -= sp80; + local->unk24 -= time_delta; } else{ if(func_8038D388()) - func_8038C8A0(this, 5); + chJinxyHeadSandybutt_setState(this, CHJINXYHEADSANDYBUTT_STATE_5_UNK); } }//L8038CF1C - if(this->state == 4 || this->state == 5){ - local->unkC += ((this->state == 4)? -1 : 1) * sp80; + if(this->state == CHJINXYHEADSANDYBUTT_STATE_4_UNK + || this->state == CHJINXYHEADSANDYBUTT_STATE_5_UNK) + { + local->unkC += ((this->state == 4)? -1 : 1) * time_delta; if(1.0f < local->unkC){ local->unkC = 1.0f; - func_8038C8A0(this, 4); + chJinxyHeadSandybutt_setState(this, CHJINXYHEADSANDYBUTT_STATE_4_UNK); return; } else if(local->unkC < -1.0f){ local->unkC = -1.0f; - func_8038C8A0(this, 5); + chJinxyHeadSandybutt_setState(this, CHJINXYHEADSANDYBUTT_STATE_5_UNK); return; } sp5C[0] = local->unkC*300.0f; @@ -241,21 +268,21 @@ void func_8038CC98(Actor *this){ this->position_y = local->unk18[1] + sp5C[1]; this->position_z = local->unk18[2] + sp5C[2]; if(0.8 <= local->unkC){ - f12 = 1.0 - (local->unkC - 0.8)/0.2; + f12 = 1.0 - (local->unkC - 0.8) / 0.2; } else if(local->unkC <= -0.8){ - f12 = 1.0 - (-local->unkC - 0.8)/0.2; + f12 = 1.0 - (-local->unkC - 0.8) / 0.2; } else{ f12 = 1.0f; } - func_8030DB04(local->sfxsourceIdx, f12*24000.0f, this->position, 200.0f, 1500.0f); + func_8030DB04(local->sfxsourceIdx, f12 * 24000.0f, this->position, 200.0f, 1500.0f); if(!func_8038D388()){ - func_8038C8A0(this, 3); + chJinxyHeadSandybutt_setState(this, CHJINXYHEADSANDYBUTT_STATE_3_UNK); } }//L8038D110 - if(this->state == 6){ + if(this->state == CHJINXYHEADSANDYBUTT_STATE_6_FED){ skeletalAnim_getProgressRange(this->unk148, &sp58, &sp54); if(sp58 < 0.28 && 0.28 <= sp54){ FUNC_8030E624(SFX_4C_LIP_SMACK, 1.0f, 28000); @@ -268,18 +295,18 @@ void func_8038CC98(Actor *this){ } if(0.81 <= sp54){ FUNC_8030E624(SFX_97_BLUBBER_BURPS, 1.0f, 28000); - func_8038C8A0(this, 7); + chJinxyHeadSandybutt_setState(this, CHJINXYHEADSANDYBUTT_STATE_7_GO_AWAY); } }//L8038D228 - if(this->state == 7){ - local->unkC += 0.5*sp80; + if(this->state == CHJINXYHEADSANDYBUTT_STATE_7_GO_AWAY){ + local->unkC += 0.5 * time_delta; if(1.0f < local->unkC){ - func_8038C8A0(this, 8); + chJinxyHeadSandybutt_setState(this, CHJINXYHEADSANDYBUTT_STATE_8_COMPLETED); } sp48[0] = 0.0f; sp48[1] = 0.0f; - sp48[2] = local->unkC*-600.0f; + sp48[2] = local->unkC * -600.0f; ml_vec3f_yaw_rotate_copy(sp48, sp48, this->yaw); this->position_x = local->unk18[0] + sp48[0]; this->position_y = local->unk18[1] + sp48[1]; @@ -287,11 +314,13 @@ void func_8038CC98(Actor *this){ }//L8038D2F0 if(local->unk0){ - if(this->state == 4 || this->state == 5){ + if(this->state == CHJINXYHEADSANDYBUTT_STATE_4_UNK + || this->state == CHJINXYHEADSANDYBUTT_STATE_5_UNK) + { local->unk0 = 0; local->unk10++; if(local->unk10 == 3){ - func_8038C8A0(this, 6); + chJinxyHeadSandybutt_setState(this, CHJINXYHEADSANDYBUTT_STATE_6_FED); } else{ coMusicPlayer_playMusic(COMUSIC_2B_DING_B, 28000); diff --git a/src/GV/ch/rubee.c b/src/GV/rubee.c similarity index 56% rename from src/GV/ch/rubee.c rename to src/GV/rubee.c index 6bdacb80d..43befb426 100644 --- a/src/GV/ch/rubee.c +++ b/src/GV/rubee.c @@ -3,10 +3,10 @@ #include "functions.h" #include "variables.h" -void func_80389B1C(Actor *this); +void chRubee_update(Actor *this); /* .data */ -ActorAnimationInfo D_80390EA0[] = { +ActorAnimationInfo chRubeeAnimations[] = { {0x00, 0.0f}, {ASSET_DF_ANIM_RUBEE_PET_TOOTS, 4.5f}, {ASSET_E3_ANIM_RUBEE_IDLE, 2.0f}, @@ -15,29 +15,38 @@ ActorAnimationInfo D_80390EA0[] = { {ASSET_DF_ANIM_RUBEE_PET_TOOTS, 4.5f} }; -ActorInfo D_80390ED0 = { MARKER_A9_RUBEE, ACTOR_11B_RUBEE, ASSET_3DD_MODEL_RUBEE, - 0x2, D_80390EA0, - func_80389B1C, actor_update_func_80326224, actor_draw, +ActorInfo chRubee = { + MARKER_A9_RUBEE, ACTOR_11B_RUBEE, ASSET_3DD_MODEL_RUBEE, + 0x2, chRubeeAnimations, + chRubee_update, actor_update_func_80326224, actor_draw, 2500, 0, 1.6f, 0 }; +enum chrubee_state_e { + CH_RUBEE_STATE_0_NOT_INIT, + CH_RUBEE_STATE_1_IDLE, + CH_RUBEE_STATE_2_IDLE, + CH_RUBEE_STATE_3_PLAYING_SONG, + CH_RUBEE_STATE_4_UNK, + CH_RUBEE_STATE_5_UNK +}; /* .code */ void func_80389A20(ActorMarker *caller, enum asset_e text_id, s32 arg2){ Actor *this = marker_getActor(caller); func_8038E18C(); - subaddie_set_state_with_direction(this, 3, 0.0f, 1); + subaddie_set_state_with_direction(this, CH_RUBEE_STATE_3_PLAYING_SONG, 0.0f, 1); } void func_80389A60(Actor *this){ - gcdialog_showDialog(ASSET_A70_DIALOG_RUBEE_HELPED, 4, NULL, this->marker, func_80389A20, NULL); - this->has_met_before = true; - subaddie_set_state(this, 5); + gcdialog_showDialog(VER_SELECT(ASSET_A70_DIALOG_RUBEE_HELPED, 0x92C, 0, 0), 4, NULL, this->marker, func_80389A20, NULL); + this->has_met_before = TRUE; + subaddie_set_state(this, CH_RUBEE_STATE_5_UNK); } void func_80389ABC(Actor *this){ if(this->unk138_23){ - func_80389A20(this->marker, ASSET_A70_DIALOG_RUBEE_HELPED, -1); + func_80389A20(this->marker, VER_SELECT(ASSET_A70_DIALOG_RUBEE_HELPED, 0x92C, 0, 0), -1); } else{ this->unk138_23 = true; @@ -46,9 +55,9 @@ void func_80389ABC(Actor *this){ } } -void func_80389B1C(Actor *this){ +void chRubee_update(Actor *this){ if(!this->volatile_initialized){ - this->lifetime_value = (f32) func_8038E184(); + this->lifetime_value = (f32) rubeeEggPot_getEggGoal(); this->has_met_before = jiggyscore_isCollected(JIGGY_43_GV_HISTUP) || mapSpecificFlags_get(0); this->unk138_23 = jiggyscore_isCollected(JIGGY_43_GV_HISTUP) || mapSpecificFlags_get(2); this->volatile_initialized = true; @@ -62,21 +71,26 @@ void func_80389B1C(Actor *this){ anctrl_setTransitionDuration(this->anctrl, 0.15f); - if(this->state == 1 || this->state == 2){ - if(! this->has_met_before && subaddie_playerIsWithinSphereAndActive(this, 250) && !subaddie_playerIsWithinSphereAndActive(this, 0x50)){ - gcdialog_showDialog(ASSET_A6F_DIALOG_RUBEE_MEET, 0xe, this->position, NULL, NULL, NULL); - this->has_met_before = true; - mapSpecificFlags_set(0, true); + if(this->state == CH_RUBEE_STATE_1_IDLE + || this->state == CH_RUBEE_STATE_2_IDLE) + { + if(! this->has_met_before + && subaddie_playerIsWithinSphereAndActive(this, 250) + && !subaddie_playerIsWithinSphereAndActive(this, 0x50)) + { + gcdialog_showDialog(VER_SELECT(ASSET_A6F_DIALOG_RUBEE_MEET, 0x92B, 0, 0), 0xE, this->position, NULL, NULL, NULL); + this->has_met_before = TRUE; + mapSpecificFlags_set(0, TRUE); } } switch(this->state){ - case 1://L80389CC4 + case CH_RUBEE_STATE_1_IDLE://L80389CC4 if(this->lifetime_value <= (f32)func_8038E178()){ func_80389ABC(this); } else if(actor_animationIsAt(this, 0.99f)){ - subaddie_maybe_set_state(this, 2, 0.9f); + subaddie_maybe_set_state(this, CH_RUBEE_STATE_2_IDLE, 0.9f); } if( actor_animationIsAt(this, 0.42f) @@ -92,27 +106,27 @@ void func_80389B1C(Actor *this){ } break; - case 2: //L80389DB0 + case CH_RUBEE_STATE_2_IDLE: //L80389DB0 if(this->lifetime_value <= (f32)func_8038E178()){ func_80389ABC(this); } else if(actor_animationIsAt(this, 0.99f)){ - subaddie_maybe_set_state(this, 1, 0.4f); + subaddie_maybe_set_state(this, CH_RUBEE_STATE_1_IDLE, 0.4f); } break; - case 3: //L80389E14 + case CH_RUBEE_STATE_3_PLAYING_SONG: //L80389E14 if( actor_animationIsAt(this, 0.2f)){ func_8025A58C(500, 400); coMusicPlayer_playMusic(COMUSIC_27_GV_RUBEES_SONG, 28000); } if( actor_animationIsAt(this, 0.99f)){ - subaddie_set_state(this, 4); + subaddie_set_state(this, CH_RUBEE_STATE_4_UNK); } break; - case 4: //L80389E64 + case CH_RUBEE_STATE_4_UNK: //L80389E64 if(!func_8038E178()) - subaddie_set_state(this, 2); + subaddie_set_state(this, CH_RUBEE_STATE_2_IDLE); break; }//L80389E80 } diff --git a/src/GV/pyramid_trigger.c b/src/GV/sandybutteggtoll.c similarity index 69% rename from src/GV/pyramid_trigger.c rename to src/GV/sandybutteggtoll.c index 568c38890..cf82896bc 100644 --- a/src/GV/pyramid_trigger.c +++ b/src/GV/sandybutteggtoll.c @@ -1,14 +1,15 @@ -// BanjoDecomp: code_6F80.c +// BanjoDecomp: GV/sandybutteggtoll.c #include #include "functions.h" #include "variables.h" -void func_8038D3AC(Actor *this); +void chSandybuttEggToll_update(Actor *this); /* .data */ -ActorInfo D_80391260 = { 0x1A5, 0x288, 0x402, +ActorInfo chSandybuttEggToll = { + MARKER_1A5_SANDYBUTT_EGG_TOLL, 0x288, ASSET_402_MODEL_EGG_TOLL, 0, NULL, - func_8038D3AC, NULL, func_80325340, + chSandybuttEggToll_update, NULL, func_80325340, 0, 0, 0.0f, 0 }; @@ -20,11 +21,11 @@ void func_8038D370(ActorMarker *this_marker, ActorMarker *other_marker){ D_80391AA0 = 5; } -int func_8038D388(void){ +bool func_8038D388(void){ return D_80391AA0 ? 1 : 0; } -void func_8038D3AC(Actor *this){ +void chSandybuttEggToll_update(Actor *this){ if(!this->volatile_initialized){ this->volatile_initialized = true; marker_setCollisionScripts(this->marker, func_8038D370, NULL, NULL); diff --git a/src/GV/smoke_particle.c b/src/GV/smoke_particle.c index 41f471ae7..371669359 100644 --- a/src/GV/smoke_particle.c +++ b/src/GV/smoke_particle.c @@ -7,7 +7,9 @@ void GV_func_8038A084(Actor *this); /* .data */ -ActorInfo D_80390F40 = { 0x24F, 0x37C, 0x0, +// Hot Sand Smoke Emitter? +ActorInfo D_80390F40 = { + 0x24F, 0x37C, 0x0, 0, NULL, GV_func_8038A084, actor_update_func_80326224, func_80325340, 2000, 0, 0.0f, 0 diff --git a/src/LAIR/bss_pad.c b/src/LAIR/bss_pad.c deleted file mode 100644 index f0c8cfff4..000000000 --- a/src/LAIR/bss_pad.c +++ /dev/null @@ -1,2 +0,0 @@ -// BanjoDecomp: bss_pad.c -static char pad_lair_80395350[0x10]; //padding diff --git a/src/MM/ch/conga.c b/src/MM/ch/conga.c index fc6098492..0fa98a1b5 100644 --- a/src/MM/ch/conga.c +++ b/src/MM/ch/conga.c @@ -1,10 +1,13 @@ -// BanjoDecomp: conga.c -#include "functions.h" +// BanjoDecomp: MM/ch/conga.c +#include #include "rand.h" +#include "functions.h" #include "variables.h" -#include -#include #include + +#include "bk_math.h" // [port] SQ macro +#include "conga.h" + #ifndef MIN #define MIN(s,t) ((s)<(t)?(s):(t)) #endif @@ -18,18 +21,19 @@ void subaddie_turnToYaw(Actor *, f32); void subaddie_set_state_with_direction(Actor*, s32, f32, s32); void bundle_setYaw(f32); void timed_exitStaticCamera(f32); +Actor *actor_spawnWithYaw_s32(s32 actor_id, s32 position[3], s32 yaw); void MM_checkMMChecksums(void); void chConga_update(Actor *); -typedef struct chconga_s{ +typedef struct chconga_s { TUPLE(s32, orangeSpawnPosition); s32 unkC; s32 unk10; u8 pad14[0x4]; s32 unk18; s32 unk1C; -}ActorLocal_Conga; +} ActorLocal_Conga; /* .data */ @@ -58,26 +62,26 @@ bool __chConga_isPlayerNearCongaTree(Actor * this){ f32 unused_tmpz; if (gsworld_getMap() != MAP_2_MM_MUMBOS_MOUNTAIN) { - return false; + return FALSE; } if (!this->unk10_12) { - return false; + return FALSE; } player_getPosition(plyr_pos); if (plyr_pos[1] < 300.0f || 600.0f < plyr_pos[1]) { - return false; + return FALSE; } unused_tmpz = plyr_pos[2] - 5029.0f; if (52900.0f < (plyr_pos[0] - -5011.0f) * (plyr_pos[0] - -5011.0f) + (plyr_pos[2] - 5029.0f) * (plyr_pos[2] - 5029.0f)) { - return false; + return FALSE; } - return true; + return TRUE; } void func_80386FB0(Actor *this){ @@ -127,7 +131,7 @@ void func_80387168(ActorMarker *marker, ActorMarker *other_marker){ actorPtr->unk38_31++; actorPtr->unk10_12 = MIN(actorPtr->unk38_31, 0xA); - if( actorPtr->unk38_31 == 3 + if( actorPtr->unk38_31 == 3 && !jiggyscore_isCollected(JIGGY_A_MM_CONGA) ){ subaddie_set_state_with_direction(actorPtr, 8, 0 ,1); @@ -141,7 +145,7 @@ void func_80387168(ActorMarker *marker, ActorMarker *other_marker){ ){ func_8038708C(actorPtr, 2); if(actorPtr->unk38_31 == 1){ - gcdialog_showDialog(ASSET_B39_DIALOG_CONGA_HIT_BY_EGG, 4, actorPtr->position, 0, 0, 0); + gcdialog_showDialog(VER_SELECT(ASSET_B39_DIALOG_CONGA_HIT_BY_EGG, 0x957, 0, 0), 4, actorPtr->position, 0, 0, 0); } } } @@ -151,10 +155,10 @@ void func_80387168(ActorMarker *marker, ActorMarker *other_marker){ int func_803872EC(void){ s32 text_id = gcdialog_getCurrentTextId(); - return text_id == ASSET_B37_DIALOG_CONGA_SAFE_UP_HERE - || text_id == ASSET_B38_DIALOG_CONGA_DEFEAT + return text_id == VER_SELECT(ASSET_B37_DIALOG_CONGA_SAFE_UP_HERE, 0x955, 0, 0) + || text_id == VER_SELECT(ASSET_B38_DIALOG_CONGA_DEFEAT, 0x956, 0, 0) || volatileFlag_get(VOLATILE_FLAG_1F_IN_CHARACTER_PARADE) - || text_id == ASSET_B3B_DIALOG_CONGA_ORANGE_PAD_JIGGY + || text_id == VER_SELECT(ASSET_B3B_DIALOG_CONGA_ORANGE_PAD_JIGGY, 0x959, 0, 0) || text_id == ASSET_B45_DIALOG_JIGGY_COLLECT_10 || text_id == ASSET_B51_DIALOG_BOTTLES_HOW_TO_EXIT_LEVEL; } @@ -183,7 +187,7 @@ void __chConga_sendOrangeProjectile(ActorMarker *congaMarker){ congaPtr->unk10_12 -= (congaPtr->unk10_12 && ( conga_state == 7)); MM_checkMMChecksums(); congaPtr->actor_specific_1_f = 2.0f; - orangePtr = actor_spawnWithYaw_s32(ACTOR_14_ORANGE_PROJECTILE, &conga_localPtr->orangeSpawnPosition, congaPtr->yaw); + orangePtr = actor_spawnWithYaw_s32(ACTOR_14_ORANGE_PROJECTILE, conga_localPtr->orangeSpawnPosition, congaPtr->yaw); if(orangePtr != NULL){ player_getPosition(plyr.pos); @@ -210,169 +214,192 @@ void __chConga_sendOrangeProjectile(ActorMarker *congaMarker){ } } -void chConga_update(Actor *this){ +void chConga_update(Actor *this) { + f32 unused; NodeProp *node_prop; s32 sp3C; - this->marker->propPtr->unk8_3 = (timedFuncQueue_is_empty())?1:0; - if(!this->initialized){ + this->marker->propPtr->unk8_3 = timedFuncQueue_is_empty() ? 1 : 0; // [port] def takes no args + + if (!this->initialized) { ((ActorLocal_Conga *)&this->local)->unkC = 1; this->unk16C_0 = 1; - this->initialized = true; + this->initialized = TRUE; this->velocity_x = 0.0f; this->actor_specific_1_f = 0.0f; node_prop = nodeprop_findByActorIdAndActorPosition(0x150, this); ((ActorLocal_Conga *)&this->local)->unk1C = nodeprop_getRadius(node_prop); nodeprop_getPosition_s32(node_prop, &((ActorLocal_Conga *)&this->local)->unk10); } - if(0.0f == this->actor_specific_1_f){ + + if (0.0f == this->actor_specific_1_f) { this->actor_specific_1_f = (actorArray_findActorFromMarkerId(MARKER_36_ORANGE_COLLECTIBLE) != NULL)? 2.0f: 1.0f; } - if(0.0f != this->velocity_x){ + + if (0.0f != this->velocity_x) { this->velocity_x -= 1.0f; if(0.0f == this->velocity_x){ - __spawnQueue_add_1((GenFunction_1)func_80387100, (uintptr_t)this->marker); + __spawnQueue_add_1((GenFunction_1)func_80387100, reinterpret_cast(uintptr_t, this->marker)); } } + marker_setCollisionScripts(this->marker, NULL, NULL, func_80387168); - if( !subaddie_playerIsWithinSphereAndActive(this, 2100) + + if (!subaddie_playerIsWithinSphereAndActive(this, 2100) && this->state != 2 - && this->state != 8 - ){ + && this->state != 8) { + if(this->state > 3 && this->state < 8){ actor_loopAnimation(this); subaddie_set_state_with_direction(this, 1, 0.76f, 1); } + return; } sp3C = subaddie_playerIsWithinSphereAndActive(this, 1000); - if( func_8032A9E4(((ActorLocal_Conga *)&this->local)->unk10, ((ActorLocal_Conga *)&this->local)->unk18, ((ActorLocal_Conga *)&this->local)->unk1C) + + if (func_8032A9E4(((ActorLocal_Conga *)&this->local)->unk10, ((ActorLocal_Conga *)&this->local)->unk18, ((ActorLocal_Conga *)&this->local)->unk1C) && !this->unk138_23 - && gcdialog_showDialog(ASSET_B37_DIALOG_CONGA_SAFE_UP_HERE, 0, 0, 0, 0, 0) - ){ + && gcdialog_showDialog(VER_SELECT(ASSET_B37_DIALOG_CONGA_SAFE_UP_HERE, 0x955, 0, 0), 0, 0, 0, 0, 0)) { this->unk138_23 = 1; - mapSpecificFlags_set(MM_SPECIFIC_FLAG_A_UNKNOWN, true); + mapSpecificFlags_set(MM_SPECIFIC_FLAG_A_UNKNOWN, TRUE); }//L803878F8 - if( sp3C && !this->has_met_before){ - if(gcdialog_showDialog((player_getTransformation()== TRANSFORM_2_TERMITE) ? ASSET_B3E_DIALOG_CONGA_MEET_AS_TERMITE : ASSET_B3C_DIALOG_CONGA_MEET, 0, this->position, 0,0,0)){ - this->has_met_before = true; + if (sp3C && !this->has_met_before) { + if (gcdialog_showDialog((player_getTransformation()== TRANSFORM_2_TERMITE) ? ASSET_B3E_DIALOG_CONGA_MEET_AS_TERMITE : VER_SELECT(ASSET_B3C_DIALOG_CONGA_MEET, 0x95A, 0, 0), 0, this->position, 0,0,0)) { + this->has_met_before = TRUE; } } //L80387968 - switch(this->state){ - case 1://80387990 + switch (this->state) { + case CONGA_STATE_IDLE://80387990 actor_loopAnimation(this); func_80386FB0(this); __chConga_playRandomNoise(); + if(actor_animationIsAt(this, 0.0f) || actor_animationIsAt(this, 0.45f)){ if(randf() < 0.2){ anctrl_setDirection(this->anctrl, anctrl_isPlayedForwards(this->anctrl)?0:1); }; }//L80387A18 - if(actor_animationIsAt(this, 0.66f)){ - subaddie_maybe_set_state_position_direction(this, 6, 0, 1, 0.38f); + + if (actor_animationIsAt(this, 0.66f)) { + subaddie_maybe_set_state_position_direction(this, CONGA_STATE_BEAT_CHEST_STOP, 0, 1, 0.38f); } - if( sp3C + + if (sp3C && player_movementGroup() != BSGROUP_1_INTR && !__chConga_isPlayerNearCongaTree(this) && timedFuncQueue_is_empty() && !func_8032A9E4(((ActorLocal_Conga *)&this->local)->unk10, ((ActorLocal_Conga *)&this->local)->unk18, ((ActorLocal_Conga *)&this->local)->unk1C) - && !func_803872EC() - ){ - subaddie_set_state_with_direction(this, 4, 0.0f, 1); + && !func_803872EC()) { + + subaddie_set_state_with_direction(this, CONGA_STATE_TARGET_GROUND, 0.0f, 1); }//L80387AC0 - if( player_movementGroup() != BSGROUP_1_INTR + + if (player_movementGroup() != BSGROUP_1_INTR && __chConga_isPlayerNearCongaTree(this) && this->unk38_31 != 0 - && !func_803872EC() - ){ - subaddie_set_state_with_direction(this, 7, 0.0f, 1); + && !func_803872EC()) { + + subaddie_set_state_with_direction(this, CONGA_STATE_TARGET_BANJO, 0.0f, 1); } break; - case 6: //L80387B24 + case CONGA_STATE_BEAT_CHEST_STOP: //L80387B24 ((ActorLocal_Conga *)&this->local)->unkC = 1; actor_playAnimationOnce(this); __chConga_playRandomNoise(); - if( anctrl_isPlayedForwards(this->anctrl) == true - && actor_animationIsAt(this, 0.0f) - ){ - subaddie_set_state_with_direction(this, 5, 0.0f, 1); - } - else if( !anctrl_isPlayedForwards(this->anctrl) - && actor_animationIsAt(this, 0.001f) - ){ - subaddie_set_state_with_direction(this, 1, 0.76f, 1); + + if (anctrl_isPlayedForwards(this->anctrl) == TRUE + && actor_animationIsAt(this, 0.0f)) { + + subaddie_set_state_with_direction(this, CONGA_STATE_BEAT_CHEST, 0.0f, 1); + } else if (!anctrl_isPlayedForwards(this->anctrl) + && actor_animationIsAt(this, 0.001f)) { + subaddie_set_state_with_direction(this, CONGA_STATE_IDLE, 0.76f, 1); } + break; - case 5: //L80387BC0 + case CONGA_STATE_BEAT_CHEST: //L80387BC0 ((ActorLocal_Conga *)&this->local)->unkC = 1; actor_loopAnimation(this); __chConga_playRandomNoise(); - if( actor_animationIsAt(this, 0.99f)){ - subaddie_maybe_set_state_position_direction(this, 6, 0.999f, 0, sp3C ? 1.0 : 0.4); + + if (actor_animationIsAt(this, 0.99f)) { + subaddie_maybe_set_state_position_direction(this, CONGA_STATE_BEAT_CHEST_STOP, 0.999f, 0, sp3C ? 1.0 : 0.4); }//L80387C30 - if( actor_animationIsAt(this, 0.9f) - || actor_animationIsAt(this, 0.4f) - ){ + + if (actor_animationIsAt(this, 0.9f) + || actor_animationIsAt(this, 0.4f)) { func_8030E6D4(SFX_3FB_UNKNOWN); } + break; - case 4: //L80387C74 - if(actor_animationIsAt(this, 0.6f)){ + case CONGA_STATE_TARGET_GROUND: //L80387C74 + if (actor_animationIsAt(this, 0.6f)) { func_8030E58C(SFX_2_CLAW_SWIPE, 0.7f); } + func_80386FB0(this); - if( !sp3C + + if (!sp3C || player_is_in_jiggy_jig() || __chConga_isPlayerNearCongaTree(this) || !timedFuncQueue_is_empty() - || func_803872EC() - ){ - subaddie_set_state_with_direction(this, 1, 0.0f, 1); + || func_803872EC()) { + + subaddie_set_state_with_direction(this, CONGA_STATE_IDLE, 0.0f, 1); } + break; - case 2: //L80387D0C + case CONGA_STATE_HIT: //L80387D0C actor_playAnimationOnce(this); - if(actor_animationIsAt(this, 0.99f)){ - subaddie_set_state_with_direction(this, 1, 0.0f, 1); + if (actor_animationIsAt(this, 0.99f)) { + subaddie_set_state_with_direction(this, CONGA_STATE_IDLE, 0.0f, 1); } + break; - case 8: //L80387D4C + case CONGA_STATE_ROAR: //L80387D4C actor_playAnimationOnce(this); - if(actor_animationIsAt(this, 0.99f)){ - subaddie_set_state_with_direction(this, 3, 0.0f, 1); - gcdialog_showDialog(ASSET_B38_DIALOG_CONGA_DEFEAT, 0xe, this->position, this->marker, func_80387370, NULL); + + if (actor_animationIsAt(this, 0.99f)) { + subaddie_set_state_with_direction(this, CONGA_STATE_MOPEY, 0.0f, 1); + gcdialog_showDialog(VER_SELECT(ASSET_B38_DIALOG_CONGA_DEFEAT, 0x956, 0, 0), 0xe, this->position, this->marker, func_80387370, NULL); } + break; - case 3: //L80387DB8 + case CONGA_STATE_MOPEY: //L80387DB8 actor_loopAnimation(this); - if(jiggyscore_isCollected(JIGGY_A_MM_CONGA)){ - subaddie_set_state_with_direction(this, 1, 0.0f, 1); + + if (jiggyscore_isCollected(JIGGY_A_MM_CONGA)) { + subaddie_set_state_with_direction(this, CONGA_STATE_IDLE, 0.0f, 1); } + break; - case 7: //L80387DF0 - if(this->unk10_12 == 0){ - if(actor_animationIsAt(this, 0.97f)){ + case CONGA_STATE_TARGET_BANJO: //L80387DF0 + if (this->unk10_12 == 0) { + if (actor_animationIsAt(this, 0.97f)) { ((ActorLocal_Conga *)&this->local)->unkC = 1; - subaddie_set_state_with_direction(this, 6, 0.0f, 1); + subaddie_set_state_with_direction(this, CONGA_STATE_BEAT_CHEST_STOP, 0.0f, 1); } } + break; }//L80387E38 - if( (this->state == 4 && actor_animationIsAt(this, 0.56f)) - || (this->state == 7 && actor_animationIsAt(this, 0.468f)) - ){ - vec3fArray_get_vec3i(this->marker->unk44, 5, (s32 *)this->local); - __spawnQueue_add_1((GenFunction_1)__chConga_sendOrangeProjectile, (uintptr_t)this->marker); //spawn orange + + if ((this->state == CONGA_STATE_TARGET_GROUND && actor_animationIsAt(this, 0.56f)) + || (this->state == CONGA_STATE_TARGET_BANJO && actor_animationIsAt(this, 0.468f))) { + + vec3fArray_get_vec3i(this->marker->unk44, 5, (s32 *)&this->local); // [port] writes 3 s32 into actor local + __spawnQueue_add_1((GenFunction_1)__chConga_sendOrangeProjectile, reinterpret_cast(uintptr_t, this->marker)); //spawn orange } } diff --git a/src/MM/ch/conga.h b/src/MM/ch/conga.h new file mode 100644 index 000000000..ede0eeddb --- /dev/null +++ b/src/MM/ch/conga.h @@ -0,0 +1,11 @@ +// BanjoDecomp: MM/ch/conga.h +enum conga_state_s { + CONGA_STATE_IDLE = 1, + CONGA_STATE_HIT = 2, + CONGA_STATE_MOPEY = 3, // After defeat, waiting for Banjo to collect the jiggy + CONGA_STATE_TARGET_GROUND = 4, + CONGA_STATE_BEAT_CHEST = 5, + CONGA_STATE_BEAT_CHEST_STOP = 6, // Though depending on the animation, he'll go back to beating his chest + CONGA_STATE_TARGET_BANJO = 7, // Targeting Banjo when he's at eye level + CONGA_STATE_ROAR = 8 // When Conga is defeated +}; diff --git a/src/MM/ch/hut.c b/src/MM/ch/hut.c index f35116f5d..36c96b86e 100644 --- a/src/MM/ch/hut.c +++ b/src/MM/ch/hut.c @@ -42,7 +42,7 @@ Actor *chhut_draw(ActorMarker *this, Gfx **gfx, Mtx **mtx, Vtx **vtx) { s32 is_intact_or_destroyed = actorPtr->state == HUT_STATE_0_INTACT || actorPtr->state == HUT_STATE_2_DESTROYED; this->propPtr->unk8_3 = is_intact_or_destroyed; - func_8033A45C(1, is_not_destroyed); + modelRender_setAppendageVisibility(1, is_not_destroyed); return actor_draw(this, gfx, mtx, vtx); } @@ -117,7 +117,7 @@ void chhut_update(Actor *this) { if (150.0f < diff_pos[1] && player_getActiveHitbox(this->marker) == HITBOX_1_BEAK_BUSTER - && func_8028F20C() + && player_isStableWithExtraSteps() && LENGTH_VEC3F(diff_pos) < 350.0f ){ diff_pos[0] = this->position_x; diff --git a/src/MM/ch/juju.c b/src/MM/ch/juju.c index 992c8553f..0dda2dd3c 100644 --- a/src/MM/ch/juju.c +++ b/src/MM/ch/juju.c @@ -20,7 +20,6 @@ void chjuju_update(Actor *this); Actor *chjuju_draw(ActorMarker *, Gfx **, Mtx **, Vtx **); /* .bss */ -u8 MM_pad_80389C80[0x10]; s32 mm_juju_count; /* .data */ @@ -210,7 +209,7 @@ void chjuju_update(Actor *this) { switch (jujuPtr->animation_state) { case JUJU_ANIMATION_STATE_1_YAWING: //L80389624 previous_yaw = this->yaw; - this->yaw += ((11 - mm_juju_count * 2) * time_getDelta() * 60.0f) / 2; + this->yaw += ((11 - mm_juju_count * 2) * time_getDelta() * (float)FRAMERATE) / 2; if (360.0f < this->yaw) { has_completed_full_turn = true; diff --git a/src/MM/ch/lmonkey.c b/src/MM/ch/lmonkey.c index 329617b05..eb3b9cb53 100644 --- a/src/MM/ch/lmonkey.c +++ b/src/MM/ch/lmonkey.c @@ -44,7 +44,7 @@ void __chlmonkey_updateBringOrange(Actor **this_ptr) { player_setCarryObjectPoseInHorizontalRadius((*this_ptr)->position, 800.0f, ACTOR_29_ORANGE_COLLECTIBLE, this_ptr); if (subaddie_playerIsWithinSphereAndActive(*this_ptr, 345) && - bacarry_get_markerId() == MARKER_36_ORANGE_COLLECTIBLE && + bacarry_getMarkerId() == MARKER_36_ORANGE_COLLECTIBLE && player_throwCarriedObject()) { func_8028FA34(0xc6, *this_ptr); diff --git a/src/MM/ch/orange.c b/src/MM/ch/orange.c index b5ff73df1..3260f8b81 100644 --- a/src/MM/ch/orange.c +++ b/src/MM/ch/orange.c @@ -31,7 +31,7 @@ f32 D_80389A00[3] = {0.0f, 0.0f, 0.0f}; void __chorange_collisionCallback(ActorMarker *marker, ActorMarker *other_marker) { if (!player_isDead() && !mapSpecificFlags_get(MM_SPECIFIC_FLAG_8_HIT_WITH_ORANGE) && - gcdialog_showDialog(ASSET_B3A_DIALOG_CONGA_HITS_PLAYER, 0, 0, 0, NULL, NULL)) { + gcdialog_showDialog(VER_SELECT(ASSET_B3A_DIALOG_CONGA_HITS_PLAYER, 0x958, 0, 0), 0, 0, 0, NULL, NULL)) { mapSpecificFlags_set(MM_SPECIFIC_FLAG_8_HIT_WITH_ORANGE, true); } diff --git a/src/MM/ch/orangepad.c b/src/MM/ch/orangepad.c index f5980ca62..e87b5a5b6 100644 --- a/src/MM/ch/orangepad.c +++ b/src/MM/ch/orangepad.c @@ -1,31 +1,29 @@ -// BanjoDecomp: orangepad.c +// BanjoDecomp: MM/ch/orangepad.c +#include #include "functions.h" #include "variables.h" -#include +#include "bk_math.h" // [port] TUPLE_ASSIGN -#include +#include "core2/staticcamera.h" -/* extern functions */ -void actor_update_func_80326224(Actor *); -extern void particleEmitter_func_802EFA20(ParticleEmitter *, f32, f32); +#include "conga.h" +#include "orangepad.h" extern void port_breakable_recordBreak(s32 markerId, s32 x, s32 y, s32 z); extern s32 port_breakable_isBroken(s32 map, s32 markerId, s32 x, s32 y, s32 z); -/* public functions */ -void chorangepad_update(Actor *); +void chOrangePad_update(Actor *); -/* .data */ ActorInfo chOrangePadInfo = { MARKER_66_ORANGE_PAD, ACTOR_57_ORANGE_PAD, ASSET_2EB_MODEL_ORANGE_PAD, 0, NULL, - chorangepad_update, actor_update_func_80326224, actor_draw, + chOrangePad_update, actor_update_func_80326224, actor_draw, 0, 0, 0.0f, 0 }; -/*.code */ -void __chorangepad_spawnJiggy(s32 x, s32 y, s32 z) { +void spawnJiggy(s32 x, s32 y, s32 z) { f32 pos[3]; + TUPLE_ASSIGN(pos, x, y, z); jiggy_spawn(JIGGY_8_MM_ORANGE_PADS, pos); } @@ -35,108 +33,115 @@ void handleOrangeCollision(ActorMarker *marker) { Actor *closest_orange_pad; f32 position[3]; ParticleEmitter *p_ctrl; - s32 temp_a0; + s32 camera_id; - position[0] = marker->propPtr->x; + position[0] = marker->propPtr->x; // [port] ActorProp uses x/y/z members position[1] = marker->propPtr->y; position[2] = marker->propPtr->z; - closest_orange_pad = actorArray_findClosestActorFromActorId(position, ACTOR_57_ORANGE_PAD, 1, &distance_to_orange_pad); + closest_orange_pad = actorArray_findClosestActorFromActorId(position, ACTOR_57_ORANGE_PAD, ORANGE_PAD_STATE_HIT, &distance_to_orange_pad); + + if (!closest_orange_pad || 500.0f < distance_to_orange_pad) { + return; + } + + closest_orange_pad->state = ORANGE_PAD_STATE_HIT; + port_breakable_recordBreak((s32)closest_orange_pad->marker->id, (s32)closest_orange_pad->position[0], (s32)closest_orange_pad->position[1], (s32)closest_orange_pad->position[2]); + + if (actorArray_findClosestActorFromActorId(position, ACTOR_57_ORANGE_PAD, ORANGE_PAD_STATE_HIT, &distance_to_orange_pad)) { + // There are still other pads on the ground, play progress ding + coMusicPlayer_playMusic(COMUSIC_2B_DING_B, 22000); + } else { // No more pads, dispense jiggy + camera_id = (closest_orange_pad->secondaryId == ORANGE_PAD_RIGHT) ? MM_ORANGE_PAD_JIGGY_SPAWN_RIGHT + : (closest_orange_pad->secondaryId == ORANGE_PAD_LEFT) ? MM_ORANGE_PAD_JIGGY_SPAWN_LEFT + : MM_ORANGE_PAD_JIGGY_SPAWN_TOP; + + gcStaticCamera_activate(camera_id); + + position[1] += 50.0f; + timedFunc_set_3(0.6f, (GenFunction_3) spawnJiggy, (s32) position[0], (s32) position[1], (s32) position[2]); - if (closest_orange_pad && !(500.0f < distance_to_orange_pad)) { - closest_orange_pad->state = 1; - port_breakable_recordBreak((s32)closest_orange_pad->marker->id, (s32)closest_orange_pad->position[0], (s32)closest_orange_pad->position[1], (s32)closest_orange_pad->position[2]); + coMusicPlayer_playMusic(COMUSIC_2D_PUZZLE_SOLVED_FANFARE, 0x7FFF); - if (actorArray_findClosestActorFromActorId(position, ACTOR_57_ORANGE_PAD, 1, &distance_to_orange_pad)) { - coMusicPlayer_playMusic(COMUSIC_2B_DING_B, 22000); + if (!jiggyscore_isCollected(JIGGY_8_MM_ORANGE_PADS)) { + gcdialog_showDialog(VER_SELECT(ASSET_B3B_DIALOG_CONGA_ORANGE_PAD_JIGGY, 0x959, 0, 0), 4, NULL, NULL, NULL, NULL); } - else { - temp_a0 = (closest_orange_pad->secondaryId == 0x106) ? 0x10 - : (closest_orange_pad->secondaryId == 0x76) ? 0xf - : 0xe; - - gcStaticCamera_activate(temp_a0); - position[1] += 50.0f; - timedFunc_set_3(0.6f, (GenFunction_3) __chorangepad_spawnJiggy, (s32) position[0], (s32) position[1], (s32) position[2]); - coMusicPlayer_playMusic(COMUSIC_2D_PUZZLE_SOLVED_FANFARE, 0x7FFF); - - if (!jiggyscore_isCollected(JIGGY_8_MM_ORANGE_PADS)) { - gcdialog_showDialog(ASSET_B3B_DIALOG_CONGA_ORANGE_PAD_JIGGY, 4, NULL, NULL, NULL, NULL); - } - }// L803865D8 - - // Emmit sparkles - p_ctrl = partEmitMgr_newEmitter(30); - particleEmitter_setPosition(p_ctrl, closest_orange_pad->position); - particleEmitter_setModel(p_ctrl, ASSET_89F_MODEL_ORANGE_PARTICLE); - particleEmitter_setStartingScaleRange(p_ctrl, 0.09f, 0.19f); - particleEmitter_setFinalScaleRange(p_ctrl, 0.0f, 0.0f); - particleEmitter_setParticleVelocityRange(p_ctrl, -200.0f, 500.0f, -200.0f, 200.0f, 700.0f, 200.0f); - particleEmitter_setAccelerationRange(p_ctrl, 0.0f, -1200.0f, 0.0f, 0.0f, -1200.0f, 0.0f); - particleEmitter_setAngularVelocityRange(p_ctrl, -600.0f, -600.0f, -600.0f, 600.0f, 600.0f, 600.0f); - particleEmitter_setSpawnIntervalRange(p_ctrl, 0.0f, 0.01f); - particleEmitter_setParticleLifeTimeRange(p_ctrl, 4.0f, 4.0f); - particleEmitter_func_802EF9F8(p_ctrl, 0.01f); - particleEmitter_func_802EFA18(p_ctrl, 3); - particleEmitter_func_802EFA20(p_ctrl, 1.0f, 1.3f); - particleEmitter_emitN(p_ctrl, 30); } + + // Spawn orange particles + p_ctrl = partEmitMgr_newEmitter(ORANGE_PARTICLE_COUNT); + + particleEmitter_setPosition(p_ctrl, closest_orange_pad->position); + particleEmitter_setModel(p_ctrl, ASSET_89F_MODEL_ORANGE_PARTICLE); + particleEmitter_setStartingScaleRange(p_ctrl, 0.09f, 0.19f); + particleEmitter_setFinalScaleRange(p_ctrl, 0.0f, 0.0f); + particleEmitter_setParticleVelocityRange(p_ctrl, -200.0f, 500.0f, -200.0f, 200.0f, 700.0f, 200.0f); + particleEmitter_setAccelerationRange(p_ctrl, 0.0f, -1200.0f, 0.0f, 0.0f, -1200.0f, 0.0f); + particleEmitter_setAngularVelocityRange(p_ctrl, -600.0f, -600.0f, -600.0f, 600.0f, 600.0f, 600.0f); + particleEmitter_setSpawnIntervalRange(p_ctrl, 0.0f, 0.01f); + particleEmitter_setParticleLifeTimeRange(p_ctrl, 4.0f, 4.0f); + particleEmitter_func_802EF9F8(p_ctrl, 0.01f); + particleEmitter_func_802EFA18(p_ctrl, 3); + particleEmitter_func_802EFA20(p_ctrl, 1.0f, 1.3f); + + particleEmitter_emitN(p_ctrl, ORANGE_PARTICLE_COUNT); } -void chOrangePad_handleOrangeCollision(NodeProp *arg0, ActorMarker *arg1) { - handleOrangeCollision(arg1); +void chOrangePad_handleOrangeCollision(s32 _, ActorMarker *marker) { + handleOrangeCollision(marker); } -void chorangepad_update(Actor *this) { - Actor *closest_actor; +void chOrangePad_update(Actor *this) { + Actor *conga; f32 unused; f32 min_distance; if (!this->initialized) { this->marker->propPtr->unk8_3 = 1; actor_collisionOff(this); - this->initialized = true; - }//L803867B0 + this->initialized = TRUE; + } if (!this->volatile_initialized) { - this->partnerActor = actorArray_findClosestActorFromActorId(this->position, 8, -1, &min_distance)->marker; - this->volatile_initialized = true; - }//L803867E0 - - if (this->partnerActor) { - closest_actor = marker_getActor(this->partnerActor); + this->partnerActor = actorArray_findClosestActorFromActorId(this->position, ACTOR_8_CONGA, -1, &min_distance)->marker; + this->volatile_initialized = TRUE; } - if (this->state != 1 + // Anchor: a teammate already broke this pad — adopt the hit state. + if (this->state != ORANGE_PAD_STATE_HIT && port_breakable_isBroken((s32)gsworld_getMap(), (s32)this->marker->id, (s32)this->position[0], (s32)this->position[1], (s32)this->position[2])) { - this->state = 1; + this->state = ORANGE_PAD_STATE_HIT; } - if (subaddie_playerIsWithinSphereAndActive(this, 0x28) && - !player_movementGroup() && - !mapSpecificFlags_get(MM_SPECIFIC_FLAG_CONGA_WARNED_BLOCKS) && - closest_actor->state != 3) { + if (this->partnerActor) { + conga = marker_getActor(this->partnerActor); + } + + if (subaddie_playerIsWithinSphereAndActive(this, CONGA_WARN_DISTANCE) + && !player_movementGroup() + && !mapSpecificFlags_get(MM_SPECIFIC_FLAG_CONGA_WARNED_BLOCKS) + && conga->state != CONGA_STATE_MOPEY) { - if (gcdialog_showDialog(ASSET_B3D_DIALOG_CONGA_TOUCH_PAD, 0, NULL, NULL, NULL, NULL)) { - mapSpecificFlags_set(MM_SPECIFIC_FLAG_CONGA_WARNED_BLOCKS, true); + if (gcdialog_showDialog(VER_SELECT(ASSET_B3D_DIALOG_CONGA_TOUCH_PAD, 0x95B, 0, 0), 0, NULL, NULL, NULL, NULL)) { + mapSpecificFlags_set(MM_SPECIFIC_FLAG_CONGA_WARNED_BLOCKS, TRUE); } } - if (this->state == 1) { + if (this->state == ORANGE_PAD_STATE_HIT) { if (this->lifetime_value < 72.0f) { commonParticle_add(this->marker, 5, func_80329904); commonParticle_new(9, this->marker->unk14_21); } - this->lifetime_value = MIN(255.0, this->lifetime_value + 7.0); + // Tick up respawn by 7 every update + this->lifetime_value = MIN(ORANGE_PAD_HIT_LIFETIME, this->lifetime_value + ORANGE_PAD_LIFETIME_INCREMENT); - if (255.0 == this->lifetime_value) { + if (ORANGE_PAD_HIT_LIFETIME == this->lifetime_value) { marker_despawn(this->marker); } - } - else { - }//L80386928 + } else { } // Can't remove the else ;.; + // If hit, then fade out actor_setOpacity(this, 0xFF - (s32) this->lifetime_value); -}//*/ +} diff --git a/src/MM/ch/orangepad.h b/src/MM/ch/orangepad.h new file mode 100644 index 000000000..7bf31b536 --- /dev/null +++ b/src/MM/ch/orangepad.h @@ -0,0 +1,14 @@ +// BanjoDecomp: MM/ch/orangepad.h +#define ORANGE_PARTICLE_COUNT 30 +#define CONGA_WARN_DISTANCE 0x28 +#define ORANGE_PAD_HIT_LIFETIME 255.0 +#define ORANGE_PAD_LIFETIME_INCREMENT 7.0 + +enum orange_pad_state_e { + ORANGE_PAD_STATE_HIT = 1 +}; + +enum orange_pad_ids { + ORANGE_PAD_LEFT = 0x76, + ORANGE_PAD_RIGHT = 0x106 +}; diff --git a/src/MM/checksums.c b/src/MM/checksums.c new file mode 100644 index 000000000..4a743d96f --- /dev/null +++ b/src/MM/checksums.c @@ -0,0 +1,7 @@ +// BanjoDecomp: MM/checksums.c +#include +#include "checksums.h" + +// !! THIS FILE MUST BE LINKED FIRST FOR THIS OVERLAY !! + +/* bss */ struct overlay_checksums_s gChecksumsMM; diff --git a/src/MM/crc.c b/src/MM/crc.c index 425dffd03..585d2b88d 100644 --- a/src/MM/crc.c +++ b/src/MM/crc.c @@ -4,11 +4,9 @@ #include "functions.h" #include "variables.h" -/* .data */ -//TODO Implement CRC calculation in Makefile(?) -u32 D_803899C0 = 0x000C740C; //MM.code CRC1 -u32 D_803899C4 = 0xCD249CB3; //MM.code CRC2 -u32 D_803899C8 = 0x0000D44F; //MM.data CRC1 (with this value = 0) +s32 D_803899C0 = VER_SELECT(0x000C740C, 0x000C896A, 0, 0); // MM_TEXT_CRC1 +s32 D_803899C4 = VER_SELECT(0xCD249CB3, 0xED04CB8F, 0, 0); // MM_TEXT_CRC2 +s32 D_803899C8 = VER_SELECT(0x0000D44F, 0x0000D9E8, 0, 0); // MM_DATA_CRC1 void chmumbo_func_802D1724(void); diff --git a/src/MM/actor_spawninit.c b/src/MM/mmspawnqueue.c similarity index 97% rename from src/MM/actor_spawninit.c rename to src/MM/mmspawnqueue.c index e348cf674..2642fae14 100644 --- a/src/MM/actor_spawninit.c +++ b/src/MM/mmspawnqueue.c @@ -1,4 +1,4 @@ -// BanjoDecomp: code_24C0.c +// BanjoDecomp: MM/mmspawnqueue.c /*!!!DONE!!!*/ #include #include "functions.h" diff --git a/src/MMM/bathroom_particles.c b/src/MMM/bathroom_particles.c index 5b528374f..c8b3d68bf 100644 --- a/src/MMM/bathroom_particles.c +++ b/src/MMM/bathroom_particles.c @@ -1,4 +1,4 @@ -// BanjoDecomp: (core2 origin - unknown exact file) +// BanjoDecomp: core2/code_13A00.c #include #include "functions.h" #include "variables.h" @@ -30,7 +30,7 @@ void func_8029A990(void){ else func_8029C304(1); - _player_getPosition(plyr_pos); + playerPosition_get(plyr_pos); plyr_pos[1] = floor_getCurrentFloorYPosition(); pCtrl = func_802F4094(plyr_pos, 25.0f); particleEmitter_setParticleVelocityRange(pCtrl, @@ -119,7 +119,7 @@ void func_8029AC34(Struct5Ds *arg0, s32 arg1){ void func_8029ACD4(void){ f32 plyr_pos[3]; - _player_getPosition(plyr_pos); + playerPosition_get(plyr_pos); func_802F4894(D_8037D190, plyr_pos); func_802F4884( D_8037D190, func_80294660(), floor_getCurrentFloorYPosition()); } diff --git a/src/MMM/bss_pad.c b/src/MMM/bss_pad.c deleted file mode 100644 index dfa4ab11e..000000000 --- a/src/MMM/bss_pad.c +++ /dev/null @@ -1,2 +0,0 @@ -// BanjoDecomp: bss_pad.c -char pad_D_8038C4C0[0x10]; diff --git a/src/MMM/ch/flowerpot.c b/src/MMM/ch/cemetarypot.c similarity index 95% rename from src/MMM/ch/flowerpot.c rename to src/MMM/ch/cemetarypot.c index 75452f162..05989845a 100644 --- a/src/MMM/ch/flowerpot.c +++ b/src/MMM/ch/cemetarypot.c @@ -1,4 +1,4 @@ -// BanjoDecomp: code_DC0.c +// BanjoDecomp: MMM/ch/cemetarypot.c #include #include "functions.h" #include "variables.h" @@ -40,11 +40,11 @@ void chFlowerpot_setRemaining(s32 arg0) { void MMM_func_803871FC(Actor *this) { switch (this->state) { case FLOWER_POT_STATE_1_IDLE: - func_8033A45C(3, false); + modelRender_setAppendageVisibility(3, false); break; case FLOWER_POT_STATE_2_FLOWERED: - func_8033A45C(3, true); + modelRender_setAppendageVisibility(3, true); break; } diff --git a/src/MMM/ch/loggo.c b/src/MMM/ch/loggo.c index c56424ce9..b5fa97e95 100644 --- a/src/MMM/ch/loggo.c +++ b/src/MMM/ch/loggo.c @@ -42,7 +42,7 @@ void __chLoggo_collide(ActorMarker *this_marker, ActorMarker *other_marker) { Actor *this = marker_getActor(this_marker); if ((player_getTransformation() == TRANSFORM_3_PUMPKIN) && !fileProgressFlag_get(FILEPROG_89_ENTERED_LOGGO_AS_PUMPKIN)) { - if (gcdialog_showDialog(ASSET_ADF_DIALOG_ENTER_LOGGO, 0x2B, this->position, this->marker, &__chLoggo_textCallback, 0) != 0) { + if (gcdialog_showDialog(VER_SELECT(ASSET_ADF_DIALOG_ENTER_LOGGO, 0x951, 0, 0), 0x2B, this->position, this->marker, &__chLoggo_textCallback, 0) != 0) { actor_collisionOff(this); fileProgressFlag_set(FILEPROG_89_ENTERED_LOGGO_AS_PUMPKIN, true); } @@ -56,8 +56,8 @@ void __chLoggo_collide(ActorMarker *this_marker, ActorMarker *other_marker) { } if ((player_getTransformation() == TRANSFORM_1_BANJO) && !fileProgressFlag_get(FILEPROG_88_TRIED_LOGGO_AS_BEAR)) { - if (gcdialog_showDialog(ASSET_ADE_DIALOG_LOGGO_AS_BEAR, 0x2A, this->position, NULL, NULL, NULL)) { - fileProgressFlag_set(FILEPROG_88_TRIED_LOGGO_AS_BEAR, true); + if (gcdialog_showDialog(VER_SELECT(ASSET_ADE_DIALOG_LOGGO_AS_BEAR, 0x950, 0, 0), 0x2A, this->position, NULL, NULL, NULL)) { + fileProgressFlag_set(FILEPROG_88_TRIED_LOGGO_AS_BEAR, TRUE); } } } @@ -82,8 +82,8 @@ void chLoggo_update(Actor *this) { this->lifetime_value = 0.0f; if (!fileProgressFlag_get(FILEPROG_8A_EXITED_LOGGO) && levelSpecificFlags_get(LEVEL_FLAG_33_MMM_UNKNOWN)) { - if (gcdialog_showDialog(ASSET_AE0_DIALOG_EXIT_LOGGO, 4, NULL, NULL, NULL, NULL)) { - fileProgressFlag_set(FILEPROG_8A_EXITED_LOGGO, true); + if (gcdialog_showDialog(VER_SELECT(ASSET_AE0_DIALOG_EXIT_LOGGO, 0x952, 0, 0), 4, NULL, NULL, NULL, NULL)) { + fileProgressFlag_set(FILEPROG_8A_EXITED_LOGGO, TRUE); } } } diff --git a/src/MMM/ch/napper.c b/src/MMM/ch/napper.c index fc1e928c4..6497c4eb4 100644 --- a/src/MMM/ch/napper.c +++ b/src/MMM/ch/napper.c @@ -66,8 +66,8 @@ void func_80386ACC(ActorMarker *this_marker, ActorMarker *other_marker){ Actor *this = marker_getActor(this_marker); if(!this->has_met_before){ - if(gcdialog_showDialog(0xad8, 0, NULL, NULL, NULL, NULL)){ - this->has_met_before = true; + if(gcdialog_showDialog(VER_SELECT(0xAD8, 0x94A, 0, 0), 0, NULL, NULL, NULL, NULL)){ + this->has_met_before = TRUE; } } } @@ -77,14 +77,14 @@ Actor *chnapper_draw(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx){ ActorLocal_Napper *local = (ActorLocal_Napper *)&this->local; if(this->state == 1){ - func_8033A45C(1, true); - func_8033A45C(2, false); - func_8033A45C(3, false); + modelRender_setAppendageVisibility(1, true); + modelRender_setAppendageVisibility(2, false); + modelRender_setAppendageVisibility(3, false); } else { - func_8033A45C(1, false); - func_8033A45C(2, BOOL(local->unk10)); - func_8033A45C(3, (local->unk10) ? false : true); + modelRender_setAppendageVisibility(1, false); + modelRender_setAppendageVisibility(2, BOOL(local->unk10)); + modelRender_setAppendageVisibility(3, (local->unk10) ? false : true); } if(this->state == 1){ //set model alpha diff --git a/src/MMM/ch/portrait.c b/src/MMM/ch/portrait.c index e7a7d9e9d..f7e68c1a3 100644 --- a/src/MMM/ch/portrait.c +++ b/src/MMM/ch/portrait.c @@ -1,4 +1,4 @@ -// BanjoDecomp: code_2F60.c +// BanjoDecomp: MMM/ch/portrait.c #include #include "functions.h" #include "variables.h" @@ -63,7 +63,7 @@ ActorInfo chPortraitMinion = { /* .code */ Actor *chPortrait_draw(ActorMarker *marker, Gfx **graphics, Mtx **matrix, Vtx **vertex) { - func_8033A45C(3, marker_getActor(marker)->unk38_31); + modelRender_setAppendageVisibility(3, marker_getActor(marker)->unk38_31); return actor_draw(marker, graphics, matrix, vertex); } diff --git a/src/MMM/ch/portrait_chompa.c b/src/MMM/ch/portraitchompa.c similarity index 98% rename from src/MMM/ch/portrait_chompa.c rename to src/MMM/ch/portraitchompa.c index 6603137f1..788572ddf 100644 --- a/src/MMM/ch/portrait_chompa.c +++ b/src/MMM/ch/portraitchompa.c @@ -1,4 +1,4 @@ -// BanjoDecomp: code_16B0.c +// BanjoDecomp: MMM/ch/portraitchompa.c #include #include "functions.h" #include "variables.h" @@ -100,7 +100,7 @@ void __chChompa_die(ActorMarker *this_marker, ActorMarker *other_marker) { chChompa_setState(this, CHOMPA_STATE_5_DYING); } -void __chChompa_spwanPortrait(ActorMarker *marker) { +void __chChompa_spawnPortrait(ActorMarker *marker) { Actor *this = marker_getActor(reinterpret_cast(ActorMarker *, marker)); enum asset_e portrait_id; Actor *portrait; @@ -206,7 +206,7 @@ void chChompa_update(Actor *this) { this->volatile_initialized = true; this->unk16C_0 = true; marker_setCollisionScripts(this->marker, NULL, __chChompa_hit, __chChompa_die); - __spawnQueue_add_1((GenFunction_1) __chChompa_spwanPortrait, (uintptr_t)this->marker); + __spawnQueue_add_1((GenFunction_1) __chChompa_spawnPortrait, (uintptr_t)this->marker); chChompa_setState(this, this->state < CHOMPA_STATE_5_DYING ? CHOMPA_STATE_1_IDLE : CHOMPA_STATE_6_DEAD); }//L803880B4 diff --git a/src/MMM/ch/limbo.c b/src/MMM/ch/skeleton.c similarity index 95% rename from src/MMM/ch/limbo.c rename to src/MMM/ch/skeleton.c index c07aee95d..f0d6464fa 100644 --- a/src/MMM/ch/limbo.c +++ b/src/MMM/ch/skeleton.c @@ -1,4 +1,4 @@ -// BanjoDecomp: (core2 origin - unknown exact file) +// BanjoDecomp: core2/ch/skeleton.c #include #include "functions.h" #include "variables.h" @@ -41,7 +41,7 @@ void func_8035CCA0(ParticleEmitter *pCtrl, Actor *this, enum asset_e model_id) { } -void chskeleton_despawn(ActorMarker *marker, s32 arg1) { +void chLimbo_die(ActorMarker *marker, s32 arg1) { Actor *this; this = marker_getActor(marker); @@ -79,7 +79,7 @@ static void _chskeleton_init(Actor *this) { local->exitInvulnerableStateVolume = 1.0f; local->unkC_28 = true; local->hitFunction = (void (*)(ActorMarker *, ActorMarker *)) humanoidBaddie_enterInvulnerableState; - local->dieFunction = (void (*)(ActorMarker *, ActorMarker *)) chskeleton_despawn; + local->dieFunction = (void (*)(ActorMarker *, ActorMarker *)) chLimbo_die; } diff --git a/src/MMM/ch/tumblar.c b/src/MMM/ch/tumblar.c index 9a22036b5..b0e74dd94 100644 --- a/src/MMM/ch/tumblar.c +++ b/src/MMM/ch/tumblar.c @@ -1,4 +1,4 @@ -// BanjoDecomp: code_47D0.c +// BanjoDecomp: MMM/ch/tumblar.c #include "core1/core1.h" #include "functions.h" #include "variables.h" @@ -126,9 +126,8 @@ void __chTumblar_congratulationTextCallback(ActorMarker *marker, enum asset_e te mapSpecificFlags_set(MMM_SPECIFIC_FLAG_TUMBLAR_BROKEN, true); } -void chTumblar_congratulate(void *arg0_, s32 arg1) { - Struct_MMM_47D0_0 *arg0 = (Struct_MMM_47D0_0 *)arg0_; - gcdialog_showDialog(ASSET_ADB_DIALOG_TUMBLAR_COMPLETE, 4, NULL, arg0->jiggy_marker, __chTumblar_congratulationTextCallback, NULL); +void chTumblar_congratulate(Struct_MMM_47D0_0 *arg0, s32 arg1) { + gcdialog_showDialog(VER_SELECT(ASSET_ADB_DIALOG_TUMBLAR_COMPLETE, 0x94D, 0, 0), 4, NULL, arg0->jiggy_marker, __chTumblar_congratulationTextCallback, NULL); arg0->state = TUMBLAR_STATE_1_CONGRATULATING; } @@ -221,8 +220,8 @@ void chTumblar_update(Struct_MMM_47D0_0 *arg0, Struct68s *arg1, f32 tick) { func_8035179C_copyPosition(arg1, position); if (!mapSpecificFlags_get(MMM_SPECIFIC_FLAG_0_UNKNOWN) && arg0->state == TUMBLAR_STATE_0_IDLE && ml_vec3f_horizontal_distance_zero_likely(position, plyr_pos) < 250.0f) { - if (gcdialog_showDialog(ASSET_ADA_DIALOG_TUMBLAR_MEET, 0, NULL, NULL, NULL, NULL)) { - mapSpecificFlags_set(0, true); + if (gcdialog_showDialog(VER_SELECT(ASSET_ADA_DIALOG_TUMBLAR_MEET, 0x94C, 0, 0), 0, NULL, NULL, NULL, NULL)) { + mapSpecificFlags_set(0, TRUE); } } diff --git a/src/MMM/checksums.c b/src/MMM/checksums.c new file mode 100644 index 000000000..d501a3cda --- /dev/null +++ b/src/MMM/checksums.c @@ -0,0 +1,7 @@ +// BanjoDecomp: MMM/checksums.c +#include +#include "checksums.h" + +// !! THIS FILE MUST BE LINKED FIRST FOR THIS OVERLAY !! + +/* bss */ struct overlay_checksums_s gChecksumsMMM; diff --git a/src/MMM/crc.c b/src/MMM/crc.c index 2df0fe00e..f8aca93a3 100644 --- a/src/MMM/crc.c +++ b/src/MMM/crc.c @@ -1,7 +1,8 @@ // BanjoDecomp: crc.c #include +#include "checksums.h" +#include "version.h" -u32 D_8038C300 = 0x00146061; -u32 D_8038C304 = 0xEC79D7B4; -u32 D_8038C308 = 0x0001B98D; -u32 D_8038C30C = 0x0; +s32 D_8038C300 = VER_SELECT(0x00146061, 0x00148214, 0, 0); // MMM_TEXT_CRC1 +s32 D_8038C304 = VER_SELECT(0xEC79D7B4, 0xE11088CE, 0, 0); // MMM_TEXT_CRC2 +s32 D_8038C308 = VER_SELECT(0x0001B98D, 0x0001C16B, 0, 0); // MMM_DATA_CRC1 diff --git a/src/MMM/minigame_organ.c b/src/MMM/minigame_organ.c index d9d1053d2..7333e0340 100644 --- a/src/MMM/minigame_organ.c +++ b/src/MMM/minigame_organ.c @@ -179,7 +179,7 @@ void func_803898EC() { } void func_80389910() { - gcdialog_showDialog(ASSET_AD5_DIALOG_MOTZAND_COMPLETE, 0xE, NULL, NULL, MMM_func_80389810, NULL); + gcdialog_showDialog(VER_SELECT(ASSET_AD5_DIALOG_MOTZAND_COMPLETE, 0x947, 0, 0), 0xE, NULL, NULL, MMM_func_80389810, NULL); timedFunc_set_2(0.0f, (GenFunction_2)coMusicPlayer_playMusic, COMUSIC_2D_PUZZLE_SOLVED_FANFARE, 0x7FFF); timed_setStaticCameraToNode(2.0f, 0); timedFunc_set_0(2.1f, (GenFunction_0)MMM_func_803898A0); @@ -200,10 +200,10 @@ void organMinigame_setState(s32 next_state){ if (next_state == 2) { if (Me.pattern == 0) { Me.pattern = 1; - gcdialog_showDialog(ASSET_AD3_DIALOG_MOTZAND_MEET, 4, NULL, NULL, MMM_func_80389810, NULL); + gcdialog_showDialog(VER_SELECT(ASSET_AD3_DIALOG_MOTZAND_MEET, 0x945, 0, 0), 4, NULL, NULL, MMM_func_80389810, NULL); } else {//L80389A84 - gcdialog_showDialog(ASSET_AD6_DIALOG_MOTZAND_RETRY, 4, NULL, NULL, MMM_func_80389810, NULL); + gcdialog_showDialog(VER_SELECT(ASSET_AD6_DIALOG_MOTZAND_RETRY, 0x948, 0, 0), 4, NULL, NULL, MMM_func_80389810, NULL); } }//L80389A9C @@ -220,13 +220,13 @@ void organMinigame_setState(s32 next_state){ }//L80389AF4 if(next_state == 4){ - gcdialog_showDialog(ASSET_ADD_DIALOG_MOTZAND_MISS, 4, NULL, NULL, MMM_func_80389810, NULL); + gcdialog_showDialog(VER_SELECT(ASSET_ADD_DIALOG_MOTZAND_MISS, 0x94F, 0, 0), 4, NULL, NULL, MMM_func_80389810, NULL); func_80387720(Me.motzhand_marker); } if(next_state == 5){ Me.pattern++; - gcdialog_showDialog(ASSET_AD4_DIALOG_MOTZAND_HALFWAY, 4, NULL, NULL, MMM_func_80389810, NULL); + gcdialog_showDialog(VER_SELECT(ASSET_AD4_DIALOG_MOTZAND_HALFWAY, 0x946, 0, 0), 4, NULL, NULL, MMM_func_80389810, NULL); func_80387720(Me.motzhand_marker); } diff --git a/src/MMM/minigame_shed.c b/src/MMM/minigame_shed.c index 70ac8f5ea..83b217794 100644 --- a/src/MMM/minigame_shed.c +++ b/src/MMM/minigame_shed.c @@ -84,7 +84,7 @@ void func_8038A140(s32 arg0) { if (MMM_D_8038C510.unk8 == 1) { mapSpecificFlags_set(MMM_SPECIFIC_FLAG_3_UNKNOWN, 1); } - item_set(ITEM_0_HOURGLASS_TIMER, 75*60 - 1); + item_set(ITEM_0_HOURGLASS_TIMER, 75*FRAMERATE - 1); item_set(6, 1); } if (MMM_D_8038C510.unk8 == 3) { diff --git a/src/MMM/actor_spawninit.c b/src/MMM/mmmspawnqueue.c similarity index 58% rename from src/MMM/actor_spawninit.c rename to src/MMM/mmmspawnqueue.c index 2e3f1e97d..21ea8bf39 100644 --- a/src/MMM/actor_spawninit.c +++ b/src/MMM/mmmspawnqueue.c @@ -1,24 +1,26 @@ -// BanjoDecomp: code_2040.c +// BanjoDecomp: MMM/mmmspawnqueue.c #include #include "core1/core1.h" #include "functions.h" #include "variables.h" #include "actor.h" -extern ActorInfo D_8038BC28; -extern ActorInfo D_8038BCDC; -extern ActorInfo D_8038BC4C; -extern ActorInfo D_8038BDB4; -extern ActorInfo D_8038BDD8; -extern ActorInfo D_8038BDFC; -extern ActorInfo D_8038BC94; -extern ActorInfo D_8038BC70; -extern ActorInfo D_8038BD00; -extern ActorInfo D_8038BD24; -extern ActorInfo D_8038BD48; -extern ActorInfo D_8038BD6C; -extern ActorInfo D_8038BCB8; -extern ActorInfo D_8038BD90; +#include "core2/dustemitter.h" + +extern ActorInfo chShackDoor; +extern ActorInfo chMansionDoor; +extern ActorInfo chCellarHatch; +extern ActorInfo chChuchGateLeftLock; +extern ActorInfo chHedgeGateRightLock1; +extern ActorInfo chHedgeGateRightLock2; +extern ActorInfo chChuchDoor; +extern ActorInfo ch1881BarrelTop; +extern ActorInfo chXBarrelTop; +extern ActorInfo chMMMWindow; +extern ActorInfo chMMMWideWindow; +extern ActorInfo chMMMTallWindow; +extern ActorInfo chDiningDoor; +extern ActorInfo chMMMClockSwitch; extern ActorInfo chNapper; extern ActorInfo D_8038BA68; extern ActorInfo chMotzhand; @@ -32,20 +34,20 @@ extern ActorInfo chPortraitTeeHee; extern ActorInfo chPortraitMinion; extern ActorInfo D_80367E70; -extern ActorInfo D_80372C3C; +extern ActorInfo chPurpleTeeHee; extern void core1_7090_initSfxSource(s32, s32, s32, f32); extern void func_8025AE0C(s32, f32); extern BKCollisionTriangle *func_80309B48(f32[3], f32[3], f32[3], u32); -void func_802D3D54(Actor *this); -void func_803888B8(Actor *this); -Actor *func_80388994(ActorMarker *marker, Gfx ** gfx, Mtx **mtx, Vtx **vtx); -void func_80388BDC(Actor *this); -void func_80388FE4(Actor *this); -void func_80389004(Actor *this); -void func_80389060(Actor *this); -void func_803890B8(Actor *this); +void chMMMBreakableWooden_update(Actor *this); +void chMMMGate_update(Actor *this); +Actor *chMMMGate_draw(ActorMarker *marker, Gfx ** gfx, Mtx **mtx, Vtx **vtx); +void chChurchDoor_update(Actor *this); +void chMMMClockSwitch_update(Actor *this); +void chMMMWoodenDoor_update(Actor *this); +void chXBarrelTop_update(Actor *this); +void chMMMWindow_update(Actor *this); /* .data */ ActorAnimationInfo D_8038BBE0[] = { @@ -60,101 +62,101 @@ ActorAnimationInfo D_8038BBE0[] = { {0x00, 0.0f} }; -ActorInfo D_8038BC28 = { - 0x9C, 0x109, 0x3CD, +ActorInfo chShackDoor = { + MARKER_9C_SHACK_DOOR, ACTOR_109_SHACK_DOOR, ASSET_3CD_MODEL_SHACK_DOOR, 0x1, NULL, - func_802D3D54, actor_update_func_80326224, actor_drawFullDepth, + chMMMBreakableWooden_update, actor_update_func_80326224, actor_drawFullDepth, 0, 0, 0.0f, 0 }; -ActorInfo D_8038BC4C = { - 0x9E, 0x10B, 0x3CF, +ActorInfo chCellarHatch = { + MARKER_9E_CELLAR_HATCH, ACTOR_10B_CELLAR_HATCH, ASSET_3CF_MODEL_CELLAR_HATCH, 0x1, NULL, - func_802D3D54, actor_update_func_80326224, actor_drawFullDepth, + chMMMBreakableWooden_update, actor_update_func_80326224, actor_drawFullDepth, 0, 0, 0.0f, 0 }; -ActorInfo D_8038BC70 = { - 0x9A, 0xCB, 0x3CC, +ActorInfo ch1881BarrelTop = { + MARKER_9A_1881_BARREL_TOP, ACTOR_CB_1881_BARREL_TOP, ASSET_3CC_MODEL_1881_BARREL_TOP, 0x1, NULL, - func_802D3D54, actor_update_func_80326224, actor_drawFullDepth, + chMMMBreakableWooden_update, actor_update_func_80326224, actor_drawFullDepth, 0, 0, 0.0f, 0 }; -ActorInfo D_8038BC94 = { - 0xA2, 0x114, 0x3D3, +ActorInfo chChuchDoor = { + MARKER_A2_CHURCH_DOOR, ACTOR_114_CHURCH_DOOR, ASSET_3D3_MODEL_CHURCH_DOOR, 0x1, NULL, - func_80388BDC, actor_update_func_80326224, actor_drawFullDepth, + chChurchDoor_update, actor_update_func_80326224, actor_drawFullDepth, 0, 0, 0.0f, 0 }; -ActorInfo D_8038BCB8 = { - 0xE7, 0x265, 0x4DA, +ActorInfo chDiningDoor = { + MARKER_E7_DINING_DOOR, ACTOR_265_DINING_DOOR, ASSET_4DA_MODEL_DINING_DOOR, 0x1, NULL, - func_80389004, actor_update_func_80326224, actor_drawFullDepth, + chMMMWoodenDoor_update, actor_update_func_80326224, actor_drawFullDepth, 0, 0, 0.0f, 0 }; -ActorInfo D_8038BCDC = { - 0x9D, 0x10A, 0x3CE, +ActorInfo chMansionDoor = { + MARKER_9D_MANSION_DOOR, ACTOR_10A_MANSION_DOOR, ASSET_3CE_MODEL_MANSION_DOOR, 0x1, NULL, - func_80389004, actor_update_func_80326224, actor_drawFullDepth, + chMMMWoodenDoor_update, actor_update_func_80326224, actor_drawFullDepth, 0, 0, 0.0f, 0 }; -ActorInfo D_8038BD00 = { - 0xD3, 0x191, 0x50B, +ActorInfo chXBarrelTop = { + MARKER_D3_X_BARREL_TOP, ACTOR_191_X_BARREL_TOP, ASSET_50B_MODEL_X_BARREL_TOP, 0x1, NULL, - func_80389060, actor_update_func_80326224, actor_drawFullDepth, + chXBarrelTop_update, actor_update_func_80326224, actor_drawFullDepth, 0, 0, 0.0f, 0 }; -ActorInfo D_8038BD24 = { -0x123, 0x2E8, 0x4C0, +ActorInfo chMMMWindow = { + MARKER_123_WINDOW, ACTOR_2E8_WINDOW, ASSET_4C0_MODEL_WINDOW, 0x1, NULL, - func_803890B8, actor_update_func_80326224, actor_drawFullDepth, + chMMMWindow_update, actor_update_func_80326224, actor_drawFullDepth, 0, 0, 0.0f, 0 }; -ActorInfo D_8038BD48 = { -0x1F2, 0x2E9, 0x4C1, +ActorInfo chMMMWideWindow = { + MARKER_1F2_WIDE_WINDOW, ACTOR_2E9_WIDE_WINDOW, ASSET_4C1_MODEL_WIDE_WINDOW, 0x1, NULL, - func_803890B8, actor_update_func_80326224, actor_drawFullDepth, + chMMMWindow_update, actor_update_func_80326224, actor_drawFullDepth, 0, 0, 0.0f, 0 }; -ActorInfo D_8038BD6C = { -0x1F3, 0x2EA, 0x4C2, +ActorInfo chMMMTallWindow = { + MARKER_1F3_TALL_WINDOW, ACTOR_2EA_TALL_WINDOW, ASSET_4C2_MODEL_TALL_WINDOW, 0x1, NULL, - func_803890B8, actor_update_func_80326224, actor_drawFullDepth, + chMMMWindow_update, actor_update_func_80326224, actor_drawFullDepth, 0, 0, 0.0f, 0 }; -ActorInfo D_8038BD90 = { - 0xFE, 0x1FD, 0x43D, +ActorInfo chMMMClockSwitch = { + MARKER_FE_MMM_CLOCK_SWITCH, ACTOR_1FD_MMM_CLOCK_SWITCH, ASSET_43D_MODEL_MMM_CLOCK_SWITCH, 0x1, D_8038BBE0, - func_80388FE4, actor_update_func_80326224, actor_draw, + chMMMClockSwitch_update, actor_update_func_80326224, actor_draw, 0, 0, 0.0f, 0 }; -ActorInfo D_8038BDB4 = { - 0x9F, 0x10C, 0x3D0, +ActorInfo chChuchGateLeftLock = { + MARKER_9F_CHURCH_GATE_LEFT_LOCK, ACTOR_10C_CHURCH_GATE_LEFT_LOCK, ASSET_3D0_MODEL_CHURCH_GATE_LEFT_LOCK, 0x1, NULL, - func_803888B8, actor_update_func_80326224, func_80388994, + chMMMGate_update, actor_update_func_80326224, chMMMGate_draw, 0, 0, 0.0f, 0 }; -ActorInfo D_8038BDD8 = { - 0xA0, 0x10D, 0x3D1, +ActorInfo chHedgeGateRightLock1 = { + MARKER_A0_HEDGE_GATE_RIGHT_LOCK_1, ACTOR_10D_HEDGE_GATE_RIGHT_LOCK_1, ASSET_3D1_MODEL_HEDGE_GATE_RIGHT_LOCK_1, 0x1, NULL, - func_803888B8, actor_update_func_80326224, func_80388994, + chMMMGate_update, actor_update_func_80326224, chMMMGate_draw, 0, 0, 0.0f, 0 }; -ActorInfo D_8038BDFC = { - 0xFF, 0x1FE, 0x43E, +ActorInfo chHedgeGateRightLock2 = { + MARKER_FF_HEDGE_GATE_RIGHT_LOCK_2, ACTOR_1FE_HEDGE_GATE_RIGHT_LOCK_2, ASSET_43E_MODEL_HEDGE_GATE_RIGHT_LOCK_2, 0x1, NULL, - func_803888B8, actor_update_func_80326224, func_80388994, + chMMMGate_update, actor_update_func_80326224, chMMMGate_draw, 0, 0, 0.0f, 0 }; @@ -205,25 +207,28 @@ f32 MMM_func_80388430(Actor *this, s32 arg1, s32 arg2, f32 arg3) { s32 func_80388670(ActorMarker * this_marker, ActorMarker * other_marker){ Actor *this = marker_getActor(this_marker); - f32 sp20[3]; + f32 player_position[3]; - player_getPosition(sp20); + player_getPosition(player_position); switch(this->marker->id){ - case 0x9f: //L803886D0 - return (-335.0f < sp20[0] && sp20[0] < -200.0f) && (-2730.0f < sp20[2] && sp20[2] < -2400.0f); + case MARKER_9F_CHURCH_GATE_LEFT_LOCK: //L803886D0 + return (-335.0f < player_position[0] && player_position[0] < -200.0f) + && (-2730.0f < player_position[2] && player_position[2] < -2400.0f); - case 0xa0: //L80388770 - return (-2915.0f < sp20[0] && sp20[0] < -2584.0f) && ( -500.0f < sp20[2] && sp20[2] < -355.0f); + case MARKER_A0_HEDGE_GATE_RIGHT_LOCK_1: //L80388770 + return (-2915.0f < player_position[0] && player_position[0] < -2584.0f) + && ( -500.0f < player_position[2] && player_position[2] < -355.0f); - case 0xFF: //L80388810 - return (5470.0f < sp20[0] && sp20[0] < 5920.0f) && ( -850.0f < sp20[2] && sp20[2] < -780.0f); + case MARKER_FF_HEDGE_GATE_RIGHT_LOCK_2: //L80388810 + return (5470.0f < player_position[0] && player_position[0] < 5920.0f) + && ( -850.0f < player_position[2] && player_position[2] < -780.0f); default: return false; } } -void func_803888B8(Actor *this){ +void chMMMGate_update(Actor *this){ func_803300C0(this->marker, func_80388670); func_802D3CE8(this); this->lifetime_value = 0.0f; @@ -245,7 +250,7 @@ void func_803888B8(Actor *this){ } } -Actor *func_80388994(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx) { +Actor *chMMMGate_draw(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx) { static s32 i; Actor *this; @@ -283,7 +288,7 @@ void func_80388B2C(Actor *this, f32 arg1) { } } -void func_80388BDC(Actor *this) { +void chChurchDoor_update(Actor *this) { f64 phi_f0; func_802D3D74(this); @@ -320,9 +325,9 @@ void func_80388BDC(Actor *this) { if ((this->yaw <= 270.0f) && (this->yaw > 260.0f)) { subaddie_set_state(this, 7U); this->yaw = 270.0f; - gcsfx_playAtSampleRate(0x7F); + gcsfx_play(0x7F); core1_7090_freeSfxSource(0); - func_802D68F0(0xE); + code_4C020_setHourglassTimer(0xE); item_set(6, 1); } break; @@ -352,7 +357,7 @@ void func_80388BDC(Actor *this) { if ((this->yaw >= 0.0f) && (this->yaw < 10.0f)) { subaddie_set_state(this, 1U); this->yaw = 0.0f; - gcsfx_playAtSampleRate(SFX_7F_HEAVYDOOR_SLAM); + gcsfx_play(SFX_7F_HEAVYDOOR_SLAM); mapSpecificFlags_set(MMM_SPECIFIC_FLAG_0_UNKNOWN, false); core1_7090_freeSfxSource(0); if (!this->unk38_31) { @@ -361,17 +366,17 @@ void func_80388BDC(Actor *this) { } this->unk38_31 = 0; this->lifetime_value = 0.0f; - volatileFlag_setAndTriggerDialog_0(VOLATILE_FLAG_AD_MMM_CHURCH_DOOR_MISSED); + progressDialog_setAndTriggerDialog_0(VOLATILE_FLAG_AD_MMM_CHURCH_DOOR_MISSED); } break; } } -void func_80388FE4(Actor *this) { +void chMMMClockSwitch_update(Actor *this) { func_802D4A9C(this,0); } -void func_80389004(Actor *this){ +void chMMMWoodenDoor_update(Actor *this){ func_802D3CE8(this); if (!this->volatile_initialized) { @@ -382,8 +387,8 @@ void func_80389004(Actor *this){ } } -void func_80389060(Actor *this){ - if(!this->initialized && sns_get_item_state(SNS_ITEM_EGG_CYAN, true)){ +void chXBarrelTop_update(Actor *this){ + if(!this->initialized && sns_get_item_state(SNS_ITEM_EGG_CYAN, TRUE)){ marker_despawn(this->marker); } else{ @@ -391,26 +396,26 @@ void func_80389060(Actor *this){ } } -void func_803890B8(Actor *this) { - func_802D3D54(this); +void chMMMWindow_update(Actor *this) { + chMMMBreakableWooden_update(this); chTumblar_checkMMMChecksums(); } void MMM_func_803890E0(void){ - spawnableActorList_add(&D_8038BC28, actor_new, ACTOR_FLAG_NONE); - spawnableActorList_add(&D_8038BCDC, actor_new, ACTOR_FLAG_NONE); - spawnableActorList_add(&D_8038BC4C, actor_new, ACTOR_FLAG_NONE); - spawnableActorList_add(&D_8038BDB4, actor_new, ACTOR_FLAG_UNKNOWN_6); - spawnableActorList_add(&D_8038BDD8, actor_new, ACTOR_FLAG_UNKNOWN_6); - spawnableActorList_add(&D_8038BDFC, actor_new, ACTOR_FLAG_UNKNOWN_6 | ACTOR_FLAG_UNKNOWN_10); - spawnableActorList_add(&D_8038BC94, actor_new, ACTOR_FLAG_NONE); - spawnableActorList_add(&D_8038BC70, actor_new, ACTOR_FLAG_NONE); - spawnableActorList_add(&D_8038BD00, actor_new, ACTOR_FLAG_NONE); - spawnableActorList_add(&D_8038BD24, actor_new, ACTOR_FLAG_UNKNOWN_9 | ACTOR_FLAG_UNKNOWN_10 | ACTOR_FLAG_UNKNOWN_15); - spawnableActorList_add(&D_8038BD48, actor_new, ACTOR_FLAG_UNKNOWN_9 | ACTOR_FLAG_UNKNOWN_10 | ACTOR_FLAG_UNKNOWN_15); - spawnableActorList_add(&D_8038BD6C, actor_new, ACTOR_FLAG_UNKNOWN_9 | ACTOR_FLAG_UNKNOWN_10 | ACTOR_FLAG_UNKNOWN_15); - spawnableActorList_add(&D_8038BCB8, actor_new, ACTOR_FLAG_UNKNOWN_9 | ACTOR_FLAG_UNKNOWN_10 | ACTOR_FLAG_UNKNOWN_15); - spawnableActorList_add(&D_8038BD90, actor_new, ACTOR_FLAG_UNKNOWN_3); + spawnableActorList_add(&chShackDoor, actor_new, ACTOR_FLAG_NONE); + spawnableActorList_add(&chMansionDoor, actor_new, ACTOR_FLAG_NONE); + spawnableActorList_add(&chCellarHatch, actor_new, ACTOR_FLAG_NONE); + spawnableActorList_add(&chChuchGateLeftLock, actor_new, ACTOR_FLAG_UNKNOWN_6); + spawnableActorList_add(&chHedgeGateRightLock1, actor_new, ACTOR_FLAG_UNKNOWN_6); + spawnableActorList_add(&chHedgeGateRightLock2, actor_new, ACTOR_FLAG_UNKNOWN_6 | ACTOR_FLAG_UNKNOWN_10); + spawnableActorList_add(&chChuchDoor, actor_new, ACTOR_FLAG_NONE); + spawnableActorList_add(&ch1881BarrelTop, actor_new, ACTOR_FLAG_NONE); + spawnableActorList_add(&chXBarrelTop, actor_new, ACTOR_FLAG_NONE); + spawnableActorList_add(&chMMMWindow, actor_new, ACTOR_FLAG_UNKNOWN_9 | ACTOR_FLAG_UNKNOWN_10 | ACTOR_FLAG_UNKNOWN_15); + spawnableActorList_add(&chMMMWideWindow, actor_new, ACTOR_FLAG_UNKNOWN_9 | ACTOR_FLAG_UNKNOWN_10 | ACTOR_FLAG_UNKNOWN_15); + spawnableActorList_add(&chMMMTallWindow, actor_new, ACTOR_FLAG_UNKNOWN_9 | ACTOR_FLAG_UNKNOWN_10 | ACTOR_FLAG_UNKNOWN_15); + spawnableActorList_add(&chDiningDoor, actor_new, ACTOR_FLAG_UNKNOWN_9 | ACTOR_FLAG_UNKNOWN_10 | ACTOR_FLAG_UNKNOWN_15); + spawnableActorList_add(&chMMMClockSwitch, actor_new, ACTOR_FLAG_UNKNOWN_3); spawnableActorList_add(&chNapper, actor_new, ACTOR_FLAG_UNKNOWN_5 | ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_11 | ACTOR_FLAG_UNKNOWN_12); spawnableActorList_add(&D_8038BA68, actor_new, ACTOR_FLAG_UNKNOWN_8); spawnableActorList_add(&chMotzhand, actor_new, ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_11 | ACTOR_FLAG_UNKNOWN_17); @@ -423,5 +428,5 @@ void MMM_func_803890E0(void){ spawnableActorList_add(&chPortraitTreeAndMoon, actor_new, ACTOR_FLAG_UNKNOWN_6 | ACTOR_FLAG_UNKNOWN_23); spawnableActorList_add(&chPortraitTeeHee, actor_new, ACTOR_FLAG_UNKNOWN_6 | ACTOR_FLAG_UNKNOWN_23); spawnableActorList_add(&chPortraitMinion, actor_new, ACTOR_FLAG_UNKNOWN_6 | ACTOR_FLAG_UNKNOWN_23); - spawnableActorList_add(&D_80372C3C, actor_new, ACTOR_FLAG_UNKNOWN_0 | ACTOR_FLAG_UNKNOWN_3 | ACTOR_FLAG_UNKNOWN_5 | ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_8 | ACTOR_FLAG_UNKNOWN_12 | ACTOR_FLAG_UNKNOWN_17 | ACTOR_FLAG_UNKNOWN_19); + spawnableActorList_add(&chPurpleTeeHee, actor_new, ACTOR_FLAG_UNKNOWN_0 | ACTOR_FLAG_UNKNOWN_3 | ACTOR_FLAG_UNKNOWN_5 | ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_8 | ACTOR_FLAG_UNKNOWN_12 | ACTOR_FLAG_UNKNOWN_17 | ACTOR_FLAG_UNKNOWN_19); } diff --git a/src/MMM/napper_room.c b/src/MMM/napper_room.c index 30603b795..17f2d4264 100644 --- a/src/MMM/napper_room.c +++ b/src/MMM/napper_room.c @@ -55,7 +55,7 @@ void func_803895B0(s32 arg0) { } void func_803895D8(ActorMarker *caller, enum asset_e text_id, s32 arg2) { - if (text_id == 0xAD7) { + if (text_id == VER_SELECT(ASSET_AD7_DIALOG_NAPPER_AWAKE, 0x949, 0, 0)) { timed_playSfx(0.1f, SFX_3F5_UNKNOWN, 1.0f, 30000); timed_exitStaticCamera(1.5f); func_80324E38(1.5f, 0); @@ -82,7 +82,7 @@ void func_8038966C(void){ MMM_D_8038C4E0.unk2 = true; func_80324E38(0.0f, 3); timed_setStaticCameraToNode(0.2f, 1); - func_80324DBC(0.2f, 0xad9, 6, NULL, NULL, func_803895D8, NULL); + func_80324DBC(0.2f, VER_SELECT(ASSET_AD9_DIALOG_NAPPER_COMPLETE, 0x94B, 0, 0), 6, NULL, NULL, func_803895D8, NULL); }//L80389700 if(MMM_D_8038C4E0.unk1 != 1) @@ -109,8 +109,8 @@ void func_8038966C(void){ if (!levelSpecificFlags_get(LEVEL_FLAG_1B_MMM_UNKNOWN)) { func_80324E38(0.0f, 3); timed_setStaticCameraToNode(0.0f, 0); - func_80324DBC(0.0f, 0xad7, 6, NULL, NULL, func_803895D8, NULL); - levelSpecificFlags_set(LEVEL_FLAG_1B_MMM_UNKNOWN, true); + func_80324DBC(0.0f, VER_SELECT(ASSET_AD7_DIALOG_NAPPER_AWAKE, 0x949, 0, 0), 6, NULL, NULL, func_803895D8, NULL); + levelSpecificFlags_set(LEVEL_FLAG_1B_MMM_UNKNOWN, TRUE); } } } diff --git a/src/RBB/actor_spawninit.c b/src/RBB/actor_spawninit.c deleted file mode 100644 index c7492be54..000000000 --- a/src/RBB/actor_spawninit.c +++ /dev/null @@ -1,231 +0,0 @@ -// BanjoDecomp: code_640.c -#include -#include "core1/core1.h" -#include "functions.h" -#include "variables.h" -#include "prop.h" -#include "actor.h" - -#include "port/Patches/Patches.h" - - -extern ActorInfo D_80390D20; -extern ActorInfo D_80390050; -extern ActorInfo D_80390200; -extern ActorInfo D_80390270; -extern ActorInfo D_80390D50; -extern ActorInfo D_803906E0; -extern ActorInfo D_80390738; -extern ActorInfo D_803907D0; -extern ActorInfo D_803907F4; -extern ActorInfo D_80390818; -extern ActorInfo D_8039083C; -extern ActorInfo D_803904C0; -extern ActorInfo D_803904E4; -extern ActorInfo D_80390508; -extern ActorInfo D_803903B0; -extern ActorInfo D_803903D4; -extern ActorInfo D_803903F8; -extern ActorInfo D_80390640; -extern ActorInfo D_80390664; -extern ActorInfo D_80390688; -extern ActorInfo D_803906B0; -extern ActorInfo D_803908C0; -extern ActorInfo D_803908E4; -extern ActorInfo D_80390908; -extern ActorInfo D_803909B0; -extern ActorInfo D_803909D4; -extern ActorInfo RBB_D_803909F8; -extern ActorInfo D_80390A50; -extern ActorInfo D_80390380; -extern ActorInfo D_80390A80; //anchorswitch -extern ActorInfo RBB_D_80390AB0; //dolphin -extern ActorInfo RBB_D_80390AE0; //anchor -extern ActorInfo RBB_D_80390B10; -extern ActorInfo D_80390B40; //rarewareflag -extern ActorInfo RBB_D_80390BD0; -extern ActorInfo D_80390BF4; -extern ActorInfo D_80390C18; -extern ActorInfo RBB_D_80390C3C; -extern ActorInfo RBB_D_80390CF0; -extern ActorInfo D_80390D88; -extern ActorInfo D_80390DAC; //TNTpart_IDStruct; -extern ActorInfo RBB_D_80390E00; -extern ActorInfo D_80390E34; -extern ActorInfo D_80390E58; -extern ActorInfo D_803900E0; -extern ActorInfo D_80390104; //captcabinwooddoor -extern ActorInfo D_80390128; -extern ActorInfo D_8039014C; -extern ActorInfo D_803901B8; -extern ActorInfo D_803901DC; -extern ActorInfo D_80390170;//skylight -extern ActorInfo D_80390194;//honeycombswitch - - - -extern void func_802D3D54(Actor *); - -void func_80386A7C(Actor *); -void func_80386BF8(Actor *arg0); -Actor *func_80386B9C(ActorMarker *marker, Gfx **gdl, Mtx **mptr, Vtx **arg3); - - -/* .data */ -ActorAnimationInfo D_803900C0[4] = { - {0, 0.0f}, - {0, 0.0f}, - {0xD4, 0.15f}, - {0xD5, 0.5f} -}; - -ActorInfo D_803900E0 = { - 0x107, 0x21D, 0x493, 0x1, NULL, - func_802D3D54, actor_update_func_80326224, actor_drawFullDepth, - 0, 0, 0.0f, 0 -}; - -ActorInfo D_80390104 = { - 0x108, 0x21C, 0x492, 0x1, NULL, - func_802D3D54, actor_update_func_80326224, actor_drawFullDepth, - 0, 0, 0.0f, 0 -}; - -ActorInfo D_80390128 = { - 0x22D, 0x266, 0x4BA, 0x1, NULL, - func_802D3D54, actor_update_func_80326224, actor_drawFullDepth, - 0, 0, 0.0f, 0 -}; - -ActorInfo D_8039014C = { - 0x22E, 0x267, 0x4BB, 0x1, NULL, - func_802D3D54, actor_update_func_80326224, actor_drawFullDepth, - 0, 0, 0.0f, 0 -}; - -ActorInfo D_80390170 = { - 0x235, 0x23F, 0x4E2, 0x1, NULL, - func_802D3D54, actor_update_func_80326224, actor_drawFullDepth, - 0, 0, 0.0f, 0 -}; - -ActorInfo D_80390194 = { - 0x15F, 0x18F, 0x42F, 0x1, D_803900C0, - func_80386BF8, actor_update_func_80326224, actor_draw, - 0, 0, 0.0f, 0 -}; - -ActorInfo D_803901B8 = { - 0x22F, 0x263, 0x4DB, 0x1, NULL, - func_80386A7C, actor_update_func_80326224, func_80386B9C, - 0, 0, 0.0f, 0 -}; - -ActorInfo D_803901DC = { - 0x230, 0x264, 0x4DE, 0x1, NULL, - func_80386A7C, actor_update_func_80326224, func_80386B9C, - 0, 0, 0.0f, 0 -}; - - -/* .code */ -s32 func_80386A30(f32 arg0[3]){ - s32 r; - - r = (arg0[0] < 0.0f)? 0 : 1; - - return ((arg0[2] < 0.0f)? 0 : 2) + r; -} - -void func_80386A7C(Actor *this){ - f32 viewport[3]; - s32 sp28; - s32 temp_v0; - - func_802D3D74(this); - this->depth_mode = 1; - viewport_getPosition_vec3f(viewport); - sp28 = func_80386A30(this->position); - temp_v0 = func_80386A30(viewport); - this->unk38_0 = 0; - // [port] Extend the bespoke distance cull with draw distance; quadrant occlusion below stays. - f32 cull = 8000.0f * port_drawDistanceMul(); - if(viewport[0] + cull < this->position_x || this->position_x < viewport[0] - cull) - return; - - if( !( (sp28 ^ temp_v0) & 2 - && (-5000.0f < viewport[0] && viewport[0] < 6000.0f) - && (viewport[2] < -600.0f || 600.0f < viewport[2]) - ) - && ( sp28 ^ temp_v0) != 3 - ){ - this->unk38_0 = 1; - } -} - -Actor *func_80386B9C(ActorMarker *marker, Gfx **gdl, Mtx **mptr, Vtx **arg3){ - Actor *actor = marker_getActor(marker); - - return (actor->unk38_0) ? actor_drawFullDepth(marker, gdl, mptr, arg3): NULL; -} - -void func_80386BF8(Actor *arg0){ - if(!mapSpecificFlags_get(0) && honeycombscore_get(HONEYCOMB_F_RBB_BOAT_HOUSE)) - mapSpecificFlags_set(0, true); - func_802D4A9C(arg0, 0); -} - -void RBB_func_80386C48(void){ - spawnableActorList_add(&D_80390D20, actor_new, ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_11 | ACTOR_FLAG_UNKNOWN_14); - spawnableActorList_add(&D_80390050, actor_new, ACTOR_FLAG_NONE); - spawnableActorList_add(&D_80390200, actor_new, ACTOR_FLAG_UNKNOWN_7); - spawnableActorList_add(&D_80390270, actor_new, ACTOR_FLAG_UNKNOWN_7); - spawnableActorList_add(&D_80390D50, actor_new, ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_10 | ACTOR_FLAG_UNKNOWN_14 | ACTOR_FLAG_UNKNOWN_27); - spawnableActorList_add(&D_803906E0, actor_new, ACTOR_FLAG_UNKNOWN_7); - spawnableActorList_add(&D_80390738, actor_new, ACTOR_FLAG_UNKNOWN_7); - spawnableActorList_add(&D_803907D0, actor_new, ACTOR_FLAG_UNKNOWN_3 | ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_10 | ACTOR_FLAG_UNKNOWN_13 | ACTOR_FLAG_UNKNOWN_14); - spawnableActorList_add(&D_803907F4, actor_new, ACTOR_FLAG_UNKNOWN_3 | ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_10 | ACTOR_FLAG_UNKNOWN_13 | ACTOR_FLAG_UNKNOWN_14); - spawnableActorList_add(&D_80390818, actor_new, ACTOR_FLAG_UNKNOWN_3 | ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_10 | ACTOR_FLAG_UNKNOWN_13 | ACTOR_FLAG_UNKNOWN_14); - spawnableActorList_add(&D_8039083C, actor_new, ACTOR_FLAG_UNKNOWN_3 | ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_10 | ACTOR_FLAG_UNKNOWN_13 | ACTOR_FLAG_UNKNOWN_14); - spawnableActorList_add(&D_803904C0, actor_new, ACTOR_FLAG_UNKNOWN_3 | ACTOR_FLAG_UNKNOWN_10 | ACTOR_FLAG_UNKNOWN_13 | ACTOR_FLAG_UNKNOWN_14); - spawnableActorList_add(&D_803904E4, actor_new, ACTOR_FLAG_UNKNOWN_3 | ACTOR_FLAG_UNKNOWN_10 | ACTOR_FLAG_UNKNOWN_13 | ACTOR_FLAG_UNKNOWN_14); - spawnableActorList_add(&D_80390508, actor_new, ACTOR_FLAG_UNKNOWN_3 | ACTOR_FLAG_UNKNOWN_10 | ACTOR_FLAG_UNKNOWN_13 | ACTOR_FLAG_UNKNOWN_14); - spawnableActorList_add(&D_803903B0, actor_new, ACTOR_FLAG_UNKNOWN_3 | ACTOR_FLAG_UNKNOWN_10 | ACTOR_FLAG_UNKNOWN_13 | ACTOR_FLAG_UNKNOWN_14); - spawnableActorList_add(&D_803903D4, actor_new, ACTOR_FLAG_UNKNOWN_3 | ACTOR_FLAG_UNKNOWN_10 | ACTOR_FLAG_UNKNOWN_13 | ACTOR_FLAG_UNKNOWN_14); - spawnableActorList_add(&D_803903F8, actor_new, ACTOR_FLAG_UNKNOWN_3 | ACTOR_FLAG_UNKNOWN_10 | ACTOR_FLAG_UNKNOWN_13 | ACTOR_FLAG_UNKNOWN_14); - spawnableActorList_add(&D_80390640, actor_new, ACTOR_FLAG_UNKNOWN_10); - spawnableActorList_add(&D_80390664, actor_new, ACTOR_FLAG_UNKNOWN_10); - spawnableActorList_add(&D_80390688, actor_new, ACTOR_FLAG_UNKNOWN_10); - spawnableActorList_add(&D_803906B0, actor_new, ACTOR_FLAG_NONE); - spawnableActorList_add(&D_803908C0, actor_new, ACTOR_FLAG_UNKNOWN_7); - spawnableActorList_add(&D_803908E4, actor_new, ACTOR_FLAG_UNKNOWN_7); - spawnableActorList_add(&D_80390908, actor_new, ACTOR_FLAG_UNKNOWN_7); - spawnableActorList_add(&D_803909B0, actor_new, ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_11); - spawnableActorList_add(&D_803909D4, actor_new, ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_11); - spawnableActorList_add(&RBB_D_803909F8, actor_new, ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_11); - spawnableActorList_add(&D_80390A50, actor_new, ACTOR_FLAG_UNKNOWN_7); - spawnableActorList_add(&D_80390380, actor_new, ACTOR_FLAG_UNKNOWN_1 | ACTOR_FLAG_UNKNOWN_3 | ACTOR_FLAG_UNKNOWN_5 | ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_8 | ACTOR_FLAG_UNKNOWN_11); - spawnableActorList_add(&D_80390A80, actor_new, ACTOR_FLAG_UNKNOWN_7); //anchorswitch - spawnableActorList_add(&RBB_D_80390AB0, actor_new, ACTOR_FLAG_UNKNOWN_3 | ACTOR_FLAG_UNKNOWN_6 | ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_11); //dolphin - spawnableActorList_add(&RBB_D_80390AE0, actor_new, ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_10 | ACTOR_FLAG_UNKNOWN_11); //anchor - spawnableActorList_add(&RBB_D_80390B10, actor_new, ACTOR_FLAG_UNKNOWN_7); - spawnableActorList_add(&D_80390B40, actor_new, ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_11); //rarewareflag - spawnableActorList_add(&RBB_D_80390BD0, actor_new, ACTOR_FLAG_UNKNOWN_2 | ACTOR_FLAG_UNKNOWN_3 | ACTOR_FLAG_UNKNOWN_5 | ACTOR_FLAG_UNKNOWN_10 | ACTOR_FLAG_UNKNOWN_11); - spawnableActorList_add(&D_80390BF4, actor_new, ACTOR_FLAG_UNKNOWN_2 | ACTOR_FLAG_UNKNOWN_3 | ACTOR_FLAG_UNKNOWN_5 | ACTOR_FLAG_UNKNOWN_10 | ACTOR_FLAG_UNKNOWN_11); - spawnableActorList_add(&D_80390C18, actor_new, ACTOR_FLAG_UNKNOWN_2 | ACTOR_FLAG_UNKNOWN_3 | ACTOR_FLAG_UNKNOWN_5 | ACTOR_FLAG_UNKNOWN_10 | ACTOR_FLAG_UNKNOWN_11); - spawnableActorList_add(&RBB_D_80390C3C, actor_new, ACTOR_FLAG_UNKNOWN_2 | ACTOR_FLAG_UNKNOWN_3 | ACTOR_FLAG_UNKNOWN_5 | ACTOR_FLAG_UNKNOWN_10 | ACTOR_FLAG_UNKNOWN_11); - spawnableActorList_add(&RBB_D_80390CF0, actor_new, ACTOR_FLAG_UNKNOWN_7); - spawnableActorList_add(&D_80390D88, actor_new, ACTOR_FLAG_UNKNOWN_0 | ACTOR_FLAG_UNKNOWN_3 | ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_11 | ACTOR_FLAG_UNKNOWN_25); - spawnableActorList_add(&D_80390DAC, actor_new, ACTOR_FLAG_UNKNOWN_0 | ACTOR_FLAG_UNKNOWN_3 | ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_11 | ACTOR_FLAG_UNKNOWN_25); - spawnableActorList_add(&RBB_D_80390E00, actor_new, ACTOR_FLAG_UNKNOWN_7); - spawnableActorList_add(&D_80390E34, actor_new, ACTOR_FLAG_UNKNOWN_7); - spawnableActorList_add(&D_80390E58, actor_new, ACTOR_FLAG_UNKNOWN_7); - spawnableActorList_add(&D_803900E0, actor_new, ACTOR_FLAG_NONE); - spawnableActorList_add(&D_80390104, actor_new, ACTOR_FLAG_UNKNOWN_9 | ACTOR_FLAG_UNKNOWN_10 | ACTOR_FLAG_UNKNOWN_15); //captcabinwooddoor - spawnableActorList_add(&D_80390128, actor_new, ACTOR_FLAG_NONE); - spawnableActorList_add(&D_8039014C, actor_new, ACTOR_FLAG_NONE); - spawnableActorList_add(&D_803901B8, actor_new, ACTOR_FLAG_UNKNOWN_9 | ACTOR_FLAG_UNKNOWN_10 | ACTOR_FLAG_UNKNOWN_15); - spawnableActorList_add(&D_803901DC, actor_new, ACTOR_FLAG_UNKNOWN_9 | ACTOR_FLAG_UNKNOWN_10 | ACTOR_FLAG_UNKNOWN_15); - spawnableActorList_add(&D_80390170, actor_new, ACTOR_FLAG_UNKNOWN_9 | ACTOR_FLAG_UNKNOWN_10 | ACTOR_FLAG_UNKNOWN_15); //skylight - spawnableActorList_add(&D_80390194, actor_new, ACTOR_FLAG_UNKNOWN_3); //honeycombswitch -} diff --git a/src/RBB/bss_pad.c b/src/RBB/bss_pad.c deleted file mode 100644 index e0e22c075..000000000 --- a/src/RBB/bss_pad.c +++ /dev/null @@ -1,2 +0,0 @@ -// BanjoDecomp: bss_pad.c -char pad_RBB_80391270[0x10]; diff --git a/src/RBB/ch/anchor.c b/src/RBB/ch/anchor.c index 53acfa10c..1072d5bb8 100644 --- a/src/RBB/ch/anchor.c +++ b/src/RBB/ch/anchor.c @@ -3,28 +3,35 @@ #include "functions.h" #include "variables.h" -void func_8038BF28(Actor *this); +void chAnchor_update(Actor *this); /* .data */ -ActorInfo RBB_D_80390AE0 = { - 0x31, 0x1C9, 0x41D, 0x0, NULL, - func_8038BF28, NULL, actor_draw, +ActorInfo chAnchor = { + MARKER_31_ANCHOR, ACTOR_1C9_ANCHOR, ASSET_41D_MODEL_ANCHOR, + 0x0, NULL, + chAnchor_update, NULL, actor_draw, 0, 0, 0.0f, 0 }; +enum chanchor_state_e { + CH_ANCHOR_STATE_0_NOT_INIT, + CH_ANCHOR_STATE_1_LOWERED, + CH_ANCHOR_STATE_2_RAISED +}; + /* .code */ -void RBB_func_8038BEA0(Actor *this, s32 arg1){ - if(arg1 == 1) +void chAnchor_setState(Actor *this, s32 next_state){ + if(next_state == CH_ANCHOR_STATE_1_LOWERED) skeletalAnim_set(this->unk148, ASSET_141_ANIM_ANCHOR_LOWERED, 0.0f, 5.5f); - if(arg1 == 2){ + if(next_state == CH_ANCHOR_STATE_2_RAISED){ skeletalAnim_set(this->unk148, ASSET_142_ANIM_ANCHOR_RISING, 0.0f, 8.0f); skeletalAnim_setBehavior(this->unk148, SKELETAL_ANIM_2_ONCE); } - this->state = arg1; + this->state = next_state; } -void func_8038BF28(Actor *this){ +void chAnchor_update(Actor *this){ if(!this->volatile_initialized){ this->volatile_initialized = true; this->position_x = -5100.0f; @@ -32,14 +39,16 @@ void func_8038BF28(Actor *this){ this->position_z = 1460.0f; this->marker->propPtr->unk8_3 = 1; this->yaw = 0.0f; - RBB_func_8038BEA0(this, 1); + chAnchor_setState(this, CH_ANCHOR_STATE_1_LOWERED); if(jiggyscore_isSpawned(JIGGY_53_RBB_SNORKEL)){ marker_despawn(this->marker); } } else{ - if(this->state == 1 && mapSpecificFlags_get(8)){ - RBB_func_8038BEA0(this, 2); + if(this->state == CH_ANCHOR_STATE_1_LOWERED + && mapSpecificFlags_get(8)) + { + chAnchor_setState(this, CH_ANCHOR_STATE_2_RAISED); } } } diff --git a/src/RBB/ch/anchorctrl.c b/src/RBB/ch/anchorctrl.c index 3cc1bc66c..51d4fc3cc 100644 --- a/src/RBB/ch/anchorctrl.c +++ b/src/RBB/ch/anchorctrl.c @@ -4,21 +4,29 @@ #include "variables.h" -void __chAnchorCtrl_setState(Actor *this, s32 new_state); +void __chAnchorCtrl_setState(Actor *this, s32 next_state); void chAnchorCtrl_update(Actor *this); /* .data */ -ActorInfo RBB_D_80390B10 = { - 0x199, 0x1CB, 0x0, 0x0, NULL, +ActorInfo chAnchorCtrl = { + 0x199, 0x1CB, 0x0, + 0x0, NULL, chAnchorCtrl_update, NULL, func_80325340, 0, 0, 0.0f, 0 }; +enum chanchorctrl_state_e { + CH_ANCHOR_CTRL_STATE_0_NOT_INIT, + CH_ANCHOR_CTRL_STATE_1_LOWERED, + CH_ANCHOR_CTRL_STATE_2_RAISING, + CH_ANCHOR_CTRL_STATE_3_RAISED +}; + /* .code */ void func_8038C000(void){ s32 sp1C = func_802F9AA8(SFX_7D_ANCHOR_LIFTING); - func_802FA060(sp1C, 0x6978, 0x6978, 0.0f); + func_802FA060(sp1C, 27000, 27000, 0.0f); func_802F9F80(sp1C, 0.5f, 7.0f, 0.5f); } @@ -29,26 +37,27 @@ void func_8038C058(void){ } void __chAnchorCtrl_spawnJiggy(ActorMarker *marker, enum asset_e id, s32 arg2){ - static f32 D_80390B34[3] = {-5100.0f, -2550.0f, 1470.0f}; + static f32 chAnchorCtrlJiggyPosition[3] = {-5100.0f, -2550.0f, 1470.0f}; Actor *actor = marker_getActor(marker); - jiggy_spawn(JIGGY_53_RBB_SNORKEL, D_80390B34); - timed_setStaticCameraToNode(0.5f, 0xb); - __chAnchorCtrl_setState(actor, 3); + jiggy_spawn(JIGGY_53_RBB_SNORKEL, chAnchorCtrlJiggyPosition); + timed_setStaticCameraToNode(0.5f, 0xB); + __chAnchorCtrl_setState(actor, CH_ANCHOR_CTRL_STATE_3_RAISED); } -void __chAnchorCtrl_setState(Actor *this, s32 new_state){ - if(new_state == 2){ +void __chAnchorCtrl_setState(Actor *this, s32 next_state){ + if(next_state == CH_ANCHOR_CTRL_STATE_2_RAISING) + { ncStaticCamera_setToNode(0xC); func_80324E38(0.0f, 3); timedFunc_set_0(1.0f, func_8038C000); - timedFunc_set_2(1.0f, (GenFunction_2)mapSpecificFlags_set, 8, true); + timedFunc_set_2(1.0f, (GenFunction_2)mapSpecificFlags_set, RBB_MAIN_SPECIFIC_FLAG_8_UNK, true); timed_playSfx(2.1f, SFX_3F6_RUBBING, 0.6f, 32700); - timedFunc_set_2(2.7f, (GenFunction_2)mapSpecificFlags_set, 4, true); + timedFunc_set_2(2.7f, (GenFunction_2)mapSpecificFlags_set, RBB_MAIN_SPECIFIC_FLAG_4_ANCHOR_LIFTING, true); timedFunc_set_0(3.0f, func_8038C058); - func_80324DBC(3.0f, ASSET_B9C_DIALOG_SNORKEL_COMPLETE, 7, NULL, this->marker, __chAnchorCtrl_spawnJiggy, NULL); + func_80324DBC(3.0f, VER_SELECT(ASSET_B9C_DIALOG_SNORKEL_COMPLETE, 0x971, 0, 0), 7, NULL, this->marker, __chAnchorCtrl_spawnJiggy, NULL); }//L8038C1D8 - this->state = new_state; + this->state = next_state; } void chAnchorCtrl_update(Actor *this){ @@ -56,17 +65,19 @@ void chAnchorCtrl_update(Actor *this){ this->volatile_initialized = true; if (levelSpecificFlags_getSet(LEVEL_FLAG_30_RBB_UNKNOWN, false)) { - __chAnchorCtrl_setState(this, 2); + __chAnchorCtrl_setState(this, CH_ANCHOR_CTRL_STATE_2_RAISING); } else { - __chAnchorCtrl_setState(this, 1); + __chAnchorCtrl_setState(this, CH_ANCHOR_CTRL_STATE_1_LOWERED); } if(jiggyscore_isSpawned(JIGGY_53_RBB_SNORKEL)) marker_despawn(this->marker); }//L8038C27C - if(this->state == 3 && !mapSpecificFlags_get(4)){ + if(this->state == CH_ANCHOR_CTRL_STATE_3_RAISED + && !mapSpecificFlags_get(RBB_MAIN_SPECIFIC_FLAG_4_ANCHOR_LIFTING)) + { timed_exitStaticCamera(0.0f); func_80324E38(0.0f, 0); timedFunc_set_0(0.0f, musicKeepsPlaying); diff --git a/src/RBB/ch/anchorswitch.c b/src/RBB/ch/anchorswitch.c index 92754c457..0d3aa33e2 100644 --- a/src/RBB/ch/anchorswitch.c +++ b/src/RBB/ch/anchorswitch.c @@ -6,33 +6,40 @@ void chAnchorSwitch_update(Actor *this); /* .data */ -ActorInfo D_80390A80 = { - 0x2F, 0x1C7, 0x41B, 0x0, NULL, +ActorInfo chAnchorSwitch = { + MARKER_2F_ANCHOR_SWITCH, ACTOR_1C7_ANCHOR_SWITCH, ASSET_41B_MODEL_ANCHOR_SWITCH, + 0x0, NULL, chAnchorSwitch_update, NULL, actor_draw, 0, 0, 0.0f, 0 }; +enum chanchorswitch_state_e { + CH_ANCHOR_SWITCH_STATE_0_NOT_INIT, + CH_ANCHOR_SWITCH_STATE_1_NOT_PRESSED, + CH_ANCHOR_SWITCH_STATE_2_PRESSED +}; + /* .code */ -void __chAnchorSwitch_setState(Actor *this, s32 arg1){ - if(arg1 == 2){ - if(this->state == 1){ +void __chAnchorSwitch_setState(Actor *this, s32 next_state){ + if(next_state == CH_ANCHOR_SWITCH_STATE_2_PRESSED){ + if(this->state == CH_ANCHOR_SWITCH_STATE_1_NOT_PRESSED){ func_8030E6D4(SFX_90_SWITCH_PRESS); } actor_collisionOff(this); this->position_y -= 35.0f; - if(this->state == 1){ + if(this->state == CH_ANCHOR_SWITCH_STATE_1_NOT_PRESSED){ levelSpecificFlags_set(LEVEL_FLAG_30_RBB_UNKNOWN, true); volatileFlag_set(VOLATILE_FLAG_E, 1); timedFunc_set_0(1.0f, musicKeepsPlaying); timedFunc_set_3(1.0f, (GenFunction_3)transitionToMap, MAP_31_RBB_RUSTY_BUCKET_BAY, 0, 0); } } - this->state = arg1; + this->state = next_state; } void __chAnchorSwitch_press(ActorMarker *marker, ActorMarker *arg1){ Actor *actor = marker_getActor(marker); - __chAnchorSwitch_setState(actor, 2); + __chAnchorSwitch_setState(actor, CH_ANCHOR_SWITCH_STATE_2_PRESSED); } void chAnchorSwitch_update(Actor *this){ @@ -41,8 +48,8 @@ void chAnchorSwitch_update(Actor *this){ this->marker->propPtr->unk8_3 = 1; marker_setCollisionScripts(this->marker, NULL, __chAnchorSwitch_press, NULL); if(jiggyscore_isSpawned(JIGGY_53_RBB_SNORKEL)) - __chAnchorSwitch_setState(this, 2); + __chAnchorSwitch_setState(this, CH_ANCHOR_SWITCH_STATE_2_PRESSED); else - __chAnchorSwitch_setState(this, 1); + __chAnchorSwitch_setState(this, CH_ANCHOR_SWITCH_STATE_1_NOT_PRESSED); } } diff --git a/src/RBB/ch/axle.c b/src/RBB/ch/axle.c index da1f91bab..619da6ef7 100644 --- a/src/RBB/ch/axle.c +++ b/src/RBB/ch/axle.c @@ -6,73 +6,96 @@ /* typedefs and declarations */ typedef struct { s16 unk0; - f32 unk4[3]; - f32 unk10; + f32 position[3]; + f32 startingRoll; f32 unk14; f32 unk18[3]; -}ActorLocal_RBB_2A70_0; +} ActorLocal_ChSpinningFlatPlatform_0; typedef struct { - ActorLocal_RBB_2A70_0 *unk0; - f32 unk4[3]; - f32 unk10[3]; + ActorLocal_ChSpinningFlatPlatform_0 *unk0; + f32 currentRotation[3]; + f32 nextRotation[3]; f32 unk1C; u8 pad20[0x4]; f32 unk24; -}ActorLocal_RBB_2A70; +} ActorLocal_ChSpinningFlatPlatform; -void func_803890BC(Actor *this); +void chSpinningFlatPlatform_update(Actor *this); /* .data */ -ActorLocal_RBB_2A70_0 D_80390430[] = { - {ACTOR_178_RBB_SPINNING_FLAT_PLATFORM_1, {0.0f, -60.0f, 2450.0f}, 0.0f, 6.0f, { 0.0f, -100.0f, 1900.0f}}, - {ACTOR_179_RBB_SPINNING_FLAT_PLATFORM_2, {-1600.0f, 730.0f, -700.0f}, 270.0f, 6.0f, { -1600.0f, 810.0f, -1400.0f}}, - {ACTOR_17A_RBB_SPINNING_FLAT_PLATFORM_3, {1600.0f, 730.0f, -700.0f}, 270.0f, 5.0f, { 1600.0f, 810.0f, -1400.0f}}, - 0 +ActorLocal_ChSpinningFlatPlatform_0 chSpinningFlatPlatformTable[] = { + { + ACTOR_178_RBB_SPINNING_FLAT_PLATFORM_1, + {0.0f, -60.0f, 2450.0f}, + 0.0f, + 6.0f, + {0.0f, -100.0f, 1900.0f} + }, + { + ACTOR_179_RBB_SPINNING_FLAT_PLATFORM_2, + {-1600.0f, 730.0f, -700.0f}, + 270.0f, + 6.0f, + { -1600.0f, 810.0f, -1400.0f}}, + { + ACTOR_17A_RBB_SPINNING_FLAT_PLATFORM_3, + {1600.0f, 730.0f, -700.0f}, + 270.0f, + 5.0f, + {1600.0f, 810.0f, -1400.0f} + }, + { 0 } // [port] decomp uses NULL; actorId is s16 and clang errors on -Wint-conversion }; -ActorInfo D_803904C0 = { - 0x188, 0x178, 0x40C, 0x0, NULL, - func_803890BC, NULL, actor_draw, +ActorInfo chSpinningFlatPlatform1 = { + MARKER_188_RBB_SPINNING_FLAT_PLATFORM_1, ACTOR_178_RBB_SPINNING_FLAT_PLATFORM_1, ASSET_40C_MODEL_RBB_SPINNING_FLAT_PLATFORM_1, 0x0, NULL, + chSpinningFlatPlatform_update, NULL, actor_draw, 0, 0, 0.0f, 0 }; -ActorInfo D_803904E4 = { - 0x189, 0x179, 0x40D, 0x0, NULL, - func_803890BC, NULL, actor_draw, +ActorInfo chSpinningFlatPlatform2 = { + MARKER_189_RBB_SPINNING_FLAT_PLATFORM_2, ACTOR_179_RBB_SPINNING_FLAT_PLATFORM_2, ASSET_40D_MODEL_RBB_SPINNING_FLAT_PLATFORM_2, 0x0, NULL, + chSpinningFlatPlatform_update, NULL, actor_draw, 0, 0, 0.0f, 0 }; -ActorInfo D_80390508 = { - 0x18A, 0x17A, 0x40E, 0x0, NULL, - func_803890BC, NULL, actor_draw, +ActorInfo chSpinningFlatPlatform3 = { + MARKER_18A_RBB_SPINNING_FLAT_PLATFORM_3, ACTOR_17A_RBB_SPINNING_FLAT_PLATFORM_3, ASSET_40E_MODEL_RBB_SPINNING_FLAT_PLATFORM_3, 0x0, NULL, + chSpinningFlatPlatform_update, NULL, actor_draw, 0, 0, 0.0f, 0 }; +enum chspinningflatplatform_state_e { + CH_SPINNING_FLAT_PLATFORM_STATE_0_NOT_INIT, + CH_SPINNING_FLAT_PLATFORM_STATE_1_IDLE, + CH_SPINNING_FLAT_PLATFORM_STATE_2_ROTATING +}; + /* .code */ -ActorLocal_RBB_2A70_0 *func_80388E60(Actor *this){ - ActorLocal_RBB_2A70_0 * iPtr; - for(iPtr = D_80390430; iPtr->unk0 != 0; iPtr++){ +ActorLocal_ChSpinningFlatPlatform_0 *func_80388E60(Actor *this){ + ActorLocal_ChSpinningFlatPlatform_0 * iPtr; + for(iPtr = chSpinningFlatPlatformTable; iPtr->unk0 != 0; iPtr++){ if(iPtr->unk0 == this->modelCacheIndex) return iPtr; } return NULL; } -void func_80388EB8(Actor *this, s32 arg1){ - ActorLocal_RBB_2A70 *local = (ActorLocal_RBB_2A70 *)&this->local; +void chSpinningFlatPlatform_setState(Actor *this, s32 next_state){ + ActorLocal_ChSpinningFlatPlatform *local = (ActorLocal_ChSpinningFlatPlatform *)&this->local; s32 sp30; - if(this->state == 2) + if(this->state == CH_SPINNING_FLAT_PLATFORM_STATE_2_ROTATING) sfx_playFadeShorthandDefault(SFX_7F_HEAVYDOOR_SLAM, 0.8f, 32000, this->position, 1000, 2300); - this->state = arg1; + this->state = next_state; local->unk24 = 0.0f; - if(this->state == 1) + if(this->state == CH_SPINNING_FLAT_PLATFORM_STATE_1_IDLE) local->unk24 = local->unk0->unk14; - if(this->state == 2){ + if(this->state == CH_SPINNING_FLAT_PLATFORM_STATE_2_ROTATING){ sp30 = func_802F9AA8(SFX_94_COGS_ROTATING); func_802F9DB8(sp30, 1.0f, 1.0f, 0.0f); func_802F9EC4(sp30, local->unk0->unk18, 1700, 2500); @@ -82,49 +105,52 @@ void func_80388EB8(Actor *this, s32 arg1){ this->yaw += ( 360.0f <= this->yaw) ? -360 : 0; this->roll += ( 360.0f <= this->roll) ? -360 : 0; - local->unk4[0] = this->pitch; - local->unk4[1] = this->yaw; - local->unk4[2] = this->roll; + local->currentRotation[0] = this->pitch; + local->currentRotation[1] = this->yaw; + local->currentRotation[2] = this->roll; - local->unk10[0] = this->pitch; - local->unk10[1] = this->yaw; - local->unk10[2] = this->roll + 360.0f; + local->nextRotation[0] = this->pitch; + local->nextRotation[1] = this->yaw; + local->nextRotation[2] = this->roll + 360.0f; local->unk1C = 0.0f; sfx_playFadeShorthandDefault(SFX_7F_HEAVYDOOR_SLAM, 0.8f, 32000, this->position, 900, 1800); }//L803890A8 } -void func_803890BC(Actor *this){ - ActorLocal_RBB_2A70 *local = (ActorLocal_RBB_2A70 *)&this->local; - f32 sp38 = time_getDelta(); - f32 sp2C[3]; +void chSpinningFlatPlatform_update(Actor *this){ + ActorLocal_ChSpinningFlatPlatform *local = (ActorLocal_ChSpinningFlatPlatform *)&this->local; + f32 time_delta = time_getDelta(); + f32 rotation[3]; + if(!this->volatile_initialized){ actor_collisionOff(this); this->marker->propPtr->unk8_3 = 1; this->volatile_initialized = true; local->unk0 = func_80388E60(this); - this->position[0] = local->unk0->unk4[0]; - this->position[1] = local->unk0->unk4[1]; - this->position[2] = local->unk0->unk4[2]; - this->roll = local->unk0->unk10; - if(this->state == 0) - func_80388EB8(this, 1); + this->position[0] = local->unk0->position[0]; + this->position[1] = local->unk0->position[1]; + this->position[2] = local->unk0->position[2]; + this->roll = local->unk0->startingRoll; + if(this->state == CH_SPINNING_FLAT_PLATFORM_STATE_0_NOT_INIT) + chSpinningFlatPlatform_setState(this, CH_SPINNING_FLAT_PLATFORM_STATE_1_IDLE); }//L80389164 - if(ml_timer_update(&local->unk24, sp38)) - func_80388EB8(this, (this->state == 1) ? 2 : 1); + if(ml_timer_update(&local->unk24, time_delta)) + chSpinningFlatPlatform_setState(this, + (this->state == CH_SPINNING_FLAT_PLATFORM_STATE_1_IDLE) ? + CH_SPINNING_FLAT_PLATFORM_STATE_2_ROTATING : CH_SPINNING_FLAT_PLATFORM_STATE_1_IDLE); //L803891A8 - if(this->state == 2){ - local->unk1C += 0.25 * sp38; + if(this->state == CH_SPINNING_FLAT_PLATFORM_STATE_2_ROTATING){ + local->unk1C += 0.25 * time_delta; if(1.0f < local->unk1C) local->unk1C = 1.0f; - ml_vec3f_interpolate_fast(sp2C, local->unk4, local->unk10, local->unk1C); - this->pitch = sp2C[0]; - this->yaw = sp2C[1]; - this->roll = sp2C[2]; + ml_vec3f_interpolate_fast(rotation, local->currentRotation, local->nextRotation, local->unk1C); + this->pitch = rotation[0]; + this->yaw = rotation[1]; + this->roll = rotation[2]; if(local->unk1C == 1.0f) - func_80388EB8(this, 1); + chSpinningFlatPlatform_setState(this, CH_SPINNING_FLAT_PLATFORM_STATE_1_IDLE); }//L80389264 } diff --git a/src/RBB/ch/bellbuoy.c b/src/RBB/ch/bellbuoy.c index 0ac91646b..04937bccf 100644 --- a/src/RBB/ch/bellbuoy.c +++ b/src/RBB/ch/bellbuoy.c @@ -8,118 +8,127 @@ /* typedefs and declarations */ typedef struct { f32 unk0; - ActorMarker *unk4; - f32 unk8[3]; - f32 unk14[3]; + ActorMarker *jinjoMarker; + f32 position[3]; + f32 rotation[3]; s32 unk20; - f32 unk24[3]; -}ActorLocal_7B20; + f32 timer[3]; +} ActorLocal_7B20; -void func_8038DF6C(Actor* this); +void chBellBuoy_update(Actor* this); /* .data */ -ActorInfo D_80390D20 = { - 0x1AA, 0x296, 0x43B, 0x0, NULL, - func_8038DF6C, NULL, actor_draw, +ActorInfo chBellBuoy = { + MARKER_1AA_BELL_BUOY, ACTOR_296_BELL_BUOY, ASSET_43B_MODEL_BELL_BUOY, + 0x0, NULL, + chBellBuoy_update, NULL, actor_draw, 0, 0, 0.0f, 0 }; +enum chbellbuoy_state_e { + CH_BELL_BUOY_STATE_0_NOT_INIT, + CH_BELL_BUOY_STATE_1_INIT +}; /*.code */ -void func_8038DF10(Actor *this, int arg1){ - if(arg1 == 1){ - skeletalAnim_set(this->unk148, 0x16a, 0, 1.2f); +void chBellBuoy_setState(Actor *this, int next_state){ + if(next_state == CH_BELL_BUOY_STATE_1_INIT){ + skeletalAnim_set(this->unk148, ASSET_16A_ANIM_BELL_BUOY, 0, 1.2f); } - this->state = arg1; + this->state = next_state; } -void func_8038DF6C(Actor* this){ - f32 sp7C[3]; - f32 sp70[3]; +void chBellBuoy_update(Actor* this){ + f32 rotation_delta[3]; + f32 position_delta[3]; f32 sp6C; - f32 sp68 = time_getDelta(); - f32 sp5C[3]; - f32 sp58; + f32 time_delta = time_getDelta(); + f32 new_rotation[3]; + f32 distance; ActorLocal_7B20 *local = (ActorLocal_7B20 *)&this->local; - Actor* other; - int i; + Actor* jinjo; + int actor_id; if(!this->volatile_initialized){ this->marker->propPtr->unk8_3 = 1; this->volatile_initialized = true; local->unk0 = randf2(80.0f, 100.0f); - local->unk4 = NULL; + local->jinjoMarker = NULL; local->unk20 = 0; - local->unk24[0] = 0.0f; - local->unk24[1] = 1.0f; - local->unk24[2] = 0.5f; - local->unk8[0] = this->position_x; - local->unk8[1] = this->position_y; - local->unk8[2] = this->position_z; - local->unk14[0] = this->pitch; - local->unk14[1] = this->yaw; - local->unk14[2] = this->roll; - func_8038DF10(this, 1); + local->timer[0] = 0.0f; + local->timer[1] = 1.0f; + local->timer[2] = 0.5f; + local->position[0] = this->position_x; + local->position[1] = this->position_y; + local->position[2] = this->position_z; + local->rotation[0] = this->pitch; + local->rotation[1] = this->yaw; + local->rotation[2] = this->roll; + chBellBuoy_setState(this, CH_BELL_BUOY_STATE_1_INIT); }//L8038E050 + if(++local->unk20 == 2){ - for(i = 0x5e; i < 0x63; i++){ + // Actor 0x5E through 0x62 are Jinjos + for(actor_id = 0x5E; actor_id < 0x63; actor_id++){ - other = actorArray_findClosestActorFromActorId(this->position, i, -1, &sp58); - if(sp58 < 300.0f){ - local->unk4 = other->marker; - other->position_x = this->position_x; - other->position_y = this->position_y; - other->position_z = this->position_z; + jinjo = actorArray_findClosestActorFromActorId(this->position, actor_id, -1, &distance); + if(distance < 300.0f){ + local->jinjoMarker = jinjo->marker; + jinjo->position_x = this->position_x; + jinjo->position_y = this->position_y; + jinjo->position_z = this->position_z; break; } } } - if(ml_timer_update(&local->unk24[1], sp68)){ - local->unk24[1] = randf2(1.5f, 2.5f); + + if(ml_timer_update(&local->timer[1], time_delta)){ + local->timer[1] = randf2(1.5f, 2.5f); sfx_playFadeShorthandDefault(SFX_40E_UNKNOWN, 1.5f, 20000, this->position, 500, 1500); }//L8038E118 - if(ml_timer_update(&local->unk24[2], sp68)){ - local->unk24[2] = randf2(3.5f, 5.5f); - func_8030E878(SFX_69_WHIPCRACK_CREAKING, randf2(1.1f, 1.2f), 0x55f0, this->position, 500.0f, 1500.0f); + if(ml_timer_update(&local->timer[2], time_delta)){ + local->timer[2] = randf2(3.5f, 5.5f); + func_8030E878(SFX_69_WHIPCRACK_CREAKING, randf2(1.1f, 1.2f), 22000, this->position, 500.0f, 1500.0f); }//L8038E184 - local->unk24[0] += sp68; - sp70[0] = 0.0f; - sp70[1] = sinf((local->unk24[0]*local->unk0)/ 180.0 * 3.141592654) * 10.0f; - sp70[2] = 0.0f; + local->timer[0] += time_delta; + position_delta[0] = 0.0f; + position_delta[1] = sinf((local->timer[0] * local->unk0) / 180.0 * BAD_PI) * 10.0f; + position_delta[2] = 0.0f; - sp7C[0] = cosf((local->unk24[0]*local->unk0)/ 180.0 * 3.141592654)*7.5; - sp7C[1] = sinf((local->unk24[0]*local->unk0)/ 180.0 * 3.141592654)*3.0; - sp7C[2] = 0.0f; + rotation_delta[0] = cosf((local->timer[0] * local->unk0) / 180.0 * BAD_PI) * 7.5; + rotation_delta[1] = sinf((local->timer[0] * local->unk0) / 180.0 * BAD_PI) * 3.0; + rotation_delta[2] = 0.0f; - this->position_x = local->unk8[0] + sp70[0]; - this->position_y = local->unk8[1] + sp70[1]; - this->position_z = local->unk8[2] + sp70[2]; + this->position_x = local->position[0] + position_delta[0]; + this->position_y = local->position[1] + position_delta[1]; + this->position_z = local->position[2] + position_delta[2]; - sp5C[0] = local->unk14[0] + sp7C[0]; - sp5C[1] = local->unk14[1] + sp7C[1]; - sp5C[2] = local->unk14[2] + sp7C[2]; + new_rotation[0] = local->rotation[0] + rotation_delta[0]; + new_rotation[1] = local->rotation[1] + rotation_delta[1]; + new_rotation[2] = local->rotation[2] + rotation_delta[2]; - this->pitch = sp5C[0]; - this->yaw = sp5C[1]; - this->roll = sp5C[2]; + this->pitch = new_rotation[0]; + this->yaw = new_rotation[1]; + this->roll = new_rotation[2]; - if(local->unk4){ - other = marker_getActor(local->unk4); - if(!(other->state < 7)){ - local->unk4 = NULL; + if(local->jinjoMarker){ + jinjo = marker_getActor(local->jinjoMarker); + // State 7-9 Are Collecting Jinjo States + if(!(jinjo->state < 7)){ + local->jinjoMarker = NULL; }else{ - other->pitch = sp5C[0]; - other->roll = sp5C[2]; - TUPLE_ASSIGN(sp5C, 0.0f, 48.0f, 0.0f); - ml_vec3f_pitch_rotate_copy(sp5C, sp5C, this->pitch); - ml_vec3f_yaw_rotate_copy(sp5C, sp5C, this->yaw); + jinjo->pitch = new_rotation[0]; + jinjo->roll = new_rotation[2]; + TUPLE_ASSIGN(new_rotation, 0.0f, 48.0f, 0.0f); + ml_vec3f_pitch_rotate_copy(new_rotation, new_rotation, this->pitch); + ml_vec3f_yaw_rotate_copy(new_rotation, new_rotation, this->yaw); - other->position_x = sp5C[0] + this->position_x; - other->position_y = sp5C[1] + this->position_y; - other->position_z = sp5C[2] + this->position_z; + jinjo->position_x = new_rotation[0] + this->position_x; + jinjo->position_y = new_rotation[1] + this->position_y; + jinjo->position_z = new_rotation[2] + this->position_z; } }//L8038E39C } diff --git a/src/RBB/ch/boombox.c b/src/RBB/ch/boombox.c index c33cbace4..4d9d66c83 100644 --- a/src/RBB/ch/boombox.c +++ b/src/RBB/ch/boombox.c @@ -15,8 +15,8 @@ typedef struct { f32 *unk0; f32 unk4; f32 unk8[3]; - f32 unk14[3]; - f32 unk20[3]; + f32 currentPosition[3]; + f32 targetPosition[3]; f32 unk2C; f32 unk30; s32 unk34; @@ -24,29 +24,38 @@ typedef struct { u8 unk39; }ActorLocal_RBB_8520; -void func_8038F190(Actor *this, s32 arg1); -Actor *func_8038F4B0(ActorMarker *marker, Gfx **gdl, Mtx **mptr, Vtx **arg3); -void func_8038F618(Actor *this); +void chBoomBox_setState(Actor *this, s32 arg1); +Actor *chBoomBox_draw(ActorMarker *marker, Gfx **gdl, Mtx **mptr, Vtx **arg3); +void chBoomBox_update(Actor *this); /* .data */ f32 D_80390D80[2] = {1.8f, 1.0f}; -ActorInfo D_80390D88 = { - MARKER_1B7_BOOM_BOX, ACTOR_2A4_BOOM_BOX_SLOW, ASSET_48C_MODEL_BOOM_BOX, 0x0, NULL, - func_8038F618, NULL, func_8038F4B0, +ActorInfo chBoomBoxSlow = { + MARKER_1B7_BOOM_BOX, ACTOR_2A4_BOOM_BOX_SLOW, ASSET_48C_MODEL_BOOM_BOX, + 0x0, NULL, + chBoomBox_update, NULL, chBoomBox_draw, 0, 0, 0.0f, 0 }; -ActorInfo D_80390DAC = { - MARKER_1B7_BOOM_BOX, ACTOR_30D_BOOM_BOX_FAST, ASSET_48C_MODEL_BOOM_BOX, 0x0, NULL, - func_8038F618, NULL, func_8038F4B0, +ActorInfo chBoomBoxFast = { + MARKER_1B7_BOOM_BOX, ACTOR_30D_BOOM_BOX_FAST, ASSET_48C_MODEL_BOOM_BOX, + 0x0, NULL, + chBoomBox_update, NULL, chBoomBox_draw, 0, 0, 0.0f, 0 }; s32 RBB_D_80390DD0[3] = {0xDE, 0xA7, 0x71}; s32 D_80390DDC[4] = {0xFF, 0xFF, 0xFF, 0xFF}; -f32 D_80390DEC[4] = {0.0f, 0.0f , 0.0f, 0.0f}; +f32 D_80390DEC[4] = {0.0f, 0.0f, 0.0f, 0.0f}; + +enum chboombox_state_e { + CH_BOOM_BOX_STATE_0_NOT_INIT, + CH_BOOM_BOX_STATE_1_UNK, + CH_BOOM_BOX_STATE_2_UNK, + CH_BOOM_BOX_STATE_3_EXPLODE +}; /* .bss */ f32 D_803912A0[3]; @@ -65,13 +74,13 @@ void func_8038E920(Actor *this){ void func_8038E92C(Actor *this){ ActorLocal_RBB_8520 *local = (ActorLocal_RBB_8520 *)&this->local; - if(this->state == 2 && local->unk34 == 0) + if(this->state == CH_BOOM_BOX_STATE_2_UNK && local->unk34 == 0) return; if(ml_timer_update( &local->unk30, time_getDelta())) - func_8038F190(this, 3); + chBoomBox_setState(this, CH_BOOM_BOX_STATE_3_EXPLODE); } -void func_8038E998(Actor *this){ +void chBoomBox_emitSmokeBeforeExplosion(Actor *this){ ParticleEmitter *other = partEmitMgr_newEmitter(2); f32 temp_f0; @@ -87,7 +96,7 @@ void func_8038E998(Actor *this){ particleEmitter_emitN(other, 2); } -void func_8038EAB4(Actor *this){ +void chBoomBox_emitExplosion(Actor *this){ ParticleEmitter *other; func_802BB3DC(0, 60.0f, 0.9f); other = partEmitMgr_newEmitter(1); @@ -105,7 +114,7 @@ void func_8038EAB4(Actor *this){ particleEmitter_emitN(other, 1); } -void func_8038EC14(Actor *this){ +void chBoomBox_emitSmokeAfterExplosion(Actor *this){ ParticleEmitter *other; other = partEmitMgr_newEmitter(6); particleEmitter_setSprite(other, ASSET_70E_SPRITE_SMOKE_2); @@ -121,7 +130,7 @@ void func_8038EC14(Actor *this){ particleEmitter_emitN(other, 6); } -void func_8038ED3C(Actor * actor, s32 arg1){ +void chBoomBox_emitModelsAfterExplosion(Actor * actor, s32 arg1){ ParticleEmitter *other = partEmitMgr_newEmitter(0xa); particleEmitter_setAccelerationRange(other, 0.0f, -800.0f, 0.0f, 0.0f, -800.0f, 0.0f); particleEmitter_func_802EF9F8(other, 0.6f); @@ -141,77 +150,77 @@ int func_8038EE90(Actor *this){ f32 sp20[3]; ActorLocal_RBB_8520 *local = (ActorLocal_RBB_8520 *)&this->local; - sp2C[0] = local->unk14[0]; - sp2C[1] = local->unk14[1]; - sp2C[2] = local->unk14[2]; + sp2C[0] = local->currentPosition[0]; + sp2C[1] = local->currentPosition[1]; + sp2C[2] = local->currentPosition[2]; - sp20[0] = local->unk20[0]; - sp20[1] = local->unk20[1]; - sp20[2] = local->unk20[2]; + sp20[0] = local->targetPosition[0]; + sp20[1] = local->targetPosition[1]; + sp20[2] = local->targetPosition[2]; sp2C[1] += 75.0f; sp20[1] += 75.0f; return func_803342AC(&sp2C, &sp20, 100.0f); } -int func_8038EF08(Actor *this, f32 position[3], f32 arg2){ - f32 sp54[3]; - int sp50; +bool chBoombox_isValidMovePosition(Actor *this, f32 position[3], f32 speed_multiplier){ + f32 position_diff[3]; + bool ceiling_exists; ActorLocal_RBB_8520 *local = (ActorLocal_RBB_8520 *)&this->local; - f32 sp40[3]; - f32 sp3C; - f32 sp30[3]; + f32 ceiling_check_position[3]; + f32 collision_radius; + f32 ceiling_collision_output[3]; - sp54[0] = position[0] - this->position_x; - sp54[1] = position[1] - this->position_y; - sp54[2] = position[2] - this->position_z; - if(180.0 < LENGTH_VEC3F(sp54)) - ml_vec3f_set_length(sp54, 150.0f); + position_diff[0] = position[0] - this->position_x; + position_diff[1] = position[1] - this->position_y; + position_diff[2] = position[2] - this->position_z; + if(180.0 < LENGTH_VEC3F(position_diff)) + ml_vec3f_set_length(position_diff, 150.0f); - local->unk20[0] = sp54[0] + this->position_x; - local->unk20[1] = sp54[1] + this->position_y; - local->unk20[2] = sp54[2] + this->position_z; - - local->unk20[1] = mapModel_getFloorY(local->unk20); - - sp40[0] = local->unk20[0]; - sp40[1] = local->unk20[1] + this->scale*100.0f; - sp40[2] = local->unk20[2]; - sp3C = this->scale*60.0f; - if(func_80309EB0(&sp40, sp3C, &sp30, 0)){ - sp50 = 1; + local->targetPosition[0] = position_diff[0] + this->position_x; + local->targetPosition[1] = position_diff[1] + this->position_y; + local->targetPosition[2] = position_diff[2] + this->position_z; + + local->targetPosition[1] = mapModel_getFloorY(local->targetPosition); + + ceiling_check_position[0] = local->targetPosition[0]; + ceiling_check_position[1] = local->targetPosition[1] + this->scale * 100.0f; + ceiling_check_position[2] = local->targetPosition[2]; + collision_radius = this->scale * 60.0f; + if(func_80309EB0(&ceiling_check_position, collision_radius, &ceiling_collision_output, 0)){ + ceiling_exists = true; }else{ - sp50 = 0; + ceiling_exists = false; } - if( !func_80329210(this, &local->unk20) - || ((local->unk2C + 30.0f) < local->unk20[1]) - || sp50 + if( !func_80329210(this, &local->targetPosition) + || ((local->unk2C + 30.0f) < local->targetPosition[1]) + || ceiling_exists ){ - local->unk20[0] = this->position_x; - local->unk20[1] = this->position_y; - local->unk20[2] = this->position_z; + local->targetPosition[0] = this->position_x; + local->targetPosition[1] = this->position_y; + local->targetPosition[2] = this->position_z; if(local->unk39 < 3 && ++local->unk39 == 3){ local->unk39 = 0; - return 0; + return false; } }else{ local->unk34 = func_8038EE90(this); if(local->unk34 == 0){ - local->unk20[0] = this->position_x; - local->unk20[1] = this->position_y; - local->unk20[2] = this->position_z; + local->targetPosition[0] = this->position_x; + local->targetPosition[1] = this->position_y; + local->targetPosition[2] = this->position_z; } } - skeletalAnim_set(this->unk148, ASSET_147_ANIM_BOOMBOX_MOVE, 0.1f, randf2(-0.1f, 0.1f) + (1.0/arg2)*0.4); + skeletalAnim_set(this->unk148, ASSET_147_ANIM_BOOMBOX_MOVE, 0.1f, randf2(-0.1f, 0.1f) + (1.0 / speed_multiplier) * 0.4); skeletalAnim_setBehavior(this->unk148, SKELETAL_ANIM_2_ONCE); - local->unk14[0] = this->position_x; - local->unk14[1] = this->position_y; - local->unk14[2] = this->position_z; - return 1; + local->currentPosition[0] = this->position_x; + local->currentPosition[1] = this->position_y; + local->currentPosition[2] = this->position_z; + return true; } -void func_8038F190(Actor *this, s32 arg1){ +void chBoomBox_setState(Actor *this, s32 next_state){ f32 player_position[3]; ActorLocal_RBB_8520 *local = (ActorLocal_RBB_8520 *)&this->local; @@ -222,68 +231,68 @@ void func_8038F190(Actor *this, s32 arg1){ local->unk34 = false; } - if(arg1 == 1){ + if(next_state == CH_BOOM_BOX_STATE_1_UNK){ skeletalAnim_set(this->unk148, ASSET_147_ANIM_BOOMBOX_MOVE, 0.2f, 1.0f); skeletalAnim_setBehavior(this->unk148, SKELETAL_ANIM_4_STOPPED); }//L8038F204 - if(arg1 == 2){ - int sp3C = 0; + if(next_state == CH_BOOM_BOX_STATE_2_UNK){ + bool is_valid_move_position = false; if(func_80329210(this, &player_position)){ local->unk4 += 0.3; if(*local->unk0 < local->unk4) local->unk4 = *local->unk0; - sp3C = func_8038EF08(this, player_position, local->unk4); + is_valid_move_position = chBoombox_isValidMovePosition(this, player_position, local->unk4); }//L8038F28C - if(!sp3C){ + if(!is_valid_move_position){ func_8038E920(this); local->unk4 -= 0.5; if(local->unk4 < 0.5) local->unk4 = 0.5f; - func_8038EF08(this, local->unk8, local->unk4); + chBoombox_isValidMovePosition(this, local->unk8, local->unk4); } }//L8038F2FC - if(arg1 == 3){ - func_8038FB6C(); + if(next_state == CH_BOOM_BOX_STATE_3_EXPLODE){ + chBoomBoxMinigameCtrl_countDec(); actor_collisionOff(this); func_80324D54(0.0f, SFX_1B_EXPLOSION_1, 1.0f, 0x7d00, this->position, 1000.0f, 2000.0f); skeletalAnim_set(this->unk148, ASSET_148_ANIM_BOOMBOX_DIE, 0.2f, 1.0f); skeletalAnim_setBehavior(this->unk148, SKELETAL_ANIM_2_ONCE); - func_8038EAB4(this); - func_8038EC14(this); - func_8038ED3C(this, 0x53a); - func_8038ED3C(this, 0x53b); - func_8038ED3C(this, 0x53c); + chBoomBox_emitExplosion(this); + chBoomBox_emitSmokeAfterExplosion(this); + chBoomBox_emitModelsAfterExplosion(this, ASSET_53A_MODEL_SHRAPNAL_PIECE_EYE); + chBoomBox_emitModelsAfterExplosion(this, ASSET_53B_MODEL_SHRAPNAL_PIECE_SPIKE); + chBoomBox_emitModelsAfterExplosion(this, ASSET_53C_MODEL_SHRAPNAL_PIECE_PLATE); func_80326310(this); this->unk10_1 = 0; func_8038E920(this); }//L8038F3C8 - this->state = arg1; + this->state = next_state; } void func_8038F3F0(ActorMarker *marker, ActorMarker *arg1){ Actor* actor = marker_getActor(marker); if(actor->state < 3){ - func_8038F190(actor, 3); + chBoomBox_setState(actor, CH_BOOM_BOX_STATE_3_EXPLODE); } } void func_8038F430(ActorMarker *marker, ActorMarker *arg1){ Actor* actor = marker_getActor(marker); - f32 sp18[3]; + f32 player_position[3]; if(actor->state < 3){ - player_getPosition(sp18); - if(ml_vec3f_distance(actor->position, sp18) < 300.0f) + player_getPosition(player_position); + if(ml_vec3f_distance(actor->position, player_position) < 300.0f) func_8028F55C(5, actor->marker); - func_8038F190(actor, 3); + chBoomBox_setState(actor, CH_BOOM_BOX_STATE_3_EXPLODE); }//L8038F4A4 } -Actor * func_8038F4B0(ActorMarker *marker, Gfx **gdl, Mtx **mptr, Vtx **arg3){ +Actor * chBoomBox_draw(ActorMarker *marker, Gfx **gdl, Mtx **mptr, Vtx **arg3){ Actor *actor; ActorLocal_RBB_8520 *local; s32 sp28[4]; @@ -292,10 +301,10 @@ Actor * func_8038F4B0(ActorMarker *marker, Gfx **gdl, Mtx **mptr, Vtx **arg3){ actor = marker_getActor(marker); local = (ActorLocal_RBB_8520 *)&actor->local; - func_8033A45C(1,2); - func_8033A45C(3,1); - func_8033A45C(6,1); - func_8033A45C(7,1); + modelRender_setAppendageVisibility(1,2); + modelRender_setAppendageVisibility(3,1); + modelRender_setAppendageVisibility(6,1); + modelRender_setAppendageVisibility(7,1); if(local->unk30 > 0.0f && local->unk30 <= 1.0){ temp_f2 = 2*(3*local->unk30 - (s32)(3*local->unk30)); if (temp_f2 > 1.0f) @@ -313,18 +322,18 @@ Actor * func_8038F4B0(ActorMarker *marker, Gfx **gdl, Mtx **mptr, Vtx **arg3){ return actor_draw(marker, gdl, mptr, arg3); } -void func_8038F618(Actor *this){ - f32 sp7C[3]; +void chBoomBox_update(Actor *this){ + f32 player_position[3]; int sp78; ActorLocal_RBB_8520 *local = (ActorLocal_RBB_8520 *)&this->local; f32 sp70 = time_getDelta(); - f32 sp6C; - f32 sp68; - f32 sp5C[3]; + f32 prev_anim_progress; + f32 curr_anim_progress; + f32 this_position[3]; f32 sp50[3]; - f32 sp4C; - f32 sp48; - f32 sp44; + f32 horizontal_distance; + f32 distance_in_front; + f32 side_angle_radian; f32 pad0; @@ -336,33 +345,33 @@ void func_8038F618(Actor *this){ local->unk8[2] = this->position_z; local->unk38 = 0; local->unk39 = 0; - local->unk0 = &D_80390D80[(this->modelCacheIndex == 0x30d)? 1 : 0]; + local->unk0 = &D_80390D80[(this->modelCacheIndex == ACTOR_30D_BOOM_BOX_FAST)? 1 : 0]; local->unk2C = mapModel_getFloorY(this->position); local->unk34 = 0; local->unk4 = 0.5f; local->unk30 = 0.0f; marker_setCollisionScripts(this->marker, func_8038F430, func_8038F3F0, func_8038F430); - func_8038F190(this, 1); + chBoomBox_setState(this, CH_BOOM_BOX_STATE_1_UNK); return; }//L8038F714 - player_getPosition(sp7C); - sp78 = func_80329210(this, &sp7C); + player_getPosition(player_position); + sp78 = func_80329210(this, &player_position); if(!local->unk38){ local->unk38 = true; - func_8038FB54(); + chBoomBoxMinigameCtrl_countInc(); } func_8038E92C(this); - if(this->state == 1){ - if(sp78 && ml_vec3f_distance(this->position, sp7C) < 500.0f){ - func_8038F190(this, 2); + if(this->state == CH_BOOM_BOX_STATE_1_UNK){ + if(sp78 && ml_vec3f_distance(this->position, player_position) < 500.0f){ + chBoomBox_setState(this, CH_BOOM_BOX_STATE_2_UNK); } }//L8038F7A0 - if(this->state == 2){ - sp5C[0] = this->position_x; - sp5C[1] = this->position_y; - sp5C[2] = this->position_z; + if(this->state == CH_BOOM_BOX_STATE_2_UNK){ + this_position[0] = this->position_x; + this_position[1] = this->position_y; + this_position[2] = this->position_z; if(0.0f != local->unk30 && !sp78) func_8038E920(this); @@ -370,28 +379,30 @@ void func_8038F618(Actor *this){ if(0.0f == local->unk30 && sp78) func_8038E910(this); - skeletalAnim_getProgressRange(this->unk148, &sp6C, &sp68); + skeletalAnim_getProgressRange(this->unk148, &prev_anim_progress, &curr_anim_progress); - if(0.1 <= sp68 && sp68 <= 0.6) - ml_vec3f_interpolate_fast(this->position, local->unk14, local->unk20, (sp68 - 0.1) /0.5 ); - if(sp6C < 0.6 && 0.6 <= sp68) + if(0.1 <= curr_anim_progress && curr_anim_progress <= 0.6) + ml_vec3f_interpolate_fast(this->position, local->currentPosition, local->targetPosition, (curr_anim_progress - 0.1) / 0.5); + if(prev_anim_progress < 0.6 && 0.6 <= curr_anim_progress) func_8030E878(SFX_6C_LOCKUP_CLOSING, 1.1 + randf2(-0.05f, 0.05f), 20000, this->position, 500.0f, 1000.0f); - if(sp6C < 0.1 && 0.1 <= sp68) - func_8038E998(this); + if(prev_anim_progress < 0.1 && 0.1 <= curr_anim_progress) + chBoomBox_emitSmokeBeforeExplosion(this); - sp50[0] = local->unk20[0] - local->unk14[0]; - sp50[1] = local->unk20[1] - local->unk14[1]; - sp50[2] = local->unk20[2] - local->unk14[2]; + sp50[0] = local->targetPosition[0] - local->currentPosition[0]; + sp50[1] = local->targetPosition[1] - local->currentPosition[1]; + sp50[2] = local->targetPosition[2] - local->currentPosition[2]; - func_80258A4C(D_80390DEC, this->yaw - 90.0f, sp50, &sp4C, &sp48, &sp44); + func_80258A4C( + D_80390DEC, this->yaw - 90.0f, sp50, + &horizontal_distance, &distance_in_front, &side_angle_radian); - this->yaw += (sp44*400.0f)*sp70; + this->yaw += (side_angle_radian * 400.0f) * sp70; if(skeletalAnim_getLoopCount(this->unk148) > 0){ if(ml_vec3f_distance(this->position, local->unk8) < 10.0f){ - func_8038F190(this, 1); + chBoomBox_setState(this, CH_BOOM_BOX_STATE_1_UNK); }else{ - func_8038F190(this, 2); + chBoomBox_setState(this, CH_BOOM_BOX_STATE_2_UNK); } } }//L8038FA50 diff --git a/src/RBB/ch/bossboombox.c b/src/RBB/ch/bossboombox.c index 0970b3ba9..65192fb93 100644 --- a/src/RBB/ch/bossboombox.c +++ b/src/RBB/ch/bossboombox.c @@ -10,74 +10,78 @@ extern int func_803342AC(f32 (*)[3], f32(*)[3], f32); typedef struct{ - s16 unk0; + s16 actorId; //u8 pad2[2]; - f32 unk4; + f32 spawnPositionDelta; f32 unk8; u8 unkC; u8 unkD; u8 unkE; //u8 padF[1]; f32 unk10; - f32 unk14; -} Struct_RBB_5F80; + f32 volume; +} ActorLocal_ChBossBoomBoxInfo; typedef struct{ - Struct_RBB_5F80 *unk0; + ActorLocal_ChBossBoomBoxInfo *unk0; u8 unk4; u8 pad5[3]; - f32 unk8[3]; - f32 unk14[3]; + f32 currentPosition[3]; + f32 spawnPosition[3]; s32 unk20; f32 unk24; - f32 unk28; -} ActorLocal_RBB_5F80; + f32 turnAngle; +} ActorLocal_ChBossBoomBox; -void RBB_func_8038CC9C(Actor *this, s32 new_state); +void chBossBoomBox_setState(Actor *this, s32 new_state); void func_8038D7E8(ActorMarker *marker, s32 arg1); -Actor *func_8038D638(ActorMarker *marker, Gfx **gdl, Mtx ** mptr, Vtx **arg3); -void func_8038D8BC(Actor *this); +Actor *chBossBoomBox_draw(ActorMarker *marker, Gfx **gdl, Mtx ** mptr, Vtx **arg3); +void chBossBoomBox_update(Actor *this); /* .data */ -Struct_RBB_5F80 D_80390B70[4] = { +ActorLocal_ChBossBoomBoxInfo chBossBoomBoxTable[4] = { {ACTOR_281_BOSS_BOOM_BOX_LARGEST, 1.1f, 1.0f, 0x14, 0x01, 0x5, 0.9f, 0.8f}, {ACTOR_282_BOSS_BOOM_BOX_LARGE, 0.75f, 1.0f, 0xF, 0x02, 0x4, 1.1f, 0.9f}, {ACTOR_283_BOSS_BOOM_BOX_MEDIUM, 0.5f, 2.0f, 0xA, 0x02, 0x3, 1.3f, 1.0f}, {ACTOR_284_BOSS_BOOM_BOX_SMALL, 0.25f, 2.0f, 0x5, 0x02, 0x2, 1.5f, 1.1f}, }; -ActorInfo RBB_D_80390BD0 = { - MARKER_1A1_BOSS_BOOM_BOX_LARGEST, ACTOR_281_BOSS_BOOM_BOX_LARGEST, ASSET_428_MODEL_BOSS_BOOM_BOX, 0x0, NULL, - func_8038D8BC, NULL, func_8038D638, +ActorInfo chBossBoomBoxLargest = { + MARKER_1A1_BOSS_BOOM_BOX_LARGEST, ACTOR_281_BOSS_BOOM_BOX_LARGEST, ASSET_428_MODEL_BOSS_BOOM_BOX, + 0x0, NULL, + chBossBoomBox_update, NULL, chBossBoomBox_draw, 0, 0, 0.0f, 0 }; -ActorInfo D_80390BF4 = { - MARKER_1A2_BOSS_BOOM_BOX_LARGE, ACTOR_282_BOSS_BOOM_BOX_LARGE, ASSET_428_MODEL_BOSS_BOOM_BOX, 0x0, NULL, - func_8038D8BC, NULL, func_8038D638, +ActorInfo chBossBoomBoxLarge = { + MARKER_1A2_BOSS_BOOM_BOX_LARGE, ACTOR_282_BOSS_BOOM_BOX_LARGE, ASSET_428_MODEL_BOSS_BOOM_BOX, + 0x0, NULL, + chBossBoomBox_update, NULL, chBossBoomBox_draw, 0, 0, 0.0f, 0 }; -ActorInfo D_80390C18 = { - MARKER_1A3_BOSS_BOOM_BOX_MEDIUM, ACTOR_283_BOSS_BOOM_BOX_MEDIUM, ASSET_428_MODEL_BOSS_BOOM_BOX, 0x0, NULL, - func_8038D8BC, NULL, func_8038D638, +ActorInfo chBossBoomBoxMedium = { + MARKER_1A3_BOSS_BOOM_BOX_MEDIUM, ACTOR_283_BOSS_BOOM_BOX_MEDIUM, ASSET_428_MODEL_BOSS_BOOM_BOX, + 0x0, NULL, + chBossBoomBox_update, NULL, chBossBoomBox_draw, 0, 0, 0.0f, 0 }; -ActorInfo RBB_D_80390C3C = { - MARKER_1A4_BOSS_BOOM_BOX_SMALL, ACTOR_284_BOSS_BOOM_BOX_SMALL, ASSET_428_MODEL_BOSS_BOOM_BOX, 0x0, NULL, - func_8038D8BC, NULL, func_8038D638, +ActorInfo chBossBoomBoxSmall = { + MARKER_1A4_BOSS_BOOM_BOX_SMALL, ACTOR_284_BOSS_BOOM_BOX_SMALL, ASSET_428_MODEL_BOSS_BOOM_BOX, + 0x0, NULL, + chBossBoomBox_update, NULL, chBossBoomBox_draw, 0, 0, 0.0f, 0 }; -s32 D_80390C60[3] = {0xDE, 0xA7, 0x71}; +s32 ChBossBoomBoxSmoke1RGB[3] = {0xDE, 0xA7, 0x71}; ParticleSettingsVelocityAcceleration D_80390C6C = { { {-200.0f, 200.0f, -200.0f}, {200.0f, 500.0f, 200.0f} }, { {0.0f, -800.0f, 0.0f}, {0.0f, -800.0f, 0.0f} } }; -s32 D_80390C9C[3] = {0xDE, 0xA7, 0x71}; +s32 ChBossBoomBoxSmoke2RGB[3] = {0xDE, 0xA7, 0x71}; ParticleSettingsVelocityAccelerationPosition D_80390CA8 = { { {-200.0f, 0.0f, -200.0f}, {200.0f, -50.0f, 200.0f} }, @@ -85,30 +89,42 @@ ParticleSettingsVelocityAccelerationPosition D_80390CA8 = { { {-10.0f, -10.0f, -10.0f}, {10.0f, 10.0f, 10.0f} } }; +enum chbossboombox_state_e { + CH_BOSS_BOOM_BOX_STATE_0_NOT_INIT, + CH_BOSS_BOOM_BOX_STATE_1_WAITING_FOR_PLAYER, + CH_BOSS_BOOM_BOX_STATE_2_HIDES_JIGGY, + CH_BOSS_BOOM_BOX_STATE_3_ATTACK_PLAYER, + CH_BOSS_BOOM_BOX_STATE_4_PUSH_BACK, + CH_BOSS_BOOM_BOX_STATE_5_BREAKING, + CH_BOSS_BOOM_BOX_STATE_6_COMPLETE, + CH_BOSS_BOOM_BOX_STATE_7_UNK, + CH_BOSS_BOOM_BOX_STATE_8_FF_TIMER_RUN_OUT +}; + /* .bss */ u8 D_80391280; s32 pad_80391284; -f32 D_80391288[3]; +f32 chBossBoomBoxJiggyPosition[3]; /* .code */ void RBB_func_8038C370(ActorMarker *marker, s32 arg1){ Actor *actor = marker_getActor(marker); - RBB_func_8038CC9C(actor, arg1); + chBossBoomBox_setState(actor, arg1); } void func_8038C39C(Actor *this){ - ActorLocal_RBB_5F80 *local = (ActorLocal_RBB_5F80 *) &this->local; + ActorLocal_ChBossBoomBox *local = (ActorLocal_ChBossBoomBox *) &this->local; ParticleEmitter *other = partEmitMgr_newEmitter(local->unk0->unkE); particleEmitter_setSprite(other, ASSET_70E_SPRITE_SMOKE_2); particleEmitter_setFade(other, 0.0f, 0.1f); particleEmitter_setStartingFrameRange(other, 0, 7); particleEmitter_setDrawMode(other, 4); particleEmitter_setPosition(other, this->position); - particleEmitter_setStartingScaleRange(other, local->unk0->unk4*1, local->unk0->unk4*3.0f); - particleEmitter_setFinalScaleRange(other, 3.0f*local->unk0->unk4, local->unk0->unk4*7.0f); + particleEmitter_setStartingScaleRange(other, local->unk0->spawnPositionDelta * 1, local->unk0->spawnPositionDelta * 3.0f); + particleEmitter_setFinalScaleRange(other, 3.0f*local->unk0->spawnPositionDelta, local->unk0->spawnPositionDelta * 7.0f); particleEmitter_setSpawnPositionRange(other, - local->unk0->unk4*-200.0f, local->unk0->unk4*100.0f, local->unk0->unk4*-200.0f, - local->unk0->unk4*200.0f, local->unk0->unk4*100.0f, local->unk0->unk4*200.0f + local->unk0->spawnPositionDelta * -200.0f, local->unk0->spawnPositionDelta * 100.0f, local->unk0->spawnPositionDelta * -200.0f, + local->unk0->spawnPositionDelta * 200.0f, local->unk0->spawnPositionDelta * 100.0f, local->unk0->spawnPositionDelta * 200.0f ); particleEmitter_setParticleVelocityRange(other, -50.0f, 100.0f, -50.0f, @@ -119,43 +135,42 @@ void func_8038C39C(Actor *this){ } void RBB_func_8038C538(Actor *this){ - ActorLocal_RBB_5F80 *local = (ActorLocal_RBB_5F80 *) &this->local; + ActorLocal_ChBossBoomBox *local = (ActorLocal_ChBossBoomBox *) &this->local; ParticleEmitter *other = partEmitMgr_newEmitter(3*local->unk0->unkE); particleEmitter_setSprite(other, ASSET_70E_SPRITE_SMOKE_2); particleEmitter_setFade(other, 0.1f, 0.3f); particleEmitter_setDrawMode(other, 4); particleEmitter_setStartingFrameRange(other, 0, 7); particleEmitter_setPosition(other, this->position); - particleEmitter_setStartingScaleRange(other, local->unk0->unk4*1, local->unk0->unk4*6.0f); - particleEmitter_setFinalScaleRange(other, 0.5*local->unk0->unk4, local->unk0->unk4*3.0f); + particleEmitter_setStartingScaleRange(other, local->unk0->spawnPositionDelta * 1, local->unk0->spawnPositionDelta * 6.0f); + particleEmitter_setFinalScaleRange(other, 0.5*local->unk0->spawnPositionDelta, local->unk0->spawnPositionDelta * 3.0f); particleEmitter_setSpawnPositionRange(other, - local->unk0->unk4*-300.0f, local->unk0->unk4*100.0f, local->unk0->unk4*-300.0f, - local->unk0->unk4*300.0f, local->unk0->unk4*300.0f, local->unk0->unk4*300.0f + local->unk0->spawnPositionDelta * -300.0f, local->unk0->spawnPositionDelta * 100.0f, local->unk0->spawnPositionDelta * -300.0f, + local->unk0->spawnPositionDelta * 300.0f, local->unk0->spawnPositionDelta * 300.0f, local->unk0->spawnPositionDelta * 300.0f ); particleEmitter_setParticleVelocityRange(other, -70.0f, 50.0f, -70.0f, 70.0f, 100.0f, 70.0f ); - particleEmitter_setRGB(other, D_80390C60); + particleEmitter_setRGB(other, ChBossBoomBoxSmoke1RGB); particleEmitter_setParticleLifeTimeRange(other, 3.0f, 4.0f); - particleEmitter_emitN(other, 3*local->unk0->unkE); - + particleEmitter_emitN(other, 3 * local->unk0->unkE); } void RBB_func_8038C70C(Actor *this){ - ActorLocal_RBB_5F80 *local = (ActorLocal_RBB_5F80 *) &this->local; + ActorLocal_ChBossBoomBox *local = (ActorLocal_ChBossBoomBox *) &this->local; ParticleEmitter *other = partEmitMgr_newEmitter(0xa); particleEmitter_func_802EF9F8(other, 0.6f); particleEmitter_func_802EFA18(other, 3); particleEmitter_setDrawMode(other, 4); - particleEmitter_setModel(other, 0x427); + particleEmitter_setModel(other, ASSET_427_MODEL_WOODEN_PLANK); particleEmitter_setSpawnPositionRange(other, - local->unk0->unk4 * -300.0f, local->unk0->unk4 * 100.0f, local->unk0->unk4 * -300.0f, - local->unk0->unk4 * 300.0f, local->unk0->unk4 * 200.0f, local->unk0->unk4 * 300.0f + local->unk0->spawnPositionDelta * -300.0f, local->unk0->spawnPositionDelta * 100.0f, local->unk0->spawnPositionDelta * -300.0f, + local->unk0->spawnPositionDelta * 300.0f, local->unk0->spawnPositionDelta * 200.0f, local->unk0->spawnPositionDelta * 300.0f ); particleEmitter_setPosition(other, this->position); - particleEmitter_setStartingScaleRange(other, local->unk0->unk4*0.3, local->unk0->unk4*0.8); + particleEmitter_setStartingScaleRange(other, local->unk0->spawnPositionDelta * 0.3, local->unk0->spawnPositionDelta*0.8); particleEmitter_setAngularVelocityRange(other, -600.0f, -600.0f, -600.0f, 600.0f, 600.0f, 600.0f @@ -168,24 +183,24 @@ void RBB_func_8038C70C(Actor *this){ } void func_8038C8A8(Actor * this){ - ActorLocal_RBB_5F80 *local = (ActorLocal_RBB_5F80 *) &this->local; + ActorLocal_ChBossBoomBox *local = (ActorLocal_ChBossBoomBox *) &this->local; ParticleEmitter *other = partEmitMgr_newEmitter(5); - f32 sp24[3]; + f32 particle_position[3]; - player_getPosition(sp24); - sp24[1] += 50.0f; + player_getPosition(particle_position); + particle_position[1] += 50.0f; particleEmitter_setSprite(other, ASSET_70E_SPRITE_SMOKE_2); particleEmitter_setFade(other, 0.0, 0.5f); particleEmitter_setDrawMode(other, 4); particleEmitter_setStartingFrameRange(other, 0, 7); - particleEmitter_setPosition(other, sp24); - particleEmitter_setStartingScaleRange(other, local->unk0->unk4*1, local->unk0->unk4*3.0f); - particleEmitter_setFinalScaleRange(other, local->unk0->unk4*3.0f, local->unk0->unk4*6.0f); + particleEmitter_setPosition(other, particle_position); + particleEmitter_setStartingScaleRange(other, local->unk0->spawnPositionDelta * 1, local->unk0->spawnPositionDelta * 3.0f); + particleEmitter_setFinalScaleRange(other, local->unk0->spawnPositionDelta * 3.0f, local->unk0->spawnPositionDelta * 6.0f); particleEmitter_setVelocityAccelerationAndPositionRanges(other, &D_80390CA8); particleEmitter_setParticleLifeTimeRange(other, 1.0f, 2.0f); - particleEmitter_setRGB(other, D_80390C9C); + particleEmitter_setRGB(other, ChBossBoomBoxSmoke2RGB); particleEmitter_emitN(other, 5); } @@ -194,17 +209,17 @@ void chbossboombox_respawnJiggy(s32 position_x, s32 position_y, s32 position_z){ if(jiggy) marker_despawn(jiggy->marker); - D_80391288[0] = (f32)position_x; - D_80391288[1] = (f32)(position_y + 0x28); - D_80391288[2] = (f32)position_z; - jiggy_spawn(JIGGY_56_RBB_BOSS_BOOM_BOX, D_80391288); + chBossBoomBoxJiggyPosition[0] = (f32)position_x; + chBossBoomBoxJiggyPosition[1] = (f32)(position_y + 0x28); + chBossBoomBoxJiggyPosition[2] = (f32)position_z; + jiggy_spawn(JIGGY_56_RBB_BOSS_BOOM_BOX, chBossBoomBoxJiggyPosition); } void func_8038CA70(Actor *this, f32(*arg1)[3]){ f32 tmp_f; - ActorLocal_RBB_5F80 *local = (ActorLocal_RBB_5F80 *) &this->local; + ActorLocal_ChBossBoomBox *local = (ActorLocal_ChBossBoomBox *) &this->local; - tmp_f = local->unk0->unk4 * 300.0f; + tmp_f = local->unk0->spawnPositionDelta * 300.0f; if( (*arg1)[0] - tmp_f < -1400.0f) (*arg1)[0] = -1400.0f + tmp_f; @@ -221,7 +236,7 @@ void func_8038CA70(Actor *this, f32(*arg1)[3]){ } void func_8038CB34(ActorMarker *marker, enum asset_e arg1, s32 arg2){ - comusic_8025AB44(COMUSIC_62_RBB_BOOMBOX, -1, 0x12C); + comusic_8025AB44(COMUSIC_62_RBB_BOOMBOX, -1, 300); } void func_8038CB68(ActorMarker *marker, enum asset_e arg1, s32 arg2){ @@ -240,55 +255,52 @@ void chbossboombox_hideJiggy(void){ int RBB_func_8038CBF0(Actor *this){ f32 sp2C[3]; f32 sp20[3]; - ActorLocal_RBB_5F80 *local = (ActorLocal_RBB_5F80 *) &this->local; + ActorLocal_ChBossBoomBox *local = (ActorLocal_ChBossBoomBox *) &this->local; - sp2C[0] = local->unk8[0]; - sp2C[1] = local->unk8[1]; - sp2C[2] = local->unk8[2]; + sp2C[0] = local->currentPosition[0]; + sp2C[1] = local->currentPosition[1]; + sp2C[2] = local->currentPosition[2]; - sp20[0] = local->unk14[0]; - sp20[1] = local->unk14[1]; - sp20[2] = local->unk14[2]; - - sp2C[1] += 300.0f * local->unk0->unk4; - sp20[1] += 300.0f * local->unk0->unk4; - return func_803342AC(&sp2C, &sp20, local->unk0->unk4 * 400.0f); + sp20[0] = local->spawnPosition[0]; + sp20[1] = local->spawnPosition[1]; + sp20[2] = local->spawnPosition[2]; + sp2C[1] += 300.0f * local->unk0->spawnPositionDelta; + sp20[1] += 300.0f * local->unk0->spawnPositionDelta; + return func_803342AC(&sp2C, &sp20, local->unk0->spawnPositionDelta * 400.0f); } -void RBB_func_8038CC9C(Actor *this, s32 new_state){ - f32 sp8C[3]; +void chBossBoomBox_setState(Actor *this, s32 new_state){ + f32 player_position[3]; f32 sp80[3]; - ActorLocal_RBB_5F80 *local = (ActorLocal_RBB_5F80 *) &this->local; + ActorLocal_ChBossBoomBox *local = (ActorLocal_ChBossBoomBox *) &this->local; int i; f32 pad; - f32 sp68[3]; - f32 player_position; - f32 sp60; - f32 sp5C; - f32 sp58; - - - - player_getPosition(sp8C); + f32 spawn_position[3]; + f32 position_delta; + f32 horizontal_distance; + f32 distance_in_front; + f32 side_angle_radian; + + player_getPosition(player_position); - sp8C[1] = 0.0f; + player_position[1] = 0.0f; - sp80[0] = sp8C[0] - this->position_x; - sp80[1] = sp8C[1] - this->position_y; - sp80[2] = sp8C[2] - this->position_z; - if(this->state == 2){ + sp80[0] = player_position[0] - this->position_x; + sp80[1] = player_position[1] - this->position_y; + sp80[2] = player_position[2] - this->position_z; + if(this->state == CH_BOSS_BOOM_BOX_STATE_2_HIDES_JIGGY){ chbossboombox_hideJiggy(); } - if(this->state == 7){ + if(this->state == CH_BOSS_BOOM_BOX_STATE_7_UNK){ actor_collisionOn(this); } - local->unk8[0] = this->position_x; - local->unk8[1] = this->position_y; - local->unk8[2] = this->position_z; - local->unk24 = local->unk28 = this->yaw; + local->currentPosition[0] = this->position_x; + local->currentPosition[1] = this->position_y; + local->currentPosition[2] = this->position_z; + local->unk24 = local->turnAngle = this->yaw; this->state = new_state; if(local->unk20){ @@ -296,13 +308,13 @@ void RBB_func_8038CC9C(Actor *this, s32 new_state){ local->unk20 = 0; } - if(this->state == 1){ + if(this->state == CH_BOSS_BOOM_BOX_STATE_1_WAITING_FOR_PLAYER){ skeletalAnim_set(this->unk148, ASSET_146_ANIM_BOSS_BOOMBOX_APPEAR, 0.0f, 2.0f); skeletalAnim_setBehavior(this->unk148, SKELETAL_ANIM_4_STOPPED); } - if(this->state == 2){ - func_8025A58C(0, 0xfa0); + if(this->state == CH_BOSS_BOOM_BOX_STATE_2_HIDES_JIGGY){ + func_8025A58C(0, 4000); coMusicPlayer_playMusic(COMUSIC_62_RBB_BOOMBOX, -1); func_8025AABC(COMUSIC_62_RBB_BOOMBOX); skeletalAnim_set(this->unk148, ASSET_146_ANIM_BOSS_BOOMBOX_APPEAR, 0.0f, 2.4f); @@ -321,44 +333,46 @@ void RBB_func_8038CC9C(Actor *this, s32 new_state){ timedFunc_set_2(2.4f, (GenFunction_2)RBB_func_8038C370, (uintptr_t)this->marker, 3); } else{//L8038CEFC - timedFunc_set_3(2.4f, (GenFunction_3)comusic_8025AB44, COMUSIC_62_RBB_BOOMBOX, 0x1f40, 0x12C); - func_80324DBC(2.4f, ASSET_B9E_DIALOG_BOSS_BOOM_BOX_MEET, 4, NULL, this->marker, func_8038CB34, func_8038CB68); + timedFunc_set_3(2.4f, (GenFunction_3)comusic_8025AB44, COMUSIC_62_RBB_BOOMBOX, 8000, 300); + func_80324DBC(2.4f, VER_SELECT(ASSET_B9E_DIALOG_BOSS_BOOM_BOX_MEET, 0x973, 0, 0), 4, NULL, this->marker, func_8038CB34, func_8038CB68); } }//L8038CF60 - if(this->state == 3 || this->state == 4){ - func_8030E878(0x3f2, local->unk0->unk14, 0x6d60, this->position, 500.0f, 1000.0f); - skeletalAnim_set(this->unk148, ASSET_147_ANIM_BOOMBOX_MOVE, 0.2f, (1.0/(local->unk0->unk8)*randf2(1.0f, 1.1f))); + if( this->state == CH_BOSS_BOOM_BOX_STATE_3_ATTACK_PLAYER + || this->state == CH_BOSS_BOOM_BOX_STATE_4_PUSH_BACK) + { + func_8030E878(SFX_3F2_BOING, local->unk0->volume, 28000, this->position, 500.0f, 1000.0f); + skeletalAnim_set(this->unk148, ASSET_147_ANIM_BOOMBOX_MOVE, 0.2f, (1.0 / (local->unk0->unk8) * randf2(1.0f, 1.1f))); skeletalAnim_setBehavior(this->unk148, SKELETAL_ANIM_2_ONCE); - ml_vec3f_set_length(sp80, (this->state == 4)? -0x32*(2 + func_80326218()) : 300.0f/local->unk0->unk8); - local->unk14[0] = sp80[0] + this->position_x; - local->unk14[1] = sp80[1] + this->position_y; - local->unk14[2] = sp80[2] + this->position_z; - local->unk14[1] = 0.0f; - func_8038CA70(this, &local->unk14); + ml_vec3f_set_length(sp80, (this->state == 4)? -0x32 * (2 + func_80326218()) : 300.0f / local->unk0->unk8); + local->spawnPosition[0] = sp80[0] + this->position_x; + local->spawnPosition[1] = sp80[1] + this->position_y; + local->spawnPosition[2] = sp80[2] + this->position_z; + local->spawnPosition[1] = 0.0f; + func_8038CA70(this, &local->spawnPosition); }//L8038D0B8 - if(this->state == 5){ + if(this->state == CH_BOSS_BOOM_BOX_STATE_5_BREAKING){ actor_collisionOff(this); - timed_playSfx(0.2f, SFX_D9_WOODEN_CRATE_BREAKING_1, 0.9f, 0x7530); + timed_playSfx(0.2f, SFX_D9_WOODEN_CRATE_BREAKING_1, 0.9f, 30000); skeletalAnim_set(this->unk148, ASSET_148_ANIM_BOOMBOX_DIE, 0.2f, 1.0f); skeletalAnim_setBehavior(this->unk148, SKELETAL_ANIM_2_ONCE); ml_vec3f_set_length(sp80, -300.f); - local->unk14[0] = sp80[0] + this->position_x; - local->unk14[1] = sp80[1] + this->position_y; - local->unk14[2] = sp80[2] + this->position_z; - local->unk14[1] = 0.0f; - func_8038CA70(this, &local->unk14); + local->spawnPosition[0] = sp80[0] + this->position_x; + local->spawnPosition[1] = sp80[1] + this->position_y; + local->spawnPosition[2] = sp80[2] + this->position_z; + local->spawnPosition[1] = 0.0f; + func_8038CA70(this, &local->spawnPosition); RBB_func_8038C70C(this); RBB_func_8038C538(this); }//L8038D17C - if(this->state == 6){ + if(this->state == CH_BOSS_BOOM_BOX_STATE_6_COMPLETE){ func_80326310(this); - if(local->unk0->unk0 == ACTOR_284_BOSS_BOOM_BOX_SMALL){ + if(local->unk0->actorId == ACTOR_284_BOSS_BOOM_BOX_SMALL){ if(++D_80391280 == 8){ - func_8025A58C(-1, 0x190); - comusic_8025AB44(COMUSIC_62_RBB_BOOMBOX, 0, 0x190); + func_8025A58C(-1, 400); + comusic_8025AB44(COMUSIC_62_RBB_BOOMBOX, 0, 400); func_8025AABC(COMUSIC_62_RBB_BOOMBOX); if(volatileFlag_get(VOLATILE_FLAG_2_FF_IN_MINIGAME)){ item_set(ITEM_6_HOURGLASS, 0); @@ -367,101 +381,116 @@ void RBB_func_8038CC9C(Actor *this, s32 new_state){ } else{//L8038D220 timedFunc_set_3(0.0f, (GenFunction_3)chbossboombox_respawnJiggy, (s32)this->position_x, (s32)this->position_y, (s32)this->position_z); - gcdialog_showDialog(ASSET_B9F_DIALOG_BOSS_BOOM_BOX_COMPLETE, 4, 0, 0, 0, 0); + gcdialog_showDialog(VER_SELECT(ASSET_B9F_DIALOG_BOSS_BOOM_BOX_COMPLETE, 0x974, 0, 0), 4, 0, 0, 0, 0); } }//L8038D278 } else{//L8038D28C - sp68[0] = this->position_x + 200.0f*local->unk0->unk4; - sp68[1] = this->position_y + 80.0f*local->unk0->unk4; - sp68[2] = this->position_z; - __spawnQueue_add_4((GenFunction_4)spawnQueue_actor_f32, local->unk0->unk0 + 1, reinterpret_cast(s32, sp68[0]), reinterpret_cast(s32, sp68[1]), reinterpret_cast(s32, sp68[2])); - - sp68[0] = this->position_x - 200.0f*local->unk0->unk4; - sp68[1] = this->position_y + 80.0f*local->unk0->unk4; - sp68[2] = this->position_z; - __spawnQueue_add_4((GenFunction_4)spawnQueue_actor_f32, local->unk0->unk0 + 1, reinterpret_cast(s32, sp68[0]), reinterpret_cast(s32, sp68[1]), reinterpret_cast(s32, sp68[2])); + spawn_position[0] = this->position_x + 200.0f * local->unk0->spawnPositionDelta; + spawn_position[1] = this->position_y + 80.0f * local->unk0->spawnPositionDelta; + spawn_position[2] = this->position_z; + __spawnQueue_add_4( + (GenFunction_4)spawnQueue_actor_f32, + local->unk0->actorId + 1, + reinterpret_cast(s32, spawn_position[0]), + reinterpret_cast(s32, spawn_position[1]), + reinterpret_cast(s32, spawn_position[2])); + + spawn_position[0] = this->position_x - 200.0f * local->unk0->spawnPositionDelta; + spawn_position[1] = this->position_y + 80.0f * local->unk0->spawnPositionDelta; + spawn_position[2] = this->position_z; + __spawnQueue_add_4( + (GenFunction_4)spawnQueue_actor_f32, + local->unk0->actorId + 1, + reinterpret_cast(s32, spawn_position[0]), + reinterpret_cast(s32, spawn_position[1]), + reinterpret_cast(s32, spawn_position[2])); } }//L8038D378 - if(this->state == 7){ + if(this->state == CH_BOSS_BOOM_BOX_STATE_7_UNK){ actor_collisionOff(this); func_803262E4(this); skeletalAnim_set(this->unk148, ASSET_147_ANIM_BOOMBOX_MOVE, 0.0f, 1.0f); skeletalAnim_setBehavior(this->unk148, SKELETAL_ANIM_2_ONCE); - local->unk8[0] = this->position_x; - local->unk8[1] = this->position_y; - local->unk8[2] = this->position_z; + local->currentPosition[0] = this->position_x; + local->currentPosition[1] = this->position_y; + local->currentPosition[2] = this->position_z; - local->unk14[0] = this->position_x; - local->unk14[1] = this->position_y; - local->unk14[2] = this->position_z; + local->spawnPosition[0] = this->position_x; + local->spawnPosition[1] = this->position_y; + local->spawnPosition[2] = this->position_z; local->unk20 = RBB_func_8038CBF0(this); }//L8038D3FC - if(this->state == 3 || this->state == 4 || this->state == 5){ + if(this->state == CH_BOSS_BOOM_BOX_STATE_3_ATTACK_PLAYER + || this->state == CH_BOSS_BOOM_BOX_STATE_4_PUSH_BACK + || this->state == CH_BOSS_BOOM_BOX_STATE_5_BREAKING) + { local->unk20 = RBB_func_8038CBF0(this); if( local->unk20 == 0){ - player_position = local->unk0->unk4*300.0f; + position_delta = local->unk0->spawnPositionDelta * 300.0f; for(i = 0; i < 10; i++){ - local->unk14[0] = local->unk8[0] + randf2(-player_position, player_position); - local->unk14[1] = local->unk14[1]; - local->unk14[2] = local->unk8[2] + randf2(-player_position, player_position); - func_8038CA70(this, &local->unk14); + local->spawnPosition[0] = local->currentPosition[0] + randf2(-position_delta, position_delta); + local->spawnPosition[1] = local->spawnPosition[1]; + local->spawnPosition[2] = local->currentPosition[2] + randf2(-position_delta, position_delta); + func_8038CA70(this, &local->spawnPosition); local->unk20 = RBB_func_8038CBF0(this); if(local->unk20) break; } - if(i == 0xa){ - local->unk14[0] = local->unk8[0]; - local->unk14[2] = local->unk8[2]; - local->unk14[1] = 0.0f; + if(i == 10){ + local->spawnPosition[0] = local->currentPosition[0]; + local->spawnPosition[2] = local->currentPosition[2]; + local->spawnPosition[1] = 0.0f; } } }//L8038D4DC - if(this->state == 3){ - func_80258A4C(this->position, this->yaw - 90.0f, sp8C, &sp60, &sp5C, &sp58); - if(0.7 < sp58) - local->unk28 += 90.0f; - else if(sp58 < -0.7){ - local->unk28 -= 90.0f; + if(this->state == CH_BOSS_BOOM_BOX_STATE_3_ATTACK_PLAYER){ + func_80258A4C( + this->position, this->yaw - 90.0f, player_position, + &horizontal_distance, &distance_in_front, &side_angle_radian); + if(0.7 < side_angle_radian) + local->turnAngle += 90.0f; + else if(side_angle_radian < -0.7){ + local->turnAngle -= 90.0f; } } } -void func_8038D590(ActorMarker *marker, ActorMarker *arg1){ +void chBossBoomBox_hitPlayer(ActorMarker *marker, ActorMarker *arg1){ Actor *actor = marker_getActor(marker); - RBB_func_8038CC9C(actor, 4); + chBossBoomBox_setState(actor, CH_BOSS_BOOM_BOX_STATE_4_PUSH_BACK); } -void func_8038D5BC(ActorMarker *marker, ActorMarker *arg1){ +void chBossBoomBox_ow(ActorMarker *marker, ActorMarker *arg1){ Actor *actor = marker_getActor(marker); - ActorLocal_RBB_5F80 *local = (ActorLocal_RBB_5F80 *) &actor->local; + ActorLocal_ChBossBoomBox *local = (ActorLocal_ChBossBoomBox *) &actor->local; - gcsfx_playWithPitch(0x3f5, local->unk0->unk10, 0x4e20); - RBB_func_8038CC9C(actor, 4); + gcsfx_playWithPitch(SFX_3F5_UNKNOWN, local->unk0->unk10, 20000); + chBossBoomBox_setState(actor, CH_BOSS_BOOM_BOX_STATE_4_PUSH_BACK); func_8038C8A8(actor); } -void func_8038D608(ActorMarker *marker, ActorMarker *other){ +void chBossBoomBox_die(ActorMarker *marker, ActorMarker *other){ func_8038D7E8(marker, other->id == 1); } -Actor *func_8038D638(ActorMarker *marker, Gfx **gdl, Mtx ** mptr, Vtx **arg3){ +Actor *chBossBoomBox_draw(ActorMarker *marker, Gfx **gdl, Mtx ** mptr, Vtx **arg3){ f32 sp3C[3]; Actor *actor = marker_getActorAndRotation(marker, sp3C); - ActorLocal_RBB_5F80 *local = (ActorLocal_RBB_5F80 *) &actor->local; - func_8033A45C(1, local->unk0->unkD); + ActorLocal_ChBossBoomBox *local = (ActorLocal_ChBossBoomBox *) &actor->local; + modelRender_setAppendageVisibility(1, local->unk0->unkD); if(local->unk0->unkD == 1){ - func_8033A45C(2, (actor->state == 4)? 2: 1); - func_8033A45C(4, (actor->state == 4)? 2: 1); - func_8033A45C(5, (actor->state == 4)? 2: 1); + modelRender_setAppendageVisibility(2, (actor->state == 4)? 2: 1); + modelRender_setAppendageVisibility(4, (actor->state == 4)? 2: 1); + modelRender_setAppendageVisibility(5, (actor->state == 4)? 2: 1); }//L8038D714 else{ - func_8033A45C(3, (actor->state == 4)? 2: 1); - func_8033A45C(6, (actor->state == 4)? 2: 1); - func_8033A45C(7, (actor->state == 4)? 2: 1); + modelRender_setAppendageVisibility(3, (actor->state == 4)? 2: 1); + modelRender_setAppendageVisibility(6, (actor->state == 4)? 2: 1); + modelRender_setAppendageVisibility(7, (actor->state == 4)? 2: 1); } modelRender_setPreDrawCallback( (model_render_pre_draw_callback_f)actor_predrawMethod, (void *)actor); modelRender_setPostDrawCallback((model_render_post_draw_callback_f)actor_postdrawMethod, (void *)marker); @@ -472,15 +501,15 @@ Actor *func_8038D638(ActorMarker *marker, Gfx **gdl, Mtx ** mptr, Vtx **arg3){ void func_8038D7E8(ActorMarker *marker, s32 arg1){ Actor *actor = marker_getActor(marker); - ActorLocal_RBB_5F80 *local = (ActorLocal_RBB_5F80 *) &actor->local; + ActorLocal_ChBossBoomBox *local = (ActorLocal_ChBossBoomBox *) &actor->local; sfx_playFadeShorthandDefault(SFX_1E_HITTING_AN_ENEMY_2, 1.0f, 20000, actor->position, 1000, 2000); gcsfx_playWithPitch(SFX_D7_GRABBA_DEATH, local->unk0->unk10, 0x7530); local->unk4 += (arg1) ? 1 : 5; if(local->unk4 >= local->unk0->unkC) - RBB_func_8038CC9C(actor, 5); + chBossBoomBox_setState(actor, CH_BOSS_BOOM_BOX_STATE_5_BREAKING); else{ - RBB_func_8038CC9C(actor, 4); + chBossBoomBox_setState(actor, CH_BOSS_BOOM_BOX_STATE_4_PUSH_BACK); } if(!arg1) @@ -490,13 +519,13 @@ void func_8038D7E8(ActorMarker *marker, s32 arg1){ void func_8038D8B4(Actor *actor){} -void func_8038D8BC(Actor *this){ +void chBossBoomBox_update(Actor *this){ f32 player_position[3]; - ActorLocal_RBB_5F80 *local = (ActorLocal_RBB_5F80 *) &this->local; - f32 sp5C; - f32 sp58; - f32 sp54; - f32 sp50; + ActorLocal_ChBossBoomBox *local = (ActorLocal_ChBossBoomBox *) &this->local; + f32 prev_anim_progress1; + f32 curr_anim_progress1; + f32 prev_anim_progress2; + f32 curr_anim_progress2; f32 sp4C; f32 tmp_f2; f32 pad; @@ -504,23 +533,23 @@ void func_8038D8BC(Actor *this){ if(!this->volatile_initialized){ this->volatile_initialized = true; - local->unk0 = &D_80390B70[this->marker->id - 0x1A1]; + local->unk0 = &chBossBoomBoxTable[this->marker->id - MARKER_1A1_BOSS_BOOM_BOX_LARGEST]; local->unk4 = 0; local->unk20 = 0; this->marker->propPtr->unk8_3 = 0; - this->scale = local->unk0->unk4; - if(local->unk0 == D_80390B70){ + this->scale = local->unk0->spawnPositionDelta; + if(local->unk0 == chBossBoomBoxTable){ this->yaw = 270.0f; } - marker_setCollisionScripts(this->marker, func_8038D590, func_8038D5BC, func_8038D608); + marker_setCollisionScripts(this->marker, chBossBoomBox_hitPlayer, chBossBoomBox_ow, chBossBoomBox_die); marker_setFreeMethod(this->marker, func_8038D8B4); - if(local->unk0->unk0 == ACTOR_281_BOSS_BOOM_BOX_LARGEST){ - RBB_func_8038CC9C(this, 1); + if(local->unk0->actorId == ACTOR_281_BOSS_BOOM_BOX_LARGEST){ + chBossBoomBox_setState(this, CH_BOSS_BOOM_BOX_STATE_1_WAITING_FOR_PLAYER); D_80391280 = 0; } else{ - RBB_func_8038CC9C(this, 7); + chBossBoomBox_setState(this, CH_BOSS_BOOM_BOX_STATE_7_UNK); } if(jiggyscore_isSpawned(JIGGY_56_RBB_BOSS_BOOM_BOX) && !volatileFlag_get(VOLATILE_FLAG_2_FF_IN_MINIGAME)) @@ -533,79 +562,82 @@ void func_8038D8BC(Actor *this){ chbossboombox_hideJiggy(); skeletalAnim_set(this->unk148, ASSET_146_ANIM_BOSS_BOOMBOX_APPEAR, 0.0f, 2.4f); skeletalAnim_setBehavior(this->unk148, SKELETAL_ANIM_2_ONCE); - this->state = 2; + this->state = CH_BOSS_BOOM_BOX_STATE_2_HIDES_JIGGY; } return; } player_getPosition(player_position); - if(this->state == 1){ + if(this->state == CH_BOSS_BOOM_BOX_STATE_1_WAITING_FOR_PLAYER){ if(volatileFlag_get(VOLATILE_FLAG_2_FF_IN_MINIGAME)){ if(volatileFlag_get(VOLATILE_FLAG_3)){ - RBB_func_8038CC9C(this, 2); + chBossBoomBox_setState(this, CH_BOSS_BOOM_BOX_STATE_2_HIDES_JIGGY); } } else{//L8038DAA8 if(ml_vec3f_distance(this->position, player_position) < 1200.0f){ - RBB_func_8038CC9C(this, 2); + chBossBoomBox_setState(this, CH_BOSS_BOOM_BOX_STATE_2_HIDES_JIGGY); } } }//L8038DAD8 - if(this->state == 2){ + if(this->state == CH_BOSS_BOOM_BOX_STATE_2_HIDES_JIGGY){ if(skeletalAnim_getAnimId(this->unk148) == ASSET_146_ANIM_BOSS_BOOMBOX_APPEAR && skeletalAnim_getLoopCount(this->unk148) > 0){ skeletalAnim_set(this->unk148, ASSET_147_ANIM_BOOMBOX_MOVE, 0.2, 1.0f); skeletalAnim_setBehavior(this->unk148, SKELETAL_ANIM_1_LOOP); } }//L8038DB30 - if( this->state == 2 || this->state == 3 || this->state == 4){ + if( this->state == CH_BOSS_BOOM_BOX_STATE_2_HIDES_JIGGY + || this->state == CH_BOSS_BOOM_BOX_STATE_3_ATTACK_PLAYER + || this->state == CH_BOSS_BOOM_BOX_STATE_4_PUSH_BACK){ if(skeletalAnim_getAnimId(this->unk148) == ASSET_147_ANIM_BOOMBOX_MOVE){ - skeletalAnim_getProgressRange(this->unk148, &sp5C, &sp58); - if(sp5C < 0.6 && 0.6 <= sp58){ - func_8030E878(SFX_6C_LOCKUP_CLOSING, randf2(-0.05f, 0.05f) + local->unk0->unk14, 20000, this->position, 500.0f, 1000.0f); + skeletalAnim_getProgressRange(this->unk148, &prev_anim_progress1, &curr_anim_progress1); + if(prev_anim_progress1 < 0.6 && 0.6 <= curr_anim_progress1){ + func_8030E878(SFX_6C_LOCKUP_CLOSING, randf2(-0.05f, 0.05f) + local->unk0->volume, 20000, this->position, 500.0f, 1000.0f); }//L8038DC04 - if(sp5C < 0.1 && 0.1 <= sp58){ + if(prev_anim_progress1 < 0.1 && 0.1 <= curr_anim_progress1){ func_8038C39C(this); } } }//L8038DC48 - if(this->state == 3 || this->state == 4){ + if(this->state == CH_BOSS_BOOM_BOX_STATE_3_ATTACK_PLAYER + || this->state == CH_BOSS_BOOM_BOX_STATE_4_PUSH_BACK){ if(volatileFlag_get(VOLATILE_FLAG_2_FF_IN_MINIGAME)){ if(item_empty(ITEM_0_HOURGLASS_TIMER)){ volatileFlag_set(VOLATILE_FLAG_3, 0); volatileFlag_set(VOLATILE_FLAG_5_FF_MINIGAME_WON, 0); - RBB_func_8038CC9C(this, 8); + chBossBoomBox_setState(this, CH_BOSS_BOOM_BOX_STATE_8_FF_TIMER_RUN_OUT); } } - skeletalAnim_getProgressRange(this->unk148, &sp54, &sp50); - if(0.1 <= sp50 && sp50 <= 0.6){ - sp4C = (sp50 - 0.1)/0.5; - ml_vec3f_interpolate_fast(this->position, local->unk8, local->unk14, sp4C); - this->yaw = local->unk24 + sp4C*(local->unk28 - local->unk24); + skeletalAnim_getProgressRange(this->unk148, &prev_anim_progress2, &curr_anim_progress2); + if(0.1 <= curr_anim_progress2 && curr_anim_progress2 <= 0.6){ + sp4C = (curr_anim_progress2 - 0.1) / 0.5; + ml_vec3f_interpolate_fast(this->position, local->currentPosition, local->spawnPosition, sp4C); + this->yaw = local->unk24 + sp4C * (local->turnAngle - local->unk24); } if(skeletalAnim_getLoopCount(this->unk148) > 0) - RBB_func_8038CC9C(this, 3); + chBossBoomBox_setState(this, CH_BOSS_BOOM_BOX_STATE_3_ATTACK_PLAYER); }//L8038DD64 - if(this->state == 5){ + if(this->state == CH_BOSS_BOOM_BOX_STATE_5_BREAKING){ if(skeletalAnim_getLoopCount(this->unk148) > 0){ - RBB_func_8038CC9C(this, 6); + chBossBoomBox_setState(this, CH_BOSS_BOOM_BOX_STATE_6_COMPLETE); }else{ tmp_f2 = skeletalAnim_getProgress(this->unk148); if(tmp_f2 <= 0.3) - tmp_f2 = tmp_f2/0.3; + tmp_f2 = tmp_f2 / 0.3; else tmp_f2 = 1.0f; - ml_vec3f_interpolate_fast(this->position, local->unk8, local->unk14, tmp_f2); + ml_vec3f_interpolate_fast(this->position, local->currentPosition, local->spawnPosition, tmp_f2); } }//L8038DE10 - if(this->state == 7){ + if(this->state == CH_BOSS_BOOM_BOX_STATE_7_UNK){ if(skeletalAnim_getLoopCount(this->unk148) > 0) - RBB_func_8038CC9C(this, 3); + chBossBoomBox_setState(this, CH_BOSS_BOOM_BOX_STATE_3_ATTACK_PLAYER); } } diff --git a/src/RBB/ch/bossboomboxctrl.c b/src/RBB/ch/bossboomboxctrl.c index b81a46f76..c29948315 100644 --- a/src/RBB/ch/bossboomboxctrl.c +++ b/src/RBB/ch/bossboomboxctrl.c @@ -7,12 +7,18 @@ void chBossBoomBoxCtrl_update(Actor *this); /* .data */ -ActorInfo RBB_D_80390CF0 = { - 0x1C0, 0x2AD, 0x0, 0x0, NULL, +ActorInfo chBossBoomBoxCtrl = { + MARKER_1C0_BOSS_BOOMBOX_CTRL, ACTOR_2AD_BOSS_BOOMBOX_CTRL, 0x0, + 0x0, NULL, chBossBoomBoxCtrl_update, NULL, func_80325340, 0, 0, 0.0f, 0 }; +enum bossboomboxctrl_state_e { + BOSS_BOOM_BOX_CTRL_STATE_0_NOT_INIT, + BOSS_BOOM_BOX_CTRL_STATE_1_INIT +}; + /* .code */ void __chBossBoomBoxCtrl_setState(Actor *this, s32 new_state){ this->state = new_state; @@ -22,11 +28,13 @@ void chBossBoomBoxCtrl_update(Actor *this){ if(!this->volatile_initialized){ this->volatile_initialized = true; - if(jiggyscore_isSpawned(JIGGY_56_RBB_BOSS_BOOM_BOX) && !volatileFlag_get(VOLATILE_FLAG_2_FF_IN_MINIGAME)){ + if(jiggyscore_isSpawned(JIGGY_56_RBB_BOSS_BOOM_BOX) + && !volatileFlag_get(VOLATILE_FLAG_2_FF_IN_MINIGAME)) + { marker_despawn(this->marker); - }else{ + } else { __spawnQueue_add_4((GenFunction_4)spawnQueue_actor_f32, ACTOR_281_BOSS_BOOM_BOX_LARGEST, reinterpret_cast(s32,this->position_x), reinterpret_cast(s32,this->position_y), reinterpret_cast(s32,this->position_z)); - __chBossBoomBoxCtrl_setState(this, 1); + __chBossBoomBoxCtrl_setState(this, BOSS_BOOM_BOX_CTRL_STATE_1_INIT); } }//L8038DEF4 } diff --git a/src/RBB/ch/cog.c b/src/RBB/ch/cog.c index 38b43adca..e8dd085ac 100644 --- a/src/RBB/ch/cog.c +++ b/src/RBB/ch/cog.c @@ -10,50 +10,61 @@ typedef struct { u8 sfxsourceIdx; }ActorLocal_RBB_27E0; -void func_80388C20(Actor *this); +void chRBBCog_update(Actor *this); /* .data */ -ActorInfo D_803903B0 = { - 0x18B, 0x17B, 0x409, 0x0, NULL, - func_80388C20, NULL, actor_draw, +ActorInfo chRBBSmallCog = { + MARKER_18B_RBB_SMALL_COG, ACTOR_17B_RBB_SMALL_COG, ASSET_409_MODEL_RBB_SMALL_COG, + 0x0, NULL, + chRBBCog_update, NULL, actor_draw, 0, 0, 0.0f, 0 }; -ActorInfo D_803903D4 = { - 0x18C, 0x17C, 0x40A, 0x0, NULL, - func_80388C20, NULL, actor_draw, +ActorInfo chRBBMediumCog = { + MARKER_18C_RBB_MEDIUM_COG, ACTOR_17C_RBB_MEDIUM_COG, ASSET_40A_MODEL_RBB_MEDIUM_COG, + 0x0, NULL, + chRBBCog_update, NULL, actor_draw, 0, 0, 0.0f, 0 }; -ActorInfo D_803903F8 = { - 0x18D, 0x17D, 0x40B, 0x0, NULL, - func_80388C20, NULL, actor_draw, +ActorInfo chRBBLargeCog = { + MARKER_18D_RBB_LARGE_COG, ACTOR_17D_RBB_LARGE_COG, ASSET_40B_MODEL_RBB_LARGE_COG, + 0x0, NULL, + chRBBCog_update, NULL, actor_draw, 0, 0, 0.0f, 0 }; -f32 D_8039041C[3] = {40.0f, -30.0f, 20.0f}; //rotation rates (deg/sec); +f32 chRBBCogRotateRates[3] = {40.0f, -30.0f, 20.0f}; //rotation rates (deg/sec); + +enum chrbbcog_state_e { + CH_RBB_COG_STATE_0_NOT_INIT, + CH_RBB_COG_STATE_1_INIT +}; /* .code */ -void func_80388BD0(Actor *this, s32 arg1){ - this->state = arg1; +void chRBBCog_setState(Actor *this, s32 next_state){ + this->state = next_state; } -void func_80388BE8(Actor *actor){ +void chRBBCog_free(Actor *actor){ ActorLocal_RBB_27E0 *local = (ActorLocal_RBB_27E0 *)&actor->local; - if(actor->modelCacheIndex == 0x17b){ + + if(actor->modelCacheIndex == ACTOR_17B_RBB_SMALL_COG){ sfxsource_freeSfxsourceByIndex(local->sfxsourceIdx); } } -void func_80388C20(Actor *this){ +void chRBBCog_update(Actor *this){ ActorLocal_RBB_27E0 *local = (ActorLocal_RBB_27E0 *)&this->local; - f32 sp28 = time_getDelta(); + f32 time_delta = time_getDelta(); + if(!this->volatile_initialized){ actor_collisionOff(this); this->marker->propPtr->unk8_3 = 1; - this->marker->actorFreeFunc = func_80388BE8; + this->marker->actorFreeFunc = chRBBCog_free; this->volatile_initialized = true; - if(this->modelCacheIndex == 0x17B){ + + if(this->modelCacheIndex == ACTOR_17B_RBB_SMALL_COG){ local->sfxsourceIdx = sfxsource_createSfxsourceAndReturnIndex(); sfxsource_set_fade_distances(local->sfxsourceIdx, 1000.0f, 2000.0f); sfxsource_set_position(local->sfxsourceIdx, this->position); @@ -63,24 +74,26 @@ void func_80388C20(Actor *this){ sfxsource_setSampleRate(local->sfxsourceIdx, 0); sfxSource_func_8030E2C4(local->sfxsourceIdx); }//L80388CFC - if(this->state == 0){ - if(this->modelCacheIndex == 0x17B){ + + if(this->state == CH_RBB_COG_STATE_0_NOT_INIT){ + if(this->modelCacheIndex == ACTOR_17B_RBB_SMALL_COG){ TUPLE_ASSIGN(this->position, 0.0f, -50.0f, 700.0f); } - else if(this->modelCacheIndex == 0x17C){//L80388DA8 + else if(this->modelCacheIndex == ACTOR_17C_RBB_MEDIUM_COG){//L80388DA8 TUPLE_ASSIGN(this->position, 0.0f, -50.0f, 500.0f); } - else if(this->modelCacheIndex == 0x17D){ + else if(this->modelCacheIndex == ACTOR_17D_RBB_LARGE_COG){ TUPLE_ASSIGN(this->position, 0.0f, -50.0f, 300.0f); } - func_80388BD0(this, 1); + chRBBCog_setState(this, CH_RBB_COG_STATE_1_INIT); } }//L80388DA8 - if(this->state == 1){ - this->roll += D_8039041C[this->modelCacheIndex - 0x17B]*sp28; + + if(this->state == CH_RBB_COG_STATE_1_INIT){ + this->roll += chRBBCogRotateRates[this->modelCacheIndex - ACTOR_17B_RBB_SMALL_COG] * time_delta; if(360.0f <= this->roll) this->roll -= 360.0f; - if(this->modelCacheIndex == 0x17B){ + if(this->modelCacheIndex == ACTOR_17B_RBB_SMALL_COG){ func_8030DB04(local->sfxsourceIdx, 25000, this->position, 1000.0f, 2000.0f); } } diff --git a/src/RBB/ch/dolphin.c b/src/RBB/ch/dolphin.c index 8731b461f..1f3bc6b15 100644 --- a/src/RBB/ch/dolphin.c +++ b/src/RBB/ch/dolphin.c @@ -8,48 +8,56 @@ ParticleEmitter *func_802EDD8C(f32 [3], f32, f32); void func_8038B900(Actor *this); /* .data */ -ActorInfo RBB_D_80390AB0 = { - 0x30, 0x1C8, 0x41C, 0x0, NULL, +ActorInfo chSnorkel = { + MARKER_30_SNORKEL, ACTOR_1C8_SNORKEL, ASSET_41C_MODEL_SNORKEL, + 0x0, NULL, NULL, func_8038B900, actor_draw, 0, 0, 0.0f, 0 }; +enum chsnorkel_state_e { + CH_SNORKEL_STATE_0_NOT_INIT, + CH_SNORKEL_STATE_1_TRAPPED, + CH_SNORKEL_STATE_2_FREED, + CH_SNORKEL_STATE_3_DESPAWN +}; + /* .code */ -void func_8038B880(Actor *this, s32 new_state){ - if(new_state == 1) +void chSnorkel_setState(Actor *this, s32 new_state){ + if(new_state == CH_SNORKEL_STATE_1_TRAPPED) skeletalAnim_set(this->unk148, ASSET_13F_ANIM_SNORKEL_STUCK, 0.0f, 5.5f); - if(new_state == 2) + if(new_state == CH_SNORKEL_STATE_2_FREED) skeletalAnim_swap(this->unk148, ASSET_13E_ANIM_SNORKEL_SWIM, 1.0f, 0.65f); this->state = new_state; } void func_8038B900(Actor *this){ - f32 sp5C; - f32 sp58; - f32 sp54; + f32 prev_anim_progress; + f32 curr_anim_progress; + f32 anim_progress; f32 sp48[3]; ParticleEmitter *other; this->marker->propPtr->unk8_3 = 1; if(this->marker->unk14_21){ - sp54 = skeletalAnim_getProgress(this->unk148); + anim_progress = skeletalAnim_getProgress(this->unk148); if( ( globalTimer_getTime() & (1 << 4) ) && ( globalTimer_getTime() & (1 << 2) ) && ( randf() < 0.90 ) ){ - if( ( this->state == 3 - && (0.255 <= sp54 && sp54 <= 0.856) + if( ( this->state == CH_SNORKEL_STATE_3_DESPAWN + && (0.255 <= anim_progress && anim_progress <= 0.856) ) - || ( this->state == 1 - && ( (0.053 <= sp54 && sp54 <= 0.35) - || (0.39 <= sp54 && sp54 <= 0.44999999999999996) - || (0.45999999999999996 <= sp54 && sp54 <= 0.52) - || (0.54 <= sp54 && sp54 <= 0.73) - || (0.76 <= sp54 && sp54 <= 0.8200000000000001) - || (0.84 <= sp54 && sp54 <= 0.9) - || (0.94 <= sp54 && sp54 <= 1.0) + || ( this->state == CH_SNORKEL_STATE_1_TRAPPED + && ( (0.053 <= anim_progress && anim_progress <= 0.35) + || (0.39 <= anim_progress && anim_progress <= 0.44999999999999996) + || (0.45999999999999996 <= anim_progress && anim_progress <= 0.52) + || (0.54 <= anim_progress && anim_progress <= 0.73) + || (0.76 <= anim_progress && anim_progress <= 0.8200000000000001) + || (0.84 <= anim_progress && anim_progress <= 0.9) + || (0.94 <= anim_progress && anim_progress <= 1.0) ) ) ){//L8038BB24 @@ -70,45 +78,45 @@ void func_8038B900(Actor *this){ this->position_y = -2600.0f; this->position_z = 1460.0f; this->yaw = 0.0f; - func_8038B880(this, 1); + chSnorkel_setState(this, CH_SNORKEL_STATE_1_TRAPPED); if(jiggyscore_isSpawned(JIGGY_53_RBB_SNORKEL)){ marker_despawn(this->marker); } } else{//L8038BC74 - skeletalAnim_getProgressRange(this->unk148, &sp5C, &sp58); - if( sp5C < 0.22 && 0.22 <= sp58 ){ + skeletalAnim_getProgressRange(this->unk148, &prev_anim_progress, &curr_anim_progress); + if( prev_anim_progress < 0.22 && 0.22 <= curr_anim_progress ){ func_8030E988(SFX_D1_SNORKEL_WAH, randf2(0.8f, 0.9f), 15000, this->position, 1500.0f, 2000.0f); } - if( sp5C < 0.54 && 0.54 <= sp58 ){ + if( prev_anim_progress < 0.54 && 0.54 <= curr_anim_progress ){ func_8030E988(SFX_D1_SNORKEL_WAH, randf2(0.9f, 1.0f), 19000, this->position, 1500.0f, 2000.0f); } - if(this->state == 1){ + if(this->state == CH_SNORKEL_STATE_1_TRAPPED){ if( !this->has_met_before - && subaddie_playerIsWithinSphereAndActive(this, 0x258) + && subaddie_playerIsWithinSphereAndActive(this, 600) && !player_movementGroup() ){ - gcdialog_showDialog(ASSET_B9B_DIALOG_SNORKEL_MEET, 4, 0, 0, 0, 0); - this->has_met_before = true; + gcdialog_showDialog(VER_SELECT(ASSET_B9B_DIALOG_SNORKEL_MEET, 0x970, 0, 0), 4, 0, 0, 0, 0); + this->has_met_before = TRUE; } } - if(this->state == 1){ - if(mapSpecificFlags_get(4)) - func_8038B880(this, 2); + if(this->state == CH_SNORKEL_STATE_1_TRAPPED){ + if(mapSpecificFlags_get(RBB_MAIN_SPECIFIC_FLAG_4_ANCHOR_LIFTING)) + chSnorkel_setState(this, CH_SNORKEL_STATE_2_FREED); } - if(this->state == 2){ + if(this->state == CH_SNORKEL_STATE_2_FREED){ if(jiggyscore_isSpawned(JIGGY_53_RBB_SNORKEL)) - func_8038B880(this, 3); + chSnorkel_setState(this, CH_SNORKEL_STATE_3_DESPAWN); } - if(this->state == 3){ + if(this->state == CH_SNORKEL_STATE_3_DESPAWN){ actor_update_func_80326224(this); if(0.99 < this->unk48){ - mapSpecificFlags_set(4, false); + mapSpecificFlags_set(RBB_MAIN_SPECIFIC_FLAG_4_ANCHOR_LIFTING, false); marker_despawn(this->marker); } } diff --git a/src/RBB/ch/eggtoll1.c b/src/RBB/ch/eggtoll1.c index ebe16eafe..dbc55fd4c 100644 --- a/src/RBB/ch/eggtoll1.c +++ b/src/RBB/ch/eggtoll1.c @@ -12,84 +12,92 @@ extern ActorArray *suBaddieActorArray; /* typedefs and declarations */ typedef struct { - s32 unk0; - s32 unk4; - s32 unk8; - s32 unkC; -}ActorLocal_RBB_0; + s32 eggsPaid; + s32 tollId; + s32 tollNum; // 0 for first toll; 1 for second toll + s32 unkC; // Either 0 or 3? +} ActorLocal_ChRBBEggToll; typedef struct { - u8 unk0; - u8 unk1; - u8 unk2; + u8 cameraNode; + u8 eggCost1; + u8 eggCost2; // Only used in Toll 2 //u8 pad3[1]; f32 unk4; s16 unk8; s16 unkA; s16 unkC; //u8 padE[2]; -}Struct_RBB_0_1; +} chRBBEggTollInfo; -void func_803866F4(Actor *this, s32 arg1); -void func_803868F0(Actor* this); +void chRBBEggToll_setState(Actor *this, s32 next_state); +void chRBBEggToll_update(Actor* this); /* .data */ -ActorInfo D_80390050 = { +ActorInfo chRBBEggToll = { MARKER_182_RBB_EGG_TOLL, ACTOR_172_RBB_EGG_TOLL, ASSET_402_MODEL_EGG_TOLL, 0x0, NULL, - func_803868F0, NULL, func_80325340, + chRBBEggToll_update, NULL, func_80325340, 0, 0, 0.0f, 0 }; -Struct_RBB_0_1 D_80390074[4] = { +chRBBEggTollInfo chRBBEggTollInfoTable[4] = { {0x0, 0x2, 0x4, 3.0f, 550, 200, -300}, {0x1, 0x4, 0x0, 4.0f, -600, 0, 0}, {0x2, 0x6, 0x0, 4.0f, -700, 0, 0}, {0x3, 0x8, 0x0, 4.0f, -1010, 0, 0} }; +enum chrbbeggtoll_state_e { + CH_RBB_EGG_TOLL_STATE_0_NOT_INIT, + CH_RBB_EGG_TOLL_STATE_1_AWAITING_TOLL, + CH_RBB_EGG_TOLL_STATE_2_FIRST_EGG_PAID, + CH_RBB_EGG_TOLL_STATE_3_TOLL_COMPLETE, + CH_RBB_EGG_TOLL_STATE_4_UNK +}; + /* .code */ static s32 eggToll_countForStage(s32 tollIdx, s32 stage) { s32 count = 0; - if (stage >= 1) count += D_80390074[tollIdx].unk1; - if (stage >= 2) count += D_80390074[tollIdx].unk2; + if (stage >= 1) count += chRBBEggTollInfoTable[tollIdx].eggCost1; + if (stage >= 2) count += chRBBEggTollInfoTable[tollIdx].eggCost2; return count; } void RBB_func_803863F0(Actor *actor, s32 arg1){ - ActorLocal_RBB_0 * local = (ActorLocal_RBB_0 *) &actor->local; + ActorLocal_ChRBBEggToll * local = (ActorLocal_ChRBBEggToll *) &actor->local; void *temp_a0; f32 sp3C[3]; f32 sp30[3]; - temp_a0 = func_8034C528(local->unk4 + 0x190); + temp_a0 = func_8034C528(local->tollId + 0x190); if(temp_a0){ - if(local->unk8 == 0){ + if(local->tollNum == 0){ sp3C[2] = 0.0f; sp30[0] = 0.0f; sp30[1] = 0.0f; sp3C[0] = sp3C[1] = sp3C[2]; - sp30[2] = (f32) D_80390074[local->unk4].unk8; + sp30[2] = (f32) chRBBEggTollInfoTable[local->tollId].unk8; } - else if(local->unk8 == 1){ + else if(local->tollNum == 1){ sp3C[0] = 0.0f; sp3C[1] = 0.0f; - sp3C[2] = (f32) D_80390074[local->unk4].unk8; + sp3C[2] = (f32) chRBBEggTollInfoTable[local->tollId].unk8; sp30[1] = 0.0f; sp30[0] = 0.0f; - sp30[2] = (f32) D_80390074[local->unk4].unkA; + sp30[2] = (f32) chRBBEggTollInfoTable[local->tollId].unkA; } else{ sp3C[0] = 0.0f; sp3C[1] = 0.0f; - sp3C[2] = (f32) D_80390074[local->unk4].unkA; + sp3C[2] = (f32) chRBBEggTollInfoTable[local->tollId].unkA; sp30[1] = 0.0f; sp30[0] = 0.0f; - sp30[2] = (f32) D_80390074[local->unk4].unkC; + sp30[2] = (f32) chRBBEggTollInfoTable[local->tollId].unkC; } if(arg1){ - func_8034DDF0(temp_a0, sp3C, sp30, D_80390074[local->unk4].unk4, 1); + func_8034DDF0(temp_a0, sp3C, sp30, chRBBEggTollInfoTable[local->tollId].unk4, 1); func_8034E174(temp_a0); } else{ @@ -99,86 +107,87 @@ void RBB_func_803863F0(Actor *actor, s32 arg1){ } void func_803865A4(ActorMarker *marker, s32 arg1){ - func_803866F4(marker_getActor(marker), arg1); + chRBBEggToll_setState(marker_getActor(marker), arg1); } void func_803865D0(ActorMarker *marker){ Actor* actor = marker_getActor(marker); - ActorLocal_RBB_0 * local = (ActorLocal_RBB_0 *) &actor->local; + ActorLocal_ChRBBEggToll * local = (ActorLocal_ChRBBEggToll *) &actor->local; RBB_func_803863F0(actor, 1); - timed_setStaticCameraToNode(0.0f, D_80390074[local->unk4].unk0); - timedFunc_set_2(0.75*D_80390074[local->unk4].unk4, (GenFunction_2) func_803865A4, (uintptr_t)actor->marker, 4); - timed_exitStaticCamera(0.75*D_80390074[local->unk4].unk4); - func_80324E38(0.75*D_80390074[local->unk4].unk4, 0); - timed_playSfx(D_80390074[local->unk4].unk4, SFX_7F_HEAVYDOOR_SLAM, 0.8f, 0x7fd0); + timed_setStaticCameraToNode(0.0f, chRBBEggTollInfoTable[local->tollId].cameraNode); + timedFunc_set_2(0.75 * chRBBEggTollInfoTable[local->tollId].unk4, (GenFunction_2) func_803865A4, (uintptr_t)actor->marker, 4); + timed_exitStaticCamera(0.75 * chRBBEggTollInfoTable[local->tollId].unk4); + func_80324E38(0.75 * chRBBEggTollInfoTable[local->tollId].unk4, 0); + timed_playSfx(chRBBEggTollInfoTable[local->tollId].unk4, SFX_7F_HEAVYDOOR_SLAM, 0.8f, 0x7FD0); } -void func_803866F4(Actor *this, s32 arg1){ - ActorLocal_RBB_0 *local = (ActorLocal_RBB_0 *) &this->local; +void chRBBEggToll_setState(Actor *this, s32 next_state){ + ActorLocal_ChRBBEggToll *local = (ActorLocal_ChRBBEggToll *) &this->local; - if(arg1 == 2){ + if(next_state == CH_RBB_EGG_TOLL_STATE_2_FIRST_EGG_PAID){ coMusicPlayer_playMusic(COMUSIC_2B_DING_B, 28000); - local = (ActorLocal_RBB_0 *) &this->local; + local = (ActorLocal_ChRBBEggToll *) &this->local; local->unkC = 3; } - if(arg1 == 3){ - local->unk8++; - port_eggToll_onAdvance((s32)gsworld_getMap(), this->secondaryId, local->unk8); + if(next_state == CH_RBB_EGG_TOLL_STATE_3_TOLL_COMPLETE){ + local->tollNum++; + port_eggToll_onAdvance((s32)gsworld_getMap(), this->secondaryId, local->tollNum); coMusicPlayer_playMusic(COMUSIC_2B_DING_B, 28000); func_80324E38(0.0f, 3); timedFunc_set_2(0.5f, (GenFunction_2) coMusicPlayer_playMusic, COMUSIC_2D_PUZZLE_SOLVED_FANFARE, 28000); timedFunc_set_1(1.0f, (GenFunction_1) func_803865D0, (uintptr_t)this->marker); }//L803867D4 - if(arg1 == 4){ - if(local->unk8 == 1 && D_80390074[local->unk4].unk2 > 0){ - func_803866F4(this, 1); + + if(next_state == CH_RBB_EGG_TOLL_STATE_4_UNK){ + if(local->tollNum == 1 && chRBBEggTollInfoTable[local->tollId].eggCost2 > 0){ + chRBBEggToll_setState(this, CH_RBB_EGG_TOLL_STATE_1_AWAITING_TOLL); return; } } - this->state = arg1; + this->state = next_state; } void func_8038685C(ActorMarker *marker){ Actor *actor = marker_getActor(marker); - ActorLocal_RBB_0 *local = (ActorLocal_RBB_0 *) &actor->local; + ActorLocal_ChRBBEggToll *local = (ActorLocal_ChRBBEggToll *) &actor->local; - if(actor->state == 1){ - local->unk0++; - if( D_80390074[local->unk4].unk1 == local->unk0 - || D_80390074[local->unk4].unk1 + D_80390074[local->unk4].unk2 == local->unk0 + if(actor->state == CH_RBB_EGG_TOLL_STATE_1_AWAITING_TOLL){ + local->eggsPaid++; + if( chRBBEggTollInfoTable[local->tollId].eggCost1 == local->eggsPaid + || chRBBEggTollInfoTable[local->tollId].eggCost1 + chRBBEggTollInfoTable[local->tollId].eggCost2 == local->eggsPaid ){ - func_803866F4(actor, 3); + chRBBEggToll_setState(actor, CH_RBB_EGG_TOLL_STATE_3_TOLL_COMPLETE); }else{ - func_803866F4(actor, 2); + chRBBEggToll_setState(actor, CH_RBB_EGG_TOLL_STATE_2_FIRST_EGG_PAID); } } } -void func_803868F0(Actor *this){ - ActorLocal_RBB_0 *local = (ActorLocal_RBB_0 *) &this->local; +void chRBBEggToll_update(Actor *this){ + ActorLocal_ChRBBEggToll *local = (ActorLocal_ChRBBEggToll *) &this->local; if(!this->volatile_initialized){ this->volatile_initialized = true; - if(this->state == 0){ - local->unk0 = 0; - local->unk4 = 0; - local->unk8 = 0; + if(this->state == CH_RBB_EGG_TOLL_STATE_0_NOT_INIT){ + local->eggsPaid = 0; + local->tollId = 0; + local->tollNum = 0; local->unkC = 0; - local->unk4 = (this->secondaryId == 0x15)? 0: local->unk4; - local->unk4 = (this->secondaryId == 0x13)? 1: local->unk4; - local->unk4 = (this->secondaryId == 0x14)? 2: local->unk4; - local->unk4 = (this->secondaryId == 0xB)? 3: local->unk4; - local->unk8 = port_eggToll_getStage((s32)gsworld_getMap(), this->secondaryId); - local->unk0 = eggToll_countForStage(local->unk4, local->unk8); - func_803866F4(this, 1); + local->tollId = (this->secondaryId == 0x15)? 0: local->tollId; + local->tollId = (this->secondaryId == 0x13)? 1: local->tollId; + local->tollId = (this->secondaryId == 0x14)? 2: local->tollId; + local->tollId = (this->secondaryId == 0x0B)? 3: local->tollId; + local->tollNum = port_eggToll_getStage((s32)gsworld_getMap(), this->secondaryId); + local->eggsPaid = eggToll_countForStage(local->tollId, local->tollNum); + chRBBEggToll_setState(this, CH_RBB_EGG_TOLL_STATE_1_AWAITING_TOLL); } RBB_func_803863F0(this, 0); }//L803869F4 - if(this->state == 2){ + if(this->state == CH_RBB_EGG_TOLL_STATE_2_FIRST_EGG_PAID){ if(--local->unkC <= 0){ - func_803866F4(this, 1); + chRBBEggToll_setState(this, CH_RBB_EGG_TOLL_STATE_1_AWAITING_TOLL); } } @@ -193,17 +202,17 @@ void port_eggToll_remoteApply(s32 map, s32 secondaryId, s32 stage) { } for (i = 0; i < suBaddieActorArray->cnt; i++) { Actor *actor = &suBaddieActorArray->data[i]; - ActorLocal_RBB_0 *local; + ActorLocal_ChRBBEggToll *local; if (actor->marker == NULL || actor->marker->id != MARKER_182_RBB_EGG_TOLL) { continue; } if (actor->secondaryId != secondaryId) { continue; } - local = (ActorLocal_RBB_0 *) &actor->local; - if (stage > local->unk8) { - local->unk8 = stage; - local->unk0 = eggToll_countForStage(local->unk4, stage); + local = (ActorLocal_ChRBBEggToll *) &actor->local; + if (stage > local->tollNum) { + local->tollNum = stage; + local->eggsPaid = eggToll_countForStage(local->tollId, stage); RBB_func_803863F0(actor, 1); coMusicPlayer_playMusic(COMUSIC_2B_DING_B, 28000); } diff --git a/src/RBB/ch/enginefan.c b/src/RBB/ch/enginefan.c index 6c9e30265..86c251635 100644 --- a/src/RBB/ch/enginefan.c +++ b/src/RBB/ch/enginefan.c @@ -22,7 +22,7 @@ typedef struct { f32 unk28; }ActorLocal_RBB_2E90; -void func_8038944C(Actor *this); +void chEngineRoomPropeller_update(Actor *this); /* .data */ @@ -57,24 +57,35 @@ Struct_RBB_2E90_0 D_80390530[] = { {0} }; -ActorInfo D_80390640 = { - MARKER_191_ENGINE_ROOM_PROPELLOR_1, ACTOR_1BB_ENGINE_ROOM_PROPELLOR_1, ASSET_40F_MODEL_ENGINE_ROOM_PROPELLER_1, 0x0, NULL, - func_8038944C, NULL, actor_draw, +ActorInfo chEngineRoomPropeller1 = { + MARKER_191_ENGINE_ROOM_PROPELLOR_1, ACTOR_1BB_ENGINE_ROOM_PROPELLOR_1, ASSET_40F_MODEL_ENGINE_ROOM_PROPELLER_1, + 0x0, NULL, + chEngineRoomPropeller_update, NULL, actor_draw, 0, 0, 0.0f, 0 }; -ActorInfo D_80390664 = { - MARKER_192_ENGINE_ROOM_PROPELLOR_2, ACTOR_1BC_ENGINE_ROOM_PROPELLOR_2, ASSET_410_MODEL_ENGINE_ROOM_PROPELLER_2, 0x0, NULL, - func_8038944C, NULL, actor_draw, +ActorInfo chEngineRoomPropeller2 = { + MARKER_192_ENGINE_ROOM_PROPELLOR_2, ACTOR_1BC_ENGINE_ROOM_PROPELLOR_2, ASSET_410_MODEL_ENGINE_ROOM_PROPELLER_2, + 0x0, NULL, + chEngineRoomPropeller_update, NULL, actor_draw, 0, 0, 0.0f, 0 }; -ActorInfo D_80390688 = { - MARKER_193_ENGINE_ROOM_PROPELLOR_3, ACTOR_1BD_ENGINE_ROOM_PROPELLOR_3, ASSET_411_MODEL_ENGINE_ROOM_PROPELLER_3, 0x0, NULL, - func_8038944C, NULL, actor_draw, +ActorInfo chEngineRoomPropeller3 = { + MARKER_193_ENGINE_ROOM_PROPELLOR_3, ACTOR_1BD_ENGINE_ROOM_PROPELLOR_3, ASSET_411_MODEL_ENGINE_ROOM_PROPELLER_3, + 0x0, NULL, + chEngineRoomPropeller_update, NULL, actor_draw, 0, 0, 0.0f, 0 }; +enum chengineroompropeller_state_e { + CH_ENGINE_ROOM_PROPELLER_STATE_0_NOT_INIT, + CH_ENGINE_ROOM_PROPELLER_STATE_1_UNK, + CH_ENGINE_ROOM_PROPELLER_STATE_2_UNK, + CH_ENGINE_ROOM_PROPELLER_STATE_3_UNK, + CH_ENGINE_ROOM_PROPELLER_STATE_4_UNK +}; + /* .code */ Struct_RBB_2E90_0 * func_80389280(Actor *this){ Struct_RBB_2E90_0 * iPtr; @@ -85,13 +96,13 @@ Struct_RBB_2E90_0 * func_80389280(Actor *this){ return NULL; } -void func_803892D8(Actor *this, s32 arg1){ +void chEngineRoomPropeller_setState(Actor *this, s32 next_state){ f32 pad; ActorLocal_RBB_2E90 *local = (ActorLocal_RBB_2E90 *)&this->local; - this->state = arg1; + this->state = next_state; local->unk28 = 0.0f; - if(this->state == 1){ + if(this->state == CH_ENGINE_ROOM_PROPELLER_STATE_1_UNK){ local->unk0[2] = 0.0f; local->unk0[1] = 0.0f; local->unk0[0] = 0.0f; @@ -99,19 +110,19 @@ void func_803892D8(Actor *this, s32 arg1){ ml_vec3f_copy(local->unk1C, local->unkC->unk1C); }//L8038935C - if(this->state == 2){ + if(this->state == CH_ENGINE_ROOM_PROPELLER_STATE_2_UNK){ ml_vec3f_copy(local->unk0, local->unkC->unk28); ml_vec3f_copy(local->unk1C, local->unkC->unk10); local->unk28 = local->unkC->unk40; }//L803893A8 - if(this->state == 3){ + if(this->state == CH_ENGINE_ROOM_PROPELLER_STATE_3_UNK){ ml_vec3f_copy(local->unk0, local->unkC->unk28); ml_vec3f_copy(local->unk1C, local->unkC->unk1C); local->unk28 = local->unkC->unk40; }//L803893F4 - if(this->state == 4){ + if(this->state == CH_ENGINE_ROOM_PROPELLER_STATE_4_UNK){ ml_vec3f_copy(local->unk0, local->unkC->unk34); ml_vec3f_copy(local->unk10, local->unkC->unk1C); local->unk1C[2] = 0.0f; @@ -120,12 +131,12 @@ void func_803892D8(Actor *this, s32 arg1){ } } -void func_8038944C(Actor *this){ +void chEngineRoomPropeller_update(Actor *this){ ActorLocal_RBB_2E90 *local = (ActorLocal_RBB_2E90 *)&this->local; f32 tick; int i; - f32 sp50[3]; - f32 sp44[3]; + f32 current_rotation[3]; + f32 next_rotation[3]; tick = time_getDelta(); @@ -133,69 +144,72 @@ void func_8038944C(Actor *this){ this->marker->propPtr->unk8_3 = 1; this->volatile_initialized = true; local->unkC = func_80389280(this); - if(this->state == 0){ + if(this->state == CH_ENGINE_ROOM_PROPELLER_STATE_0_NOT_INIT){ ml_vec3f_copy(this->position, local->unkC->unk4); local->unk0[0] = local->unk0[1] = local->unk0[2] = 0.0f; local->unk10[0] = local->unk10[1] = local->unk10[2] = 0.0f; local->unk1C[0] = local->unk1C[1] = local->unk1C[2] = 0.0f; local->unk28 = 0.0f; - func_803892D8(this, 1); + chEngineRoomPropeller_setState(this, CH_ENGINE_ROOM_PROPELLER_STATE_1_UNK); } }//L80389508 if(ml_timer_update(&local->unk28, tick)){ - if(this->state == 2) - func_803892D8(this, 3); - else if(this->state == 3) - func_803892D8(this, 2); + if(this->state == CH_ENGINE_ROOM_PROPELLER_STATE_2_UNK) + chEngineRoomPropeller_setState(this, CH_ENGINE_ROOM_PROPELLER_STATE_3_UNK); + else if(this->state == CH_ENGINE_ROOM_PROPELLER_STATE_3_UNK) + chEngineRoomPropeller_setState(this, CH_ENGINE_ROOM_PROPELLER_STATE_2_UNK); }//L80389568 switch (this->state) { - case 1: - case 2: - case 3: - case 4: - sp50[0] = this->pitch; - sp50[1] = this->yaw; - sp50[2] = this->roll; - this->pitch += local->unk10[0]*tick ; - this->yaw += local->unk10[1]*tick ; - this->roll += local->unk10[2]*tick ; - - sp44[0] = this->pitch; - sp44[1] = this->yaw; - sp44[2] = this->roll; - - for(i = 0; i < 3; i++){ - if( (sp50[i] < 90.0f && 90.0f <= sp44[i]) - || (sp50[i] < 270.0f && 270.0f <= sp44[i]) - || (sp50[i] < 180.0f && 180.0f <= sp44[i]) - || (sp50[i] < 360.0f && 360.0f <= sp44[i]) - ){ - sfx_playFadeShorthandDefault(SFX_2_CLAW_SWIPE, 0.4f, 23000, this->position, 50, 1000); - } - } - this->pitch += (360.0f <= this->pitch)? -360 : 0; - this->yaw += (360.0f <= this->yaw)? -360 : 0; - this->roll += (360.0f <= this->roll)? -360 : 0; - - for(i = 0; i < 3; i++){//L803897B8 - if( local->unk10[i] < local->unk1C[i] ){ - local->unk10[i] += local->unk0[i]*tick; - local->unk10[i] = MIN(local->unk1C[i] , local->unk10[i]); + case CH_ENGINE_ROOM_PROPELLER_STATE_1_UNK: + case CH_ENGINE_ROOM_PROPELLER_STATE_2_UNK: + case CH_ENGINE_ROOM_PROPELLER_STATE_3_UNK: + case CH_ENGINE_ROOM_PROPELLER_STATE_4_UNK: + current_rotation[0] = this->pitch; + current_rotation[1] = this->yaw; + current_rotation[2] = this->roll; + + this->pitch += local->unk10[0] * tick; + this->yaw += local->unk10[1] * tick; + this->roll += local->unk10[2] * tick; + + next_rotation[0] = this->pitch; + next_rotation[1] = this->yaw; + next_rotation[2] = this->roll; + + for(i = 0; i < 3; i++){ + if( (current_rotation[i] < 90.0f && 90.0f <= next_rotation[i]) + || (current_rotation[i] < 270.0f && 270.0f <= next_rotation[i]) + || (current_rotation[i] < 180.0f && 180.0f <= next_rotation[i]) + || (current_rotation[i] < 360.0f && 360.0f <= next_rotation[i]) + ){ + sfx_playFadeShorthandDefault(SFX_2_CLAW_SWIPE, 0.4f, 23000, this->position, 50, 1000); + } } - else if( local->unk1C[i] < local->unk10[i]){ - local->unk10[i] -= local->unk0[i]*tick; - local->unk10[i] = MAX(local->unk1C[i] , local->unk10[i]); + this->pitch += (360.0f <= this->pitch)? -360 : 0; + this->yaw += (360.0f <= this->yaw)? -360 : 0; + this->roll += (360.0f <= this->roll)? -360 : 0; + + for(i = 0; i < 3; i++){//L803897B8 + if( local->unk10[i] < local->unk1C[i] ){ + local->unk10[i] += local->unk0[i] * tick; + local->unk10[i] = MIN(local->unk1C[i] , local->unk10[i]); + } + else if( local->unk1C[i] < local->unk10[i]){ + local->unk10[i] -= local->unk0[i] * tick; + local->unk10[i] = MAX(local->unk1C[i] , local->unk10[i]); + } } - } - break; + break; }//L80389860 - if(this->state == 1 && mapSpecificFlags_get(0)){ - func_803892D8(this, 2); + if(this->state == CH_ENGINE_ROOM_PROPELLER_STATE_1_UNK + && mapSpecificFlags_get(RBB_MAIN_SPECIFIC_FLAG_0_PROPELLER)) + { + chEngineRoomPropeller_setState(this, CH_ENGINE_ROOM_PROPELLER_STATE_2_UNK); } if(tick); } diff --git a/src/RBB/ch/enginefanswitch.c b/src/RBB/ch/enginefanswitch.c index e963814e2..8b0937b79 100644 --- a/src/RBB/ch/enginefanswitch.c +++ b/src/RBB/ch/enginefanswitch.c @@ -8,25 +8,32 @@ void chEngineFanSwitch_update(Actor *this); /* .data */ -ActorInfo D_803906B0 = { - 0x194, 0x1BE, 0x412, 0x0, NULL, +ActorInfo chRBBGreyPropellerSwitch = { + MARKER_194_RBB_GREY_PROPELLER_SWITCH, ACTOR_1BE_RBB_GREY_PROPELLOR_SWITCH, ASSET_412_MODEL_RBB_GREY_PROPELLER_SWITCH, + 0x0, NULL, chEngineFanSwitch_update, NULL, actor_draw, 0, 0, 0.0f, 0 }; +enum chrbbgreypropellerswitch_state_e { + CH_RBB_GREY_PROPELLER_SWITCH_STATE_0_NOT_INIT, + CH_RBB_GREY_PROPELLER_SWITCH_STATE_1_NOT_PRESSED, + CH_RBB_GREY_PROPELLER_SWITCH_STATE_2_PRESSED +}; + /* .code */ -void RBB_func_803898A0(void){ - mapSpecificFlags_set(0, 1); +void chEngineFanSwitch_setPressedFlag(void){ + mapSpecificFlags_set(RBB_MAIN_SPECIFIC_FLAG_0_PROPELLER, true); } void chEngineFanSwitch_setState(Actor * this, s32 arg1){ this->state = arg1; - if(this->state == 2){ + if(this->state == CH_RBB_GREY_PROPELLER_SWITCH_STATE_2_PRESSED){ func_8030E6D4(SFX_90_SWITCH_PRESS); this->position_y -= 35.0f; func_80324E38(1.0f, 3); timed_setStaticCameraToNode(1.0f, 0); - timedFunc_set_0(1.0f, RBB_func_803898A0); + timedFunc_set_0(1.0f, chEngineFanSwitch_setPressedFlag); timed_exitStaticCamera(5.0f); func_80324E38(5.0f, 0); } @@ -34,8 +41,8 @@ void chEngineFanSwitch_setState(Actor * this, s32 arg1){ void __chEngineFanSwitch_pressCallback(ActorMarker *marker, ActorMarker *arg1){ Actor *actor = marker_getActor(marker); - if(actor->state == 1){ - chEngineFanSwitch_setState(actor, 2); + if(actor->state == CH_RBB_GREY_PROPELLER_SWITCH_STATE_1_NOT_PRESSED){ + chEngineFanSwitch_setState(actor, CH_RBB_GREY_PROPELLER_SWITCH_STATE_2_PRESSED); } } @@ -43,14 +50,14 @@ void chEngineFanSwitch_update(Actor *this){ if(!this->volatile_initialized){ //initialize this->marker->propPtr->unk8_3 = 1; this->volatile_initialized = true; - mapSpecificFlags_set(0, 0); + mapSpecificFlags_set(RBB_MAIN_SPECIFIC_FLAG_0_PROPELLER, false); marker_setCollisionScripts(this->marker, NULL, __chEngineFanSwitch_pressCallback, NULL); - if(this->state == 0){ + if(this->state == CH_RBB_GREY_PROPELLER_SWITCH_STATE_0_NOT_INIT){ this->position_x = -3209.95f; this->position_y = 1164.5f; this->position_z = -2649.95f; this->yaw = -90.0f; - chEngineFanSwitch_setState(this, 1); + chEngineFanSwitch_setState(this, CH_RBB_GREY_PROPELLER_SWITCH_STATE_1_NOT_PRESSED); } } // [port] Anchor temp-persist: the fan slowdown is transient map flag 0, set by pressing this diff --git a/src/RBB/ch/engineparts.c b/src/RBB/ch/engineparts.c index 59ffc0855..6515a0881 100644 --- a/src/RBB/ch/engineparts.c +++ b/src/RBB/ch/engineparts.c @@ -22,7 +22,7 @@ typedef struct { f32 unk1C; }ActorLocal_RBB_40F0; -void func_8038A724(Actor *this); +void chRBBSpinningPipe_update(Actor *this); /* .data */ Struct_RBB_40F0 D_80390760[4] = { @@ -32,65 +32,75 @@ Struct_RBB_40F0 D_80390760[4] = { {{ -300.0f, 641.5f, -400.0f}, {-500.0f, 0.0f, 0.0f}, 0x28, 1}, }; -ActorInfo D_803907D0 = { - 0x187, 0x177, 0x406, 0x0, NULL, - func_8038A724, NULL, actor_draw, +ActorInfo chRBBSpinningSinglePipe1 = { + MARKER_187_RBB_SPINNING_SINGLE_PIPE_1, ACTOR_177_RBB_SPINNING_SINGLE_PIPE_1, ASSET_406_MODEL_RBB_SPINNING_SINGLE_PIPE, 0x0, NULL, + chRBBSpinningPipe_update, NULL, actor_draw, 0, 0, 0.0f, 0 }; -ActorInfo D_803907F4 = { - 0x18E, 0x17E, 0x406, 0x0, NULL, - func_8038A724, NULL, actor_draw, +ActorInfo chRBBSpinningSinglePipe2 = { + MARKER_18E_RBB_SPINNING_SINGLE_PIPE_2, ACTOR_17E_RBB_SPINNING_SINGLE_PIPE_2, ASSET_406_MODEL_RBB_SPINNING_SINGLE_PIPE, + 0x0, NULL, + chRBBSpinningPipe_update, NULL, actor_draw, 0, 0, 0.0f, 0 }; -ActorInfo D_80390818 = { - 0x18F, 0x17F, 0x407, 0x0, NULL, - func_8038A724, NULL, actor_draw, +ActorInfo chRBBSpinningDoublePipe1 = { + MARKER_18F_RBB_SPINNING_DOUBLE_PIPE_1, ACTOR_17F_RBB_SPINNING_DOUBLE_PIPE_1, ASSET_407_MODEL_RBB_SPINNING_DOUBLEE_PIPE_RIGHT, + 0x0, NULL, + chRBBSpinningPipe_update, NULL, actor_draw, 0, 0, 0.0f, 0 }; -ActorInfo D_8039083C = { - 0x190, 0x180, 0x408, 0x0, NULL, - func_8038A724, NULL, actor_draw, +ActorInfo chRBBSpinningDoublePipe2 = { + MARKER_190_RBB_SPINNING_DOUBLE_PIPE_2, ACTOR_180_RBB_SPINNING_DOUBLE_PIPE_2, ASSET_408_MODEL_RBB_SPINNING_DOUBLEE_PIPE_LEFT, + 0x0, NULL, + chRBBSpinningPipe_update, NULL, actor_draw, 0, 0, 0.0f, 0 }; f32 D_80390860[3] = {1.0f, 0.5f, 0.5f}; +enum chrbbspinningpipe_state_e { + CH_RBB_SPINNING_PIPE_STATE_0_NOT_INIT, + CH_RBB_SPINNING_PIPE_STATE_1_UNK, + CH_RBB_SPINNING_PIPE_STATE_2_UNK, + CH_RBB_SPINNING_PIPE_STATE_3_UNK +}; + /* .code */ f32 func_8038A4E0(void) { return D_80390860[2 * levelSpecificFlags_get(LEVEL_FLAG_27_RBB_UNKNOWN) + levelSpecificFlags_get(LEVEL_FLAG_28_RBB_UNKNOWN)]; } -void func_8038A524(Actor *this, s32 arg1){ +void chRBBSpinningPipe_setState(Actor *this, s32 next_state){ ActorLocal_RBB_40F0 *local = (ActorLocal_RBB_40F0 *)&this->local; local->unk1C = 0.0f; - if(arg1 == 1){ + if(next_state == CH_RBB_SPINNING_PIPE_STATE_1_UNK){ if(D_80390760[local->unk0].unk1A){ - func_8038A524(this, 2); + chRBBSpinningPipe_setState(this, CH_RBB_SPINNING_PIPE_STATE_2_UNK); return; } - local->unk10[0] = D_80390760[local->unk0].unkC[0]*func_8038A4E0(); - local->unk10[1] = D_80390760[local->unk0].unkC[1]*func_8038A4E0(); - local->unk10[2] = D_80390760[local->unk0].unkC[2]*func_8038A4E0(); + local->unk10[0] = D_80390760[local->unk0].unkC[0] * func_8038A4E0(); + local->unk10[1] = D_80390760[local->unk0].unkC[1] * func_8038A4E0(); + local->unk10[2] = D_80390760[local->unk0].unkC[2] * func_8038A4E0(); } - if(arg1 == 2){ - local->unk10[0] = D_80390760[local->unk0].unkC[0]*func_8038A4E0(); - local->unk10[1] = D_80390760[local->unk0].unkC[1]*func_8038A4E0(); - local->unk10[2] = D_80390760[local->unk0].unkC[2]*func_8038A4E0(); + if(next_state == CH_RBB_SPINNING_PIPE_STATE_2_UNK){ + local->unk10[0] = D_80390760[local->unk0].unkC[0] * func_8038A4E0(); + local->unk10[1] = D_80390760[local->unk0].unkC[1] * func_8038A4E0(); + local->unk10[2] = D_80390760[local->unk0].unkC[2] * func_8038A4E0(); } - if(arg1 == 3){ + if(next_state == CH_RBB_SPINNING_PIPE_STATE_3_UNK){ local->unk10[2] = 0.0f; local->unk10[1] = 0.0f; local->unk10[0] = 0.0f; } - this->state = arg1; + this->state = next_state; } f32 func_8038A6B8(ActorMarker *marker){ @@ -102,13 +112,13 @@ f32 func_8038A6B8(ActorMarker *marker){ for(i = 0; i < 3; i++){ f12 += ABS(local->unk4[i]); } - return f12/500.0f; + return f12 / 500.0f; } -void func_8038A724(Actor *this){ +void chRBBSpinningPipe_update(Actor *this){ ActorLocal_RBB_40F0 *local = (ActorLocal_RBB_40F0 *)&this->local; int i; - f32 sp1C = time_getDelta(); + f32 time_delta = time_getDelta(); if(!this->volatile_initialized){ @@ -116,41 +126,41 @@ void func_8038A724(Actor *this){ this->volatile_initialized = true; actor_collisionOff(this); local->unk0 = 0; - local->unk0 = (this->modelCacheIndex == 0x17E) ? 1: local->unk0; - local->unk0 = (this->modelCacheIndex == 0x17F) ? 2: local->unk0; - local->unk0 = (this->modelCacheIndex == 0x180) ? 3: local->unk0; + local->unk0 = (this->modelCacheIndex == ACTOR_17E_RBB_SPINNING_SINGLE_PIPE_2) ? 1: local->unk0; + local->unk0 = (this->modelCacheIndex == ACTOR_17F_RBB_SPINNING_DOUBLE_PIPE_1) ? 2: local->unk0; + local->unk0 = (this->modelCacheIndex == ACTOR_180_RBB_SPINNING_DOUBLE_PIPE_2) ? 3: local->unk0; this->position_x = D_80390760[local->unk0].unk0[0]; this->position_y = D_80390760[local->unk0].unk0[1]; this->position_z = D_80390760[local->unk0].unk0[2]; - func_8038A524(this, 1); + chRBBSpinningPipe_setState(this, CH_RBB_SPINNING_PIPE_STATE_1_UNK); }//L8038A884 - this->pitch += local->unk4[0]*sp1C; - this->yaw += local->unk4[1]*sp1C; - this->roll += local->unk4[2]*sp1C; + this->pitch += local->unk4[0] * time_delta; + this->yaw += local->unk4[1] * time_delta; + this->roll += local->unk4[2] * time_delta; for(i = 0; i < 3; i++){//L8038A8D4 if(local->unk10[i] < local->unk4[i]){ - local->unk4[i] -= 75.0f*sp1C; + local->unk4[i] -= 75.0f * time_delta; local->unk4[i] = MAX(local->unk10[i], local->unk4[i]); }//L8038A924 else if(local->unk4[i] < local->unk10[i]){ - local->unk4[i] += 75.0f*sp1C; + local->unk4[i] += 75.0f * time_delta; local->unk4[i] = MIN(local->unk10[i], local->unk4[i]); } } - if(this->state == 1){ - local->unk10[0] = D_80390760[local->unk0].unkC[0]*func_8038A4E0(); - local->unk10[1] = D_80390760[local->unk0].unkC[1]*func_8038A4E0(); - local->unk10[2] = D_80390760[local->unk0].unkC[2]*func_8038A4E0(); + if(this->state == CH_RBB_SPINNING_PIPE_STATE_1_UNK){ + local->unk10[0] = D_80390760[local->unk0].unkC[0] * func_8038A4E0(); + local->unk10[1] = D_80390760[local->unk0].unkC[1] * func_8038A4E0(); + local->unk10[2] = D_80390760[local->unk0].unkC[2] * func_8038A4E0(); } - if(this->state == 2){ + if(this->state == CH_RBB_SPINNING_PIPE_STATE_2_UNK){ if(0.0f < local->unk1C){ - if(ml_timer_update(&local->unk1C, sp1C)){ - func_8038A524(this, 3); + if(ml_timer_update(&local->unk1C, time_delta)){ + chRBBSpinningPipe_setState(this, CH_RBB_SPINNING_PIPE_STATE_3_UNK); }//L8038AA8C }else{ if( local->unk4[0] == local->unk10[0] @@ -162,10 +172,10 @@ void func_8038A724(Actor *this){ } }//L8038AB04 - if(this->state == 3){ + if(this->state == CH_RBB_SPINNING_PIPE_STATE_3_UNK){ if(0.0f < local->unk1C){ - if(ml_timer_update(&local->unk1C, sp1C)){ - func_8038A524(this, 2); + if(ml_timer_update(&local->unk1C, time_delta)){ + chRBBSpinningPipe_setState(this, CH_RBB_SPINNING_PIPE_STATE_2_UNK); }//L8038AA8C }else{ if( local->unk4[0] == local->unk10[0] diff --git a/src/RBB/ch/grimlet.c b/src/RBB/ch/grimlet.c index 8005b2884..194a093b8 100644 --- a/src/RBB/ch/grimlet.c +++ b/src/RBB/ch/grimlet.c @@ -14,27 +14,34 @@ typedef struct { f32 unk14; }ActorLocal_RBB_1FC0; -Actor *func_8038846C(ActorMarker * marker, Gfx **gdl, Mtx **mptr, Vtx **arg3); -void func_80388620(Actor *this); +Actor *chGrimlet_draw(ActorMarker * marker, Gfx **gdl, Mtx **mptr, Vtx **arg3); +void chGrimlet_update(Actor *this); /* .data */ -ActorInfo D_80390380 = { - MARKER_2E_GRIMLET, ACTOR_1C6_GRIMLET, ASSET_419_MODEL_GRIMLET, 0x0, NULL, - func_80388620, NULL, func_8038846C, +ActorInfo chGrimlet = { + MARKER_2E_GRIMLET, ACTOR_1C6_GRIMLET, ASSET_419_MODEL_GRIMLET, + 0x0, NULL, + chGrimlet_update, NULL, chGrimlet_draw, 0, 0, 0.0f, 0 }; +enum chgrimlet_state_e { + CH_GRIMLET_STATE_0_NOT_INIT, + CH_GRIMLET_STATE_1_UNK, + CH_GRIMLET_STATE_2_UNK +}; + /* .code */ -void func_803883B0(Actor *this, s32 arg1){ +void chGrimlet_setState(Actor *this, s32 next_state){ ActorLocal_RBB_1FC0 *local = (ActorLocal_RBB_1FC0 *)&this->local; local->unk5 = 0; - if(arg1 == 2){ + if(next_state == CH_GRIMLET_STATE_2_UNK){ FUNC_8030E624(SFX_66_BIRD_AUUGHH, 0.6f, 32675); - skeletalAnim_set(this->unk148, 0x137, 0.0f, 0.8f); + skeletalAnim_set(this->unk148, ASSET_137_ANIM_GRIMLET_ATTACK, 0.0f, 0.8f); skeletalAnim_setBehavior(this->unk148, SKELETAL_ANIM_2_ONCE); } - this->state = arg1; + this->state = next_state; } void RBB_func_80388430(ActorMarker * marker, ActorMarker *other_marker){ @@ -44,7 +51,7 @@ void RBB_func_80388430(ActorMarker * marker, ActorMarker *other_marker){ local->unk5 = 1; } -Actor *func_8038846C(ActorMarker * marker, Gfx **gdl, Mtx **mptr, Vtx **vtx){ +Actor *chGrimlet_draw(ActorMarker * marker, Gfx **gdl, Mtx **mptr, Vtx **vtx){ Actor *actor = marker_getActor(marker); ActorLocal_RBB_1FC0 *local = (ActorLocal_RBB_1FC0 *) &actor->local; BoneTransformList *sp5C; @@ -53,7 +60,7 @@ Actor *func_8038846C(ActorMarker * marker, Gfx **gdl, Mtx **mptr, Vtx **vtx){ f32 sp40[3]; f32 sp34[3]; - if(actor->state == 0){ + if(actor->state == CH_GRIMLET_STATE_0_NOT_INIT){ return actor; } @@ -77,22 +84,22 @@ Actor *func_8038846C(ActorMarker * marker, Gfx **gdl, Mtx **mptr, Vtx **vtx){ func_8033A968(sp5C, 0x12, sp34); skeletalAnim_func_80335918(actor->unk148); } - func_8033A45C(3, (0.0f < local->unk8)? 1 : 0); - func_8033A45C(4, (0.0f < local->unk8)? 1 : 0); + modelRender_setAppendageVisibility(3, (0.0f < local->unk8)? 1 : 0); + modelRender_setAppendageVisibility(4, (0.0f < local->unk8)? 1 : 0); actor_draw(marker, gdl, mptr, vtx); local->unk4 = actor->marker->unk14_21; return actor; } -void func_80388620(Actor *this){ +void chGrimlet_update(Actor *this){ f32 plyr_pos[3]; - f32 sp60; - f32 sp5C; - f32 sp58; + f32 horizontal_distance; + f32 distance_in_front; + f32 side_angle_radian; ActorLocal_RBB_1FC0 *local = (ActorLocal_RBB_1FC0 *)&this->local; - f32 sp50 = time_getDelta(); - f32 sp4C; - f32 sp48; + f32 time_delta = time_getDelta(); + f32 prev_anim_progress; + f32 curr_anim_progress; f32 tmp_f2; if(!this->volatile_initialized){ @@ -105,80 +112,84 @@ void func_80388620(Actor *this){ local->unkC = 0.0f; local->unk10 = 0.0f; local->unk14 = 0.0f; - func_803883B0(this, 1); + chGrimlet_setState(this, CH_GRIMLET_STATE_1_UNK); } player_getPosition(plyr_pos); - func_80258A4C(this->position, this->yaw + -90.0f, plyr_pos, &sp60, &sp5C, &sp58); - if(sp60 < 600.0f) + func_80258A4C( + this->position, this->yaw + -90.0f, plyr_pos, + &horizontal_distance, &distance_in_front, &side_angle_radian); + if(horizontal_distance < 600.0f) local->unk8 = 1.0f; else{ - local->unk8 -= sp50; + local->unk8 -= time_delta; local->unk8 = MAX(0.0f, local->unk8); } if( 500.0f <= local->unk10 - && sp60 < 500.0f - && (sp58 < -0.2 || 0.2 < sp58) + && horizontal_distance < 500.0f + && (side_angle_radian < -0.2 || 0.2 < side_angle_radian) ){ FUNC_8030E624(SFX_C4_TWINKLY_MUNCHER_GRR, 0.8f, 32675); } - local->unk10 = sp60; - local->unk14 = local->unk14 + sp50; + local->unk10 = horizontal_distance; + local->unk14 = local->unk14 + time_delta; - if( sp60 < 600.0f - && -1.0f < sp58 - && sp58 < 1.0f + if( horizontal_distance < 600.0f + && -1.0f < side_angle_radian + && side_angle_radian < 1.0f && plyr_pos[1] < this->position_y + this->scale*200.0f ){ - func_80258A4C(this->position, (this->yaw + -90.0f) + local->unk0, plyr_pos, &sp60, &sp5C, &sp58); - local->unk0 += (sp58*200.0f)*sp50; - if(1.0f < local->unk14 && (sp58 < -0.1 || 0.1 < sp58)){ - gcsfx_playWithPitch(SFX_D0_GRIMLET_SQUEAK, mlAbsF(sp58) * 0.1 + 0.9, 0x4e20); + func_80258A4C( + this->position, (this->yaw + -90.0f) + local->unk0, plyr_pos, + &horizontal_distance, &distance_in_front, &side_angle_radian); + local->unk0 += (side_angle_radian * 200.0f) * time_delta; + if(1.0f < local->unk14 && (side_angle_radian < -0.1 || 0.1 < side_angle_radian)){ + gcsfx_playWithPitch(SFX_D0_GRIMLET_SQUEAK, mlAbsF(side_angle_radian) * 0.1 + 0.9, 0x4e20); local->unk14 = 0.0f; } } else{//L80388964 if(0.0f < local->unk0){ - local->unk0 -= 30.0f*sp50; + local->unk0 -= 30.0f * time_delta; local->unk0 = MAX(0.0f, local->unk0); }//L803889B4 else{ if(local->unk0 < 0.0f){ - local->unk0 += 30.0f*sp50; + local->unk0 += 30.0f * time_delta; local->unk0 = MIN(0.0f, local->unk0); } } }//L803889F8 - if(this->state == 1){ - if( sp60 < 400.0f - && -0.8 <= sp58 - && sp58 <= 0.8 + if(this->state == CH_GRIMLET_STATE_1_UNK){ + if( horizontal_distance < 400.0f + && -0.8 <= side_angle_radian + && side_angle_radian <= 0.8 && (plyr_pos[1] - this->position_y) < 100.0f && -100.0f < (plyr_pos[1] - this->position_y) ){ - func_803883B0(this, 2); + chGrimlet_setState(this, CH_GRIMLET_STATE_2_UNK); } }//L80388AB8 - if(this->state == 2){ - skeletalAnim_getProgressRange(this->unk148, &sp4C, &sp48); - if(0.6 <= sp48) - tmp_f2 = 1.0 - 2*(sp48 - 0.6); + if(this->state == CH_GRIMLET_STATE_2_UNK){ + skeletalAnim_getProgressRange(this->unk148, &prev_anim_progress, &curr_anim_progress); + if(0.6 <= curr_anim_progress) + tmp_f2 = 1.0 - 2 * (curr_anim_progress - 0.6); else - tmp_f2 = sp48*1.6666666666666667; + tmp_f2 = curr_anim_progress * 1.6666666666666667; //L80388B34 - local->unkC = tmp_f2*sp60; + local->unkC = tmp_f2 * horizontal_distance; - if( sp4C < 0.55 - && 0.55 <= sp48 + if( prev_anim_progress < 0.55 + && 0.55 <= curr_anim_progress && !local->unk5 ){ sfx_playFadeShorthandDefault(SFX_20_METAL_CLANK_1, 1.0f, 32000, this->position, 500, 2500); } if(skeletalAnim_getLoopCount(this->unk148) > 0) - func_803883B0(this, 1); + chGrimlet_setState(this, CH_GRIMLET_STATE_1_UNK); }//L80388BB0 } diff --git a/src/RBB/ch/propellor.c b/src/RBB/ch/propellor.c index 881cefc31..4cbff4e22 100644 --- a/src/RBB/ch/propellor.c +++ b/src/RBB/ch/propellor.c @@ -14,27 +14,32 @@ typedef struct { void chPropellor_update(Actor *this); /* .data */ -ActorInfo D_803906E0 = { - MARKER_185_RBB_REAR_PROPELLER, ACTOR_175_MODEL_RUSTY_BUCKET_REAR_PROPELLER, ASSET_403_MODEL_RUSTY_BUCKET_REAR_PROPELLER, +ActorInfo chRBBRearPropeller = { + MARKER_185_RBB_REAR_PROPELLER, ACTOR_175_RUSTY_BUCKET_REAR_PROPELLER, ASSET_403_MODEL_RUSTY_BUCKET_REAR_PROPELLER, 0x0, NULL, chPropellor_update, NULL, actor_draw, 0, 0, 0.0f, 0 }; -s32 D_80390704[4] = {0x258, 0x12C, 0x12C, 0}; +s32 chRBBRearPropellerSpeed[4] = {600, 300, 300, 0}; + +enum chrbbrearpropeller_state_e { + CH_RBB_REAR_PROPELLER_STATE_0_NOT_INIT, + CH_RBB_REAR_PROPELLER_STATE_1_UNK +}; /*.code */ f32 __chPropellor_getSpeed(void) { - return (f32) D_80390704[2 * levelSpecificFlags_get(LEVEL_FLAG_27_RBB_UNKNOWN) + levelSpecificFlags_get(LEVEL_FLAG_28_RBB_UNKNOWN)]; + return (f32) chRBBRearPropellerSpeed[2 * levelSpecificFlags_get(LEVEL_FLAG_27_RBB_UNKNOWN) + levelSpecificFlags_get(LEVEL_FLAG_28_RBB_UNKNOWN)]; } -void __chPropellor_setState(Actor *this, s32 arg1){ +void __chPropellor_setState(Actor *this, s32 next_state){ ActorLocal_RBB_36A0 * local = (ActorLocal_RBB_36A0 *)&this->local; - if(arg1 == 1){ + if(next_state == CH_RBB_REAR_PROPELLER_STATE_1_UNK){ local->unkC = __chPropellor_getSpeed(); local->unk4 = __chPropellor_getSpeed(); } - this->state = arg1; + this->state = next_state; } int func_80389B44(ActorMarker* marker, s32 arg1){ @@ -50,10 +55,10 @@ void func_80389B80(Actor *this, f32 arg1){ local->unk0 = func_802F9AA8(0x400); func_802F9DB8(local->unk0, arg1, arg1, 0.0f); func_802F9F80(local->unk0, 0.0f, 8999999488.0f, 0.0f); - func_802FA060(local->unk0, 0x4650, 0x4650, 0.0f); + func_802FA060(local->unk0, 18000, 18000, 0.0f); if (!levelSpecificFlags_get(LEVEL_FLAG_3_RBB_UNKNOWN) && !levelSpecificFlags_get(LEVEL_FLAG_4_RBB_UNKNOWN)) { - func_802F9EC4(local->unk0, this->position, 0x1f4, 0x7d0); + func_802F9EC4(local->unk0, this->position, 500, 2000); func_802FA0B0(local->unk0, 1); } } @@ -65,10 +70,10 @@ void __chPropellor_free(Actor *actor){ } -void chPropellor_update(Actor *this){ +void chPropellor_update(Actor *this){ ActorLocal_RBB_36A0 * local = (ActorLocal_RBB_36A0 *)&this->local; - f32 tmp; - f32 sp34 = time_getDelta(); + f32 prev_pitch; + f32 time_delta = time_getDelta(); if(!this->volatile_initialized){ this->volatile_initialized = true; @@ -91,7 +96,7 @@ void chPropellor_update(Actor *this){ }//L80389D7C local->unk4 = 0.0f; local->unkC = 0.0f; - __chPropellor_setState(this, 1); + __chPropellor_setState(this, CH_RBB_REAR_PROPELLER_STATE_1_UNK); if (levelSpecificFlags_get(local->unk8 ? LEVEL_FLAG_4_RBB_UNKNOWN : LEVEL_FLAG_3_RBB_UNKNOWN)) { ncStaticCamera_setToNode(9); @@ -105,10 +110,10 @@ void chPropellor_update(Actor *this){ } }//L80389EA8 - tmp = this->pitch; - this->pitch -= local->unkC*sp34; - if( (0.0f < tmp && this->pitch <= 0.0f) - || (180.0f < tmp && this->pitch <= 180.0f) + prev_pitch = this->pitch; + this->pitch -= local->unkC * time_delta; + if( (0.0f < prev_pitch && this->pitch <= 0.0f) + || (180.0f < prev_pitch && this->pitch <= 180.0f) ){ if (levelSpecificFlags_get(LEVEL_FLAG_3_RBB_UNKNOWN) || levelSpecificFlags_get(LEVEL_FLAG_4_RBB_UNKNOWN)) { func_8030E760(SFX_2_CLAW_SWIPE, 0.4f, 20000); @@ -123,11 +128,11 @@ void chPropellor_update(Actor *this){ if(this->state == 1){ local->unk4 = __chPropellor_getSpeed(); if(local->unkC < local->unk4){ - local->unkC += 75*sp34; + local->unkC += 75 * time_delta; local->unkC = MIN(local->unk4, local->unkC); }//L8038A03C if(local->unk4 < local->unkC){ - local->unkC -= 75*sp34; + local->unkC -= 75 * time_delta; local->unkC = MAX(local->unk4, local->unkC); } }//L8038A08C diff --git a/src/RBB/ch/propellorswitch.c b/src/RBB/ch/propellorswitch.c index e536c2023..e81a65107 100644 --- a/src/RBB/ch/propellorswitch.c +++ b/src/RBB/ch/propellorswitch.c @@ -28,25 +28,32 @@ Struct_RBB_3CB0 D_80390720[2] = { {{0xF9C0, 0x324, 0xF6A0}, 0x405, 4, 0x28} }; -ActorInfo D_80390738 = { - 0x186, 0x176, 0x404, 0x0, NULL, +ActorInfo chRBBGreenPropellerSwitch = { + MARKER_186_RBB_GREEN_PROPELLER_SWITCH, ACTOR_176_RBB_GREEN_PROPELLOR_SWITCH, ASSET_404_MODEL_RBB_GREEN_PROPELLER_SWITCH, + 0x0, NULL, chPropellorSwitch_update, NULL, chPropellorSwitch_draw, 0, 0, 0.0f, 0 }; +enum chrbbgreenpropellerswitch_state_e { + CH_RBB_GREEN_PROPELLER_SWITCH_STATE_0_NOT_INIT, + CH_RBB_GREEN_PROPELLER_SWITCH_STATE_1_NOT_PRESSED, + CH_RBB_GREEN_PROPELLER_SWITCH_STATE_2_PRESSED +}; + /* .code */ -void __chPropellorSwitch_setState(Actor *this, s32 arg1){ +void __chPropellorSwitch_setState(Actor *this, s32 next_state){ ActorLocal_RBB_3CB0 *local = (ActorLocal_RBB_3CB0 *)&this->local; - if(arg1 == 1) - if(this->state == 2) + if(next_state == CH_RBB_GREEN_PROPELLER_SWITCH_STATE_1_NOT_PRESSED) + if(this->state == CH_RBB_GREEN_PROPELLER_SWITCH_STATE_2_PRESSED) this->position_y += 40.0f; - if(arg1 == 2){ - if(this->state == 1) + if(next_state == CH_RBB_GREEN_PROPELLER_SWITCH_STATE_2_PRESSED){ + if(this->state == CH_RBB_GREEN_PROPELLER_SWITCH_STATE_1_NOT_PRESSED) func_8030E6D4(SFX_90_SWITCH_PRESS); this->position_y -= 40.0f; - if(this->state == 1){ + if(this->state == CH_RBB_GREEN_PROPELLER_SWITCH_STATE_1_NOT_PRESSED){ levelSpecificFlags_set(local->unk0->unk8, 1); musicKeepsPlaying(); timedFunc_set_1(1.1f, (GenFunction_1)func_8028F9DC, 2); @@ -56,13 +63,13 @@ void __chPropellorSwitch_setState(Actor *this, s32 arg1){ } }//L8038A1A0 - this->state = arg1; + this->state = next_state; } void func_8038A1C8(ActorMarker *marker, ActorMarker *arg1){ Actor *actor = marker_getActor(marker); if(actor->state == 1){ - __chPropellorSwitch_setState(actor, 2); + __chPropellorSwitch_setState(actor, CH_RBB_GREEN_PROPELLER_SWITCH_STATE_2_PRESSED); } else if(actor->state == 2){ rbb_propellorCtrl_start(); @@ -109,16 +116,16 @@ void chPropellorSwitch_update(Actor *this){ this->position_y = (f32)local->unk0->unk0[1]; this->position_z = (f32)local->unk0->unk0[2]; if(levelSpecificFlags_get(local->unk0->unkA)) - __chPropellorSwitch_setState(this, 2); + __chPropellorSwitch_setState(this, CH_RBB_GREEN_PROPELLER_SWITCH_STATE_2_PRESSED); else - __chPropellorSwitch_setState(this, 1); + __chPropellorSwitch_setState(this, CH_RBB_GREEN_PROPELLER_SWITCH_STATE_1_NOT_PRESSED); }//L8038A47C - if(this->state == 2){ + if(this->state == CH_RBB_GREEN_PROPELLER_SWITCH_STATE_2_PRESSED){ if( !levelSpecificFlags_get(local->unk0->unkA) && !levelSpecificFlags_get(LEVEL_FLAG_3_RBB_UNKNOWN) && !levelSpecificFlags_get(LEVEL_FLAG_4_RBB_UNKNOWN) ){ - __chPropellorSwitch_setState(this, 1); + __chPropellorSwitch_setState(this, CH_RBB_GREEN_PROPELLER_SWITCH_STATE_1_NOT_PRESSED); } } } diff --git a/src/RBB/ch/rarewareflag.c b/src/RBB/ch/rarewareflag.c index 6cb471e19..9dace4041 100644 --- a/src/RBB/ch/rarewareflag.c +++ b/src/RBB/ch/rarewareflag.c @@ -3,18 +3,19 @@ #include "functions.h" #include "variables.h" -void func_8038C300(Actor *this); +void chRarewareFlag_update(Actor *this); -ActorInfo D_80390B40 = { - 0x198, 0x1ca, 0x41e, 0x0, NULL, - func_8038C300, NULL, actor_draw, +ActorInfo chRarewareFlag = { + MARKER_198_RAREWARE_FLAG, ACTOR_1CA_RAREWARE_FLAG, ASSET_41E_MODEL_RAREWARE_FLAG, + 0x0, NULL, + chRarewareFlag_update, NULL, actor_draw, 0, 0, 0.0f, 0 }; -void func_8038C300(Actor *this){ +void chRarewareFlag_update(Actor *this){ if(!this->volatile_initialized){ this->marker->propPtr->unk8_3 = 1; this->volatile_initialized = true; - skeletalAnim_set(this->unk148, 0x140, 0.0f, 1.0f); + skeletalAnim_set(this->unk148, ASSET_140_ANIM_RAREWARE_FLAG, 0.0f, 1.0f); } } diff --git a/src/RBB/ch/rowboat.c b/src/RBB/ch/rowboat.c index 871f28c15..a1f30e8f1 100644 --- a/src/RBB/ch/rowboat.c +++ b/src/RBB/ch/rowboat.c @@ -6,19 +6,20 @@ /* typedefs and declarations */ typedef struct { f32 unk0; - f32 unk4[3]; - f32 unk10[3]; - f32 unk1C[3]; - f32 unk28; - f32 unk2C; + f32 playerInfluencedRotationDelta[3]; // something about rotation + f32 position[3]; + f32 rotation[3]; + f32 timeDelta; + f32 creakingSFXTimer; }ActorLocal_RBB_7FD0; -void func_8038E3D8(Actor *this); +void chRowboat_update(Actor *this); /* .data */ -ActorInfo D_80390D50 = { - 0x1ab, 0x297, 0x43C, 0x0, NULL, - func_8038E3D8, NULL, actor_draw, +ActorInfo chRowboat = { + MARKER_1AB_ROWBOAT, ACTOR_297_ROWBOAT, ASSET_43C_MODEL_ROWBOAT, + 0x0, NULL, + chRowboat_update, NULL, actor_draw, 0, 0, 0.0f, 0 }; @@ -28,84 +29,86 @@ void func_8038E3C0(Actor *this, s32 arg1){ this->state = arg1; } -void func_8038E3D8(Actor *this){ - f32 sp74[3]; - f32 sp68[3]; +void chRowboat_update(Actor *this){ + f32 rotation_delta[3]; + f32 position_delta[3]; ActorLocal_RBB_7FD0 *local = (ActorLocal_RBB_7FD0 *) &this->local; - int i; - f32 sp5C = time_getDelta(); - f32 sp50[3]; - f32 sp44[3]; + int rotation_parameter; + f32 time_delta = time_getDelta(); + f32 new_rotation[3]; + f32 player_position[3]; if(!this->volatile_initialized){ this->marker->propPtr->unk8_3 = 1; this->volatile_initialized = true; local->unk0 = randf2(80.0f, 100.0f); - local->unk28 = 0.0f; - local->unk2C = 0.5f; + local->timeDelta = 0.0f; + local->creakingSFXTimer = 0.5f; this->position_y -= 10.0f; - local->unk4[0] = 0.0f; - local->unk4[1] = 0.0f; - local->unk4[2] = 0.0f; - local->unk10[0] = this->position_x; - local->unk10[1] = this->position_y; - local->unk10[2] = this->position_z; - local->unk1C[0] = this->pitch; - local->unk1C[1] = this->yaw; - local->unk1C[2] = this->roll; + local->playerInfluencedRotationDelta[0] = 0.0f; + local->playerInfluencedRotationDelta[1] = 0.0f; + local->playerInfluencedRotationDelta[2] = 0.0f; + local->position[0] = this->position_x; + local->position[1] = this->position_y; + local->position[2] = this->position_z; + local->rotation[0] = this->pitch; + local->rotation[1] = this->yaw; + local->rotation[2] = this->roll; func_8038E3C0(this, 1); }//L8038E4C8 - if(ml_timer_update(&local->unk2C, sp5C)){ - local->unk2C = randf2(3.5f, 5.5f); + if(ml_timer_update(&local->creakingSFXTimer, time_delta)){ + local->creakingSFXTimer = randf2(3.5f, 5.5f); func_8030E878(SFX_69_WHIPCRACK_CREAKING, randf2(1.1f, 1.2f), 22000, this->position, 500.0f, 1500.0f); }//L8038E544 - if(func_8032DCAC() == this->marker && func_8028F20C()){ - player_getPosition(sp44); - if(sp44[0] < this->position_x - 10.0f && local->unk4[2] < 3.0f) - local->unk4[2] += 5.0f*sp5C; + if(func_8032DCAC() == this->marker && player_isStableWithExtraSteps()){ + player_getPosition(player_position); + if(player_position[0] < this->position_x - 10.0f && local->playerInfluencedRotationDelta[2] < 3.0f) + local->playerInfluencedRotationDelta[2] += 5.0f * time_delta; - if(this->position_x + 10.0f < sp44[0] && -3.0f < local->unk4[2]) - local->unk4[2] -= 5.0f*sp5C; + if(this->position_x + 10.0f < player_position[0] && -3.0f < local->playerInfluencedRotationDelta[2]) + local->playerInfluencedRotationDelta[2] -= 5.0f * time_delta; - if(this->position_z + 10.0f < sp44[2] && local->unk4[0] < 5.0f) - local->unk4[0] += 5.0f*sp5C; + if(this->position_z + 10.0f < player_position[2] && local->playerInfluencedRotationDelta[0] < 5.0f) + local->playerInfluencedRotationDelta[0] += 5.0f * time_delta; - if(sp44[2] < this->position_z - 10.0f && -5.0f < local->unk4[0]) - local->unk4[0] -= 5.0f*sp5C; + if(player_position[2] < this->position_z - 10.0f && -5.0f < local->playerInfluencedRotationDelta[0]) + local->playerInfluencedRotationDelta[0] -= 5.0f * time_delta; } else{ - for(i= 0; i< 3; i++){ - if(0.0f < local->unk4[i]){ - local->unk4[i] -= 2.5*sp5C; - if(local->unk4[i] < 0.0f) - local->unk4[i] = 0.0f; - } else if(local->unk4[i] < 0.0f) { //L8038E710 - local->unk4[i] += 2.5*sp5C; - if(0.0f < local->unk4[i]) - local->unk4[i] = 0.0f; + for(rotation_parameter = 0; rotation_parameter < 3; rotation_parameter++){ + if(0.0f < local->playerInfluencedRotationDelta[rotation_parameter]){ + local->playerInfluencedRotationDelta[rotation_parameter] -= 2.5 * time_delta; + if(local->playerInfluencedRotationDelta[rotation_parameter] < 0.0f) + local->playerInfluencedRotationDelta[rotation_parameter] = 0.0f; + } else if(local->playerInfluencedRotationDelta[rotation_parameter] < 0.0f) { //L8038E710 + local->playerInfluencedRotationDelta[rotation_parameter] += 2.5 * time_delta; + if(0.0f < local->playerInfluencedRotationDelta[rotation_parameter]) + local->playerInfluencedRotationDelta[rotation_parameter] = 0.0f; }//L8038E74C } }//L8038E754 - local->unk28 += sp5C; - sp68[0] = 0.0f; - sp68[1] = 5.0f * sinf((((local->unk28*0.8)*local->unk0)/180.0)*3.141592654); - sp68[2] = 0.0f; - sp74[0] = 4.5 * cosf(((local->unk28*local->unk0)/180.0) * 3.141592654); - sp74[1] = 1.5 * sinf((((local->unk28*0.9)*local->unk0)/180.0)*3.141592654); - sp74[2] = 0.0f; - - this->position_x = local->unk10[0] + sp68[0]; - this->position_y = local->unk10[1] + sp68[1]; - this->position_z = local->unk10[2] + sp68[2]; - - sp50[0] = local->unk1C[0] + sp74[0]; - sp50[1] = local->unk1C[1] + sp74[1]; - sp50[2] = local->unk1C[2] + sp74[2]; - - this->pitch = sp50[0] + local->unk4[0]; - this->yaw = sp50[1] + local->unk4[1]; - this->roll = sp50[2] + local->unk4[2]; + local->timeDelta += time_delta; + + position_delta[0] = 0.0f; + position_delta[1] = 5.0f * sinf((((local->timeDelta * 0.8) * local->unk0) / 180.0) * BAD_PI); + position_delta[2] = 0.0f; + + rotation_delta[0] = 4.5 * cosf(((local->timeDelta * local->unk0) / 180.0) * BAD_PI); + rotation_delta[1] = 1.5 * sinf((((local->timeDelta * 0.9) * local->unk0) / 180.0) * BAD_PI); + rotation_delta[2] = 0.0f; + + this->position_x = local->position[0] + position_delta[0]; + this->position_y = local->position[1] + position_delta[1]; + this->position_z = local->position[2] + position_delta[2]; + + new_rotation[0] = local->rotation[0] + rotation_delta[0]; + new_rotation[1] = local->rotation[1] + rotation_delta[1]; + new_rotation[2] = local->rotation[2] + rotation_delta[2]; + + this->pitch = new_rotation[0] + local->playerInfluencedRotationDelta[0]; + this->yaw = new_rotation[1] + local->playerInfluencedRotationDelta[1]; + this->roll = new_rotation[2] + local->playerInfluencedRotationDelta[2]; } diff --git a/src/RBB/ch/seaman_grublin.c b/src/RBB/ch/seamangrublin.c similarity index 97% rename from src/RBB/ch/seaman_grublin.c rename to src/RBB/ch/seamangrublin.c index ae6adc460..ece17410d 100644 --- a/src/RBB/ch/seaman_grublin.c +++ b/src/RBB/ch/seamangrublin.c @@ -1,4 +1,4 @@ -// BanjoDecomp: (core2 origin - unknown exact file) +// BanjoDecomp: core2/ch/seamangrublin.c #include #include "functions.h" #include "variables.h" diff --git a/src/RBB/ch/siren.c b/src/RBB/ch/siren.c deleted file mode 100644 index b876dbea4..000000000 --- a/src/RBB/ch/siren.c +++ /dev/null @@ -1,61 +0,0 @@ -// BanjoDecomp: code_9840.c -#include -#include "functions.h" -#include "variables.h" - -void func_8038FC48(Actor *this); - -/* typedefs and declarations */ -typedef struct { - s32 unk0; - s16 *unk4; - ActorMarker *unk8; -}ActorLocal_RBB_9840; - -/* .data */ -s16 RBB_D_80390E30[2] = {0x177, 0x17F}; -ActorInfo D_80390E34 = { - 0x1D2, 0x31B, 0x0, 0x0, NULL, - func_8038FC48, NULL, func_80325340, - 0, 0, 0.0f, 0 -}; -ActorInfo D_80390E58 = { - 0x1D3, 0x31C, 0x0, 0x0, NULL, - func_8038FC48, NULL, func_80325340, - 0, 0, 0.0f, 0 -}; - -/*.code */ -void func_8038FC30(Actor *this, s32 arg1){ - this->state = arg1; -} - -void func_8038FC48(Actor *this){ - ActorLocal_RBB_9840 *local = (ActorLocal_RBB_9840 *)&this->local; - f32 sp20; - f32 tmp_f2; - s32 tmp_a1; - - if(!this->volatile_initialized){ - this->volatile_initialized = true; - actor_collisionOff(this); - local->unk4 = RBB_D_80390E30 + (this->marker->id - 0x1d2); - local->unk8 = NULL; - - local->unk0 = func_802F9AA8(0x400); - func_802F9DB8(local->unk0, 1.0f, 1.0f, 0.0f); - func_802F9EC4(local->unk0, this->position, 0x1f4, 0x3e8); - func_802F9F80(local->unk0, 0.0f, 8999999488.0f, 0.0f); - func_802FA060(local->unk0, 22000, 22000, 0.0f); - func_8038FC30(this, 1); - } - else{//L8038FD34 - if(local->unk8 == NULL) - local->unk8 = actorArray_findActorFromActorId(*local->unk4)->marker; - sp20 = func_8038A6B8(local->unk8); - tmp_f2 = 1.5* sp20 + 0.5; - func_802F9DB8(local->unk0, tmp_f2, tmp_f2, 0.0f); - tmp_a1 = (s32) (sp20*32000.0f); - func_802FA060(local->unk0, tmp_a1, tmp_a1, 0.0f); - } -} diff --git a/src/RBB/ch/whistle.c b/src/RBB/ch/whistle.c index 4517e787e..8b55fc1a7 100644 --- a/src/RBB/ch/whistle.c +++ b/src/RBB/ch/whistle.c @@ -5,45 +5,48 @@ /* typedefs and declarations */ typedef struct { - s16 unk0; - f32 unk4[3]; + s16 actorId; + f32 position[3]; s16 unk10; s16 unk12; s16 unk14; //u8 pad16[2]; -}Struct_RBB_4C70; +} ActorLocal_ChRBBWhistleInfo; typedef struct { - Struct_RBB_4C70 *unk0; - f32 unk4[3]; + ActorLocal_ChRBBWhistleInfo *unk0; + f32 particlePosition[3]; }ActorLocal_RBB_4C70; -Actor *func_8038B230(ActorMarker *marker, Gfx** gdl, Mtx** mptr, Vtx **arg3); -void func_8038B340(Actor *this); +Actor *chRBBWhistle_draw(ActorMarker *marker, Gfx** gdl, Mtx** mptr, Vtx **arg3); +void chRBBWhistle_update(Actor *this); /* .data */ -Struct_RBB_4C70 D_80390950[] = { - { 0x1C2, {-3720.0f, 800.0f, -350.0f}, 0x1, 0x136, 0x3FF}, - { 0x1C3, {-3720.0f, 800.0f, 0.0f}, 0x2, 0x135, 0x3FE}, - { 0x1C4, {-3720.0f, 800.0f, 350.0f}, 0x3, 0x134, 0x3FD}, - 0 +ActorLocal_ChRBBWhistleInfo chRBBWhistleInfo[] = { + { ACTOR_1C2_WHISTLE_1, {-3720.0f, 800.0f, -350.0f}, 0x1, 0x136, 0x3FF}, + { ACTOR_1C3_WHISTLE_2, {-3720.0f, 800.0f, 0.0f}, 0x2, 0x135, 0x3FE}, + { ACTOR_1C4_WHISTLE_3, {-3720.0f, 800.0f, 350.0f}, 0x3, 0x134, 0x3FD}, + { 0 } // [port] decomp uses NULL; actorId is s16 and clang errors on -Wint-conversion }; -ActorInfo D_803909B0 = { - 0x2A, 0x1C2, 0x416, 0x0, NULL, - func_8038B340, NULL, func_8038B230, +ActorInfo chRBBWhistle1 = { + MARKER_2A_WHISTLE_1_YELLOW, ACTOR_1C2_WHISTLE_1, ASSET_416_MODEL_WHISTLE, + 0x0, NULL, + chRBBWhistle_update, NULL, chRBBWhistle_draw, 0, 0, 0.0f, 0 }; -ActorInfo D_803909D4 = { - 0x2B, 0x1C3, 0x416, 0x0, NULL, - func_8038B340, NULL, func_8038B230, +ActorInfo chRBBWhistle2 = { + MARKER_2B_WHISTLE_2_YELLOW, ACTOR_1C3_WHISTLE_2, ASSET_416_MODEL_WHISTLE, + 0x0, NULL, + chRBBWhistle_update, NULL, chRBBWhistle_draw, 0, 0, 0.0f, 0 }; -ActorInfo RBB_D_803909F8 = { - 0x2C, 0x1C4, 0x416, 0x0, NULL, - func_8038B340, NULL, func_8038B230, +ActorInfo chRBBWhistle3 = { + MARKER_2C_WHISTLE_3_YELLOW, ACTOR_1C4_WHISTLE_3, ASSET_416_MODEL_WHISTLE, + 0x0, NULL, + chRBBWhistle_update, NULL, chRBBWhistle_draw, 0, 0, 0.0f, 0 }; @@ -56,26 +59,32 @@ ParticleScaleAndLifetimeRanges D_80390A1C = { 0.5f }; +enum chrbbwhistle_state_e { + CH_RBB_WHISTLE_STATE_0_NOT_INIT, + CH_RBB_WHISTLE_STATE_1_IDLE, + CH_RBB_WHISTLE_STATE_2_BLOWING +}; + /* .code */ -Struct_RBB_4C70 *func_8038B060(Actor *this){ - Struct_RBB_4C70 * iPtr; - for(iPtr = D_80390950; iPtr->unk0 != 0; iPtr++){ - if(iPtr->unk0 == this->modelCacheIndex) +ActorLocal_ChRBBWhistleInfo *func_8038B060(Actor *this){ + ActorLocal_ChRBBWhistleInfo * iPtr; + for(iPtr = chRBBWhistleInfo; iPtr->actorId != NULL; iPtr++){ + if(iPtr->actorId == this->modelCacheIndex) return iPtr; } return NULL; } -void RBB_func_8038B0B8(Actor *this, s32 arg1){ +void chRBBWhistle_setState(Actor *this, s32 next_state){ ActorLocal_RBB_4C70 *local = (ActorLocal_RBB_4C70 *)&this->local; ParticleEmitter *other; - this->state = arg1; + this->state = next_state; - if(this->state == 2){ + if(this->state == CH_RBB_WHISTLE_STATE_2_BLOWING){ skeletalAnim_set(this->unk148, local->unk0->unk12, 0.0f, 0.5f); skeletalAnim_setBehavior(this->unk148, SKELETAL_ANIM_2_ONCE); - timed_playSfx(0.1f, local->unk0->unk14, 1.0f, 0x7d00); + timed_playSfx(0.1f, local->unk0->unk14, 1.0f, 32000); other = partEmitMgr_newEmitter(0xa); particleEmitter_setSprite(other, ASSET_70E_SPRITE_SMOKE_2); particleEmitter_setAccelerationRange(other, @@ -87,7 +96,7 @@ void RBB_func_8038B0B8(Actor *this, s32 arg1){ -5.0f, -5.0f, 0.0f, 5.0f, 5.0f, 0.0f ); - particleEmitter_setPosition(other, local->unk4); + particleEmitter_setPosition(other, local->particlePosition); particleEmitter_setParticleVelocityRange(other, -400.0f, 0.0f, -30.0f, -800.0f, 0.0f, 30.0f @@ -97,10 +106,10 @@ void RBB_func_8038B0B8(Actor *this, s32 arg1){ } } -Actor *func_8038B230(ActorMarker *marker, Gfx** gdl, Mtx** mptr, Vtx **arg3){ +Actor *chRBBWhistle_draw(ActorMarker *marker, Gfx** gdl, Mtx** mptr, Vtx **arg3){ Actor *actor = marker_getActor(marker); ActorLocal_RBB_4C70 *local = (ActorLocal_RBB_4C70 *)&actor->local; - f32 sp3C[3]; + f32 actor_rotation[3]; if(actor->state == 0) return actor; @@ -109,45 +118,45 @@ Actor *func_8038B230(ActorMarker *marker, Gfx** gdl, Mtx** mptr, Vtx **arg3){ modelRender_setBoneTransformList(skeletalAnim_getBoneTransformList(actor->unk148)); } - sp3C[0] = actor->pitch; - sp3C[1] = actor->yaw; - sp3C[2] = actor->roll; + actor_rotation[0] = actor->pitch; + actor_rotation[1] = actor->yaw; + actor_rotation[2] = actor->roll; modelRender_setPreDrawCallback((model_render_pre_draw_callback_f)actor_predrawMethod, (void *)actor); modelRender_setRefPoints(func_80329934()); - modelRender_draw(gdl, mptr, actor->position, sp3C, actor->scale, NULL, marker_loadModelBin(marker)); - vec3fArray_get_vec3f(func_80329934(), 5, local->unk4); - local->unk4[0] -= 60.0f; + modelRender_draw(gdl, mptr, actor->position, actor_rotation, actor->scale, NULL, marker_loadModelBin(marker)); + vec3fArray_get_vec3f(func_80329934(), 5, local->particlePosition); + local->particlePosition[0] -= 60.0f; return actor; } -void func_8038B340(Actor * this){ +void chRBBWhistle_update(Actor * this){ ActorLocal_RBB_4C70 *local = (ActorLocal_RBB_4C70 *)&this->local; if(!this->volatile_initialized){ this->marker->propPtr->unk8_3 = 1; this->volatile_initialized = true; local->unk0 = func_8038B060(this); - local->unk4[2] = 0.0f; - local->unk4[1] = 0.0f; - local->unk4[0] = 0.0f; + local->particlePosition[2] = 0.0f; + local->particlePosition[1] = 0.0f; + local->particlePosition[0] = 0.0f; - this->position_x = local->unk0->unk4[0]; - this->position_y = local->unk0->unk4[1]; - this->position_z = local->unk0->unk4[2]; + this->position_x = local->unk0->position[0]; + this->position_y = local->unk0->position[1]; + this->position_z = local->unk0->position[2]; this->yaw = -90.0f; this->scale = 0.25f; - RBB_func_8038B0B8(this, 1); + chRBBWhistle_setState(this, CH_RBB_WHISTLE_STATE_1_IDLE); }//L8038B3E4 - if(this->state == 1){ + if(this->state == CH_RBB_WHISTLE_STATE_1_IDLE){ if(mapSpecificFlags_get(local->unk0->unk10)) - RBB_func_8038B0B8(this, 2); + chRBBWhistle_setState(this, CH_RBB_WHISTLE_STATE_2_BLOWING); } - if(this->state == 2){ + if(this->state == CH_RBB_WHISTLE_STATE_2_BLOWING){ if( skeletalAnim_getLoopCount(this->unk148) > 0 ) - RBB_func_8038B0B8(this, 1); + chRBBWhistle_setState(this, CH_RBB_WHISTLE_STATE_1_IDLE); } } diff --git a/src/RBB/ch/whistlectrl.c b/src/RBB/ch/whistlectrl.c index 76d6dc6e7..3cde18b54 100644 --- a/src/RBB/ch/whistlectrl.c +++ b/src/RBB/ch/whistlectrl.c @@ -3,24 +3,31 @@ #include "functions.h" #include "variables.h" -extern ActorInfo D_80390FD0; - typedef struct { - s16 unk0; + s16 currentIndex; s16 unk2; - u8 *unk4; + u8 *codeString; }ActorLocal_RBB_5060; void chWhistleCtrl_update(Actor * this); /* .data */ -ActorInfo D_80390A50 = { - 0x2D, 0x1C5, 0x0, 0x0, NULL, +ActorInfo chRBBWhistleCtrl = { + MARKER_2D_WHISTLE_CTRL, ACTOR_1C5_WHISTLE_CTRL, 0x0, + 0x0, NULL, chWhistleCtrl_update, NULL, func_80325340, 0, 0, 0.0f, 0 }; -f32 D_80390A74[3] = {-3820.0f, 850.0f, 0.0f}; //whistle jiggy spawn position +f32 chRBBWhistleCtrlJiggyPosition[3] = {-3820.0f, 850.0f, 0.0f}; + +enum chrbbwhistlectrl_state_e { + CH_RBB_WHISTLE_CTRL_STATE_0_NOT_INIT, + CH_RBB_WHISTLE_CTRL_STATE_1_AWAITING_PLAYER, + CH_RBB_WHISTLE_CTRL_STATE_2_COMPLETE +}; + +#define RBB_WHISTLE_CODE "312111" /* .code */ void __chWhistleCtrl_setState(Actor *actor, s32 arg1){ @@ -29,7 +36,7 @@ void __chWhistleCtrl_setState(Actor *actor, s32 arg1){ void __chWhistleCtrl_soundWhistle(void){ bundle_setYaw(225.0f); - jiggy_spawn(JIGGY_54_RBB_WHISTLE, D_80390A74); + jiggy_spawn(JIGGY_54_RBB_WHISTLE, chRBBWhistleCtrlJiggyPosition); } void __chWhistleCtrl_correct(void){ @@ -53,13 +60,13 @@ void __chWhistleCtrl_complete(void){ s32 chWhistleCtrl_newEvent(Actor *this, s32 whistle_id, Actor *other){ ActorLocal_RBB_5060 *local = (ActorLocal_RBB_5060 *)&this->local; - if(this->state != 1) + if(this->state != CH_RBB_WHISTLE_CTRL_STATE_1_AWAITING_PLAYER) return 0; - if(whistle_id + 0x30 == local->unk4[local->unk0]){ //correct - if(local->unk4[++local->unk0] == 0){ //end of string + if(whistle_id + 0x30 == local->codeString[local->currentIndex]){ //correct + if(local->codeString[++local->currentIndex] == 0){ //end of string timedFunc_set_0(0.6f, __chWhistleCtrl_complete); //spawn jiggy - __chWhistleCtrl_setState(this, 2); + __chWhistleCtrl_setState(this, CH_RBB_WHISTLE_CTRL_STATE_2_COMPLETE); return 3; }else{ timedFunc_set_0(0.6f, __chWhistleCtrl_correct); @@ -68,7 +75,7 @@ s32 chWhistleCtrl_newEvent(Actor *this, s32 whistle_id, Actor *other){ } else{ //wrong timedFunc_set_1(1.0f, (GenFunction_1)__chWhistleCtrl_wrong, (uintptr_t)other->marker); - local->unk0 = 0; + local->currentIndex = 0; return 2; } } @@ -79,10 +86,10 @@ void chWhistleCtrl_update(Actor *this){ if(!this->volatile_initialized){ this->volatile_initialized = true; local->unk2 = 1; - local->unk4 = "312111"; + local->codeString = RBB_WHISTLE_CODE; if(jiggyscore_isSpawned(JIGGY_54_RBB_WHISTLE)) - __chWhistleCtrl_setState(this, 2); + __chWhistleCtrl_setState(this, CH_RBB_WHISTLE_CTRL_STATE_2_COMPLETE); else - __chWhistleCtrl_setState(this, 1); + __chWhistleCtrl_setState(this, CH_RBB_WHISTLE_CTRL_STATE_1_AWAITING_PLAYER); } } diff --git a/src/RBB/ch/whistleswitch.c b/src/RBB/ch/whistleswitch.c index 443d4206f..37134cce5 100644 --- a/src/RBB/ch/whistleswitch.c +++ b/src/RBB/ch/whistleswitch.c @@ -8,106 +8,114 @@ BKVertexList *vtxList_clone(BKVertexList *); /* typedefs and declarations */ typedef struct { - s16 unk0; - f32 unk4[3]; - s16 unk10; - u8 pad12[2]; -}Struct_RBB_47D0; + s16 actorId; + f32 position[3]; + s16 mapSpecificFlag; +} Struct_ChWhistleSwitchInfo; typedef struct { u8 unk0; u8 pad1[3]; - Struct_RBB_47D0 *unk4; + Struct_ChWhistleSwitchInfo *whistleSwitchInfo; f32 unk8; BKVertexList *unkC; -}ActorLocal_RBB_47D0; +} ActorLocal_RBB_47D0; -Actor *func_8038AD9C(ActorMarker *marker, Gfx** gdl, Mtx** mptr, Vtx **arg3); -void func_8038AEB8(Actor *this); +Actor *chRBBWhistleSwitch_draw(ActorMarker *marker, Gfx** gdl, Mtx** mptr, Vtx **arg3); +void chRBBWhistleSwitch_update(Actor *this); /* .data */ -Struct_RBB_47D0 D_80390870[4] = { - {0x1BF, {-3950.0f, 690.0f, -350.0f}, 1}, - {0x1C0, {-3950.0f, 690.0f, 0.0f}, 2}, - {0x1C1, {-3950.0f, 690.0f, 350.0f}, 3}, - 0 +Struct_ChWhistleSwitchInfo chWhistleSwitchTable[4] = { + {ACTOR_1BF_WHISTLE_SWITCH_1, {-3950.0f, 690.0f, -350.0f}, RBB_MAIN_SPECIFIC_FLAG_1_WHISTLE_SWITCH_1}, + {ACTOR_1C0_WHISTLE_SWITCH_2, {-3950.0f, 690.0f, 0.0f}, RBB_MAIN_SPECIFIC_FLAG_2_WHISTLE_SWITCH_2}, + {ACTOR_1C1_WHISTLE_SWITCH_3, {-3950.0f, 690.0f, 350.0f}, RBB_MAIN_SPECIFIC_FLAG_3_WHISTLE_SWITCH_3}, + { 0 } // [port] decomp uses NULL; actorId is s16 and clang errors on -Wint-conversion }; -extern ActorInfo D_803908C0 = { - 0x195, 0x1BF, 0x413, 0x0, NULL, - func_8038AEB8, NULL, func_8038AD9C, +extern ActorInfo chRBBWhistleSwitch1 = { + MARKER_195_WHISTLE_SWITCH_1, ACTOR_1BF_WHISTLE_SWITCH_1, ASSET_413_MODEL_WHISTLE_SWITCH_1, + 0x0, NULL, + chRBBWhistleSwitch_update, NULL, chRBBWhistleSwitch_draw, 0, 0, 0.0f, 0 }; -extern ActorInfo D_803908E4 = { - 0x196, 0x1C0, 0x414, 0x0, NULL, - func_8038AEB8, NULL, func_8038AD9C, + +extern ActorInfo chRBBWhistleSwitch2 = { + MARKER_196_WHISTLE_SWITCH_2, ACTOR_1C0_WHISTLE_SWITCH_2, ASSET_414_MODEL_WHISTLE_SWITCH_2, + 0x0, NULL, + chRBBWhistleSwitch_update, NULL, chRBBWhistleSwitch_draw, 0, 0, 0.0f, 0 }; -extern ActorInfo D_80390908 = { - 0x197, 0x1C1, 0x415, 0x0, NULL, - func_8038AEB8, NULL, func_8038AD9C, +extern ActorInfo chRBBWhistleSwitch3 = { + MARKER_197_WHISTLE_SWITCH_3, ACTOR_1C1_WHISTLE_SWITCH_3, ASSET_415_MODEL_WHISTLE_SWITCH_3, + 0x0, NULL, + chRBBWhistleSwitch_update, NULL, chRBBWhistleSwitch_draw, 0, 0, 0.0f, 0 }; s32 D_8039092C[3] = { 0, 0xFF, 0}; s32 D_80390938[3] = { 0xFF, 0, 0}; +enum chrbbwhistleswitch_state_e { + CH_RBB_WHISTLE_SWITCH_STATE_0_NOT_INIT, + CH_RBB_WHISTLE_SWITCH_STATE_1_UNK, + CH_RBB_WHISTLE_SWITCH_STATE_2_UNK +}; + /* .code */ -Struct_RBB_47D0 *RBB_func_8038ABC0(Actor *arg0){ - Struct_RBB_47D0 *iPtr = D_80390870; - while(iPtr->unk0 != 0){ - if(iPtr->unk0 == arg0->modelCacheIndex) +Struct_ChWhistleSwitchInfo *chWhistleSwitch_getInfoPointer(Actor *this){ + Struct_ChWhistleSwitchInfo *iPtr = chWhistleSwitchTable; + while(iPtr->actorId != NULL){ + if(iPtr->actorId == this->modelCacheIndex) return iPtr; iPtr++; } return NULL; } -void func_8038AC18(Actor *this, s32 new_state){ +void chRBBWhistleSwitch_setState(Actor *this, s32 new_state){ ActorLocal_RBB_47D0 *local = (ActorLocal_RBB_47D0 *)&this->local; Actor *whistle_ctrl; local->unk8 = 0.0f; - if(new_state == 2){ + if(new_state == CH_RBB_WHISTLE_SWITCH_STATE_2_UNK){ func_8030E6D4(SFX_90_SWITCH_PRESS); local->unkC = vtxList_clone(modelbin_getVtxList(marker_loadModelBin(this->marker))); - mapSpecificFlags_set(local->unk4->unk10, true); + mapSpecificFlags_set(local->whistleSwitchInfo->mapSpecificFlag, true); this->position_y -= 30.0f; local->unk8 = 1.0f; - whistle_ctrl = actorArray_findActorFromActorId(0x1c5); + whistle_ctrl = actorArray_findActorFromActorId(ACTOR_1C5_WHISTLE_CTRL); if(whistle_ctrl){ - local->unk0 = chWhistleCtrl_newEvent(whistle_ctrl, this->modelCacheIndex - 0x1be, this); + local->unk0 = chWhistleCtrl_newEvent(whistle_ctrl, this->modelCacheIndex - ACTOR_1BE_RBB_GREY_PROPELLOR_SWITCH, this); } }//L8038ACD0 - if(this->state == 2){ - this->position_x = local->unk4->unk4[0]; - this->position_y = local->unk4->unk4[1]; - this->position_z = local->unk4->unk4[2]; + if(this->state == CH_RBB_WHISTLE_SWITCH_STATE_2_UNK){ + this->position_x = local->whistleSwitchInfo->position[0]; + this->position_y = local->whistleSwitchInfo->position[1]; + this->position_z = local->whistleSwitchInfo->position[2]; vtxList_free(local->unkC); } this->state = new_state; } -void func_8038AD3C(ActorMarker *marker, ActorMarker *arg1){ +void chRBBWhistleSwitch_press(ActorMarker *marker, ActorMarker *arg1){ Actor *actor = marker_getActor(marker); if(actor->state == 1) - func_8038AC18(actor, 2); + chRBBWhistleSwitch_setState(actor, 2); } -void func_8038AD7C(Actor *this){ - func_8038AC18(this, 0); +void chRBBWhistleSwitch_free(Actor *this){ + chRBBWhistleSwitch_setState(this, CH_RBB_WHISTLE_SWITCH_STATE_0_NOT_INIT); } -Actor *func_8038AD9C(ActorMarker *marker, Gfx **gdl, Mtx **mptr, Vtx **arg3){ +Actor *chRBBWhistleSwitch_draw(ActorMarker *marker, Gfx **gdl, Mtx **mptr, Vtx **arg3){ Actor * actor = marker_getActor(marker); ActorLocal_RBB_47D0 *local = (ActorLocal_RBB_47D0 *)&actor->local; BKModelBin *temp_v0; f32 pad0; s32 *sp1C; - if(actor->state == 0) return actor; @@ -118,7 +126,7 @@ Actor *func_8038AD9C(ActorMarker *marker, Gfx **gdl, Mtx **mptr, Vtx **arg3){ temp_v0 = marker_loadModelBin(marker); sp1C = (local->unk0 == 2) ? D_80390938 : D_8039092C; vtxList_tintColorsFrom(local->unkC, sp1C, - (local->unk4->unk4[1] - actor->position_y)/30.0, + (local->whistleSwitchInfo->position[1] - actor->position_y) / 30.0, modelbin_getVtxList(temp_v0) ); modelRender_setVertexList(local->unkC); @@ -126,37 +134,37 @@ Actor *func_8038AD9C(ActorMarker *marker, Gfx **gdl, Mtx **mptr, Vtx **arg3){ return actor_draw(marker, gdl, mptr, arg3); } -void func_8038AEB8(Actor *this){ +void chRBBWhistleSwitch_update(Actor *this){ ActorLocal_RBB_47D0 *local = (ActorLocal_RBB_47D0 *)&this->local; - f32 sp20 = time_getDelta(); - s32 tmp; + f32 time_delta = time_getDelta(); + s32 y_position; if(!this->volatile_initialized){ this->volatile_initialized = true; this->marker->propPtr->unk8_3 = 1; - this->marker->actorFreeFunc = func_8038AD7C; - marker_setCollisionScripts(this->marker, NULL, func_8038AD3C, NULL); - local->unk4 = RBB_func_8038ABC0(this); - mapSpecificFlags_set(local->unk4->unk10, false); - this->position_x = local->unk4->unk4[0]; - this->position_y = local->unk4->unk4[1]; - this->position_z = local->unk4->unk4[2]; + this->marker->actorFreeFunc = chRBBWhistleSwitch_free; + marker_setCollisionScripts(this->marker, NULL, chRBBWhistleSwitch_press, NULL); + local->whistleSwitchInfo = chWhistleSwitch_getInfoPointer(this); + mapSpecificFlags_set(local->whistleSwitchInfo->mapSpecificFlag, false); + this->position_x = local->whistleSwitchInfo->position[0]; + this->position_y = local->whistleSwitchInfo->position[1]; + this->position_z = local->whistleSwitchInfo->position[2]; this->yaw = -90.0f; - func_8038AC18(this, 1); + chRBBWhistleSwitch_setState(this, CH_RBB_WHISTLE_SWITCH_STATE_1_UNK); }//L8038AF88 - if(ml_timer_update(&local->unk8, sp20)) - func_8038AC18(this, 1); + if(ml_timer_update(&local->unk8, time_delta)) + chRBBWhistleSwitch_setState(this, CH_RBB_WHISTLE_SWITCH_STATE_1_UNK); - if(this->state == 2){ - tmp = (s32)this->position_y; - if(this->position_y < local->unk4->unk4[1]) - this->position_y += 60.0f*sp20; + if(this->state == CH_RBB_WHISTLE_SWITCH_STATE_2_UNK){ + y_position = (s32)this->position_y; + if(this->position_y < local->whistleSwitchInfo->position[1]) + this->position_y += 60.0f * time_delta; - if( tmp < local->unk4->unk4[1] - 15.0f - && local->unk4->unk4[1] - 15.0f <= this->position_y + if( y_position < local->whistleSwitchInfo->position[1] - 15.0f + && local->whistleSwitchInfo->position[1] - 15.0f <= this->position_y ){ - mapSpecificFlags_set(local->unk4->unk10, false); + mapSpecificFlags_set(local->whistleSwitchInfo->mapSpecificFlag, false); } }//L8038B044 } diff --git a/src/RBB/checksums.c b/src/RBB/checksums.c new file mode 100644 index 000000000..37275e9d0 --- /dev/null +++ b/src/RBB/checksums.c @@ -0,0 +1,7 @@ +// BanjoDecomp: RBB/checksums.c +#include +#include "checksums.h" + +// !! THIS FILE MUST BE LINKED FIRST FOR THIS OVERLAY !! + +/* bss */ struct overlay_checksums_s gChecksumsRBB; diff --git a/src/RBB/crane_boombox.c b/src/RBB/crane_boombox.c index 4656215e7..d3bc55879 100644 --- a/src/RBB/crane_boombox.c +++ b/src/RBB/crane_boombox.c @@ -6,14 +6,16 @@ #include + /* typedefs and declarations */ -void func_803881E8(Actor *this, s32 arg1); -void RBB_func_803882F4(Actor *this); +void chTNTDownSwitch_setState(Actor *this, s32 arg1); +void chTNTDownSwitch_update(Actor *this); /* .data */ -ActorInfo D_80390270 = { - 0x184, 0x174, 0x402, 0x0, NULL, - RBB_func_803882F4, NULL, func_80325340, +ActorInfo chTNTDownSwitch = { + MARKER_184_RBB_TNT_DOWN_SWITCH, ACTOR_174_RBB_TNT_DOWN_SWITCH, ASSET_402_MODEL_EGG_TOLL, + 0x0, NULL, + chTNTDownSwitch_update, NULL, func_80325340, 0, 0, 0.0f, 0 }; @@ -22,11 +24,11 @@ s32 D_803902A4[4] = { 0x76, 0, 0, 0xff}; s32 D_803902B4[4] = { 0x76, 0, 0, 0xff}; s32 D_803902C4[4] = { 0xff, 0, 0, 0xff}; - f32 D_803902D4[3] = {4500.0f, 0.0f, 500.0f}; f32 D_803902E0[3] = {4500.0f, 0.0f, 500.0f}; f32 D_803902EC[3] = {4000.0f, -600.0f, 0.0f}; f32 D_803902F8[3] = {4500.0f, 0.0f, 500.0f}; + ParticleScaleAndLifetimeRanges D_80390304 = { { 5.0f, 5.0f}, { 5.0f, 5.0f}, @@ -38,11 +40,18 @@ ParticleScaleAndLifetimeRanges D_80390304 = { f32 D_8039032C[3] = {3700.0f, -300.0f, -300.0f}; f32 D_80390338[3] = {4500.0f, 100.0f, 400.0f}; + ParticleSettingsVelocityAcceleration D_80390344= { {{-700.0f, 200.0f, -700.0f}, {700.0f, 500.0f, 700.0f}}, {{ 0.0f, -800.0f, 0.0f}, { 0.0f, -800.0f, 0.0f}} }; +enum chtntdownswitch_state_e { + CH_TNT_DOWN_SWITCH_STATE_0_NOT_INIT, + CH_TNT_DOWN_SWITCH_STATE_1_NOT_PRESSED, + CH_TNT_DOWN_SWITCH_STATE_2_PRESSED +}; + /*.code */ void RBB_func_80387960(f32 arg0){ f32 sp34[3]; @@ -114,7 +123,7 @@ void func_80387B8C(s32 arg0, s32 arg1){ Struct70s *tmp_s70 = func_8034C528(arg0); if(tmp_s70){ Struct6Ds *v0 = &tmp_s70->type_6D; - func_8034DFB0(v0, D_80390294, D_803902A4, (f64)arg1/1000.0); + func_8034DFB0(v0, D_80390294, D_803902A4, (f64)arg1 / 1000.0); } } @@ -124,11 +133,11 @@ void func_80387BEC(s32 arg0, s32 arg1){ tmp_s70 = func_8034C528(arg0); if(tmp_s70){ Struct6Ds *v0 = &tmp_s70->type_6D; - func_8034DFB0(v0, D_803902B4, D_803902C4, (f64)arg1/1000.0); + func_8034DFB0(v0, D_803902B4, D_803902C4, (f64)arg1 / 1000.0); } } -void func_80387C5C(void){ +void chTNTDownSwitch_emitExplosion(void){ ParticleEmitter *actor; func_802BB3DC(0, 60.0f, 0.9f); @@ -145,7 +154,7 @@ void func_80387C5C(void){ particleEmitter_emitInVolume(actor, D_803902D4, D_803902E0, 1); } -void func_80387D80(void){ +void chTNTDownSwitch_emitSmoke(void){ ParticleEmitter *actor = partEmitMgr_newEmitter(3); particleEmitter_setSprite(actor, ASSET_70E_SPRITE_SMOKE_2); particleEmitter_setStartingFrameRange(actor, 0, 7); @@ -154,11 +163,11 @@ void func_80387D80(void){ particleEmitter_emitInVolume(actor, D_803902EC, D_803902F8, 3); } -void func_80387E20(void){ +void chTNTDownSwitch_emitWoodenPlank(void){ ParticleEmitter *actor = partEmitMgr_newEmitter(0x19); particleEmitter_func_802EF9F8(actor, 0.6f); particleEmitter_func_802EFA18(actor, 3); - particleEmitter_setModel(actor, 0x427); + particleEmitter_setModel(actor, ASSET_427_MODEL_WOODEN_PLANK); particleEmitter_setStartingScaleRange(actor, 0.05f, 0.4f); particleEmitter_setAngularVelocityRange(actor, -600.0f, -600.0f, -600.0f, 600.0f, 600.0f, 600.0f); particleEmitter_setSpawnIntervalRange(actor, 0.0f, 0.01f); @@ -167,67 +176,67 @@ void func_80387E20(void){ particleEmitter_emitInVolume(actor, D_8039032C, D_80390338, 0x19); } -void RBB_func_80387F18(ActorMarker *marker, s32 arg1){ - func_803881E8(marker_getActor(marker), arg1); +void chTNTDownSwitch_setStateByMarker(ActorMarker *marker, s32 next_state){ + chTNTDownSwitch_setState(marker_getActor(marker), next_state); } void RBB_func_80387F44(void){ baMotor_80250E94(0.5f, 1.0f, 1.5f, 0.0f, 1.0f, 1.5f); } -void func_80387F88(ActorMarker *marker){ +void chTNTDownSwitch_emits(ActorMarker *marker){ Actor *actor = marker_getActor(marker); - timedFunc_set_0(0.0f, func_80387C5C); + timedFunc_set_0(0.0f, chTNTDownSwitch_emitExplosion); timed_playSfx(0.1f, SFX_1B_EXPLOSION_1, 1.0f, 22000); timed_playSfx(0.1f, SFX_1B_EXPLOSION_1, 1.0f, 22000); - timedFunc_set_0(0.3f, func_80387E20); + timedFunc_set_0(0.3f, chTNTDownSwitch_emitWoodenPlank); timedFunc_set_0(0.5f, func_80387A54); timedFunc_set_0(0.4f, func_80387B24); timed_playSfx(0.41f, SFX_1B_EXPLOSION_1, 0.8f, 22000); timed_playSfx(0.41f, SFX_1B_EXPLOSION_1, 0.8f, 22000); - timedFunc_set_0(0.55f, func_80387D80); + timedFunc_set_0(0.55f, chTNTDownSwitch_emitSmoke); timed_playSfx(0.71f, SFX_1B_EXPLOSION_1, 0.6f, 22000); timed_playSfx(0.71f, SFX_1B_EXPLOSION_1, 0.6f, 22000); - timedFunc_set_0(0.8f, func_80387D80); + timedFunc_set_0(0.8f, chTNTDownSwitch_emitSmoke); timed_playSfx(1.0f, SFX_1A_BIG_THINGS_FALL_OVER, 1.0f, 22000); timed_playSfx(2.0f, SFX_1A_BIG_THINGS_FALL_OVER, 0.8f, 22000); timed_playSfx(3.0f, SFX_1A_BIG_THINGS_FALL_OVER, 0.6f, 22000); timed_exitStaticCamera(4.0f); func_80324E38(4.0f, 0); - timedFunc_set_2(4.0f, (GenFunction_2) RBB_func_80387F18, (uintptr_t)actor->marker, 3); + timedFunc_set_2(4.0f, (GenFunction_2) chTNTDownSwitch_setStateByMarker, (uintptr_t)actor->marker, 3); } -void func_80388154(ActorMarker *marker){ +void chTNTDownSwitch_dropTNTActions(ActorMarker *marker){ Actor *actor = marker_getActor(marker); func_803879F0(); timedFunc_set_0(0.0f, (GenFunction_0) RBB_func_80387F44); - timed_playSfx(0.0f, SFX_7F_HEAVYDOOR_SLAM, 1.0f, 0x7fc6); + timed_playSfx(0.0f, SFX_7F_HEAVYDOOR_SLAM, 1.0f, 32710); timedFunc_set_2(1.2f, (GenFunction_2) func_80387B8C, 0x19f, 0); timed_setStaticCameraToNode(1.2f, 8); - timedFunc_set_1(1.5f, (GenFunction_1) func_80387F88, (uintptr_t)actor->marker); + timedFunc_set_1(1.5f, (GenFunction_1) chTNTDownSwitch_emits, (uintptr_t)actor->marker); } -void func_803881E8(Actor *this, s32 arg1){ - this->state = arg1; - if(this->state == 2){ +void chTNTDownSwitch_setState(Actor *this, s32 next_state){ + this->state = next_state; + if(this->state == CH_TNT_DOWN_SWITCH_STATE_2_PRESSED){ RBB_func_80387960(0.05f); timedFunc_set_2(0.05f, (GenFunction_2)func_80387BEC, 0x19f, 0x1f4); timedFunc_set_2(0.1f, (GenFunction_2)coMusicPlayer_playMusic, COMUSIC_2B_DING_B, 28000); func_80324E38(0.2f, 3); timed_setStaticCameraToNode(1.1f, 7); - timedFunc_set_1(1.6f, (GenFunction_1)func_80388154, (uintptr_t)this->marker); + timedFunc_set_1(1.6f, (GenFunction_1)chTNTDownSwitch_dropTNTActions, (uintptr_t)this->marker); levelSpecificFlags_set(LEVEL_FLAG_2D_RBB_UNKNOWN, true); } } -void func_803882B4(ActorMarker *marker, ActorMarker *arg1){ +void chTNTDownSwitch_pushSwitch(ActorMarker *marker, ActorMarker *arg1){ Actor *actor = marker_getActor(marker); - if(actor->state == 1) - func_803881E8(actor, 2); + if(actor->state == CH_TNT_DOWN_SWITCH_STATE_1_NOT_PRESSED) + chTNTDownSwitch_setState(actor, CH_TNT_DOWN_SWITCH_STATE_2_PRESSED); } -void RBB_func_803882F4(Actor *this){ +void chTNTDownSwitch_update(Actor *this){ if(!this->volatile_initialized){ this->volatile_initialized = true; @@ -235,12 +244,12 @@ void RBB_func_803882F4(Actor *this){ func_80387AC0(); RBB_func_80387960(0.0f); func_80387B24(); - func_803881E8(this, 3); + chTNTDownSwitch_setState(this, 3); } else { - marker_setCollisionScripts(this->marker, NULL, func_803882B4, NULL); + marker_setCollisionScripts(this->marker, NULL, chTNTDownSwitch_pushSwitch, NULL); suSetSpriteScale(this, 1.1f); - func_803881E8(this, 1); + chTNTDownSwitch_setState(this, 1); } } // Anchor: teammate opened the entrance (LEVEL_FLAG_2D) - snap to opened state. @@ -248,6 +257,6 @@ void RBB_func_803882F4(Actor *this){ func_80387AC0(); RBB_func_80387960(0.0f); func_80387B24(); - func_803881E8(this, 3); + chTNTDownSwitch_setState(this, 3); } } diff --git a/src/RBB/crane_jiggycage.c b/src/RBB/crane_jiggycage.c index 87c71599d..3be35a292 100644 --- a/src/RBB/crane_jiggycage.c +++ b/src/RBB/crane_jiggycage.c @@ -6,8 +6,8 @@ #include /* typedefs and declarations */ -void func_803878B0(Actor *this); -void func_8038756C(Actor *this, s32 arg1); +void chCageUpSwitch_update(Actor *this); +void chCageUpSwitch_setState(Actor *this, s32 arg1); // Anchor: set while replaying a teammate's crane action; suppresses camera pans and auto-raise. static s32 sCraneRemote = 0; @@ -15,9 +15,10 @@ extern void port_jiggyCrane_broadcast(s32 stage); extern ActorArray *suBaddieActorArray; /* .data */ -ActorInfo D_80390200 = { - 0x183, 0x173, 0x402, 0x0, NULL, - func_803878B0, NULL, func_80325340, +ActorInfo chCageUpSwitch = { + MARKER_183_RBB_CAGE_UP_SWITCH, ACTOR_173_RBB_CAGE_UP_SWITCH, ASSET_402_MODEL_EGG_TOLL, + 0x0, NULL, + chCageUpSwitch_update, NULL, func_80325340, 0, 0, 0.0f, 0 }; @@ -28,16 +29,24 @@ s32 D_80390254[4] = { 0xff, 0, 0, 0xff}; f32 D_80390264[3] = {-4900.0f, 0.0f, 0.0f}; +enum chcageupswitch_state_e { + CH_CAGE_UP_SWITCH_STATE_0_NOT_INIT, + CH_CAGE_UP_SWITCH_STATE_1_NOT_PRESSED, + CH_CAGE_UP_SWITCH_STATE_2_RAISING_CAGE, + CH_CAGE_UP_SWITCH_STATE_3_TIMED_RAISED_CAGE, + CH_CAGE_UP_SWITCH_STATE_4_LOWER_CAGE +}; + /* .code */ -void func_80387090(ActorMarker *marker, s32 arg1){ - func_8038756C(marker_getActor(marker), arg1); +void chCageUpSwitch_setStateByMarker(ActorMarker *marker, s32 next_state){ + chCageUpSwitch_setState(marker_getActor(marker), next_state); } void func_803870BC(s32 arg0, s32 arg1){ Struct70s *tmp_s70 = func_8034C528(arg0); if(tmp_s70){ Struct6Ds *temp_v0 = &tmp_s70->type_6D; - func_8034DFB0(temp_v0, D_80390224, D_80390234, (f64)arg1/1000.0); + func_8034DFB0(temp_v0, D_80390224, D_80390234, (f64)arg1 / 1000.0); } } @@ -47,7 +56,7 @@ void func_8038711C(s32 arg0, s32 arg1){ tmp_s70 = func_8034C528(arg0); if(tmp_s70){ Struct6Ds *temp_v0 = &tmp_s70->type_6D; - func_8034DFB0(temp_v0, D_80390244, D_80390254, (f64)arg1/1000.0); + func_8034DFB0(temp_v0, D_80390244, D_80390254, (f64)arg1 / 1000.0); } } @@ -78,7 +87,7 @@ void func_8038718C(ActorMarker *marker){ timed_exitStaticCamera(5.0f); func_80324E38(5.0f, 0); } - timedFunc_set_2(5.0f, (GenFunction_2) func_80387090, (uintptr_t) marker, 3); + timedFunc_set_2(5.0f, (GenFunction_2) chCageUpSwitch_setStateByMarker, (uintptr_t)marker, CH_CAGE_UP_SWITCH_STATE_3_TIMED_RAISED_CAGE); } void func_80387308(ActorMarker *marker){ @@ -100,24 +109,23 @@ void func_80387308(ActorMarker *marker){ timed_playSfx(0.5f, SFX_7F_HEAVYDOOR_SLAM, 0.8f, 19000); timed_playSfx(0.5f, SFX_7F_HEAVYDOOR_SLAM, 0.9f, 19000); timed_playSfx(0.5f, SFX_7F_HEAVYDOOR_SLAM, 1.0f, 19000); - timedFunc_set_2(0.5f, (GenFunction_2) func_80387090, (uintptr_t)actor->marker, 1); + timedFunc_set_2(0.5f, (GenFunction_2) chCageUpSwitch_setStateByMarker, (uintptr_t)actor->marker, CH_CAGE_UP_SWITCH_STATE_1_NOT_PRESSED); timedFunc_set_2(1.5f, (GenFunction_2) func_803870BC, 0x19d, 0x1f4); if (!sCraneRemote) { timed_exitStaticCamera(1.5f); func_80324E38(1.5f, 0); } - } void func_80387488(ActorMarker *marker){ - f32 sp1C[3]; + f32 player_position[3]; Actor *actor = marker_getActor(marker); - player_getPosition(sp1C); - if(-50.0f < sp1C[1] && sp1C[1] < 600.0f){ - sp1C[1] = 0; - if(ml_vec3f_distance(sp1C, D_80390264) < 500.0f){ + player_getPosition(player_position); + if(-50.0f < player_position[1] && player_position[1] < 600.0f){ + player_position[1] = 0; + if(ml_vec3f_distance(player_position, D_80390264) < 500.0f){ timedFunc_set_1(1.0f, (GenFunction_1) func_80387488, (uintptr_t)actor->marker); return; } @@ -129,7 +137,7 @@ void func_80387488(ActorMarker *marker){ timedFunc_set_1(0.5f, (GenFunction_1) func_80387308, (uintptr_t)actor->marker); } -void func_8038756C(Actor *this, s32 arg1){ +void chCageUpSwitch_setState(Actor *this, s32 next_state){ f32 sp6C[3]; f32 sp60[3]; void * temp_v0; @@ -140,7 +148,7 @@ void func_8038756C(Actor *this, s32 arg1){ f32 sp30[3]; f32 sp24[3]; - if(arg1 == 1){ + if(next_state == CH_CAGE_UP_SWITCH_STATE_1_NOT_PRESSED){ sCraneRemote = 0; if(this->state != 0){ sp6C[0] = 0.0f; @@ -156,7 +164,7 @@ void func_8038756C(Actor *this, s32 arg1){ } }//L80387610 - if(arg1 == 2){ + if(next_state == CH_CAGE_UP_SWITCH_STATE_2_RAISING_CAGE){ if (!sCraneRemote) { port_jiggyCrane_broadcast(2); } @@ -179,16 +187,16 @@ void func_8038756C(Actor *this, s32 arg1){ timedFunc_set_1(1.1f, (GenFunction_1)func_8038718C, (uintptr_t)this->marker); }//L80387704 - if(arg1 == 3){ + if(next_state == CH_CAGE_UP_SWITCH_STATE_3_TIMED_RAISED_CAGE){ item_set(ITEM_6_HOURGLASS, 1); - item_set(ITEM_0_HOURGLASS_TIMER, 0x3bf); + item_set(ITEM_0_HOURGLASS_TIMER, VER_SELECT(0x3bf, 0x31f, 0, 0)); } - if(this->state == 3){ + if(this->state == CH_CAGE_UP_SWITCH_STATE_3_TIMED_RAISED_CAGE){ item_set(ITEM_6_HOURGLASS, 0); } - if(arg1 == 4){ + if(next_state == CH_CAGE_UP_SWITCH_STATE_4_LOWER_CAGE){ if (!sCraneRemote) { port_jiggyCrane_broadcast(4); } @@ -210,32 +218,32 @@ void func_8038756C(Actor *this, s32 arg1){ timedFunc_set_1(4.0f, (GenFunction_1)func_80387488, (uintptr_t)this->marker); }//L80387828 - this->state = arg1; + this->state = next_state; } -void func_80387850(ActorMarker *marker, ActorMarker *arg1){ +void chCageUpSwitch_pushSwitch(ActorMarker *marker, ActorMarker *arg1){ Actor *actor = marker_getActor(marker); - if(actor->state == 1){ - func_8038756C(actor, 2); + if(actor->state == CH_CAGE_UP_SWITCH_STATE_1_NOT_PRESSED){ + chCageUpSwitch_setState(actor, CH_CAGE_UP_SWITCH_STATE_2_RAISING_CAGE); } } -void func_80387890(Actor *this){ - func_8038756C(this, 0); +void chCageUpSwitch_free(Actor *this){ + chCageUpSwitch_setState(this, CH_CAGE_UP_SWITCH_STATE_0_NOT_INIT); } -void func_803878B0(Actor *this){ +void chCageUpSwitch_update(Actor *this){ if(!this->volatile_initialized){ this->volatile_initialized = true; - this->marker->actorFreeFunc = func_80387890; - marker_setCollisionScripts(this->marker, NULL, func_80387850, NULL); + this->marker->actorFreeFunc = chCageUpSwitch_free; + marker_setCollisionScripts(this->marker, NULL, chCageUpSwitch_pushSwitch, NULL); suSetSpriteScale(this, 1.1f); - func_8038756C(this, 1); + chCageUpSwitch_setState(this, CH_CAGE_UP_SWITCH_STATE_1_NOT_PRESSED); } - if(this->state == 3 && !sCraneRemote){ + if(this->state == CH_CAGE_UP_SWITCH_STATE_3_TIMED_RAISED_CAGE && !sCraneRemote){ if(item_empty(ITEM_0_HOURGLASS_TIMER)){ - func_8038756C(this, 4); + chCageUpSwitch_setState(this, CH_CAGE_UP_SWITCH_STATE_4_LOWER_CAGE); } } } @@ -248,12 +256,13 @@ void port_jiggyCrane_remoteApply(s32 stage) { } for (i = 0; i < suBaddieActorArray->cnt; i++) { Actor *actor = &suBaddieActorArray->data[i]; - if (actor->marker == NULL || actor->marker->id != 0x183) { + if (actor->marker == NULL || actor->marker->id != MARKER_183_RBB_CAGE_UP_SWITCH) { continue; } - if ((stage == 2 && actor->state == 1) || (stage == 4 && actor->state == 3)) { + if ((stage == 2 && actor->state == CH_CAGE_UP_SWITCH_STATE_1_NOT_PRESSED) + || (stage == 4 && actor->state == CH_CAGE_UP_SWITCH_STATE_3_TIMED_RAISED_CAGE)) { sCraneRemote = 1; - func_8038756C(actor, stage); + chCageUpSwitch_setState(actor, stage); } return; } diff --git a/src/RBB/miniboombox_container.c b/src/RBB/miniboombox_container.c index 0fb74ee1d..f997a4634 100644 --- a/src/RBB/miniboombox_container.c +++ b/src/RBB/miniboombox_container.c @@ -5,59 +5,67 @@ extern -void RBB_func_8038FB84(Actor *this); +void chBoomBoxMinigameCtrl_update(Actor *this); /* .data */ -ActorInfo RBB_D_80390E00 = { - 0x1B8, 0x2A5, 0x0, 0x0, NULL, - RBB_func_8038FB84, NULL, func_80325340, +ActorInfo chBoomBoxMinigameCtrl = { + MARKER_1B8_BOOM_BOX_MINIGAME_CTRL, ACTOR_2A5_BOOM_BOX_MINIGAME_CTRL, 0x0, + 0x0, NULL, + chBoomBoxMinigameCtrl_update, NULL, func_80325340, 0, 0, 0.0f, 0 }; +enum chboomboxminigamectrl_state_e { + CH_BOOMBOX_MINIGAME_CTRL_STATE_0_NOT_INIT, + CH_BOOMBOX_MINIGAME_CTRL_STATE_1_INIT, + CH_BOOMBOX_MINIGAME_CTRL_STATE_2_PARTIAL_COMPLETE, + CH_BOOMBOX_MINIGAME_CTRL_STATE_3_COMPLETE +}; + /* .bss */ -u8 D_803912B0; +u8 chBoomBoxMinigameRemainingCount; /* .code */ -void RBB_func_8038FA60(ActorMarker *marker){ +void chBoomBoxMinigameCtrl_spawnExtraLife(ActorMarker *marker){ Actor *actor = marker_getActor(marker); bundle_setYaw(actor->yaw); bundle_spawn_f32(BUNDLE_6_MM_HUT_EXTRA_LIFE, actor->position); } -void func_8038FA9C(Actor *this, s32 arg1){ - if(arg1 == 3){ +void chBoomBoxMinigameCtrl_setState(Actor *this, s32 next_state){ + if(next_state == CH_BOOMBOX_MINIGAME_CTRL_STATE_3_COMPLETE){ func_80324E38(0.0f, 3); timedFunc_set_2(1.0f, (GenFunction_2)coMusicPlayer_playMusic, COMUSIC_2B_DING_B, 28000); timed_setStaticCameraToNode(1.8f, 1); - timedFunc_set_1(2.0f, (GenFunction_1) RBB_func_8038FA60, (uintptr_t)this->marker); + timedFunc_set_1(2.0f, (GenFunction_1) chBoomBoxMinigameCtrl_spawnExtraLife, (uintptr_t)this->marker); timed_exitStaticCamera(5.0f); func_80324E38(5.0f, 0); } - this->state = arg1; + this->state = next_state; } -void func_8038FB54(void){ - D_803912B0++; +void chBoomBoxMinigameCtrl_countInc(void){ + chBoomBoxMinigameRemainingCount++; } -void func_8038FB6C(void){ - D_803912B0--; +void chBoomBoxMinigameCtrl_countDec(void){ + chBoomBoxMinigameRemainingCount--; } -void RBB_func_8038FB84(Actor *this){ +void chBoomBoxMinigameCtrl_update(Actor *this){ if(!this->volatile_initialized){ this->volatile_initialized = true; - D_803912B0 = 0; - func_8038FA9C(this, 1); + chBoomBoxMinigameRemainingCount = 0; + chBoomBoxMinigameCtrl_setState(this, CH_BOOMBOX_MINIGAME_CTRL_STATE_1_INIT); } - if(this->state == 1){ - if(D_803912B0 > 0) - func_8038FA9C(this, 2); + if(this->state == CH_BOOMBOX_MINIGAME_CTRL_STATE_1_INIT){ + if(chBoomBoxMinigameRemainingCount > 0) + chBoomBoxMinigameCtrl_setState(this, CH_BOOMBOX_MINIGAME_CTRL_STATE_2_PARTIAL_COMPLETE); } - if(this->state == 2){ - if(D_803912B0 == 0) - func_8038FA9C(this, 3); + if(this->state == CH_BOOMBOX_MINIGAME_CTRL_STATE_2_PARTIAL_COMPLETE){ + if(chBoomBoxMinigameRemainingCount == 0) + chBoomBoxMinigameCtrl_setState(this, CH_BOOMBOX_MINIGAME_CTRL_STATE_3_COMPLETE); } } diff --git a/src/RBB/propellorctrl.c b/src/RBB/propellorctrl.c index e9ae4c96d..ec2f6f6e8 100644 --- a/src/RBB/propellorctrl.c +++ b/src/RBB/propellorctrl.c @@ -17,7 +17,7 @@ void __propellorCtrl_setState(s32 arg0){ } if(arg0 == 2){ - item_set(ITEM_3_PROPELLOR_TIMER, 3900 - 1); + item_set(ITEM_3_PROPELLOR_TIMER, VER_SELECT(3900, 3250, 0, 0) - 1); item_set(ITEM_9_PROPELLOR, 1); } @@ -27,7 +27,7 @@ void __propellorCtrl_setState(s32 arg0){ item_set(ITEM_9_PROPELLOR,0); if(arg0 == 3 && !jiggyscore_isCollected(JIGGY_57_RBB_PROPELLOR)){ timedFunc_set_1(0.5f, (GenFunction_1)func_802FAD64, 3); - func_80324DBC(1.0f, ASSET_B9D_DIALOG_GRUNTY_PROPELLER_MISS, 4, NULL, NULL, NULL, NULL); + func_80324DBC(1.0f, VER_SELECT(ASSET_B9D_DIALOG_GRUNTY_PROPELLER_MISS, 0x972, 0, 0), 4, NULL, NULL, NULL, NULL); } else{ func_802FAD64(3); diff --git a/src/RBB/rbbspawnqueue.c b/src/RBB/rbbspawnqueue.c new file mode 100644 index 000000000..770a7fd51 --- /dev/null +++ b/src/RBB/rbbspawnqueue.c @@ -0,0 +1,239 @@ +// BanjoDecomp: RBB/rbbspawnqueue.c +#include +#include "core1/core1.h" +#include "functions.h" +#include "variables.h" +#include "prop.h" +#include "actor.h" + +#include "port/Patches/Patches.h" + + +extern ActorInfo chBellBuoy; +extern ActorInfo chRBBEggToll; +extern ActorInfo chCageUpSwitch; +extern ActorInfo chTNTDownSwitch; +extern ActorInfo chRowboat; +extern ActorInfo chRBBRearPropeller; +extern ActorInfo chRBBGreenPropellerSwitch; +extern ActorInfo chRBBSpinningSinglePipe1; +extern ActorInfo chRBBSpinningSinglePipe2; +extern ActorInfo chRBBSpinningDoublePipe1; +extern ActorInfo chRBBSpinningDoublePipe2; +extern ActorInfo chSpinningFlatPlatform1; +extern ActorInfo chSpinningFlatPlatform2; +extern ActorInfo chSpinningFlatPlatform3; +extern ActorInfo chRBBSmallCog; +extern ActorInfo chRBBMediumCog; +extern ActorInfo chRBBLargeCog; +extern ActorInfo chEngineRoomPropeller1; +extern ActorInfo chEngineRoomPropeller2; +extern ActorInfo chEngineRoomPropeller3; +extern ActorInfo chRBBGreyPropellerSwitch; +extern ActorInfo chRBBWhistleSwitch1; +extern ActorInfo chRBBWhistleSwitch2; +extern ActorInfo chRBBWhistleSwitch3; +extern ActorInfo chRBBWhistle1; +extern ActorInfo chRBBWhistle2; +extern ActorInfo chRBBWhistle3; +extern ActorInfo chRBBWhistleCtrl; +extern ActorInfo chGrimlet; +extern ActorInfo chAnchorSwitch; //anchorswitch +extern ActorInfo chSnorkel; //dolphin +extern ActorInfo chAnchor; //anchor +extern ActorInfo chAnchorCtrl; +extern ActorInfo chRarewareFlag; //rarewareflag +extern ActorInfo chBossBoomBoxLargest; +extern ActorInfo chBossBoomBoxLarge; +extern ActorInfo chBossBoomBoxMedium; +extern ActorInfo chBossBoomBoxSmall; +extern ActorInfo chBossBoomBoxCtrl; +extern ActorInfo chBoomBoxSlow; +extern ActorInfo chBoomBoxFast; //TNTpart_IDStruct; +extern ActorInfo chBoomBoxMinigameCtrl; +extern ActorInfo chRBBSpinningSinglePipeSfxCtrl; +extern ActorInfo chRBBSpinningDoublePipeSfxCtrl; +extern ActorInfo chEngineRoomDoor; +extern ActorInfo chCabinClosetDoor; //captcabinwooddoor +extern ActorInfo chShipShadowWindow; +extern ActorInfo chShipSunnyWindow; +extern ActorInfo chSunnyLifeboat; +extern ActorInfo chShadowLifeboat; +extern ActorInfo chCrackedSkylight;//skylight +extern ActorInfo chRbbHoneycombSwitch;//honeycombswitch + + + +extern void chMMMBreakableWooden_update(Actor *); + +void func_80386A7C(Actor *); +void func_80386BF8(Actor *arg0); +Actor *func_80386B9C(ActorMarker *marker, Gfx **gdl, Mtx **mptr, Vtx **arg3); + + +/* .data */ +ActorAnimationInfo D_803900C0[4] = { + {0, 0.0f}, + {0, 0.0f}, + {0xD4, 0.15f}, + {0xD5, 0.5f} +}; + +ActorInfo chEngineRoomDoor = { + MARKER_107_ENGINE_ROOM_DOOR, ACTOR_21D_ENGINE_ROOM_DOOR, ASSET_493_MODEL_ENGINE_ROOM_DOOR, + 0x1, NULL, + chMMMBreakableWooden_update, actor_update_func_80326224, actor_drawFullDepth, + 0, 0, 0.0f, 0 +}; + +ActorInfo chCabinClosetDoor = { + MARKER_108_CABIN_CLOSET_DOOR, ACTOR_21C_CABIN_CLOSET_DOOR, ASSET_492_MODEL_CABIN_CLOSET_DOOR, + 0x1, NULL, + chMMMBreakableWooden_update, actor_update_func_80326224, actor_drawFullDepth, + 0, 0, 0.0f, 0 +}; + +ActorInfo chShipShadowWindow = { + MARKER_22D_SHIP_SHADOW_WINDOW, ACTOR_266_SHIP_SHADOW_WINDOW, ASSET_4BA_MODEL_SHIP_SHADOW_WINDOW, + 0x1, NULL, + chMMMBreakableWooden_update, actor_update_func_80326224, actor_drawFullDepth, + 0, 0, 0.0f, 0 +}; + +ActorInfo chShipSunnyWindow = { + MARKER_22E_SHIP_SUNNY_WINDOW, ACTOR_267_SHIP_SUNNY_WINDOW, ASSET_4BB_MODEL_SHIP_SUNNY_WINDOW, + 0x1, NULL, + chMMMBreakableWooden_update, actor_update_func_80326224, actor_drawFullDepth, + 0, 0, 0.0f, 0 +}; + +ActorInfo chCrackedSkylight = { + MARKER_235_CRACKED_SKYLIGHT, ACTOR_23F_CRACKED_SKYLIGHT, ASSET_4E2_MODEL_CRACKED_SKYLIGHT, + 0x1, NULL, + chMMMBreakableWooden_update, actor_update_func_80326224, actor_drawFullDepth, + 0, 0, 0.0f, 0 +}; + +ActorInfo chRbbHoneycombSwitch = { + MARKER_15F_RBB_HONEYCOMB_SWITCH, ACTOR_18F_RBB_HONEYCOMB_SWITCH, ASSET_42F_MODEL_RBB_HONEYCOMB_SWITCH, + 0x1, D_803900C0, + func_80386BF8, actor_update_func_80326224, actor_draw, + 0, 0, 0.0f, 0 +}; + +ActorInfo chSunnyLifeboat = { + MARKER_22F_SUNNY_LIFEBOAT, ACTOR_263_SUNNY_LIFEBOAT, ASSET_4DB_MODEL_SUNNY_LIFEBOAT, + 0x1, NULL, + func_80386A7C, actor_update_func_80326224, func_80386B9C, + 0, 0, 0.0f, 0 +}; + +ActorInfo chShadowLifeboat = { + MARKER_230_SHADOW_LIFEBOAT, ACTOR_264_SHADOW_LIFEBOAT, ASSET_4DE_MODEL_SHADOW_LIFEBOAT, + 0x1, NULL, + func_80386A7C, actor_update_func_80326224, func_80386B9C, + 0, 0, 0.0f, 0 +}; + + +/* .code */ +s32 func_80386A30(f32 arg0[3]){ + s32 r; + + r = (arg0[0] < 0.0f)? 0 : 1; + + return ((arg0[2] < 0.0f)? 0 : 2) + r; +} + +void func_80386A7C(Actor *this){ + f32 viewport[3]; + s32 sp28; + s32 temp_v0; + + func_802D3D74(this); + this->depth_mode = 1; + viewport_getPosition_vec3f(viewport); + sp28 = func_80386A30(this->position); + temp_v0 = func_80386A30(viewport); + this->unk38_0 = 0; + // [port] Extend the bespoke distance cull with draw distance; quadrant occlusion below stays. + f32 cull = 8000.0f * port_drawDistanceMul(); + if(viewport[0] + cull < this->position_x || this->position_x < viewport[0] - cull) + return; + + if( !( (sp28 ^ temp_v0) & 2 + && (-5000.0f < viewport[0] && viewport[0] < 6000.0f) + && (viewport[2] < -600.0f || 600.0f < viewport[2]) + ) + && ( sp28 ^ temp_v0) != 3 + ){ + this->unk38_0 = 1; + } +} + +Actor *func_80386B9C(ActorMarker *marker, Gfx **gdl, Mtx **mptr, Vtx **arg3){ + Actor *actor = marker_getActor(marker); + + return (actor->unk38_0) ? actor_drawFullDepth(marker, gdl, mptr, arg3): NULL; +} + +void func_80386BF8(Actor *arg0){ + if(!mapSpecificFlags_get(RBB_BOAT_ROOM_SPECIFIC_FLAG_0_HONEYCOMB_SPAWNED) && honeycombscore_get(HONEYCOMB_F_RBB_BOAT_HOUSE)) + mapSpecificFlags_set(RBB_BOAT_ROOM_SPECIFIC_FLAG_0_HONEYCOMB_SPAWNED, true); + func_802D4A9C(arg0, 0); +} + +void RBB_func_80386C48(void){ + spawnableActorList_add(&chBellBuoy, actor_new, ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_11 | ACTOR_FLAG_UNKNOWN_14); + spawnableActorList_add(&chRBBEggToll, actor_new, ACTOR_FLAG_NONE); + spawnableActorList_add(&chCageUpSwitch, actor_new, ACTOR_FLAG_UNKNOWN_7); + spawnableActorList_add(&chTNTDownSwitch, actor_new, ACTOR_FLAG_UNKNOWN_7); + spawnableActorList_add(&chRowboat, actor_new, ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_10 | ACTOR_FLAG_UNKNOWN_14 | ACTOR_FLAG_UNKNOWN_27); + spawnableActorList_add(&chRBBRearPropeller, actor_new, ACTOR_FLAG_UNKNOWN_7); + spawnableActorList_add(&chRBBGreenPropellerSwitch, actor_new, ACTOR_FLAG_UNKNOWN_7); + spawnableActorList_add(&chRBBSpinningSinglePipe1, actor_new, ACTOR_FLAG_UNKNOWN_3 | ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_10 | ACTOR_FLAG_UNKNOWN_13 | ACTOR_FLAG_UNKNOWN_14); + spawnableActorList_add(&chRBBSpinningSinglePipe2, actor_new, ACTOR_FLAG_UNKNOWN_3 | ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_10 | ACTOR_FLAG_UNKNOWN_13 | ACTOR_FLAG_UNKNOWN_14); + spawnableActorList_add(&chRBBSpinningDoublePipe1, actor_new, ACTOR_FLAG_UNKNOWN_3 | ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_10 | ACTOR_FLAG_UNKNOWN_13 | ACTOR_FLAG_UNKNOWN_14); + spawnableActorList_add(&chRBBSpinningDoublePipe2, actor_new, ACTOR_FLAG_UNKNOWN_3 | ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_10 | ACTOR_FLAG_UNKNOWN_13 | ACTOR_FLAG_UNKNOWN_14); + spawnableActorList_add(&chSpinningFlatPlatform1, actor_new, ACTOR_FLAG_UNKNOWN_3 | ACTOR_FLAG_UNKNOWN_10 | ACTOR_FLAG_UNKNOWN_13 | ACTOR_FLAG_UNKNOWN_14); + spawnableActorList_add(&chSpinningFlatPlatform2, actor_new, ACTOR_FLAG_UNKNOWN_3 | ACTOR_FLAG_UNKNOWN_10 | ACTOR_FLAG_UNKNOWN_13 | ACTOR_FLAG_UNKNOWN_14); + spawnableActorList_add(&chSpinningFlatPlatform3, actor_new, ACTOR_FLAG_UNKNOWN_3 | ACTOR_FLAG_UNKNOWN_10 | ACTOR_FLAG_UNKNOWN_13 | ACTOR_FLAG_UNKNOWN_14); + spawnableActorList_add(&chRBBSmallCog, actor_new, ACTOR_FLAG_UNKNOWN_3 | ACTOR_FLAG_UNKNOWN_10 | ACTOR_FLAG_UNKNOWN_13 | ACTOR_FLAG_UNKNOWN_14); + spawnableActorList_add(&chRBBMediumCog, actor_new, ACTOR_FLAG_UNKNOWN_3 | ACTOR_FLAG_UNKNOWN_10 | ACTOR_FLAG_UNKNOWN_13 | ACTOR_FLAG_UNKNOWN_14); + spawnableActorList_add(&chRBBLargeCog, actor_new, ACTOR_FLAG_UNKNOWN_3 | ACTOR_FLAG_UNKNOWN_10 | ACTOR_FLAG_UNKNOWN_13 | ACTOR_FLAG_UNKNOWN_14); + spawnableActorList_add(&chEngineRoomPropeller1, actor_new, ACTOR_FLAG_UNKNOWN_10); + spawnableActorList_add(&chEngineRoomPropeller2, actor_new, ACTOR_FLAG_UNKNOWN_10); + spawnableActorList_add(&chEngineRoomPropeller3, actor_new, ACTOR_FLAG_UNKNOWN_10); + spawnableActorList_add(&chRBBGreyPropellerSwitch, actor_new, ACTOR_FLAG_NONE); + spawnableActorList_add(&chRBBWhistleSwitch1, actor_new, ACTOR_FLAG_UNKNOWN_7); + spawnableActorList_add(&chRBBWhistleSwitch2, actor_new, ACTOR_FLAG_UNKNOWN_7); + spawnableActorList_add(&chRBBWhistleSwitch3, actor_new, ACTOR_FLAG_UNKNOWN_7); + spawnableActorList_add(&chRBBWhistle1, actor_new, ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_11); + spawnableActorList_add(&chRBBWhistle2, actor_new, ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_11); + spawnableActorList_add(&chRBBWhistle3, actor_new, ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_11); + spawnableActorList_add(&chRBBWhistleCtrl, actor_new, ACTOR_FLAG_UNKNOWN_7); + spawnableActorList_add(&chGrimlet, actor_new, ACTOR_FLAG_UNKNOWN_1 | ACTOR_FLAG_UNKNOWN_3 | ACTOR_FLAG_UNKNOWN_5 | ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_8 | ACTOR_FLAG_UNKNOWN_11); + spawnableActorList_add(&chAnchorSwitch, actor_new, ACTOR_FLAG_UNKNOWN_7); //anchorswitch + spawnableActorList_add(&chSnorkel, actor_new, ACTOR_FLAG_UNKNOWN_3 | ACTOR_FLAG_UNKNOWN_6 | ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_11); //dolphin + spawnableActorList_add(&chAnchor, actor_new, ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_10 | ACTOR_FLAG_UNKNOWN_11); //anchor + spawnableActorList_add(&chAnchorCtrl, actor_new, ACTOR_FLAG_UNKNOWN_7); + spawnableActorList_add(&chRarewareFlag, actor_new, ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_11); //rarewareflag + spawnableActorList_add(&chBossBoomBoxLargest, actor_new, ACTOR_FLAG_UNKNOWN_2 | ACTOR_FLAG_UNKNOWN_3 | ACTOR_FLAG_UNKNOWN_5 | ACTOR_FLAG_UNKNOWN_10 | ACTOR_FLAG_UNKNOWN_11); + spawnableActorList_add(&chBossBoomBoxLarge, actor_new, ACTOR_FLAG_UNKNOWN_2 | ACTOR_FLAG_UNKNOWN_3 | ACTOR_FLAG_UNKNOWN_5 | ACTOR_FLAG_UNKNOWN_10 | ACTOR_FLAG_UNKNOWN_11); + spawnableActorList_add(&chBossBoomBoxMedium, actor_new, ACTOR_FLAG_UNKNOWN_2 | ACTOR_FLAG_UNKNOWN_3 | ACTOR_FLAG_UNKNOWN_5 | ACTOR_FLAG_UNKNOWN_10 | ACTOR_FLAG_UNKNOWN_11); + spawnableActorList_add(&chBossBoomBoxSmall, actor_new, ACTOR_FLAG_UNKNOWN_2 | ACTOR_FLAG_UNKNOWN_3 | ACTOR_FLAG_UNKNOWN_5 | ACTOR_FLAG_UNKNOWN_10 | ACTOR_FLAG_UNKNOWN_11); + spawnableActorList_add(&chBossBoomBoxCtrl, actor_new, ACTOR_FLAG_UNKNOWN_7); + spawnableActorList_add(&chBoomBoxSlow, actor_new, ACTOR_FLAG_UNKNOWN_0 | ACTOR_FLAG_UNKNOWN_3 | ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_11 | ACTOR_FLAG_UNKNOWN_25); + spawnableActorList_add(&chBoomBoxFast, actor_new, ACTOR_FLAG_UNKNOWN_0 | ACTOR_FLAG_UNKNOWN_3 | ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_11 | ACTOR_FLAG_UNKNOWN_25); + spawnableActorList_add(&chBoomBoxMinigameCtrl, actor_new, ACTOR_FLAG_UNKNOWN_7); + spawnableActorList_add(&chRBBSpinningSinglePipeSfxCtrl, actor_new, ACTOR_FLAG_UNKNOWN_7); + spawnableActorList_add(&chRBBSpinningDoublePipeSfxCtrl, actor_new, ACTOR_FLAG_UNKNOWN_7); + spawnableActorList_add(&chEngineRoomDoor, actor_new, ACTOR_FLAG_NONE); + spawnableActorList_add(&chCabinClosetDoor, actor_new, ACTOR_FLAG_UNKNOWN_9 | ACTOR_FLAG_UNKNOWN_10 | ACTOR_FLAG_UNKNOWN_15); //captcabinwooddoor + spawnableActorList_add(&chShipShadowWindow, actor_new, ACTOR_FLAG_NONE); + spawnableActorList_add(&chShipSunnyWindow, actor_new, ACTOR_FLAG_NONE); + spawnableActorList_add(&chSunnyLifeboat, actor_new, ACTOR_FLAG_UNKNOWN_9 | ACTOR_FLAG_UNKNOWN_10 | ACTOR_FLAG_UNKNOWN_15); + spawnableActorList_add(&chShadowLifeboat, actor_new, ACTOR_FLAG_UNKNOWN_9 | ACTOR_FLAG_UNKNOWN_10 | ACTOR_FLAG_UNKNOWN_15); + spawnableActorList_add(&chCrackedSkylight, actor_new, ACTOR_FLAG_UNKNOWN_9 | ACTOR_FLAG_UNKNOWN_10 | ACTOR_FLAG_UNKNOWN_15); //skylight + spawnableActorList_add(&chRbbHoneycombSwitch, actor_new, ACTOR_FLAG_UNKNOWN_3); //honeycombswitch +} diff --git a/src/RBB/siren.c b/src/RBB/siren.c new file mode 100644 index 000000000..a829ce4ae --- /dev/null +++ b/src/RBB/siren.c @@ -0,0 +1,81 @@ +// BanjoDecomp: code_9840.c +#include +#include "functions.h" +#include "variables.h" + +void chRBBSpinningPipeSfxCtrl_update(Actor *this); + +/* typedefs and declarations */ +typedef struct { + s32 unk0; + s16 *actorId; + ActorMarker *marker; +}ActorLocal_RBB_9840; + +/* +These objects only exist in RBB's engine room. +As the spinning pipes rotate, these controllers +create sound effects based off of the rotation speed. +*/ + +/* .data */ +s16 chRBBSpinningPipeSfxCtrlPipeActors[2] = { + ACTOR_177_RBB_SPINNING_SINGLE_PIPE_1, + ACTOR_17F_RBB_SPINNING_DOUBLE_PIPE_1 +}; + +ActorInfo chRBBSpinningSinglePipeSfxCtrl = { + MARKER_1D2_SPINNING_SINGLE_PIPE_SFX_CTRL, ACTOR_31B_SPINNING_SINGLE_PIPE_SFX_CTRL, 0x0, + 0x0, NULL, + chRBBSpinningPipeSfxCtrl_update, NULL, func_80325340, + 0, 0, 0.0f, 0 +}; + +ActorInfo chRBBSpinningDoublePipeSfxCtrl = { + MARKER_1D3_DOUBLE_SINGLE_PIPE_SFX_CTRL, ACTOR_31C_DOUBLE_SINGLE_PIPE_SFX_CTRL, 0x0, + 0x0, NULL, + chRBBSpinningPipeSfxCtrl_update, NULL, func_80325340, + 0, 0, 0.0f, 0 +}; + +enum chrbbspinningdoublepipesfxctrl_state_e { + CH_RBB_SPINNING_PIPE_SFX_CTRL_STATE_0_NOT_INIT, + CH_RBB_SPINNING_PIPE_SFX_CTRL_STATE_1_INIT +}; + +/*.code */ +// set state +void chRBBSpinningPipeSfxCtrl_setState(Actor *this, s32 next_state){ + this->state = next_state; +} + +// update +void chRBBSpinningPipeSfxCtrl_update(Actor *this){ + ActorLocal_RBB_9840 *local = (ActorLocal_RBB_9840 *)&this->local; + f32 sp20; + f32 tmp_f2; + s32 tmp_a1; + + if(!this->volatile_initialized){ + this->volatile_initialized = true; + actor_collisionOff(this); + local->actorId = chRBBSpinningPipeSfxCtrlPipeActors + (this->marker->id - 0x1D2); + local->marker = NULL; + + local->unk0 = func_802F9AA8(0x400); + func_802F9DB8(local->unk0, 1.0f, 1.0f, 0.0f); + func_802F9EC4(local->unk0, this->position, 500, 1000); + func_802F9F80(local->unk0, 0.0f, 8999999488.0f, 0.0f); + func_802FA060(local->unk0, 22000, 22000, 0.0f); + chRBBSpinningPipeSfxCtrl_setState(this, CH_RBB_SPINNING_PIPE_SFX_CTRL_STATE_1_INIT); + } + else{//L8038FD34 + if(local->marker == NULL) + local->marker = actorArray_findActorFromActorId(*local->actorId)->marker; + sp20 = func_8038A6B8(local->marker); + tmp_f2 = 1.5 * sp20 + 0.5; + func_802F9DB8(local->unk0, tmp_f2, tmp_f2, 0.0f); + tmp_a1 = (s32) (sp20 * 32000.0f); + func_802FA060(local->unk0, tmp_a1, tmp_a1, 0.0f); + } +} diff --git a/src/SM/ch/bottles_movecheck.c b/src/SM/bottles_movecheck.c similarity index 100% rename from src/SM/ch/bottles_movecheck.c rename to src/SM/bottles_movecheck.c diff --git a/src/SM/ch/ambient_fish.c b/src/SM/ch/ambient_fish.c index e3ed73d93..79a113b1c 100644 --- a/src/SM/ch/ambient_fish.c +++ b/src/SM/ch/ambient_fish.c @@ -1,4 +1,4 @@ -// BanjoDecomp: (unknown origin) +// BanjoDecomp: core2/code_C89C0.c #include #include "functions.h" #include "variables.h" diff --git a/src/SM/ch/jumptutorial.c b/src/SM/ch/jumptutorial.c index d8cb0862b..fd704405b 100644 --- a/src/SM/ch/jumptutorial.c +++ b/src/SM/ch/jumptutorial.c @@ -57,8 +57,8 @@ void chJumpTutorial_setState(Actor *this, s32 state) { ability_unlock(ABILITY_A_HOLD_A_JUMP_HIGHER); gcdialog_showDialog(ASSET_DF6_DIALOG_BOTTLES_HIGH_JUMP_LEARN, 0xe, this->unk1C, this->marker, __chJumpTutorial_textCallback, NULL); - this->sm_4070.dialog_id = ASSET_E1A_DIALOG_BOTTLES_UNKNOWN; - mapSpecificFlags_set(SM_SPECIFIC_FLAG_8_ABILITY_HOLD_A_JUMP_HIGHER_UNLOCKED, false); + this->sm_4070.dialog_id = VER_SELECT(ASSET_E1A_DIALOG_BOTTLES_UNKNOWN, 0xA5C, 0, 0); + mapSpecificFlags_set(SM_SPECIFIC_FLAG_8_ABILITY_HOLD_A_JUMP_HIGHER_UNLOCKED, FALSE); } break; @@ -113,8 +113,8 @@ void chJumpTutorial_update(Actor *this) { ability_unlock(ABILITY_7_FEATHERY_FLAP); gcdialog_showDialog(ASSET_DF7_DIALOG_BOTTLES_FEATHERY_FLAP_LEARN, 0xa, this->unk1C, this->marker, __chJumpTutorial_textCallback, NULL); - this->sm_4070.dialog_id = ASSET_E1B_DIALOG_BOTTLES_UNKNOWN; - mapSpecificFlags_set(SM_SPECIFIC_FLAG_8_ABILITY_HOLD_A_JUMP_HIGHER_UNLOCKED, false); + this->sm_4070.dialog_id = VER_SELECT(ASSET_E1B_DIALOG_BOTTLES_UNKNOWN, 0xA5D, 0, 0); + mapSpecificFlags_set(SM_SPECIFIC_FLAG_8_ABILITY_HOLD_A_JUMP_HIGHER_UNLOCKED, FALSE); }//L8038A730 if (mapSpecificFlags_get(SM_SPECIFIC_FLAG_9_ABILITY_FEATHERY_UNLOCKED)) { @@ -122,8 +122,8 @@ void chJumpTutorial_update(Actor *this) { ability_unlock(ABILITY_8_FLAP_FLIP); gcdialog_showDialog(ASSET_DF8_DIALOG_BOTTLES_FLAP_FLIP_LEARN, 0xa, this->unk1C, this->marker, __chJumpTutorial_textCallback, NULL); - this->sm_4070.dialog_id = ASSET_E1C_DIALOG_BOTTLES_UNKNOWN; - mapSpecificFlags_set(SM_SPECIFIC_FLAG_9_ABILITY_FEATHERY_UNLOCKED, false); + this->sm_4070.dialog_id = VER_SELECT(ASSET_E1C_DIALOG_BOTTLES_UNKNOWN, 0xA5E, 0, 0); + mapSpecificFlags_set(SM_SPECIFIC_FLAG_9_ABILITY_FEATHERY_UNLOCKED, FALSE); }//L8038A794 if (mapSpecificFlags_get(SM_SPECIFIC_FLAG_A_ABILITY_FLIP_UNLOCKED)) { @@ -149,7 +149,7 @@ void chJumpTutorial_update(Actor *this) { plyr_pos[2] = this->velocity_z; func_8028FAB0(plyr_pos); - if (func_8028EFC8() && face_buttons[FACE_BUTTON(BUTTON_B)] == true && func_8028F20C()) { + if (func_8028EFC8() && face_buttons[FACE_BUTTON(BUTTON_B)] == TRUE && player_isStableWithExtraSteps()) { if (this->sm_4070.dialog_id) { gcdialog_showDialog(dialog_id = this->sm_4070.dialog_id, 0, NULL, NULL, NULL, NULL); } diff --git a/src/SM/ch/smbottles.c b/src/SM/ch/smbottles.c index 301806e00..13c2512da 100644 --- a/src/SM/ch/smbottles.c +++ b/src/SM/ch/smbottles.c @@ -500,7 +500,7 @@ void chSmBottles_update(Actor *this) { (this->actorTypeSpecificField == 8 && !mapSpecificFlags_get(SM_SPECIFIC_FLAG_2)) || (this->actorTypeSpecificField == 8 && mapSpecificFlags_get(SM_SPECIFIC_FLAG_3_ALL_SM_ABILITIES_LEARNED) && !mapSpecificFlags_get(SM_SPECIFIC_FLAG_F)) ) {//L80389C50 - if (((ml_vec3f_distance(plyr_pos, this->unk1C) < this->actor_specific_1_f) && func_8028F20C()) || + if (((ml_vec3f_distance(plyr_pos, this->unk1C) < this->actor_specific_1_f) && player_isStableWithExtraSteps()) || mapSpecificFlags_get(SM_SPECIFIC_FLAG_10) ) {//L80389C8C if (subaddie_playerIsWithinSphereAndActive(this, 0x96)) { @@ -512,7 +512,7 @@ void chSmBottles_update(Actor *this) { } } else {//L80389CBC - if (!subaddie_playerIsWithinSphereAndActive(this, 0xfa) || player_movementGroup() || !func_8028F20C() || func_8028EC04()) { + if (!subaddie_playerIsWithinSphereAndActive(this, 250) || player_movementGroup() || !player_isStableWithExtraSteps() || func_8028EC04()) { break; } diff --git a/src/SM/ch/vegetables.c b/src/SM/ch/vegetables.c index 67dbcda32..a06ad7f2d 100644 --- a/src/SM/ch/vegetables.c +++ b/src/SM/ch/vegetables.c @@ -50,7 +50,7 @@ ActorInfo gChVegetablesTopperA = { }; ActorInfo gChVegetablesTopperB = { - MARKER_1E6_TOPPER_THE_CARROT_B, ACTOR_TOPPER_THE_CARROT_B, ASSET_4ED_MODEL_TOPPER, + MARKER_1E6_TOPPER_THE_CARROT_B, ACTOR_36F_TOPPER_THE_CARROT_B, ASSET_4ED_MODEL_TOPPER, 1, sChCarrotAnimations, __chVegetables_update, actor_update_func_80326224, __chVegetables_draw, 2000, 0, 1.0f, 0 }; @@ -70,7 +70,7 @@ ActorInfo gChVegetablesBawlA = { }; ActorInfo gChVegetablesBawlB = { - MARKER_1E7_BAWL_THE_ONION_B, ACTOR_BAWL_THE_ONION_B, ASSET_4EF_MODEL_BAWL, + MARKER_1E7_BAWL_THE_ONION_B, ACTOR_36E_BAWL_THE_ONION_B, ASSET_4EF_MODEL_BAWL, 1, sChOnionAnimations, __chVegetables_update, actor_update_func_80326224, __chVegetables_draw, 0, 0, 1.0f, 0 }; @@ -90,7 +90,7 @@ ActorInfo gChVegetablesCollywobbleA = { }; ActorInfo gChVegetablesCollywobbleB = { - MARKER_1E8_COLLYWOBBLE_THE_CAULIFLOWER_B, ACTOR_COLLYWOBBLE_B, ASSET_4EE_MODEL_COLLYWOBBLE, + MARKER_1E8_COLLYWOBBLE_THE_CAULIFLOWER_B, ACTOR_36D_COLLYWOBBLE_B, ASSET_4EE_MODEL_COLLYWOBBLE, 1, sChCauliflowerAnimations, __chVegetables_update, actor_update_func_80326224, __chVegetables_draw, 0, 0, 2.0f, 0 }; @@ -244,7 +244,7 @@ static Actor* __chVegetables_draw(ActorMarker* marker, Gfx **gdl, Mtx **mptr, Vt if (actor->has_met_before) modelRender_func_8033A470(3, 7); else - func_8033A45C(3, 0); + modelRender_setAppendageVisibility(3, 0); return actor_draw(marker, gdl, mptr, arg3); } diff --git a/src/SM/checksums.c b/src/SM/checksums.c new file mode 100644 index 000000000..52758c905 --- /dev/null +++ b/src/SM/checksums.c @@ -0,0 +1,7 @@ +// BanjoDecomp: SM/checksums.c +#include +#include "checksums.h" + +// !! THIS FILE MUST BE LINKED FIRST FOR THIS OVERLAY !! + +/* bss */ struct overlay_checksums_s gChecksumsSM; diff --git a/src/SM/ch/furniture.c b/src/SM/furniture.c similarity index 100% rename from src/SM/ch/furniture.c rename to src/SM/furniture.c diff --git a/src/SM/ch/quarrie.c b/src/SM/quarrie.c similarity index 100% rename from src/SM/ch/quarrie.c rename to src/SM/quarrie.c diff --git a/src/SM/crc.c b/src/SM/smspawnqueue.c similarity index 80% rename from src/SM/crc.c rename to src/SM/smspawnqueue.c index 0bd8884db..a22fff34e 100644 --- a/src/SM/crc.c +++ b/src/SM/smspawnqueue.c @@ -1,11 +1,13 @@ -// BanjoDecomp: code_F0.c +// BanjoDecomp: SM/smspawnqueue.c #include #include "functions.h" #include "variables.h" #include "prop.h" #include "actor.h" +#include "checksums.h" + +int ability_hasLearned(s32); -extern s32 D_80275650; extern ActorInfo gQuarrie; @@ -25,27 +27,11 @@ extern ActorInfo gBanjosChair; extern ActorInfo gBanjosStove; extern ActorInfo gRockTrappingGrunty; -extern u32 gCore1CRCs[4]; - -/* .data */ -s32 D_8038AAE0 = 0x000FE2C1; //compiled SM_code_crc_1 -s32 D_8038AAE4 = 0x8C0992D1; //compiled SM_code_crc_2 -union { - u8 byte[4]; - s32 word; -} D_8038AAE8 = {0x00, 0x01, 0xEB, 0x56}; //compiled SM_data_crc_1 (with this disabled out) +s32 D_8038AAE0 = VER_SELECT(0x000FE2C1, 0x00109339, 0, 0); // SM_TEXT_CRC1 +s32 D_8038AAE4 = VER_SELECT(0x8C0992D1, 0xC3A58E96, 0, 0); // SM_TEXT_CRC2 +s32 D_8038AAE8 = VER_SELECT(0x0001EB56, 0x00020B4D, 0, 0); // SM_DATA_CRC1 s32 D_8038AAEC = 0; -/* .bss */ -struct { - s32 unk0; //calculated SM_code_crc1 - s32 unk4; //calculated SM_code_crc2 - s32 unk8; //calculated SM_data_crc1 - s32 unkC; //calculated SM_data_crc2 -} D_8038B320; - -static bool __codeF0_areRomCrcsCorrect(); -static bool __codeF0_areCrcsValid(); /* .code */ static u32 *__codeF0_getLearnedAbilitiesAddress(){ @@ -115,16 +101,14 @@ void __codeF0_pad_func_80386614(u8 *arg0, u8 *arg1, s32 *arg2, s32 *arg3){ *arg3 = temp_v1; } -extern u8 crc_ROM_START[]; - static bool __codeF0_areRomCrcsCorrect(){ #if ANTI_TAMPER u32 sp24; - if( (osPiReadIo((u32)crc_ROM_START + 8, &sp24), sp24 == gCore1CRCs[0]) - && (osPiReadIo((u32)crc_ROM_START + 12, &sp24), sp24 == gCore1CRCs[1]) - && (osPiReadIo((u32)crc_ROM_START + 16, &sp24), sp24 == gCore1CRCs[2]) - && (osPiReadIo((u32)crc_ROM_START + 20, &sp24), sp24 == gCore1CRCs[3]) + if( (osPiReadIo((u32)crc_ROM_START + CRC_CORE1_TEXT_CHECKSUM1, &sp24), sp24 == gChecksumsCore1.text_checksum1) + && (osPiReadIo((u32)crc_ROM_START + CRC_CORE1_TEXT_CHECKSUM2, &sp24), sp24 == gChecksumsCore1.text_checksum2) + && (osPiReadIo((u32)crc_ROM_START + CRC_CORE1_DATA_CHECKSUM1, &sp24), sp24 == gChecksumsCore1.data_checksum1) + && (osPiReadIo((u32)crc_ROM_START + CRC_CORE1_DATA_CHECKSUM2, &sp24), sp24 == gChecksumsCore1.data_checksum2) ){ return true; } @@ -136,10 +120,10 @@ static bool __codeF0_areRomCrcsCorrect(){ static bool __codeF0_areCrcsValid(){ #if ANTI_TAMPER - if( D_8038B320.unk0 == D_8038AAE0 - && D_8038B320.unk4 == D_8038AAE4 - && D_8038B320.unkC == D_80275650 - && D_8038B320.unk8 == D_8038AAE8.word + D_8038AAE8.byte[0] + D_8038AAE8.byte[1] + D_8038AAE8.byte[2] + D_8038AAE8.byte[3] + if( gChecksumsSM.text_checksum1 == D_8038AAE0 + && gChecksumsSM.text_checksum2 == D_8038AAE4 + && gChecksumsSM.data_checksum2 == D_80275650 + && gChecksumsSM.data_checksum1 == D_8038AAE8 + ((u8 *) &D_8038AAE8)[0] + ((u8 *) &D_8038AAE8)[1] + ((u8 *) &D_8038AAE8)[2] + ((u8 *) &D_8038AAE8)[3] ){ return true; } diff --git a/src/SM/version_compat.c b/src/SM/version_compat.c index 7b9d27953..4765cf76a 100644 --- a/src/SM/version_compat.c +++ b/src/SM/version_compat.c @@ -3,65 +3,111 @@ #include "functions.h" #include "variables.h" -#define US_1_0 0 -#define PAL 1 - -u8 D_8038BFC2; - - -#if VERSION == US_1_0 -int func_8038AAB0(void){return 0;} - -#elif VERSION == PAL -#if 0 -void func_8038AAB0(s32 arg0, s32 arg1){ - if(arg1 < 0){ - func_8031A844(); - } - else{ - D_8038BFC2 = arg1; - func_8038B4D0(3); - } - } - - #pragma GLOBAL_ASM("asm/nonmatchings/SM/code_46C0/func_8038A8F0.s") - void func_8038A8F0(s32 arg0) { - u8 temp_v0; - - switch (arg0) { /* irregular */ - case 1: - D_8038BFC1 = 1; - func_80319400(); - break; - case 2: - D_8038BFC8->unk0 = (s32) D_8038BD38; - D_8038BFC8->unk4 = (s32) D_8038BD3C; - D_8038BFC8->unk10 = (s32) D_8038BD40; - D_8038BFC8->unk20 = (s32) D_8038BD44; - D_8038BFC8->unk30 = (s32) D_8038BD48; - func_8031A5E4(&D_8038BD30, &D_8038BD34, (void *)0x8038BFC8, 0xA, &D_8038B490); - break; - case 3: - temp_v0 = *(u8 *)0x8038BFC2; - if (temp_v0 != 0) { - func_8031B9A4(temp_v0 - 1, 0x80390000); - } - func_802FAF44(0); - D_8038BFC1 = 0; - break; - } - D_8038BFC0 = (s8) arg0; - } - - - #pragma GLOBAL_ASM("asm/nonmatchings/SM/code_46C0/func_8038A9E4.s") - - #pragma GLOBAL_ASM("asm/nonmatchings/SM/code_46C0/func_8038AA30.s") - - #pragma GLOBAL_ASM("asm/nonmatchings/SM/code_46C0/func_8038AA64.s") - - #pragma GLOBAL_ASM("asm/nonmatchings/SM/code_46C0/func_8038AA74.s") - - #pragma GLOBAL_ASM("asm/nonmatchings/SM/code_46C0/func_8038AAE8.s") -#endif +#if VERSION == VERSION_USA_1_0 + +int func_8038AAB0(void) { + return 0; +} + +#elif VERSION == VERSION_PAL + +struct language_selection_screen_s { + u8 *unk0; + u8 *unk4; + u64 unk8; + + u8 *unk10; + u32 unk14; + u64 unk18; + + u8 *unk20; + u32 unk24; + u64 unk28; + + u8 *unk30; + u32 unk34; + u64 unk38; +}; + +/* data */ +u32 D_8038BD30_pal = 0x0C68696A; +u32 D_8038BD34_pal = 0x02010101; +u8 *D_8038BD38_pal = "WHICH LANGUAGE WOULD"; +u8 *D_8038BD3C_pal = "YOU LIKE TO USE?"; +u8 *D_8038BD40_pal = "ENGLISH"; +u8 *D_8038BD44_pal = "FRANaAIS"; +u8 *D_8038BD48_pal = "DEUTSCH"; + +/* bss */ +u8 D_8038BFC0_pal; +u8 D_8038BFC1_pal; +u8 D_8038BFC2_pal; +struct language_selection_screen_s D_8038BFC8_pal; + +/* text */ +void func_8038B4D0_pal(s32 arg0); + +void func_8038B490_pal(s32 arg0, s32 arg1) { + if (arg1 < 0) { + /*func_8031A844_pal*/gcquiz_func_8031A48C(); + return; + } + D_8038BFC2_pal = arg1; + func_8038B4D0_pal(3); +} + +void func_8038B4D0_pal(s32 arg0) { + switch (arg0) { /* irregular */ + case 1: + D_8038BFC1_pal = 1; + /*func_80319400_pal*/gcquiz_init(); + break; + case 2: + D_8038BFC8_pal.unk0 = D_8038BD38_pal; + D_8038BFC8_pal.unk4 = D_8038BD3C_pal; + D_8038BFC8_pal.unk10 = D_8038BD40_pal; + D_8038BFC8_pal.unk20 = D_8038BD44_pal; + D_8038BFC8_pal.unk30 = D_8038BD48_pal; + /*func_8031A5E4_pal*/__gcquiz_unused(&D_8038BD30_pal, &D_8038BD34_pal, &D_8038BFC8_pal, 0xA, &func_8038B490_pal); + break; + case 3: + if (D_8038BFC2_pal) { + func_8031B5C4(D_8038BFC2_pal - 1); + } + func_802FAD64(ITEM_0_HOURGLASS_TIMER); + D_8038BFC1_pal = 0; + break; + } + D_8038BFC0_pal = (s8) arg0; +} + +void func_8038B5C4_pal(void) { + if (gsworld_getMap() == MAP_91_FILE_SELECT) { + func_8038B4D0_pal(func_8031B638() ? 3 : 1); + } +} + +void func_8038B610_pal(void) { + if (gsworld_getMap() == MAP_91_FILE_SELECT) { + /*func_80319540_pal*/gcquiz_free(); + } +} + +void func_8038B644_pal(s32 arg0, s32 arg1, s32 arg2) { +} + +void func_8038B654_pal(void) { + if ((D_8038BFC1_pal) && (getGameMode() == 3)) { + /*func_8031A25C_pal*/gcquiz_func_80319EA4(); + if (D_8038BFC0_pal == 1) { + timedFunc_set_1(1.0f, func_8038B4D0_pal, 2); + func_8038B4D0_pal(0); + } + } +} + +u8 func_8038B6C8_pal(void) { + return D_8038BFC1_pal; +} + #endif diff --git a/src/TTC/actor_spawninit.c b/src/TTC/actor_spawninit.c index d6b94daf3..ea46aa3ec 100644 --- a/src/TTC/actor_spawninit.c +++ b/src/TTC/actor_spawninit.c @@ -26,7 +26,7 @@ extern ActorInfo gChTreasurehuntRedQuestionMark; extern ActorInfo gChTreasurehuntRedX; extern ActorInfo gChTreasure; -extern void func_802D3D54(Actor *this); +extern void chMMMBreakableWooden_update(Actor *this); static void __code26D0_genericUpdateFunc(Actor *this); static void __code26D0_palmTreeUpdateFunc(Actor *this); @@ -37,14 +37,14 @@ static void __code26D0_sharkfoodIslandUpdateFunc(Actor *this); ActorInfo gBlubberShipTopHatch = { MARKER_A1_BLUBBER_SHIP_TOP_HATCH, ACTOR_10E_BLUBBER_SHIP_TOP_HATCH, ASSET_3D2_MODEL_BLUBBER_SHIP_TOP_HATCH, 0x1, NULL, - func_802D3D54, actor_update_func_80326224, actor_drawFullDepth, + chMMMBreakableWooden_update, actor_update_func_80326224, actor_drawFullDepth, 0, 0, 0.0f, 0 }; ActorInfo gLighthouseDoor = { MARKER_EA_LIGHTHOUSE_DOOR, ACTOR_13E_LIGHTHOUSE_DOOR, ASSET_3D6_MODEL_LIGHTHOUSE_DOOR, 0x1, NULL, - func_802D3D54, actor_update_func_80326224, actor_drawFullDepth, + chMMMBreakableWooden_update, actor_update_func_80326224, actor_drawFullDepth, 0, 0, 0.0f, 0 }; @@ -77,7 +77,7 @@ ActorInfo gStairs1 = { }; ActorInfo gStairs2 = { - MARKER_269_STAIRS_2, ACTOR_2E1_TTC_STAIRS_2, ASSET_3B7_MODEL_TTC_STAIRS_1, + MARKER_269_STAIRS_2, ACTOR_2E1_TTC_STAIRS_2, ASSET_3B7_MODEL_TTC_STAIRS_2, 0x1, NULL, __code26D0_genericUpdateFunc, actor_update_func_80326224, actor_drawFullDepth, 0, 0, 0.0f, 0 diff --git a/src/TTC/ch/blubber.c b/src/TTC/ch/blubber.c index 91202f8d5..e71349ade 100644 --- a/src/TTC/ch/blubber.c +++ b/src/TTC/ch/blubber.c @@ -66,7 +66,7 @@ static void __chBlubber_showTextCallback(ActorMarker *caller, enum asset_e text_ Actor *this = marker_getActor(caller); ActorLocal_Blubber *local = (ActorLocal_Blubber*)&this->local; - if(text_id == ASSET_A0D_DIALOG_BLUBBER_COMPLETE || text_id == ASSET_A2A_DIALOG_BLUBBER_COMPLETE_JIGGY_COLLECTED){ + if(text_id == VER_SELECT(ASSET_A0D_DIALOG_BLUBBER_COMPLETE, 0x90D, 0, 0) || text_id == ASSET_A2A_DIALOG_BLUBBER_COMPLETE_JIGGY_COLLECTED){ local->unk24 = 0; } else{ @@ -92,7 +92,7 @@ static void __chBlubber_showJiggySpawnedText(ActorMarker *marker){ this->actor_specific_1_f = 0.0f; if(!mapSpecificFlags_get(TTC_SPECIFIC_FLAG_2_BLUBBER_JIGGY_SPAWNED_TEXT_SHOWN)) { - text_id = jiggyscore_isCollected(JIGGY_14_TTC_BLUBBER) ? ASSET_A2A_DIALOG_BLUBBER_COMPLETE_JIGGY_COLLECTED : ASSET_A0D_DIALOG_BLUBBER_COMPLETE; + text_id = jiggyscore_isCollected(JIGGY_14_TTC_BLUBBER) ? ASSET_A2A_DIALOG_BLUBBER_COMPLETE_JIGGY_COLLECTED : VER_SELECT(ASSET_A0D_DIALOG_BLUBBER_COMPLETE, 0x90D, 0, 0); gcdialog_showDialog(text_id, 0xf, this->position, this->marker, __chBlubber_showTextCallback, __chBlubber_showTextCallback2); mapSpecificFlags_set(TTC_SPECIFIC_FLAG_2_BLUBBER_JIGGY_SPAWNED_TEXT_SHOWN, true); } @@ -124,7 +124,7 @@ static void __func_80387774(Actor **this_ptr){ player_setCarryObjectPoseInCylinder(local->throw_target_position, local->throw_target_radius, 100.0f, ACTOR_2A_GOLD_BULLION, this_ptr); if( subaddie_playerIsWithinSphereAndActive(*this_ptr, 200) - && bacarry_get_markerId() == MARKER_37_GOLD_BULLION + && bacarry_getMarkerId() == MARKER_37_GOLD_BULLION && player_throwCarriedObject() ) { func_8028FA34(!mapSpecificFlags_get(TTC_SPECIFIC_FLAG_0_BLUBBER_UNKNOWN) ? ACTOR_149_TTC_BLUBBER_UNKNOWN : ACTOR_14A_TTC_BLUBBER_UNKNOWN, *this_ptr); @@ -196,8 +196,8 @@ static void __chBlubber_updateFunc(Actor *this){ && !this->has_met_before && item_getCount(ITEM_18_GOLD_BULLIONS) == 0 ){ - gcdialog_showDialog(ASSET_A0B_DIALOG_BLUBBER_FIRST_MEET, 0xe, this->position, this->marker, __chBlubber_showTextCallback, NULL); - this->has_met_before = true; + gcdialog_showDialog(VER_SELECT(ASSET_A0B_DIALOG_BLUBBER_FIRST_MEET, 0x90B, 0, 0), 0xe, this->position, this->marker, __chBlubber_showTextCallback, NULL); + this->has_met_before = TRUE; subaddie_set_state_forward(this, CH_BLUBBER_STATE_3_UNKNOWN); } @@ -205,7 +205,7 @@ static void __chBlubber_updateFunc(Actor *this){ && !this->unk138_23 ){ if (item_getCount(ITEM_18_GOLD_BULLIONS) == 0) { - gcdialog_showDialog(ASSET_A0C_DIALOG_BLUBBER_HALF_GOLD, 4, NULL, NULL, NULL, NULL); + gcdialog_showDialog(VER_SELECT(ASSET_A0C_DIALOG_BLUBBER_HALF_GOLD, 0x90C, 0, 0), 4, NULL, NULL, NULL, NULL); } this->unk138_23 = true; @@ -295,6 +295,6 @@ static void __chBlubber_update2Func(Actor *this){ } static Actor *__chBlubber_drawFunc(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx){ - func_8033A45C(4, 0); + modelRender_setAppendageVisibility(4, 0); return actor_draw(marker, gfx, mtx, vtx); } diff --git a/src/TTC/ch/clam.c b/src/TTC/ch/clam.c index 30e8cec20..ba46220e0 100644 --- a/src/TTC/ch/clam.c +++ b/src/TTC/ch/clam.c @@ -101,7 +101,7 @@ static bool __chClam_rotateTowardTarget(Actor *this, s32 arg1) { anctrl_setDuration(this->anctrl, 1.0f); - sp2C = (s32) ((f64) (60.0f / (f32) time_getDeltaReal_frames()) * 0.5); + sp2C = (s32) ((f64) ((float)FRAMERATE / (f32) time_getDeltaReal_frames()) * 0.5); if ((this->unk1C[0] != 0.0f) || !__chClam_updateFuncTarget(this, sp2C)) { if (((f64) anctrl_getAnimTimer(this->anctrl) < 0.1) && ((f64) randf() < 0.5)) { if (this->unk1C[0] != 0.0f) { @@ -230,7 +230,7 @@ static void __chClam_takeDamage(ActorMarker *this_marker, ActorMarker *other_mar __chClam_emitLargeShellParticles(this->position, 2); __chClam_emitEyeParticles(this->position, 2); __chClam_emitSmallShellParticles(this->position, 0xC); - func_803115C4(0xa14); + func_803115C4(VER_SELECT(ASSET_A14_DIALOG_CLAM_TAUNT, 0x914, 0, 0)); marker_despawn(this->marker); } @@ -247,8 +247,8 @@ static void __chClam_attackOther(ActorMarker *this_marker, ActorMarker *other_ma if(baiFrame_getState() == 3) return; - if( !mapSpecificFlags_get(TTC_SPECIFIC_FLAG_5_CLAM_FIRST_MEET_TEXT_SHOWN) && gcdialog_showDialog(ASSET_A14_DIALOG_CLAM_TAUNT, 0, NULL, NULL, NULL, NULL)){ - mapSpecificFlags_set(TTC_SPECIFIC_FLAG_5_CLAM_FIRST_MEET_TEXT_SHOWN, true); + if( !mapSpecificFlags_get(TTC_SPECIFIC_FLAG_5_CLAM_FIRST_MEET_TEXT_SHOWN) && gcdialog_showDialog(VER_SELECT(ASSET_A14_DIALOG_CLAM_TAUNT, 0x914, 0, 0), 0, NULL, NULL, NULL, NULL)){ + mapSpecificFlags_set(TTC_SPECIFIC_FLAG_5_CLAM_FIRST_MEET_TEXT_SHOWN, TRUE); } // [port] Match JP: only drop while fewer than 8 eggs / 5 red feathers are on the diff --git a/src/TTC/ch/leaky.c b/src/TTC/ch/leaky.c index dddc8d7c6..20002471d 100644 --- a/src/TTC/ch/leaky.c +++ b/src/TTC/ch/leaky.c @@ -71,7 +71,7 @@ static void __chLeaky_updateFunc(Actor *this) { && !this->has_met_before && subaddie_playerIsWithinSphereAndActive(this, 250) && !subaddie_playerIsWithinSphereAndActive(this, 160) && !player_movementGroup() - && gcdialog_showDialog(ASSET_A1A_DIALOG_LEAKY_FIRST_MEET, 0, NULL, NULL, NULL, NULL) + && gcdialog_showDialog(VER_SELECT(ASSET_A1A_DIALOG_LEAKY_FIRST_MEET, 0x91A, 0, 0), 0, NULL, NULL, NULL, NULL) ){ this->has_met_before = true; } @@ -127,8 +127,8 @@ bool chLeaky_eggCollision(ActorMarker *marker){ return true; } - levelSpecificFlags_set(2, true); - levelSpecificFlags_set(5, true); - gcdialog_showDialog(ASSET_A28_DIALOG_LEAKY_DONE, 0x2a, this->position, this->marker, __chLeaky_showDoneText, NULL); - return true; + levelSpecificFlags_set(2, TRUE); + levelSpecificFlags_set(5, TRUE); + gcdialog_showDialog(VER_SELECT(ASSET_A28_DIALOG_LEAKY_DONE, 0x928, 0, 0), 0x2a, this->position, this->marker, __chLeaky_showDoneText, NULL); + return TRUE; } diff --git a/src/TTC/ch/lockup.c b/src/TTC/ch/lockup.c index 6ead9bebb..ab8f0467b 100644 --- a/src/TTC/ch/lockup.c +++ b/src/TTC/ch/lockup.c @@ -57,8 +57,8 @@ static s32 sLockup_CloseVelocity[3] = {0,0,0}; /* .code */ static Actor *__chLockup_drawFunc(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx){ Actor * actor = marker_getActor(marker); - func_8033A45C(3, actor->unk38_31); - func_8033A45C(4, actor->unk38_31); + modelRender_setAppendageVisibility(3, actor->unk38_31); + modelRender_setAppendageVisibility(4, actor->unk38_31); return actor_draw(marker, gfx, mtx, vtx); } @@ -87,9 +87,9 @@ static void __chLockup_updateFunc(Actor *this){ && subaddie_playerIsWithinSphereAndActive(this, 320) && !subaddie_playerIsWithinSphereAndActive(this, 160) && !player_movementGroup() - && gcdialog_showDialog(ASSET_A15_DIALOG_LOCKUP_SPAWNED, 0, NULL, NULL, NULL, NULL) - ){ - this->has_met_before = true; + && gcdialog_showDialog(VER_SELECT(ASSET_A15_DIALOG_LOCKUP_SPAWNED, 0x915, 0, 0), 0, NULL, NULL, NULL, NULL)) { + + this->has_met_before = TRUE; } if(!this->volatile_initialized){ diff --git a/src/TTC/ch/lockup.h b/src/TTC/ch/lockup.h new file mode 100644 index 000000000..dc17d5d73 --- /dev/null +++ b/src/TTC/ch/lockup.h @@ -0,0 +1,23 @@ +// BanjoDecomp: TTC/ch/lockup.h +#define LOCKUP_WITH_JIGGY_ID 0xA + +#define LOCKUP_CYCLE_TICKS_SLOW 0x1E +#define LOCKUP_CYCLE_TICKS_MEDIUM 0x14 +#define LOCKUP_CYCLE_TICKS_FAST 0xA +#define LOCKUP_CYCLE_TICKS_DEFAULT 10000 + +typedef struct { + s32 closedTicksCounter; + s32 openTicksCounter; +} ActorLocal_Lockup; + +static Actor *chLockup_draw(ActorMarker *this, Gfx **gfx, Mtx **mtx, Vtx **vtx); +static void chLockup_update(Actor *this); + +enum ch_lockup_states_e { + CH_LOCKUP_STATE_CLOSED = 1, + CH_LOCKUP_STATE_OPENING = 2, + CH_LOCKUP_STATE_OPEN = 3, + CH_LOCKUP_STATE_CLOSING = 4, + CH_LOCKUP_STATE_CLOSING2 = 5 +}; diff --git a/src/TTC/ch/nipper.c b/src/TTC/ch/nipper.c index 4070958c6..c9f0a2da3 100644 --- a/src/TTC/ch/nipper.c +++ b/src/TTC/ch/nipper.c @@ -89,7 +89,7 @@ static Actor *__chNipper_animFunc(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx Actor *this; this = marker_getActor(marker); - func_8033A45C(3, (this->state == 7)? 0 : 1); + modelRender_setAppendageVisibility(3, (this->state == 7)? 0 : 1); return actor_draw(marker, gfx, mtx, vtx); } @@ -180,7 +180,7 @@ static void __chNipper_dieFunc(ActorMarker *this_marker, ActorMarker *other_mark port_puzzleStep_orBits(ANCHOR_PUZZLE_TTC_NIPPER, 0x1); __chNipper_playDeathAnimation(this); this->lifetime_value = 80.0f; - gcdialog_showDialog(ASSET_A10_DIALOG_NIPPER_HURT, 4, NULL, NULL, NULL, NULL); + gcdialog_showDialog(VER_SELECT(ASSET_A10_DIALOG_NIPPER_HURT, 0x910, 0, 0), 4, NULL, NULL, NULL, NULL); return; } @@ -201,7 +201,7 @@ static void __chNipper_ow2Func(ActorMarker * this_marker, ActorMarker *other_mar this = marker_getActor(this_marker); if( !mapSpecificFlags_get(TTC_SPECIFIC_FLAG_7_NIPPER_FIRST_MEET_TEXT_SHOWN) && this->has_met_before - && gcdialog_showDialog(ASSET_A0F_DIALOG_NIPPER_HIT_BY_EGG, 0, NULL, NULL, NULL, NULL) + && gcdialog_showDialog(VER_SELECT(ASSET_A0F_DIALOG_NIPPER_HIT_BY_EGG, 0x90F, 0, 0), 0, NULL, NULL, NULL, NULL) ){ mapSpecificFlags_set(TTC_SPECIFIC_FLAG_7_NIPPER_FIRST_MEET_TEXT_SHOWN, true); } @@ -212,7 +212,7 @@ static void __chNipper_owFunc(ActorMarker * this_marker, ActorMarker *other_mark Actor *this = marker_getActor(this_marker); if( !this->unk138_23 && this->has_met_before - && gcdialog_showDialog(ASSET_A11_DIALOG_NIPPER_ATTACK, 0, NULL, NULL, NULL, NULL) + && gcdialog_showDialog(VER_SELECT(ASSET_A11_DIALOG_NIPPER_ATTACK, 0x911, 0, 0), 0, NULL, NULL, NULL, NULL) ){ this->unk138_23 = true; } @@ -286,8 +286,8 @@ static void __chNipper_updateFunc(Actor *this){ && player_movement_group != BSGROUP_A_FLYING ){ subaddie_set_state_with_direction(this, CH_NIPPER_STATE_5_SPAWNED, 0.01f, 1); - if(gcdialog_showDialog(ASSET_A0E_DIALOG_NIPPER_SPAWNED, 0xf, this->position, this->marker, __chNipper_spawnedShowTextCallback, NULL)){ - this->has_met_before = true; + if(gcdialog_showDialog(VER_SELECT(ASSET_A0E_DIALOG_NIPPER_SPAWNED, 0x90E, 0, 0), 0xf, this->position, this->marker, __chNipper_spawnedShowTextCallback, NULL)){ + this->has_met_before = TRUE; } comusic_8025AB44(COMUSIC_12_TTC_NIPPER, 5000, 300); ncStaticCamera_setToNode(11); diff --git a/src/TTC/ch/treasure.c b/src/TTC/ch/treasure.c index 018059318..3ae54cf0d 100644 --- a/src/TTC/ch/treasure.c +++ b/src/TTC/ch/treasure.c @@ -25,7 +25,7 @@ static void __chTreasure_die(ActorMarker *marker, ActorMarker *otherMarker){ Actor *this = marker_getActor(marker); __spawnQueue_add_4((GenFunction_4) spawnQueue_actor_f32, 0x4C, reinterpret_cast(s32, this->position[0]), reinterpret_cast(s32, this->position[1]), reinterpret_cast(s32, this->position[2])); func_802EE278(this, 3, 0xf, 0x3C, 0.2f, 1.2f); - func_803115C4(0xA19); + func_803115C4(VER_SELECT(0xA19, 0x919, 0, 0)); jiggy_spawn(JIGGY_11_TTC_RED_X, this->position); marker_despawn(marker); } diff --git a/src/TTC/ch/treasurehunt.c b/src/TTC/ch/treasurehunt.c index 2a0f97e10..ca861780c 100644 --- a/src/TTC/ch/treasurehunt.c +++ b/src/TTC/ch/treasurehunt.c @@ -15,7 +15,7 @@ typedef struct { static void __chTreasurehunt_updateFunc(Actor *this); static Actor *__chTreasurehunt_animFunc(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx); -extern u32 CH_TREASUREHUNT_PUZZLE_CURRENT_STEP; +extern u32 chtreasureHunt_puzzleCurrentStep; /* .data */ static f32 sChTreasurehunt_stepPositions[6][3] = { @@ -82,7 +82,7 @@ static bool __chTreasurehunt_isActiveHitboxBeakBusterHitbox(void) { if (player_getActiveHitbox(0) == HITBOX_1_BEAK_BUSTER) { comusic_id = COMUSIC_2B_DING_B; music_volume = 28000; - if (CH_TREASUREHUNT_PUZZLE_CURRENT_STEP == 5) { + if (chtreasureHunt_puzzleCurrentStep == 5) { comusic_id = COMUSIC_2D_PUZZLE_SOLVED_FANFARE; music_volume = 0x7FFF; } @@ -96,10 +96,10 @@ static void __chTreasurehunt_spawnRedXForNextStep(void) { Actor *actor; ActorLocal_TreasureHunt *local; - actor = actor_spawnWithYaw_f32(ACTOR_55_RED_X, sChTreasurehunt_stepPositions[CH_TREASUREHUNT_PUZZLE_CURRENT_STEP], 0); + actor = actor_spawnWithYaw_f32(ACTOR_55_RED_X, sChTreasurehunt_stepPositions[chtreasureHunt_puzzleCurrentStep], 0); local = (ActorLocal_TreasureHunt *)&actor->local; - actor->yaw = sChTreasurehunt_StepRedXYaws[CH_TREASUREHUNT_PUZZLE_CURRENT_STEP]; - local->unk0 = CH_TREASUREHUNT_PUZZLE_CURRENT_STEP; + actor->yaw = sChTreasurehunt_StepRedXYaws[chtreasureHunt_puzzleCurrentStep]; + local->unk0 = chtreasureHunt_puzzleCurrentStep; actor->lifetime_value = 0.0f; actor->state = 0; } @@ -108,25 +108,25 @@ static void __chTreasurehunt_spawnActorForNextStep(void) { Actor *actor; ActorLocal_TreasureHunt *local; - actor = actor_spawnWithYaw_f32((sChTreasurehunt_StepActors - 1)[CH_TREASUREHUNT_PUZZLE_CURRENT_STEP], sChTreasurehunt_stepPositions[CH_TREASUREHUNT_PUZZLE_CURRENT_STEP - 1], 0); + actor = actor_spawnWithYaw_f32((sChTreasurehunt_StepActors - 1)[chtreasureHunt_puzzleCurrentStep], sChTreasurehunt_stepPositions[chtreasureHunt_puzzleCurrentStep - 1], 0); local = (ActorLocal_TreasureHunt *)&actor->local; - actor->yaw = sChTreasurehunt_StepYaws[CH_TREASUREHUNT_PUZZLE_CURRENT_STEP - 1]; - local->unk0 = CH_TREASUREHUNT_PUZZLE_CURRENT_STEP; + actor->yaw = sChTreasurehunt_StepYaws[chtreasureHunt_puzzleCurrentStep - 1]; + local->unk0 = chtreasureHunt_puzzleCurrentStep; actor->lifetime_value = 0.0f; actor->state = 0; } static void __chTreasurehunt_checkStepProgress(s32 currentStep){ - if(CH_TREASUREHUNT_PUZZLE_CURRENT_STEP == currentStep && __chTreasurehunt_isActiveHitboxBeakBusterHitbox()){ + if(chtreasureHunt_puzzleCurrentStep == currentStep && __chTreasurehunt_isActiveHitboxBeakBusterHitbox()){ if(currentStep == 0 && !jiggyscore_isCollected(JIGGY_11_TTC_RED_X)){ - gcdialog_showDialog(ASSET_A18_DIALOG_TREASUREHUNT_FOLLOW_CLUES, 4, NULL, NULL, NULL, NULL); + gcdialog_showDialog(VER_SELECT(ASSET_A18_DIALOG_TREASUREHUNT_FOLLOW_CLUES, 0x918, 0, 0), 4, NULL, NULL, NULL, NULL); } else if(currentStep == 4){ - gcdialog_showDialog(ASSET_A19_DIALOG_TREASUREHUNT_SECOND_STEP, 4, NULL, NULL, NULL, NULL); + gcdialog_showDialog(VER_SELECT(ASSET_A19_DIALOG_TREASUREHUNT_SECOND_STEP, 0x919, 0, 0), 4, NULL, NULL, NULL, NULL); } - CH_TREASUREHUNT_PUZZLE_CURRENT_STEP++; - port_puzzleStep_orBits(ANCHOR_PUZZLE_TTC_XHUNT, (1 << CH_TREASUREHUNT_PUZZLE_CURRENT_STEP) - 1); + chtreasureHunt_puzzleCurrentStep++; + port_puzzleStep_orBits(ANCHOR_PUZZLE_TTC_XHUNT, (1 << chtreasureHunt_puzzleCurrentStep) - 1); __spawnQueue_add_0(__chTreasurehunt_spawnActorForNextStep); __spawnQueue_add_0(__chTreasurehunt_spawnRedXForNextStep); } @@ -156,7 +156,7 @@ void chTreasurehunt_checkStepProgress5(NodeProp *this, ActorMarker *arg1){ static ParticleEmitter *particleEmitter; static f32 particleTargetPosition[3]; - if(CH_TREASUREHUNT_PUZZLE_CURRENT_STEP == 5 && __chTreasurehunt_isActiveHitboxBeakBusterHitbox()){ + if(chtreasureHunt_puzzleCurrentStep == 5 && __chTreasurehunt_isActiveHitboxBeakBusterHitbox()){ particleTargetPosition[0] = (f32)this->x; particleTargetPosition[1] = (f32)this->y; particleTargetPosition[2] = (f32)this->z; @@ -174,14 +174,14 @@ void chTreasurehunt_checkStepProgress5(NodeProp *this, ActorMarker *arg1){ gcpausemenu_80314AC8(0); timedFunc_set_2(0.1f, (GenFunction_2) func_8028F45C, 9, (uintptr_t)&particleTargetPosition); timedFunc_set_1(0.1f, (GenFunction_1) gcpausemenu_80314AC8, 1); - gcdialog_showDialog(ASSET_A17_DIALOG_BURIED_TREASURE_SPAWNED, 4, NULL, NULL, NULL, NULL); - CH_TREASUREHUNT_PUZZLE_CURRENT_STEP++; + gcdialog_showDialog(VER_SELECT(ASSET_A17_DIALOG_BURIED_TREASURE_SPAWNED, 0x917, 0, 0), 4, NULL, NULL, NULL, NULL); + chtreasureHunt_puzzleCurrentStep++; port_puzzleStep_orBits(ANCHOR_PUZZLE_TTC_XHUNT, 0x3F); } } void chTreasurehunt_resetProgress(void){ - CH_TREASUREHUNT_PUZZLE_CURRENT_STEP = 0; + chtreasureHunt_puzzleCurrentStep = 0; } // Anchor: replay teammates' hunt steps, one per frame; called each frame in TTC (PuzzleStep.cpp). @@ -194,17 +194,17 @@ void chTreasurehunt_netTick(void){ sharedStep++; bits >>= 1; } - if((s32)CH_TREASUREHUNT_PUZZLE_CURRENT_STEP >= sharedStep){ + if((s32)chtreasureHunt_puzzleCurrentStep >= sharedStep){ return; } - if(CH_TREASUREHUNT_PUZZLE_CURRENT_STEP < 5){ - CH_TREASUREHUNT_PUZZLE_CURRENT_STEP++; + if(chtreasureHunt_puzzleCurrentStep < 5){ + chtreasureHunt_puzzleCurrentStep++; __spawnQueue_add_0(__chTreasurehunt_spawnActorForNextStep); __spawnQueue_add_0(__chTreasurehunt_spawnRedXForNextStep); } else{ - CH_TREASUREHUNT_PUZZLE_CURRENT_STEP++; + chtreasureHunt_puzzleCurrentStep++; if(!jiggyscore_isSpawned(JIGGY_11_TTC_RED_X) && !jiggyscore_isCollected(JIGGY_11_TTC_RED_X)){ sNetTreasurePosition[0] = sChTreasurehunt_stepPositions[5][0]; sNetTreasurePosition[1] = sChTreasurehunt_stepPositions[5][1]; @@ -237,7 +237,7 @@ static void __chTreasurehunt_updateFunc(Actor *this){ } break; case 1: - if(local->unk0 < CH_TREASUREHUNT_PUZZLE_CURRENT_STEP){ + if(local->unk0 < chtreasureHunt_puzzleCurrentStep){ this->state = 2; } break; diff --git a/src/TTC/checksums.c b/src/TTC/checksums.c new file mode 100644 index 000000000..d920d19ab --- /dev/null +++ b/src/TTC/checksums.c @@ -0,0 +1,7 @@ +// BanjoDecomp: TTC/checksums.c +#include +#include "checksums.h" + +// !! THIS FILE MUST BE LINKED FIRST FOR THIS OVERLAY !! + +/* bss */ struct overlay_checksums_s gChecksumsTTC; diff --git a/src/TTC/crc.c b/src/TTC/crc.c index 9ee04e8bb..74fbbf619 100644 --- a/src/TTC/crc.c +++ b/src/TTC/crc.c @@ -2,24 +2,11 @@ #include #include "functions.h" #include "variables.h" +#include "checksums.h" -extern s32 D_80276CB0; - -/* .data */ -// code crc0 -s32 D_8038C750 = 0x0016D2FD; -// code crc1 -s32 D_8038C754 = 0xFB70B01D; -// data crc -s32 D_8038C758 = 0x0004EFAC; - -/* .bss */ -struct { - u8 pad0[4]; - s32 unk4; - u8 pad8[4]; - s32 unkC; -} sD_8038D6F0; +s32 D_8038C750 = VER_SELECT(0x0016D2FD, 0x0016D2D7, 0, 0); // TTC_TEXT_CRC1 +s32 D_8038C754 = VER_SELECT(0xFB70B01D, 0xFCA4DD1E, 0, 0); // TTC_TEXT_CRC2 +s32 D_8038C758 = VER_SELECT(0x0004EFAC, 0x0004FD17, 0, 0); // TTC_DATA_CRC1 /* .code */ void __code3040_makeBanjoAlwaysSlippery(){ @@ -31,7 +18,7 @@ void __code3040_makeBanjoAlwaysSlippery(){ void code3040_checkTTCChecksums(void){ // [port] This crc check makes the ground in TTC slippery #if ANTI_TAMPER - if(sD_8038D6F0.unk4 != D_8038C754 || sD_8038D6F0.unkC != D_80276CB0){ + if(gChecksumsTTC.text_checksum2 != D_8038C754 || gChecksumsTTC.data_checksum2 != D_80276CB0){ __code3040_makeBanjoAlwaysSlippery(); } #endif diff --git a/src/TTC/castle.c b/src/TTC/ma/castle.c similarity index 98% rename from src/TTC/castle.c rename to src/TTC/ma/castle.c index 13902c4df..11e5c35cb 100644 --- a/src/TTC/castle.c +++ b/src/TTC/ma/castle.c @@ -170,12 +170,12 @@ static void __maCastle_setupCheatCodeTimer(s32 new_timer_state) if (volatileFlag_get(VOLATILE_FLAG_2_FF_IN_MINIGAME)) { // set timer to 50 seconds - item_set(ITEM_0_HOURGLASS_TIMER, 2999); + item_set(ITEM_0_HOURGLASS_TIMER, VER_SELECT(2999, 2499, 0, 0)); } else { // set timer to 100 seconds - item_set(ITEM_0_HOURGLASS_TIMER, 5999); + item_set(ITEM_0_HOURGLASS_TIMER, VER_SELECT(5999, 4999, 0, 0)); } item_set(ITEM_6_HOURGLASS, true); @@ -332,11 +332,11 @@ static u32 __maCastle_cheatoCodeUnlocked(s32 cheato_code_index) static void __maCastle_setVolatileFlags(u32 arg0) { int i; - volatileFlag_setAndTriggerDialog_0(VOLATILE_FLAG_C2_NOBONUS_TEXT); + progressDialog_setAndTriggerDialog_0(VOLATILE_FLAG_C2_NOBONUS_TEXT); // wish washy banjo cheat code if (arg0 & 0x400) { - volatileFlag_setAndTriggerDialog_E(VOLATILE_FLAG_C5_WISHYWASHYBANJO_TEXT); + progressDialog_setAndTriggerDialog_E(VOLATILE_FLAG_C5_WISHYWASHYBANJO_TEXT); } volatileFlag_set(VOLATILE_FLAG_78_SANDCASTLE_NO_BONUS, 0); for (i = 4; i < 11; i++) @@ -623,7 +623,7 @@ void maCastle_update(void) } if ((sMapState.banjoKazooieCodeEnteredState == 0) || (sMapState.banjoKazooieCodeEnteredState == 3)) { - if ((levelSpecificFlags_get(LEVEL_FLAG_2_TTC_UNKNOWN) || volatileFlag_get(VOLATILE_FLAG_3)) && (player_getActiveHitbox(0) == HITBOX_1_BEAK_BUSTER) && func_8028F20C()) + if ((levelSpecificFlags_get(LEVEL_FLAG_2_TTC_UNKNOWN) || volatileFlag_get(VOLATILE_FLAG_3)) && (player_getActiveHitbox(0) == HITBOX_1_BEAK_BUSTER) && player_isStableWithExtraSteps()) { mesh_id_closest_to_player = model_func_8033F3C0(sMapState.model1, player_position); if (mesh_id_closest_to_player != 0) @@ -1038,7 +1038,7 @@ static void __maCastle_eraseGameplayDialogCallback(ActorMarker *caller, enum ass { __maCastle_setNumberOfBannedCheatcodesEntered(3); __maCastle_checkSecretCheatCodeIndex(sThirdForbiddenSecretCheatCodeIndex); - gcdialog_showDialog(ASSET_FBF_DIALOG_ERASED_SAVE, 0xC, NULL, NULL, NULL, NULL); + gcdialog_showDialog(VER_SELECT(ASSET_FBF_DIALOG_ERASED_SAVE, 0xB25, 0, 0), 0xC, NULL, NULL, NULL, NULL); gameFile_clear(gameSelect_getGameNumber()); gameFile_8033CFD4(gameSelect_getGameNumber()); gameSelect_setGameNumber(-1); @@ -1073,11 +1073,11 @@ static void __maCastle_checkIfBannedCheatCodeEntered(s32 secret_cheat_code_index __maCastle_setNumberOfBannedCheatcodesEntered(2); __maCastle_checkSecretCheatCodeIndex(secret_cheat_code_index); __maCastle_resetSecretCheatCodeProgress(); - gcdialog_showDialog(ASSET_FBE_DIALOG_CHEATING_ERASE_SAVE_WARNING, 0xC, NULL, NULL, NULL, NULL); + gcdialog_showDialog(VER_SELECT(ASSET_FBE_DIALOG_CHEATING_ERASE_SAVE_WARNING, 0xB24, 0, 0), 0xC, NULL, NULL, NULL, NULL); return; case 2: sThirdForbiddenSecretCheatCodeIndex = secret_cheat_code_index; - gcdialog_showDialog(ASSET_E38_DIALOG_CHEATING_ERASE_SAVE_CONFIRMATION, 0xC, NULL, NULL, __maCastle_eraseGameplayDialogCallback, NULL); + gcdialog_showDialog(VER_SELECT(ASSET_E38_DIALOG_CHEATING_ERASE_SAVE_CONFIRMATION, 0xA7A, 0, 0), 0xC, NULL, NULL, __maCastle_eraseGameplayDialogCallback, NULL); return; } return; diff --git a/src/boot/bk_boot_1050.c b/src/boot/bk_boot_1050.c index 837606bb7..d2e5b21af 100644 --- a/src/boot/bk_boot_1050.c +++ b/src/boot/bk_boot_1050.c @@ -2,6 +2,7 @@ #include "boot/overlaytable.h" #include "boot/rarezip.h" #include "core1/main.h" +#include "checksums.h" #define ENTRY_STACK_LEN 0x2000 @@ -9,7 +10,6 @@ u8 gEntryStack[ENTRY_STACK_LEN]; extern u8 gHeapBase[]; extern u8 core1_VRAM[]; -extern u32 gCore1CRCs[4]; /// @brief Entry point of the game /// @param arg0 unused/unknown parameter @@ -34,12 +34,12 @@ void func_80000450(s32 arg0) { rarezip_init(); rarezip_uncompress_file_and_update_pointers(&in, &out); - gCore1CRCs[0] = inflate_crc1; - gCore1CRCs[1] = inflate_crc2; + gChecksumsCore1.text_checksum1 = inflate_crc1; + gChecksumsCore1.text_checksum2 = inflate_crc2; rarezip_uncompress_file_and_update_pointers(&in, &out); - gCore1CRCs[2] = inflate_crc1; - gCore1CRCs[3] = inflate_crc2; + gChecksumsCore1.data_checksum1 = inflate_crc1; + gChecksumsCore1.data_checksum2 = inflate_crc2; overlaytable_init(); diff --git a/src/core1/audio_instruments.c b/src/core1/audio_instruments.c index 5712a9080..b7830b253 100644 --- a/src/core1/audio_instruments.c +++ b/src/core1/audio_instruments.c @@ -17,11 +17,6 @@ extern void func_8025F570(ALCSPlayer *, u8); extern void func_8025F510(ALCSPlayer *, u8, u8); extern void func_8025F5C0(ALCSPlayer *, u8); -extern OSIoMesg *func_802405D0(void); -extern OSMesgQueue *func_802405C4(void); -extern ALHeap *func_802405B8(void); -extern void func_8023FA64(ALSeqpConfig *arg0); - extern u8 *soundfont2ctl_ROM_START; extern u8 *soundfont2ctl_ROM_END; extern u8 *soundfont2tbl_ROM_START; @@ -258,11 +253,11 @@ void musicInstruments_init(void){ D_802820E8.maxVoices = 0x18; D_802820E8.maxEvents = 0x55; D_802820E8.maxChannels = 0x10; - D_802820E8.heap = func_802405B8(); + D_802820E8.heap = audioManager_getALHeapInfo(); D_802820E8.initOsc = NULL; D_802820E8.updateOsc = NULL; D_802820E8.stopOsc = NULL; - func_8023FA64(&D_802820E8); + audioManager_setupSeqp(&D_802820E8); for(i = 0; i < 6; i++){ n_alCSPNew((N_ALCSPlayer *)&D_80281720[i].cseqp, &D_802820E8); } @@ -516,14 +511,14 @@ s32 gcMusic_getDefaultVolumeForTrack(s32 track_id){ return 0; } -void func_80250048(s32 track_id, u16 arg1){ +void gcMusic_setDefaultVolumeForTrack(s32 track_id, u16 arg1){ if (track_id >= 0 && track_id < 0xB0) { D_80275D40[track_id].volume = arg1; } } //song_getName -char *func_80250060(s32 track_id){ +char *gcMusic_getNameForTrack(s32 track_id){ if (track_id >= 0 && track_id < 0xB0) { return D_80275D40[track_id].name; } diff --git a/src/core1/audio_manager.c b/src/core1/audio_manager.c index 711a203b1..62ff19f63 100644 --- a/src/core1/audio_manager.c +++ b/src/core1/audio_manager.c @@ -9,6 +9,8 @@ //#include "PR/os_system.h" #include "port/ShipUtils.h" +#define DMA_BLOCK_SIZE VER_SELECT(0x200, 0x270, 0x200, 0x200) + // [port] BK audio - SDK calls stubbed, functions preserved for game code // [port] 64-bit structs with pointers are larger — double the heap @@ -17,70 +19,58 @@ #else #define AUDIO_HEAP_SIZE VER_SELECT(0x21000, 0x23A00, 0x21000, 0x21000) #endif -#define AUDIOMANAGER_THREAD_STACK_SIZE 0xE78 - -extern void n_alInit(N_ALGlobals *, ALSynConfig *); - +#define AUDIOMANAGER_THREAD_STACK_SIZE 3704 +#define NUM_SAMPLES 184 // n_audio has fixed sample count of 184 +#define NUM_OSC_STATES 48 +#define NUM_AUDIO_CMDS_PER_SECOND 150000 + +struct audio_info_mesg_data_s { + s16 unk0; + struct audio_info_s *audio_info_ptr; +}; -typedef struct AudioInfo_s { - short *data; /* Output data pointer */ - short frameSamples; /* # of samples synthesized in this frame */ - u8 pad4[2]; - s16 unk8; - u8 padA[2]; - struct AudioInfo_s *unkC; +typedef struct audio_info_s { + s16 *data; /* Output data pointer */ + s16 frame_samples; /* number of samples synthesized in this frame */ + struct audio_info_mesg_data_s reply_mesg_data; } AudioInfo; -typedef struct Struct_1D00_1_s{ - void *unk0; - u8 pad4[4]; - s16 unk8; - u8 pada[2]; - struct Struct_1D00_1_s *unkC; -} Struct_1D00_1; - -typedef struct { - u8 pad0[4]; - AudioInfo *unk4; -} Struct_1D00_2; - -typedef struct Struct_1D00_3_s{ - ALLink unk0; - uintptr_t unk8; +struct dma_state_data_s { + ALLink link; + uintptr_t unk8; // device address uintptr_t unkC; - uintptr_t unk10; -} Struct_1D00_3; + uintptr_t heap; +}; typedef struct{ u8 pad0[0x18]; }Struct_core1_1D00_4; -typedef struct struct_core1_1D00_5_s{ - struct struct_core1_1D00_5_s * next; +typedef struct osc_state_s { + struct osc_state_s *next; u8 type; - // u8 pad5[1]; - u16 unk6; - u16 unk8; - union{ - struct{u8 unk0; u8 unk1;}type1; - struct{f32 unk0;}type80; - }unkC; -}OscState; + u16 unk6; // current value + u16 unk8; // max value + union { + struct { u8 unk0; u8 unk1; } type1; + struct { f32 cents; } type80; + } unkC; +} OscState; void audioManager_create(void); void audioManagerThread_entry(void *arg); -// void func_802403B8(void); void audioManager_handleDoneMsg(AudioInfo *info); -void *func_802403B8(void *state); -void func_802403F0(void); +ALDMAproc audioManager_DMAInitProc(void *state); +void audioManager_func_802403F0(void); void audioManager_startThread(void); bool audioManager_handleFrameMsg(AudioInfo *info, AudioInfo *prev_info); s32 D_80275770 = 0; -s32 D_80275774 = 0; +bool sAudioManagerThreadStarted = false; u8 D_80275778 = 0; -s32 D_8027577C[] = { + +s32 sEffectsChain[] = { 6, /* number of sections in this effect */ 0x1900, /* total allocated memory */ /* SECTION 1 */ @@ -139,57 +129,47 @@ s32 D_8027577C[] = { 0x4500 /* low-pass filter */ }; -Struct_1D00_2 *D_80275844 = NULL; -AudioInfo *D_80275848 = NULL; -// extern int D_8027584C;//static int D_8027584C = 0; - -extern s32 osViClock; //0x80277128 +struct audio_info_mesg_data_s *D_80275844 = NULL; +AudioInfo *sPrevFinishedAudioInfo = NULL; -extern f32 D_80277620; -extern f64 D_80277628; -extern f64 D_80277630; -extern f32 D_80277638; +extern s32 osViClock; struct { - Acmd* ACMDList[2]; - AudioInfo *audioInfo[3]; + Acmd *ACMDList[2]; + AudioInfo *audio_info[3]; OSThread thread; OSMesgQueue audioFrameMsgQ; OSMesg audioFrameMsgBuf[8]; OSMesgQueue audioReplyMsgQ; OSMesg audioReplyMsgBuf[8]; + u8 thread_stack[AUDIOMANAGER_THREAD_STACK_SIZE]; } audioManager; -u8 sAudioManagerThreadStack[AUDIOMANAGER_THREAD_STACK_SIZE]; -ALHeap D_8027CFF0; -u8 * D_8027D000; -s32 D_8027D004; -OSMesgQueue D_8027D008; -OSMesg D_8027D020[3000/FRAMERATE]; -OSIoMesg D_8027D0E8; -Struct_core1_1D00_4 D_8027D100[3000/FRAMERATE]; +ALHeap sALHeapInfo; +u8 *sALHeapBuffer; +s32 pad_8027D004; +OSMesgQueue audioDMANotifyMsgQ; +OSMesg audioDMANotifyMsgBuf[3000 / FRAMERATE]; +OSIoMesg sExtraDMAMesg; +Struct_core1_1D00_4 sDMAMesgBlocks[3000 / FRAMERATE]; struct { - u8 unk0; - Struct_1D00_3 *unk4; - Struct_1D00_3 *unk8; - u8 padC[0x4]; -} D_8027D5B0; -Struct_1D00_3 D_8027D5C0[90]; -s32 D_8027DCC8; -s32 D_8027DCCC; -s32 D_8027DCD0; -N_ALGlobals D_8027DCD8; -ALSynConfig D_8027DD50; -s32 D_8027DD74; -s32 D_8027DD78; -s32 D_8027DD7C; -s32 D_8027DD80; + u8 initialized; + struct dma_state_data_s *unk4; + struct dma_state_data_s *unk8; +} sDMAState; +struct dma_state_data_s sDMAStateData[90]; +s32 sAudioInfoID; +s32 sNumDMATransfers; // DMA IO Message blocks index +s32 sCmdBufferIndex; +N_ALGlobals sn_alGlobals; +ALSynConfig sn_alConfig; +s32 sFrameSize; +s32 sMinFrameSize; +s32 sMaxFrameSize; +s32 sNumAudioCmdsPerFrame; OscState *freeOscStateList; -OscState oscStates[48]; - +OscState oscStates[NUM_OSC_STATES]; -/* .code */ -f32 _depth2Cents(u8 depth) -{ +f32 depth2Cents(u8 depth) { f32 x = 1.03099298f; f32 cents = 1.0f; @@ -205,8 +185,7 @@ f32 _depth2Cents(u8 depth) return cents; } -ALMicroTime initOsc(void **oscState, f32 *initVal, u8 oscType, u8 oscRate, u8 oscDepth, u8 oscDelay, u8 arg6) -{ +ALMicroTime initOsc(void **oscState, f32 *initVal, u8 oscType, u8 oscRate, u8 oscDepth, u8 oscDelay) { OscState *state; ALMicroTime result = 0; @@ -218,97 +197,99 @@ ALMicroTime initOsc(void **oscState, f32 *initVal, u8 oscType, u8 oscRate, u8 os result = oscDelay << 14; switch (oscType) { - case 1: - state->unk8 = 0; - state->unk6 = 259 - oscRate; - state->unkC.type1.unk0 = oscDepth >> 1; - state->unkC.type1.unk1 = 127 - state->unkC.type1.unk0; - *initVal = state->unkC.type1.unk1; - break; - case 0x80: - state->unkC.type80.unk0 = _depth2Cents(oscDepth); - state->unk8 = 0; - state->unk6 = 259 - oscRate; - *initVal = 1.0f; - break; - default: - break; + case 1: + state->unk8 = 0; + state->unk6 = 259 - oscRate; + state->unkC.type1.unk0 = oscDepth >> 1; + state->unkC.type1.unk1 = 127 - state->unkC.type1.unk0; + *initVal = state->unkC.type1.unk1; + break; + + case 0x80: + state->unkC.type80.cents = depth2Cents(oscDepth); + state->unk8 = 0; + state->unk6 = 259 - oscRate; + *initVal = 1.0f; + break; + + default: + break; } } return result; } -ALMicroTime updateOsc(void *oscState, f32 *updateVal) -{ +ALMicroTime updateOsc(void *oscState, f32 *updateVal) { f32 sp2c; OscState *state = oscState; ALMicroTime result = AL_USEC_PER_FRAME; switch (state->type) { - case 0x01: - state->unk8++; + case 0x01: + state->unk8++; - if (state->unk8 >= state->unk6) { - state->unk8 = 0; - } + if (state->unk8 >= state->unk6) { + state->unk8 = 0; + } - sp2c = (f32)state->unk8 / (f32)state->unk6; - sp2c = sinf(sp2c * BAD_TAU); - sp2c = sp2c * state->unkC.type1.unk0; - *updateVal = state->unkC.type1.unk1 + sp2c; - break; + sp2c = (f32)state->unk8 / (f32)state->unk6; + sp2c = sinf(sp2c * BAD_TAU); + sp2c = sp2c * state->unkC.type1.unk0; + *updateVal = state->unkC.type1.unk1 + sp2c; + break; - case 0x80: - state->unk8++; + case 0x80: + state->unk8++; - if (state->unk8 >= state->unk6) { - state->unk8 = 0; - } + if (state->unk8 >= state->unk6) { + state->unk8 = 0; + } - sp2c = (f32)state->unk8 / (f32)state->unk6; - sp2c = sinf(sp2c * BAD_TAU) * state->unkC.type80.unk0; - *updateVal = alCents2Ratio(sp2c); - break; - default: - break; + sp2c = (f32)state->unk8 / (f32)state->unk6; + sp2c = sinf(sp2c * BAD_TAU) * state->unkC.type80.cents; + *updateVal = alCents2Ratio(sp2c); + break; + default: + break; } return result; } -void stopOsc(OscState *oscState){ +void stopOsc(OscState *oscState) { oscState->next = freeOscStateList; freeOscStateList = oscState; } -void func_8023FA64(ALSeqpConfig *arg0) { +void audioManager_setupSeqp(ALSeqpConfig *config) { OscState *item; - s32 i; + int i; - freeOscStateList = &oscStates[0]; + freeOscStateList = &oscStates[0]; item = &oscStates[0]; - for(i = 0; i< 0x2F; i++){ - item->next = &oscStates[i+1]; + for (i = 0; i < NUM_OSC_STATES - 1; i++) { + item->next = &oscStates[i + 1]; item = item->next; } item->next = NULL; - arg0->initOsc = initOsc; - arg0->updateOsc = updateOsc; - arg0->stopOsc = stopOsc; + + config->initOsc = initOsc; + config->updateOsc = updateOsc; + config->stopOsc = stopOsc; } extern s32 osTvType; -void audioManager_init(void){ - D_8027D000 = (u8 *) bk_malloc(AUDIO_HEAP_SIZE); - bzero(D_8027D000, AUDIO_HEAP_SIZE); - alHeapInit(&D_8027CFF0, D_8027D000, AUDIO_HEAP_SIZE); +void audioManager_init(void) { + sALHeapBuffer = (u8 *) bk_malloc(AUDIO_HEAP_SIZE); + bzero(sALHeapBuffer, AUDIO_HEAP_SIZE); + alHeapInit(&sALHeapInfo, sALHeapBuffer, AUDIO_HEAP_SIZE); #if VERSION == VERSION_USA_1_0 - if(osTvType != OS_TV_NTSC) - osViClock = 0x2e6025c; + if (osTvType != OS_TV_NTSC) + osViClock = VI_MPAL_CLOCK; #elif VERSION == VERSION_PAL - osViClock = 0x2f5b2d2; + osViClock = VI_PAL_CLOCK; #endif audioManager_create(); sfxInstruments_init(); @@ -318,351 +299,317 @@ void audioManager_init(void){ void audioManager_create(void) { int i; - f32 var_f0; + f32 fsize; - osCreateMesgQueue(&D_8027D008, D_8027D020, 3000/FRAMERATE); - osCreateMesgQueue(&audioManager.audioReplyMsgQ, audioManager.audioReplyMsgBuf, 8); //audioReplyMesgQueue + osCreateMesgQueue(&audioDMANotifyMsgQ, audioDMANotifyMsgBuf, 3000 / FRAMERATE); + osCreateMesgQueue(&audioManager.audioReplyMsgQ, audioManager.audioReplyMsgBuf, 8); osCreateMesgQueue(&audioManager.audioFrameMsgQ, audioManager.audioFrameMsgBuf, 8); - var_f0 = 44000.0f/FRAMERATE; - D_8027DD74 = (s32)var_f0; - if ((f32) D_8027DD74 < var_f0) { - D_8027DD74++; + + fsize = 44000.0f / FRAMERATE; + sFrameSize = fsize; + if (sFrameSize < fsize) { + sFrameSize++; } - D_8027DD74 = ((D_8027DD74 / 0xB8) * 0xB8) + 0xB8; - D_8027DD78 = D_8027DD74 - 0xB8; - D_8027DD7C = D_8027DD74; - D_8027DD50.maxVVoices = 0x18; - D_8027DD50.maxPVoices = 0x18; - D_8027DD50.maxUpdates = 0x100; // [port] doubled — 64-bit param slots are larger, demand-based audio may call n_alAudioFrame multiple times per game frame - D_8027DD50.dmaproc = (void*)func_802403B8; - D_8027DD50.fxType = AL_FX_CUSTOM; - D_8027DD50.params = (void*) &D_8027577C; - D_8027DD50.heap = &D_8027CFF0; - D_8027DD50.outputRate = osAiSetFrequency(22000); - n_alInit(&D_8027DCD8, &D_8027DD50); - D_8027D5C0[0].unk0.prev = NULL; - D_8027D5C0[0].unk0.next = NULL; - for(i = 0; i < 89; i++){ - alLink((ALLink *)&D_8027D5C0[i+1], (ALLink *)&D_8027D5C0[i]); - D_8027D5C0[i].unk10 = (uintptr_t)alHeapDBAlloc(0, 0, D_8027DD50.heap, 1, VER_SELECT(0x200, 0x270, 0x200, 0x200)); + sFrameSize = ((sFrameSize / NUM_SAMPLES) + 1) * NUM_SAMPLES; + sMinFrameSize = sFrameSize - NUM_SAMPLES; + sMaxFrameSize = sFrameSize; + + sn_alConfig.maxVVoices = 24; + sn_alConfig.maxPVoices = 24; + sn_alConfig.maxUpdates = 0x100; // [port] doubled — 64-bit param slots are larger, demand-based audio may call n_alAudioFrame multiple times per game frame + sn_alConfig.dmaproc = (void *) audioManager_DMAInitProc; + sn_alConfig.fxType = AL_FX_CUSTOM; + sn_alConfig.params = sEffectsChain; + sn_alConfig.heap = &sALHeapInfo; + sn_alConfig.outputRate = osAiSetFrequency(22000); + n_alInit(&sn_alGlobals, &sn_alConfig); + + sDMAStateData[0].link.prev = NULL; + sDMAStateData[0].link.next = NULL; + + for (i = 0; i < 89; i++) { + alLink(&sDMAStateData[i + 1].link, &sDMAStateData[i].link); + sDMAStateData[i].heap = (uintptr_t)alHeapDBAlloc(0, 0, sn_alConfig.heap, 1, DMA_BLOCK_SIZE); } - D_8027D5C0[i].unk10 = (uintptr_t)alHeapDBAlloc(0, 0, D_8027DD50.heap, 1, VER_SELECT(0x200, 0x270, 0x200, 0x200)); - for(i = 0; i < 2; i++){ - audioManager.ACMDList[i] = bk_malloc(1200000/FRAMERATE); + + sDMAStateData[i].heap = (uintptr_t)alHeapDBAlloc(0, 0, sn_alConfig.heap, 1, DMA_BLOCK_SIZE); + + for (i = 0; i < 2; i++) { + audioManager.ACMDList[i] = bk_malloc(NUM_AUDIO_CMDS_PER_SECOND * sizeof(Acmd) / FRAMERATE); } - D_8027DD80 = 150000/FRAMERATE; - for(i = 0; i < 3; i++){ - audioManager.audioInfo[i] = alHeapDBAlloc(0, 0, D_8027DD50.heap, 1, 0x10); - audioManager.audioInfo[i]->unk8 = 0; - audioManager.audioInfo[i]->unkC = audioManager.audioInfo[i]; - audioManager.audioInfo[i]->data = bk_malloc(D_8027DD7C * 4); + sNumAudioCmdsPerFrame = NUM_AUDIO_CMDS_PER_SECOND / FRAMERATE; + + for (i = 0; i < 3; i++) { + audioManager.audio_info[i] = alHeapDBAlloc(0, 0, sn_alConfig.heap, 1, sizeof(AudioInfo)); + audioManager.audio_info[i]->reply_mesg_data.unk0 = 0; + audioManager.audio_info[i]->reply_mesg_data.audio_info_ptr = audioManager.audio_info[i]; + audioManager.audio_info[i]->data = bk_malloc(4 * sMaxFrameSize); } - osCreateThread(&audioManager.thread, 4, &audioManagerThread_entry, 0, sAudioManagerThreadStack + AUDIOMANAGER_THREAD_STACK_SIZE, 50); + osCreateThread(&audioManager.thread, 4, &audioManagerThread_entry, 0, audioManager.thread_stack + AUDIOMANAGER_THREAD_STACK_SIZE, 50); } void audioManagerThread_entry(void *arg) { - s32 phi_s1; + s32 skip_handle_done_mesg = 1; - phi_s1 = 1; - while(1){ + while (true) { osRecvMesg(&audioManager.audioFrameMsgQ, NULL, OS_MESG_BLOCK); - if (audioManager_handleFrameMsg(audioManager.audioInfo[D_8027DCC8 % 3], D_80275848)){ - if(phi_s1 == 0){ - osRecvMesg(&audioManager.audioReplyMsgQ, (OSMesg *)&D_80275844, OS_MESG_BLOCK); - audioManager_handleDoneMsg(D_80275844->unk4); - D_80275848 = D_80275844->unk4; - }else{ - phi_s1 += -1; + if (audioManager_handleFrameMsg(audioManager.audio_info[sAudioInfoID % 3], sPrevFinishedAudioInfo)) { + if (skip_handle_done_mesg == 0) { + osRecvMesg(&audioManager.audioReplyMsgQ, (OSMesg *) &D_80275844, OS_MESG_BLOCK); + audioManager_handleDoneMsg(D_80275844->audio_info_ptr); + sPrevFinishedAudioInfo = D_80275844->audio_info_ptr; + } else { + skip_handle_done_mesg--; } } } } -void func_8023FFAC(void){ - D_80275770 = osAiGetLength()/4; +void audioManager_func_8023FFAC(void) { + D_80275770 = osAiGetLength() / 4; } -void func_8023FFD4(s32 arg0, s32 arg1, s32 arg2){ - return; -} +void audioManager_func_8023FFD4(s32 arg0, s32 arg1, s32 arg2) {} bool audioManager_handleFrameMsg(AudioInfo *info, AudioInfo *prev_info){ s16 *outbuffer; - Acmd *sp38; - s32 sp34; + Acmd *command_list_end; + s32 command_list_len; + s32 ret; + f32 pad; + #if VERSION == VERSION_USA_1_0 - s32 sp30 = 0; -#else - s32 sp30; + ret = 0; #endif - f32 pad; - outbuffer = (s16 *)osVirtualToPhysical(info->data); - func_802403F0(); - func_8023FFAC(); - if(prev_info){ - sp30 = osAiSetNextBuffer(prev_info->data, prev_info->frameSamples*4); - }//L8024003C + outbuffer = (s16 *) osVirtualToPhysical(info->data); + audioManager_func_802403F0(); + audioManager_func_8023FFAC(); + if (prev_info) { + ret = osAiSetNextBuffer(prev_info->data, 4 * prev_info->frame_samples); + } #if VERSION == VERSION_USA_1_0 - if(sp30 == -1){ - func_80247F24(2, 0x7d2); - func_80247F9C(prev_info->frameSamples); - func_80247F9C(info->frameSamples); + if (ret == -1) { + gcdebugText_showLargeValue(2, 2002); + func_80247F9C(prev_info->frame_samples); + func_80247F9C(info->frame_samples); gcdebugText_pauseThread(); - } + } #endif - if((D_80275770 >= 0x139) & !D_80275778){ - info->frameSamples = D_8027DD78; + if ((D_80275770 > 312) & !D_80275778) { + info->frame_samples = sMinFrameSize; D_80275778 = 2; - } - else{ - info->frameSamples = D_8027DD74; - if(D_80275778) + } else { + info->frame_samples = sFrameSize; + if (D_80275778) D_80275778--; } - if(info->frameSamples < D_8027DD78){ - info->frameSamples = D_8027DD78; + if (info->frame_samples < sMinFrameSize) { + info->frame_samples = sMinFrameSize; } - sp38 = n_alAudioFrame(audioManager.ACMDList[D_8027DCD0], &sp34, outbuffer, info->frameSamples); + command_list_end = n_alAudioFrame(audioManager.ACMDList[sCmdBufferIndex], &command_list_len, outbuffer, info->frame_samples); #if VERSION == VERSION_USA_1_0 - if(D_8027DD80 < sp34){ - func_80247F24(2, 2000); - func_80247F9C(sp34); - func_80247F9C(D_8027DD80); + if (sNumAudioCmdsPerFrame < command_list_len) { + gcdebugText_showLargeValue(2, 2000); + func_80247F9C(command_list_len); + func_80247F9C(sNumAudioCmdsPerFrame); gcdebugText_pauseThread(); } #endif - if(sp34 == 0){ - return 0; - }else{ - core1_15B30_addAudioTaskData((Gfx **)audioManager.ACMDList[D_8027DCD0], (Gfx **)sp38, &audioManager.audioReplyMsgQ, &info->unk8); + if (command_list_len == 0) { + return false; + } else { + core1_15B30_addAudioTaskData(audioManager.ACMDList[sCmdBufferIndex], command_list_end, &audioManager.audioReplyMsgQ, OS_MESG_PTR(&info->reply_mesg_data)); // [port] OSMesg is a union on PC func_80250650(); - D_8027DCD0 ^= 1; - return 1; + sCmdBufferIndex ^= 1; + return true; } } -void audioManager_handleDoneMsg(AudioInfo *info) -{ - static int D_8027584C = true; - if (osAiGetLength() >> 2 == 0 && D_8027584C == false) { - D_8027584C = false; +void audioManager_handleDoneMsg(AudioInfo *info) { + static bool debug_var = true; + + if ((osAiGetLength() / 4) == 0 && (!debug_var)) { + debug_var = false; } } -#if VERSION == VERSION_USA_1_0 -uintptr_t func_80240204(uintptr_t addr, s32 len, void *state) -{ - void *sp44; - uintptr_t sp40; - Struct_1D00_3 *phi_s0; - Struct_1D00_3 *phi_v0; - uintptr_t new_var; - Struct_1D00_3 *sp30; - - phi_s0 = D_8027D5B0.unk4; +uintptr_t func_80240204(uintptr_t addr, s32 len, void *state) { // [port] pointer-width for 64-bit ALDMAproc + void *dest_vaddr; + uintptr_t dev_addr_low_bit; + uintptr_t dev_addr_end; + struct dma_state_data_s *phi_s0, *phi_v0, *sp30; + +#if VERSION == VERSION_PAL + phi_v0 = sDMAState.unk4; +#endif sp30 = NULL; - while (phi_s0 != NULL ) { - new_var = (phi_s0->unk8 + 0x200); - if ((phi_s0->unk8 > addr)) break; - sp30 = phi_s0; - if ((addr + len) <= new_var) { - phi_s0->unkC = (uintptr_t) D_8027DCC8; - return osVirtualToPhysical((void*)(phi_s0->unk10 + (addr - phi_s0->unk8))); - } - phi_s0 = (Struct_1D00_3 *)phi_s0->unk0.next; +#if VERSION == VERSION_USA_1_0 + for (phi_s0 = sDMAState.unk4; phi_s0 != NULL; phi_s0 = (struct dma_state_data_s *) phi_s0->link.next) { +#elif VERSION == VERSION_PAL + for (phi_s0 = phi_v0; phi_s0 != NULL; phi_s0 = (struct dma_state_data_s *) phi_s0->link.next) { +#endif + dev_addr_end = phi_s0->unk8 + DMA_BLOCK_SIZE; - } - phi_s0 = D_8027D5B0.unk8; - if (phi_s0 == NULL) { - func_80247F24(2, 0x7D1); - gcdebugText_pauseThread(); - return osVirtualToPhysical(D_8027D5B0.unk4); - } - D_8027D5B0.unk8 = (Struct_1D00_3 *)phi_s0->unk0.next; - alUnlink((ALLink *)phi_s0); - if (sp30 != NULL) { - alLink((ALLink *)phi_s0, (ALLink *)sp30); - } else { - phi_v0 = D_8027D5B0.unk4; - if (phi_v0 != NULL) { - D_8027D5B0.unk4 = phi_s0; - phi_s0->unk0.next = (ALLink *)phi_v0; - phi_s0->unk0.prev = NULL; - phi_v0->unk0.prev = (ALLink *)phi_s0; - } else { - D_8027D5B0.unk4 = phi_s0; - phi_s0->unk0.next = NULL; - phi_s0->unk0.prev = NULL; + if (phi_s0->unk8 > addr) { + break; } - } - sp44 = (void*)phi_s0->unk10; - sp40 = addr & 1; - addr -= sp40; - phi_s0->unk8 = addr; - phi_s0->unkC = (uintptr_t) D_8027DCC8; - osPiStartDma((OSIoMesg *)&D_8027D100[D_8027DCCC++], 1, 0, addr, sp44, 0x200U, &D_8027D008); - return osVirtualToPhysical(sp44) + sp40; -} -#elif VERSION == VERSION_PAL -#ifndef NONMATCHING -uintptr_t func_80240204(uintptr_t addr, s32 len, void *state); -#pragma GLOBAL_ASM("asm/nonmatchings/core1/code_1D00/func_80240204.s") -#else -uintptr_t func_80240204(uintptr_t addr, s32 len, void *state){ - void *sp44; - uintptr_t sp40; - Struct_1D00_3 *phi_s0; - Struct_1D00_3 *phi_v0; - uintptr_t new_var; - Struct_1D00_3 *sp30; - - phi_v0 = D_8027D5B0.unk4; - sp30 = NULL; - for(phi_s0 = phi_v0; phi_s0 != NULL; phi_s0 = (Struct_1D00_3 *)phi_s0->unk0.next) { - sp40 = (phi_s0->unk8 + 0x270); - if ((phi_s0->unk8 > addr)) break; sp30 = phi_s0; - if ((addr + len) <= sp40) { - phi_s0->unkC = (uintptr_t) D_8027DCC8; - return osVirtualToPhysical((void*)(phi_s0->unk10 + (addr - phi_s0->unk8))); + + if ((addr + len) <= dev_addr_end) { + phi_s0->unkC = sAudioInfoID; +#if VERSION == VERSION_USA_1_0 + return osVirtualToPhysical((u8 *) phi_s0->heap + (addr - phi_s0->unk8)); +#elif VERSION == VERSION_PAL + dev_addr_low_bit = (s32) (u8 *) phi_s0->heap + (addr - phi_s0->unk8); + return osVirtualToPhysical((void *) dev_addr_low_bit); +#endif } } - phi_s0 = D_8027D5B0.unk8; + + phi_s0 = sDMAState.unk8; if (phi_s0 == NULL) { +#if VERSION == VERSION_USA_1_0 + gcdebugText_showLargeValue(2, 2001); + gcdebugText_pauseThread(); + return osVirtualToPhysical(sDMAState.unk4); +#elif VERSION == VERSION_PAL return osVirtualToPhysical(phi_v0); +#endif } - D_8027D5B0.unk8 = (Struct_1D00_3 *)phi_s0->unk0.next; - alUnlink((ALLink *)phi_s0); + + sDMAState.unk8 = (struct dma_state_data_s *) phi_s0->link.next; + alUnlink((ALLink *) phi_s0); + if (sp30 != NULL) { - alLink((ALLink *)phi_s0, (ALLink *)sp30); + alLink((ALLink *) phi_s0, (ALLink *) sp30); } else { - phi_v0 = D_8027D5B0.unk4; + phi_v0 = sDMAState.unk4; if (phi_v0 != NULL) { - D_8027D5B0.unk4 = phi_s0; - phi_s0->unk0.next = (ALLink *)phi_v0; - phi_s0->unk0.prev = NULL; - phi_v0->unk0.prev = (ALLink *)phi_s0; + sDMAState.unk4 = phi_s0; + phi_s0->link.next = (ALLink *) phi_v0; + phi_s0->link.prev = NULL; + phi_v0->link.prev = (ALLink *) phi_s0; } else { - D_8027D5B0.unk4 = phi_s0; - phi_s0->unk0.next = NULL; - phi_s0->unk0.prev = NULL; + sDMAState.unk4 = phi_s0; + phi_s0->link.next = NULL; + phi_s0->link.prev = NULL; } } - new_var = addr & 1; - addr = addr - new_var; + dest_vaddr = (void *) phi_s0->heap; + dev_addr_low_bit = addr & 1; + addr -= dev_addr_low_bit; phi_s0->unk8 = addr; - phi_s0->unkC = (uintptr_t) D_8027DCC8; - sp44 = (void*)phi_s0->unk10; - osPiStartDma((OSIoMesg *)&D_8027D100[D_8027DCCC++], 1, 0, phi_s0->unk8, (void*)phi_s0->unk10, 0x270U, &D_8027D008); - return osVirtualToPhysical(sp44) + new_var; + phi_s0->unkC = (uintptr_t) sAudioInfoID; + osPiStartDma((OSIoMesg *)&sDMAMesgBlocks[sNumDMATransfers++], OS_MESG_PRI_HIGH, OS_READ, addr, dest_vaddr, DMA_BLOCK_SIZE, &audioDMANotifyMsgQ); + return osVirtualToPhysical(dest_vaddr) + dev_addr_low_bit; } -#endif -#endif -void *func_802403B8(void *state) { - if (D_8027D5B0.unk0 == 0) { - D_8027D5B0.unk4 = NULL; - D_8027D5B0.unk8 = &D_8027D5C0[0]; - D_8027D5B0.unk0 = 1; +ALDMAproc audioManager_DMAInitProc(void *state) { + if (!sDMAState.initialized) { + sDMAState.unk4 = NULL; + sDMAState.unk8 = sDMAStateData; + sDMAState.initialized = true; } - *(void **)state = &D_8027D5B0; - return &func_80240204; + *(void **)state = (void *) &sDMAState; + return func_80240204; } -void func_802403F0(void) { - u32 phi_s0; - OSMesg sp40; - Struct_1D00_3 *phi_s1; - Struct_1D00_3 *phi_s0_2; - - sp40.ptr = NULL; - for(phi_s0 = 0; phi_s0 < D_8027DCCC; phi_s0++){ +void audioManager_func_802403F0(void) { + u32 i; + OSMesg temp_mesg; + struct dma_state_data_s *phi_s1; + struct dma_state_data_s *phi_s0_2; + temp_mesg.ptr = NULL; + for (i = 0; i < sNumDMATransfers; i++) { #if VERSION == VERSION_USA_1_0 - if (osRecvMesg(&D_8027D008, &sp40, 0) == -1) { + if (osRecvMesg(&audioDMANotifyMsgQ, &temp_mesg, OS_MESG_NOBLOCK) == -1) { #if 0 // [port] DMA is synchronous on PC (memcpy), no completion messages to drain - func_80247F24(2, 0x7D5); - func_80247F9C(D_8027DCCC); - func_80247F9C(phi_s0); + gcdebugText_showLargeValue(2, 2005); + func_80247F9C(sNumDMATransfers); + func_80247F9C(i); gcdebugText_pauseThread(); #else break; #endif } #else - osRecvMesg(&D_8027D008, &sp40, 0); + osRecvMesg(&audioDMANotifyMsgQ, &temp_mesg, OS_MESG_NOBLOCK); #endif } - phi_s0_2 = D_8027D5B0.unk4; - while(phi_s0_2 != NULL){ - phi_s1 = (Struct_1D00_3 *)phi_s0_2->unk0.next; - if (phi_s0_2->unkC + 1 < D_8027DCC8) { - if (phi_s0_2 == D_8027D5B0.unk4) { - D_8027D5B0.unk4 = (Struct_1D00_3 *)phi_s0_2->unk0.next; + + phi_s0_2 = sDMAState.unk4; + + while (phi_s0_2 != NULL) { + phi_s1 = (struct dma_state_data_s *) phi_s0_2->link.next; + if (phi_s0_2->unkC + 1 < sAudioInfoID) { + if (phi_s0_2 == sDMAState.unk4) { + sDMAState.unk4 = (struct dma_state_data_s *)phi_s0_2->link.next; } - alUnlink((ALLink *)phi_s0_2); - if (D_8027D5B0.unk8 != NULL) { - alLink(&phi_s0_2->unk0, &D_8027D5B0.unk8->unk0); + alUnlink(&phi_s0_2->link); + if (sDMAState.unk8 != NULL) { + alLink(&phi_s0_2->link, &sDMAState.unk8->link); } else { - D_8027D5B0.unk8 = phi_s0_2; - phi_s0_2->unk0.next = NULL; - phi_s0_2->unk0.prev = NULL; + sDMAState.unk8 = phi_s0_2; + phi_s0_2->link.next = NULL; + phi_s0_2->link.prev = NULL; } } phi_s0_2 = phi_s1; } - D_8027DCCC = 0; - D_8027DCC8 += 1; + + sNumDMATransfers = 0; + sAudioInfoID++; } #if VERSION == VERSION_PAL -void *audioManager_getThread_PAL(void){ +OSThread *audioManager_getThread_PAL(void) { return &audioManager.thread; } #endif -void audioManager_stopThread(void){ - if(D_80275774){ - D_80275774 = 0; +void audioManager_stopThread(void) { + if (sAudioManagerThreadStarted) { + sAudioManagerThreadStarted = false; osStopThread(&audioManager.thread); } } -void audioManager_startThread(void){ - if(D_80275774 == 0){ - D_80275774 = 1; +void audioManager_startThread(void) { + if (!sAudioManagerThreadStarted) { + sAudioManagerThreadStarted = true; port_audioStartThread(); } } -OSThread * audioManager_getThread(void){ +OSThread *audioManager_getThread(void) { return &audioManager.thread; } -ALHeap * func_802405B8(void){ - return &D_8027CFF0; +ALHeap *audioManager_getALHeapInfo(void) { + return &sALHeapInfo; } -OSMesgQueue * func_802405C4(void){ - return &D_8027D008; +OSMesgQueue *audioManager_getDMANotifyMesgQueue(void) { + return &audioDMANotifyMsgQ; } -OSIoMesg * func_802405D0(void){ - return &D_8027D0E8; +OSIoMesg *audioManager_getExtraDMAMesg(void) { + return &sExtraDMAMesg; } -OSMesgQueue * audioManager_getFrameMesgQueue(void){ +OSMesgQueue *audioManager_getFrameMesgQueue(void) { return &audioManager.audioFrameMsgQ; } diff --git a/src/core1/io/bamotor.c b/src/core1/bamotor.c similarity index 100% rename from src/core1/io/bamotor.c rename to src/core1/bamotor.c diff --git a/src/core1/debugtext.c b/src/core1/debugtext.c index 5babb3b1c..36a329bc1 100644 --- a/src/core1/debugtext.c +++ b/src/core1/debugtext.c @@ -253,7 +253,7 @@ void func_80247D80(s32 arg0, s32 arg1, s32 arg2) { } } -void func_80247F24(s32 arg0, s32 arg1) { +void gcdebugText_showLargeValue(s32 arg0, s32 arg1) { D_80275BD0 = 0; D_80275BCC = arg0; D_80275BBC = 0xE; diff --git a/src/core1/defragmanager.c b/src/core1/defragmanager.c index 85585d207..3aa61c63c 100644 --- a/src/core1/defragmanager.c +++ b/src/core1/defragmanager.c @@ -28,13 +28,13 @@ void defragManager_free(void){ osDestroyThread(&sDefragThread); } -void defragManager_80240874(void){ +void defragManager_resume(void){ if(func_8023E000() == 3){ osSendMesgPtr(&sDefragThreadResumeSyncQueue, NULL, OS_MESG_BLOCK); } } -void defragManager_802408B0(void){ +void defragManager_pause(void){ if(func_8023E000() == 3){ osSendMesgPtr(&sDefragThreadPauseSyncQueue, NULL, OS_MESG_BLOCK); } diff --git a/src/core1/depthbuffer.c b/src/core1/depthbuffer.c index dc2db7807..2fc2381a5 100644 --- a/src/core1/depthbuffer.c +++ b/src/core1/depthbuffer.c @@ -7,67 +7,69 @@ #include struct { - void *data; - int unk4; + u16 *data; + bool unk4; } sDepthBuffer; -void func_80253190(Gfx **gfx) { - func_80253208(gfx, 0, 0, gFramebufferWidth, gFramebufferHeight, gFramebuffers[getActiveFramebuffer()]); +void depthbuffer_clear(Gfx **gfx) { + depthbuffer_clearRegion(gfx, 0, 0, gFramebufferWidth, gFramebufferHeight, gFramebuffers[getActiveFramebuffer()]); } -void func_80253208(Gfx **gfx, s32 x, s32 y, s32 w, s32 h, void *color_buffer){ - if( sDepthBuffer.data != NULL && (getGameMode() != GAME_MODE_4_PAUSED || gsworld_getEnableDraw())){ - //draw z_buffer +void depthbuffer_clearRegion(Gfx **gfx, s32 x, s32 y, s32 w, s32 h, void *color_buffer) { + if ((sDepthBuffer.data != NULL) && ((getGameMode() != GAME_MODE_4_PAUSED) || gsworld_getEnableDraw())) { gDPPipeSync((*gfx)++); gDPSetColorImage((*gfx)++, G_IM_FMT_RGBA, G_IM_SIZ_16b, gFramebufferWidth, OS_K0_TO_PHYSICAL(sDepthBuffer.data)); gDPSetCycleType((*gfx)++, G_CYC_FILL); gDPSetRenderMode((*gfx)++, G_RM_NOOP, G_RM_NOOP2); - gDPSetFillColor((*gfx)++, 0xFFFCFFFC); + gDPSetFillColor((*gfx)++, (GPACK_ZDZ(G_MAXFBZ, 0) << 16) | GPACK_ZDZ(G_MAXFBZ, 0)); gDPScisFillRectangle((*gfx)++, x, y, x + w - 1, y + h - 1); - - //draw color_buffer + gDPPipeSync((*gfx)++); gDPSetColorImage((*gfx)++, G_IM_FMT_RGBA, G_IM_SIZ_16b, gFramebufferWidth, OS_K0_TO_PHYSICAL(color_buffer)); } } -int func_80253400(void){ +bool depthbuffer_getUnk4(void) { return sDepthBuffer.unk4; } -bool depthBuffer_isPointerSet(void) { +bool depthbuffer_isDataPtrSet(void) { return sDepthBuffer.data != NULL; } -void depthBuffer_stub(void) {} +void depthbuffer_stub(void) {} -void func_80253428(int arg0) { +void depthbuffer_enable(bool enable) { u16 *var_v0; - int new_var; - if (arg0) { - var_v0 = (sDepthBuffer.data = &D_8000E800); - while (((uintptr_t) sDepthBuffer.data) % 0x40) { - var_v0 = (sDepthBuffer.data = var_v0 + 1); + + if (enable) { + sDepthBuffer.data = (u16 *) D_8000E800; + + var_v0 = sDepthBuffer.data; + while (((uintptr_t) sDepthBuffer.data) % 64) { // [port] pointer-width + sDepthBuffer.data = var_v0 + 1; + var_v0 = sDepthBuffer.data; } - (void)&D_8000E800; // decomp match - }else{ + do { } while ((D_8000E800 && 1) * 0); //remove this + } else { sDepthBuffer.data = NULL; } - sDepthBuffer.unk4 = false; + + sDepthBuffer.unk4 = FALSE; } -void func_802534A8(int arg0) { - sDepthBuffer.unk4 = (sDepthBuffer.data != NULL && arg0); +void depthbuffer_setUnk4(bool value) { + sDepthBuffer.unk4 = sDepthBuffer.data && value; } -void zBuffer_set(Gfx **gfx) { +void depthbuffer_set(Gfx **gfx) { if (sDepthBuffer.data && getGameMode() != GAME_MODE_4_PAUSED) { gDPPipeSync((*gfx)++); gDPSetDepthImage((*gfx)++, sDepthBuffer.data); } } -void *zBuffer_get(void) { +void *depthbuffer_getDataPtr(void) { return sDepthBuffer.data; } diff --git a/src/core1/display_list.c b/src/core1/display_list.c index 07bcd6cf1..fcf24b490 100644 --- a/src/core1/display_list.c +++ b/src/core1/display_list.c @@ -21,7 +21,7 @@ static s32 sStackSelector; #define MTX_STACK_COUNT 2100 #define VTX_STACK_COUNT 1290 -s32 gTextureFilterPoint; +bool sUseTexturePointFilter; struct ucode_task_data_s sUcodeTaskData[20]; s32 sCurrentUcodeTaskDataID; OSMesgQueue sTaskDataListLockMesgQueue; @@ -30,7 +30,7 @@ u16 gScissorBoxLeft; u16 gScissorBoxRight; u16 gScissorBoxTop; u16 gScissorBoxBottom; -Gfx *D_80283214; +Gfx *D_80283214; // never used void core1_15B30_requestLockForTaskDataID(void) { osRecvMesg(&sTaskDataListLockMesgQueue, NULL, OS_MESG_BLOCK); @@ -40,7 +40,7 @@ void core1_15B30_requestReleaseForTaskDataID(void) { osSendMesgPtr(&sTaskDataListLockMesgQueue, NULL, OS_MESG_BLOCK); } -void core1_15B30_addAudioTaskData(Gfx **arg0, Gfx **arg1, void *arg2, void *arg3) { +void core1_15B30_addAudioTaskData(Acmd *arg0, Acmd *arg1, OSMesgQueue *arg2, OSMesg arg3) { struct ucode_task_data_s *task_data; core1_15B30_requestLockForTaskDataID(); @@ -50,39 +50,38 @@ void core1_15B30_addAudioTaskData(Gfx **arg0, Gfx **arg1, void *arg2, void *arg3 task_data->task_type = UCODE_TASK_TYPE_AUDIO; task_data->data_ptr = arg0; task_data->data_ptr_end = arg1; - task_data->unk10 = arg2; - task_data->unk14 = (s32)(intptr_t)arg3; + task_data->audio_mesg_queue = arg2; + task_data->audio_mesg = arg3; thread5_sendTaskToQueue(OS_MESG_PTR(task_data)); } - -void func_80253640(Gfx ** gdl, void *arg1){ - D_80283214 = *gdl; - gSPSegment((*gdl)++, 0x00, 0x00000000); - gDPSetRenderMode((*gdl)++, G_RM_NOOP, G_RM_NOOP2); - gSPClearGeometryMode((*gdl)++, G_ZBUFFER | G_SHADE | G_CULL_BOTH | G_FOG | G_LIGHTING | G_TEXTURE_GEN | G_TEXTURE_GEN_LINEAR | G_LOD | G_SHADING_SMOOTH); - gDPPipeSync((*gdl)++); - gDPPipelineMode((*gdl)++, G_PM_NPRIMITIVE); - gDPSetAlphaCompare((*gdl)++, G_AC_NONE); - gDPSetColorDither((*gdl)++, G_CD_MAGICSQ); - gDPSetScissor((*gdl)++, G_SC_NON_INTERLACE, gScissorBoxLeft, gScissorBoxRight, gScissorBoxTop, gScissorBoxBottom); - func_80253208(gdl, 0, 0, gFramebufferWidth, gFramebufferHeight, arg1); - gDPSetColorImage((*gdl)++, G_IM_FMT_RGBA, G_IM_SIZ_16b, gFramebufferWidth, OS_K0_TO_PHYSICAL(arg1)); - gDPSetCycleType((*gdl)++, G_CYC_1CYCLE); - gDPSetTextureConvert((*gdl)++, G_TC_FILT); - gDPSetTextureDetail((*gdl)++, G_TD_CLAMP); - if(gTextureFilterPoint){ - gDPSetTextureFilter((*gdl)++, G_TF_POINT); +void setupFramebuffer(Gfx **gfx, void *color_buffer) { + D_80283214 = *gfx; + gSPSegment((*gfx)++, 0x00, 0x00000000); + gDPSetRenderMode((*gfx)++, G_RM_NOOP, G_RM_NOOP2); + gSPClearGeometryMode((*gfx)++, G_ZBUFFER | G_SHADE | G_CULL_BOTH | G_FOG | G_LIGHTING | G_TEXTURE_GEN | G_TEXTURE_GEN_LINEAR | G_LOD | G_SHADING_SMOOTH); + gDPPipeSync((*gfx)++); + gDPPipelineMode((*gfx)++, G_PM_NPRIMITIVE); + gDPSetAlphaCompare((*gfx)++, G_AC_NONE); + gDPSetColorDither((*gfx)++, G_CD_MAGICSQ); + gDPSetScissor((*gfx)++, G_SC_NON_INTERLACE, gScissorBoxLeft, gScissorBoxRight, gScissorBoxTop, gScissorBoxBottom); + depthbuffer_clearRegion(gfx, 0, 0, gFramebufferWidth, gFramebufferHeight, color_buffer); + gDPSetColorImage((*gfx)++, G_IM_FMT_RGBA, G_IM_SIZ_16b, gFramebufferWidth, OS_K0_TO_PHYSICAL(color_buffer)); + gDPSetCycleType((*gfx)++, G_CYC_1CYCLE); + gDPSetTextureConvert((*gfx)++, G_TC_FILT); + gDPSetTextureDetail((*gfx)++, G_TD_CLAMP); + if (sUseTexturePointFilter) { + gDPSetTextureFilter((*gfx)++, G_TF_POINT); }else{ - gDPSetTextureFilter((*gdl)++, G_TF_BILERP); + gDPSetTextureFilter((*gfx)++, G_TF_BILERP); } - gDPSetTextureLOD((*gdl)++, G_TL_TILE); - gDPSetTextureLUT((*gdl)++, G_TT_NONE); - gDPSetTexturePersp((*gdl)++, G_TP_PERSP); - zBuffer_set(gdl); + gDPSetTextureLOD((*gfx)++, G_TL_TILE); + gDPSetTextureLUT((*gfx)++, G_TT_NONE); + gDPSetTexturePersp((*gfx)++, G_TP_PERSP); + depthbuffer_set(gfx); } -void scissorBox_SetForGameMode(Gfx **gdl, s32 framebuffer_idx) { +void setupFramebufferForGamemode(Gfx **gdl, s32 framebuffer_idx) { if(getGameMode() == GAME_MODE_8_BOTTLES_BONUS || getGameMode() == GAME_MODE_A_SNS_PICTURE) { // [port] Redirect rendering to GPU-side aux FB via gsSPSetFB. @@ -92,18 +91,18 @@ void scissorBox_SetForGameMode(Gfx **gdl, s32 framebuffer_idx) { if (auxFb >= 0) { gsSPSetFB((*gdl)++, auxFb); } - scissorBox_setSmall(); - func_80253640(gdl, func_8030C704()); + picturebox_setScissorBox(); + setupFramebuffer(gdl, picturebox_getColorBuffer()); } else{ scissorBox_setDefault(); - func_80253640(gdl, gFramebuffers[framebuffer_idx]); + setupFramebuffer(gdl, gFramebuffers[framebuffer_idx]); } } -void setupScissorBoxAndFramebuffer(Gfx **gfx, uintptr_t framebuffer_address){ +void setupScissorBoxAndFramebuffer(Gfx **gfx, void *color_buffer) { gSPSegment((*gfx)++, 0x00, 0x00000000); - gDPSetColorImage((*gfx)++, G_IM_FMT_RGBA, G_IM_SIZ_16b, gFramebufferWidth, OS_PHYSICAL_TO_K0(framebuffer_address)); + gDPSetColorImage((*gfx)++, G_IM_FMT_RGBA, G_IM_SIZ_16b, gFramebufferWidth, OS_PHYSICAL_TO_K0(color_buffer)); gSPClearGeometryMode((*gfx)++, G_ZBUFFER | G_SHADE | G_CULL_BOTH | G_FOG | G_LIGHTING | G_TEXTURE_GEN | G_TEXTURE_GEN_LINEAR | G_LOD | G_SHADING_SMOOTH); gSPTexture((*gfx)++, 0, 0, 0, G_TX_RENDERTILE, G_OFF); gSPSetGeometryMode((*gfx)++, G_ZBUFFER | G_SHADE | G_SHADING_SMOOTH); @@ -120,7 +119,7 @@ void setupScissorBoxAndFramebuffer(Gfx **gfx, uintptr_t framebuffer_address){ void setupDefaultScissorBoxAndFramebuffer(Gfx **gfx, s32 framebuffer_idx){ scissorBox_setDefault(); - setupScissorBoxAndFramebuffer(gfx, (uintptr_t)gFramebuffers[framebuffer_idx]); + setupScissorBoxAndFramebuffer(gfx, gFramebuffers[framebuffer_idx]); } void core1_15B30_finishDList_renderThread(Gfx **gfx) { @@ -198,13 +197,13 @@ void core1_15B30_init(void) { scissorBox_setDefault(); } -void drawRectangle2D(Gfx **gfx, s32 x, s32 y, s32 w, s32 h, s32 r, s32 g, s32 b){ +void drawRectangle2D(Gfx **gfx, s32 x, s32 y, s32 w, s32 h, s32 r, s32 g, s32 b) { gDPPipeSync((*gfx)++); gDPPipelineMode((*gfx)++, G_PM_NPRIMITIVE); gDPSetCycleType((*gfx)++, G_CYC_FILL); gDPSetFillColor((*gfx)++, GPACK_RGBA5551(r, g, b, 1) << 16 | GPACK_RGBA5551(r, g, b, 1)); gDPSetRenderMode((*gfx)++, G_RM_NOOP, G_RM_NOOP2); - gDPScisFillRectangle((*gfx)++, x, y, x + w -1, y + h -1); + gDPScisFillRectangle((*gfx)++, x, y, x + w - 1, y + h - 1); } void graphicsCache_release(void) { @@ -219,8 +218,16 @@ void graphicsCache_release(void) { } } -void graphicsCache_init(void){ - if(sGfxStack[0] == NULL){ +void graphicsCache_init(void) { + if (sGfxStack[0] == NULL) { +#if 0 + sGfxStack[0] = (Gfx *)malloc(29600); // 3700 dlist commands + sGfxStack[1] = (Gfx *)malloc(29600); + sMtxStack[0] = (Mtx *)malloc(44800); // 700 matrices + sMtxStack[1] = (Mtx *)malloc(44800); + sVtxStack[0] = (Vtx *)malloc(6880); // 430 vertices + sVtxStack[1] = (Vtx *)malloc(6880); +#endif sGfxStack[0] = (Gfx *)GameEngine_Malloc(GFX_STACK_COUNT * sizeof(Gfx)); sGfxStack[1] = (Gfx *)GameEngine_Malloc(GFX_STACK_COUNT * sizeof(Gfx)); sMtxStack[0] = (Mtx *)GameEngine_Malloc(MTX_STACK_COUNT * sizeof(Mtx)); @@ -229,15 +236,13 @@ void graphicsCache_init(void){ sVtxStack[1] = (Vtx *)GameEngine_Malloc(VTX_STACK_COUNT * sizeof(Vtx)); dummy_func_80254464(); } + + sStackSelector = 0; - gTextureFilterPoint = 0; + sUseTexturePointFilter = FALSE; } -// [port] Verify the frame's dlist emission fit within the static stack -// capacities. If it didn't, we've already written past the buffer and -// corrupted the heap, but logging it loudly (instead of silently deferring -// to a CRT debug-heap break at the next malloc/free) makes the root cause -// obvious. Mirrors Shipwright's THGA_IsCrash() canary pattern. +// [port] Verify the frame's dlist emission fit within the static stack capacities. void graphicsCache_checkFrame(Gfx *gfxStart, Gfx *gfxEnd, Mtx *mtxStart, Mtx *mtxEnd, Vtx *vtxStart, Vtx *vtxEnd) { s32 gfxUsed = (s32)(gfxEnd - gfxStart); s32 mtxUsed = (s32)(mtxEnd - mtxStart); @@ -280,12 +285,11 @@ void core1_15B30_addTask7TaskData(s32 framebuffer_id) { thread5_sendTaskToQueue(OS_MESG_PTR(task_data)); } -void toggleTextureFilterPoint(void){ - u32 ret_val = gTextureFilterPoint; - gTextureFilterPoint = ret_val < 1; +void core1_15B30_toggleTexturePointFilter(void) { + sUseTexturePointFilter = !sUseTexturePointFilter; } -void getGraphicsStacks(Gfx **gfx, Mtx **mtx, Vtx **vtx){ +void graphicscache_swapAndGetStacks(Gfx **gfx, Mtx **mtx, Vtx **vtx) { sStackSelector = (1 - sStackSelector); *gfx = sGfxStack[sStackSelector]; *mtx = sMtxStack[sStackSelector]; diff --git a/src/core1/graphics_thread.c b/src/core1/graphics_thread.c index 3c6de06b4..a164333cc 100644 --- a/src/core1/graphics_thread.c +++ b/src/core1/graphics_thread.c @@ -1,4 +1,4 @@ -// BanjoDecomp: thread5 (osCreateThread OSId 5) +// BanjoDecomp: core1/code_8C50.c // Needs to be included here because interrupt.h contains: // typedef u32 OSIntMask; and u32 isn't defined before that. diff --git a/src/core1/math/ml.c b/src/core1/gu_matrix.c similarity index 99% rename from src/core1/math/ml.c rename to src/core1/gu_matrix.c index 79eec3915..acf6c05fd 100644 --- a/src/core1/math/ml.c +++ b/src/core1/gu_matrix.c @@ -1,4 +1,4 @@ -// BanjoDecomp: ml.c +// BanjoDecomp: core1/code_3250.c #include "core1/core1.h" #include #include diff --git a/src/core1/math/mlmtx.c b/src/core1/gu_perspective.c similarity index 93% rename from src/core1/math/mlmtx.c rename to src/core1/gu_perspective.c index b04304b3c..d17f00c60 100644 --- a/src/core1/math/mlmtx.c +++ b/src/core1/gu_perspective.c @@ -1,4 +1,4 @@ -// BanjoDecomp: mlmtx.c +// BanjoDecomp: core1/code_7F60.c #include #include #include "core1/core1.h" @@ -8,11 +8,12 @@ static void _guMtxIdentF(float mf[4][4]); -#if VERSION == VERSION_USA_1_0 -u8 D_80275900[8] = {0xCF, 0xAD, 0xA2, 0x90, 0x93, 0x4A, 0x83, 0xF1}; -#elif VERSION == VERSION_PAL -u8 D_80275900[8] = {0xD3, 0x9E, 0xA6, 0x20, 0xC7, 0x7E, 0xD5, 0xC6}; -#endif +s32 D_802758F0 = VER_SELECT(0xAD7FF2F3, 0xB585BADA, 0, 0); // BGS_DATA_CRC2 +s32 D_802758F4 = VER_SELECT(0xD884D8AC, 0xD731B7E2, 0, 0); // FP_DATA_CRC2 +s32 D_802758F8 = 0; +s32 D_802758FC = 0; +s32 D_80275900 = VER_SELECT(0xCFADA290, 0xD39EA620, 0, 0); // LAIR_DATA_CRC2 +s32 D_80275904 = VER_SELECT(0x934A83F1, 0xC77ED5C6, 0, 0); // GV_DATA_CRC2 f32 D_80275908 = BAD_DTOR; diff --git a/src/core1/init.c b/src/core1/init.c index f2cc2687f..01dbbf464 100644 --- a/src/core1/init.c +++ b/src/core1/init.c @@ -9,18 +9,16 @@ #define MAIN_THREAD_STACK_SIZE 0x17F0 -extern void audioManager_init(void); - #if VERSION == VERSION_PAL extern s32 D_80000300; #endif s32 D_80275610 = 0; s32 D_80275614 = 0; -u32 gGlobalTimer = 0; +s32 gGlobalTimer = 0; u32 sDebugVar_8027561C[] = { 0x9, 0x4, 0xA, 0x3, 0xB, 0x2, 0xC, 0x5, 0x0, 0x1, 0x6, 0xD, -1 }; // never used -u32 D_80275650 = VER_SELECT(0xAD019D3C, 0xA371A8F3, 0, 0); //SM_DATA_CRC_1 -u32 D_80275654 = VER_SELECT(0xD381B72F, 0xD0709154, 0, 0); //SM_DATA_CRC_2 +s32 D_80275650 = VER_SELECT(0xAD019D3C, 0xA371A8F3, 0, 0); //SM_DATA_CRC2 +s32 D_80275654 = VER_SELECT(0xD381B72F, 0xD0709154, 0, 0); //MM_DATA_CRC2 char sDebugVar_80275658[] = VER_SELECT("HjunkDire:218755", "HjunkDire:300875", "HjunkDire:", "HjunkDire:"); /* .bss */ @@ -72,7 +70,7 @@ void func_8023DA9C(s32 arg0){ ucode_stub1(); } -u32 globalTimer_getTimeMasked(u32 mask){ +s32 globalTimer_getTimeMasked(s32 mask) { return gGlobalTimer & mask; } @@ -160,7 +158,7 @@ void mainLoop(void){ // [port] Don't need this #if 0 if(!mapSpecificFlags_validateCRC1()){ - eeprom_writeBlocks(0, 0, 0x80397AD0, 0x40); + eeprom_writeBlocks(0, 0, (void *) PHYS_TO_K0(0x00397AD0), EEPROM_MAXBLOCKS); } #endif @@ -173,7 +171,7 @@ void mainLoop(void){ func_80255ACC(); spawnQueue_func_802C3A18(); if(func_802E4424()) - game_draw(0); + game_draw(FALSE); spawnQueue_flush(); break; }//L8023DE34 @@ -194,7 +192,7 @@ void mainLoop(void){ //render weird CRC failure image for(y= 0x1e; y < gFramebufferHeight - 0x1e; y++){//L8023DEB4 for(x = 0x14; x < 0xeb; x++){ - tmp = ((8 * globalTimer_getTime()) + ((x*x) + (y*y))); + tmp = ((globalTimer_getTime() << 3) + x * x + y * y); r = _SHIFTL(x>>3, 11, 5); g = _SHIFTL(y>>3, 6, 5); diff --git a/src/core1/math/longlong_arith.c b/src/core1/math/longlong_arith.c deleted file mode 100644 index a3cff6547..000000000 --- a/src/core1/math/longlong_arith.c +++ /dev/null @@ -1,63 +0,0 @@ -// BanjoDecomp: (unknown decomp origin) -/* MSVC provides these as compiler intrinsics, so only define them for other compilers */ -#ifndef _MSC_VER - -unsigned long long __ull_rshift(unsigned long long a0, unsigned long long a1) -{ - return a0 >> a1; -} - -unsigned long long __ll_lshift(unsigned long long a0, unsigned long long a1) -{ - return a0 << a1; -} - -long long __ll_rshift(long long a0, long long a1) -{ - return a0 >> a1; -} - -#endif /* _MSC_VER */ - -/* These are not MSVC intrinsics, so define them for all compilers */ -unsigned long long __ull_rem(unsigned long long a0, unsigned long long a1) -{ - return a0 % a1; -} - -unsigned long long __ull_div(unsigned long long a0, unsigned long long a1) -{ - return a0 / a1; -} - -long long __ll_rem(unsigned long long a0, long long a1) -{ - return a0 % a1; -} - -long long __ll_div(long long a0, long long a1) -{ - return a0 / a1; -} - -unsigned long long __ll_mul(unsigned long long a0, unsigned long long a1) -{ - return a0 * a1; -} - -void __ull_divremi(unsigned long long *div, unsigned long long *rem, unsigned long long a2, unsigned short a3) -{ - *div = a2 / a3; - *rem = a2 % a3; -} - -long long __ll_mod(long long a0, long long a1) -{ - long long tmp = a0 % a1; - if ((tmp < 0 && a1 > 0) || (tmp > 0 && a1 < 0)) - { - - tmp += a1; - } - return tmp; -} diff --git a/src/core1/math/longlong_convert.c b/src/core1/math/longlong_convert.c deleted file mode 100644 index 8fe014dbe..000000000 --- a/src/core1/math/longlong_convert.c +++ /dev/null @@ -1,40 +0,0 @@ -// BanjoDecomp: (unknown decomp origin) -long long __d_to_ll(double a0) -{ - return a0; -} - -long long __f_to_ll(float a0) -{ - return a0; -} - -unsigned long long __d_to_ull(double a0) -{ - return a0; -} - -unsigned long long __f_to_ull(float a0) -{ - return a0; -} - -double __ll_to_d(long long a0) -{ - return a0; -} - -float __ll_to_f(long long a0) -{ - return a0; -} - -double __ull_to_d(unsigned long long a0) -{ - return a0; -} - -float __ull_to_f(unsigned long long a0) -{ - return a0; -} diff --git a/src/core1/math/vector.c b/src/core1/ml.c similarity index 88% rename from src/core1/math/vector.c rename to src/core1/ml.c index 6b2302e1d..72e4be8ee 100644 --- a/src/core1/math/vector.c +++ b/src/core1/ml.c @@ -1,4 +1,4 @@ -// BanjoDecomp: (unknown decomp origin) +// BanjoDecomp: core1/ml.c #include #include "core1/core1.h" #include "functions.h" @@ -6,13 +6,8 @@ #include "version.h" #include "bk_math.h" -#if VERSION == VERSION_USA_1_0 -u32 D_80276CB0 = 0xD22FFFD8; //WHAT IS THIS? -u32 D_80276CB4 = 0xDEFEF692; //WHAT IS THIS? -#elif VERSION == VERSION_PAL -u32 D_80276CB0 = 0x90FA97CB; //WHAT IS THIS? -u32 D_80276CB4 = 0x8D96D002; //WHAT IS THIS? -#endif +s32 D_80276CB0 = VER_SELECT(0xD22FFFD8, 0x90FA97CB, 0, 0); // TTC_DATA_CRC2 +s32 D_80276CB4 = VER_SELECT(0xDEFEF692, 0x8D96D002, 0, 0); // RBB_DATA_CRC2 u16 *D_80276CB8 = NULL; //! ml_acosPrecValTblPtr @@ -122,37 +117,39 @@ f32 ml_vec3f_distance(f32 vec1[3], f32 vec2[3]) { return LENGTH_VEC3F(diff); } -f32 ml_func_802560D0(f32 arg0[3], f32 arg1[3], f32 arg2[3]) { - f32 sp4C[3]; - f32 pad48; - f32 sp3C[3]; - f32 sp38; - f32 sp34; - f32 sp30; - f32 sp24[3]; - f32 sp20; - f32 pad58; +f32 ml_vec3f_distance_to_point(f32 line_start_position[3], f32 line_end_position[3], f32 point_position[3]) { + f32 closestPointOnLine[3]; + f32 pad48; // unused + f32 pointOffsetFromLineStart[3]; + f32 pointDistanceFromLineStart; + f32 projectionFactor; + f32 projectionDistance; + f32 lineDirection[3]; + f32 lineLength; + f32 pad58; // unused - TUPLE_DIFF_COPY(sp24, arg1, arg0) - sp20 = LENGTH_VEC3F(sp24); + TUPLE_DIFF_COPY(lineDirection, line_end_position, line_start_position) + lineLength = LENGTH_VEC3F(lineDirection); - if (sp20 < 0.01) { - return ml_vec3f_distance(arg0, arg2); + if (lineLength < 0.01) { + return ml_vec3f_distance(line_start_position, point_position); } - TUPLE_DIFF_COPY(sp3C, arg2, arg0) - sp38 = LENGTH_VEC3F(sp3C); + TUPLE_DIFF_COPY(pointOffsetFromLineStart, point_position, line_start_position) + pointDistanceFromLineStart = LENGTH_VEC3F(pointOffsetFromLineStart); - if (sp38 < 0.01) { - return sp38; + if (pointDistanceFromLineStart < 0.01) { + return pointDistanceFromLineStart; } - sp34 = ((sp24[0]*sp3C[0] + sp24[1]*sp3C[1] + sp24[2]*sp3C[2]) / (sp20 * sp38)); - sp30 = (sp34 *sp38) / sp20; - sp4C[0] = arg0[0] + (sp24[0] * sp30); - sp4C[1] = arg0[1] + (sp24[1] * sp30); - sp4C[2] = arg0[2] + (sp24[2] * sp30); - return ml_vec3f_distance(sp4C, arg2); + projectionFactor = ((lineDirection[0] * pointOffsetFromLineStart[0] + + lineDirection[1] * pointOffsetFromLineStart[1] + + lineDirection[2] * pointOffsetFromLineStart[2]) / (lineLength * pointDistanceFromLineStart)); + projectionDistance = (projectionFactor * pointDistanceFromLineStart) / lineLength; + closestPointOnLine[0] = line_start_position[0] + (lineDirection[0] * projectionDistance); + closestPointOnLine[1] = line_start_position[1] + (lineDirection[1] * projectionDistance); + closestPointOnLine[2] = line_start_position[2] + (lineDirection[2] * projectionDistance); + return ml_vec3f_distance(closestPointOnLine, point_position); } f32 ml_distanceSquared_vec3f(f32 vec1[3], f32 vec2[3]) @@ -238,16 +235,14 @@ void ml_vec3f_set_length_copy(f32 dst[3], f32 src[3], f32 len) ml_vec3f_copy(dst, src); } -void func_80256664(f32 ptr[3]) -{ - u32 i; +void ml_vec3f_clamp_deg360(f32 ptr[3]) { + int i; - for (i = 0; i < 3; i++) - { + for (i = 0; i < 3; i++) { if (ptr[i] >= 0) - ptr[i] = (s32)ptr[i] % 360; + ptr[i] = (s32) ptr[i] % 360; else - ptr[i] += ((360 - (s32)ptr[i]) / 360) * 360; + ptr[i] += ((360 - (s32) ptr[i]) / 360) * 360; } } @@ -462,7 +457,7 @@ f32 func_80257248(f32 vec1[3], f32 vec2[3]) return func_8025715C(vec2[0] - vec1[0], vec2[2] - vec1[2]); } -void func_8025727C(f32 x1, f32 y1, f32 z1, f32 x2, f32 y2, f32 z2, f32 *o1, f32 *o2) +void ml_horizontal_and_vertical_angles(f32 x1, f32 y1, f32 z1, f32 x2, f32 y2, f32 z2, f32 *o1, f32 *o2) { f32 dz; f32 dy; // unused @@ -1193,15 +1188,15 @@ void func_8025901C(f32 arg0, f32 arg1[3], f32 arg2[3], f32 arg3){ }//L80259184 } -f32 func_80259198(f32 arg0, f32 arg1) +f32 ml_clamp_abs_f(f32 value, f32 max_abs_value) { - if (arg0 > arg1) - return arg1; + if (value > max_abs_value) + return max_abs_value; - if (arg0 < -arg1) - return -arg1; + if (value < -max_abs_value) + return -max_abs_value; - return arg0; + return value; } f32 mlDiffDegF(f32 arg0, f32 arg1) @@ -1269,48 +1264,51 @@ void ml_sub_delta_time(f32 *x) { *x = 0; } -void func_8025947C(f32 a0[3], f32 a1[3], f32 a2[3], f32 a3[3]) +// Perpendicular projection of point onto line using xz coordinates +void ml_project_point_onto_vecf3( + f32 closest_point_on_line[3], f32 line_start_position[3], + f32 line_end_position[3], f32 point_to_project[3]) { - f32 f0; - f32 f12; - f32 f16; - f32 f8; - f32 f18; - f32 f4; + f32 line_dx_xz; + f32 line_dz_xz; + f32 line_slope_xz; + f32 intersection_x_xz; + f32 line_intercept_xz; + f32 perpendicular_intercept_xz; - a0[1] = a1[1]; + closest_point_on_line[1] = line_start_position[1]; - f0 = a2[0] - a1[0]; + line_dx_xz = line_end_position[0] - line_start_position[0]; - if (f0 == 0) + if (line_dx_xz == 0) { - a0[0] = a1[0]; - a0[2] = a3[2]; + closest_point_on_line[0] = line_start_position[0]; + closest_point_on_line[2] = point_to_project[2]; return; } - f12 = a2[2] - a1[2]; + line_dz_xz = line_end_position[2] - line_start_position[2]; - if (f12 == 0) + if (line_dz_xz == 0) { - a0[0] = a3[0]; - a0[2] = a1[2]; + closest_point_on_line[0] = point_to_project[0]; + closest_point_on_line[2] = line_start_position[2]; return; } - f16 = f12 / f0; - f18 = a1[2] - (a1[0] * f16); + line_slope_xz = line_dz_xz / line_dx_xz; + line_intercept_xz = line_start_position[2] - (line_start_position[0] * line_slope_xz); - f8 = -1.0 / f16; + intersection_x_xz = -1.0 / line_slope_xz; - f4 = a3[2] - (a3[0] * f8); + perpendicular_intercept_xz = point_to_project[2] - (point_to_project[0] * intersection_x_xz); - f8 = (f4 - f18) / (f16 - f8); + intersection_x_xz = (perpendicular_intercept_xz - line_intercept_xz) / (line_slope_xz - intersection_x_xz); - a0[0] = f8; - a0[2] = f8 * f16 + f18; + closest_point_on_line[0] = intersection_x_xz; + closest_point_on_line[2] = intersection_x_xz * line_slope_xz + line_intercept_xz; } diff --git a/src/core1/math/matrix_stack.c b/src/core1/mlmtx.c similarity index 98% rename from src/core1/math/matrix_stack.c rename to src/core1/mlmtx.c index ba78ce751..6b5002193 100644 --- a/src/core1/math/matrix_stack.c +++ b/src/core1/mlmtx.c @@ -1,4 +1,4 @@ -// BanjoDecomp: (unknown decomp origin) +// BanjoDecomp: core1/mlmtx.c #include #include "core1/core1.h" @@ -12,13 +12,9 @@ void _guRotateF(f32 mf[4][4], f32, f32, f32, f32); f32 func_80263FF0(f32); f32 cosf(f32); -#if VERSION == VERSION_USA_1_0 - s32 D_80276570 = 0xFF62C2B8; //WHAT IS THIS? - s32 D_80276574 = 0x84D7B4F8; //CORE2_DATA_CRC2 -#elif VERSION == VERSION_PAL - s32 D_80276570 = 0xF71CBE76; //WHAT IS THIS? - s32 D_80276574 = 0xA2B6F47C; //CORE2_DATA_CRC2 -#endif +s32 D_80276570 = VER_SELECT(0xFF62C2B8, 0xF71CBE76, 0, 0); // CC_DATA_CRC2 +s32 D_80276574 = VER_SELECT(0x84D7B4F8, 0xA2B6F47C, 0, 0); // CORE2_DATA_CRC2 + f32 D_80276578 = BAD_DTOR; f32 D_8027657C = BAD_DTOR; diff --git a/src/core1/musicplayer.c b/src/core1/musicplayer.c index d7ff3d29b..ba238ec90 100644 --- a/src/core1/musicplayer.c +++ b/src/core1/musicplayer.c @@ -3,6 +3,7 @@ #include "core1/core1.h" #include "functions.h" #include "variables.h" +#include "musicplayer.h" #include "version.h" @@ -15,7 +16,7 @@ void musicTrack_setVolume(u8, s32); void func_8024FC1C(u8, s32); void func_8025AC20(enum comusic_e, s32, s32, f32, char*, s32); void func_8025AC7C(enum comusic_e comusic_id, s32 arg1, s32 arg2, f32 arg3, void *arg4, char *arg5, s32 arg6); -void comusicPlayer_free(void); +void coMusicPlayer_free(void); void func_8025A55C(s32, s32, s32); void func_8025A7DC(enum comusic_e); void func_8025ABB8(enum comusic_e, s32, s32, s32); @@ -32,7 +33,7 @@ int D_80276E34 = 0; * @param track_id * @return CoMusic* */ -CoMusic *__find_track(enum comusic_e track_id) { +CoMusic *findTrack(enum comusic_e track_id) { CoMusic *iMusPtr; CoMusic *freeSlotPtr; @@ -76,12 +77,12 @@ void func_802599B4(CoMusic *this){ func_8024FC1C(this - D_80276E30, -1); } -void comusicPlayer_init(void){ +void coMusicPlayer_init(void){ CoMusic * iPtr; s32 i; if(D_80276E30 != NULL) - comusicPlayer_free(); + coMusicPlayer_free(); D_80276E30 = (CoMusic *) bk_malloc(6*sizeof(CoMusic)); for(iPtr = D_80276E30; iPtr < D_80276E30 + 6; iPtr++){ @@ -101,7 +102,7 @@ void comusicPlayer_init(void){ } //comusic_freeAll -void comusicPlayer_free(void){ +void coMusicPlayer_free(void){ CoMusic *iPtr; func_8024FB8C(); func_8024F83C(); @@ -113,7 +114,7 @@ void comusicPlayer_free(void){ D_80276E30 = NULL; } -s32 comusic_active_track_count(void){ +s32 coMusicPlayer_getTrackCount(void){ CoMusic * iPtr; s32 cnt = 0; for(iPtr = D_80276E30; iPtr < D_80276E30 + 6; iPtr++){ @@ -123,7 +124,7 @@ s32 comusic_active_track_count(void){ return cnt; } -void comusicPlayer_update(void) { +void coMusicPlayer_update(void) { s32 temp_lo; CoMusic *var_s0; f32 dt; @@ -366,7 +367,7 @@ void func_8025A58C(u32 arg0, u32 arg1){ } -void func_8025A5AC(enum comusic_e comusic_id, s32 volume, s32 arg2){ +void playMusic(enum comusic_e comusic_id, s32 volume, s32 arg2){ CoMusic *tmp_a2; s32 sp20; @@ -374,7 +375,7 @@ void func_8025A5AC(enum comusic_e comusic_id, s32 volume, s32 arg2){ volume = gcMusic_getDefaultVolumeForTrack(comusic_id); } - tmp_a2 = __find_track(comusic_id); + tmp_a2 = findTrack(comusic_id); if(tmp_a2 == NULL) return; @@ -402,11 +403,11 @@ void func_8025A5AC(enum comusic_e comusic_id, s32 volume, s32 arg2){ } void coMusicPlayer_playMusicWeak(enum comusic_e track_id, s32 volume){ - func_8025A5AC(track_id, volume, 0); + playMusic(track_id, volume, 0); } void coMusicPlayer_playMusic(enum comusic_e track_id, s32 volume){ - func_8025A5AC(track_id, volume, 1); + playMusic(track_id, volume, 1); } //comusic_queueTrack @@ -414,7 +415,7 @@ void comusic_playTrack(enum comusic_e track_id){ CoMusic *trackPtr; s32 indx; - trackPtr = __find_track(track_id); + trackPtr = findTrack(track_id); if(trackPtr == NULL) return; @@ -437,7 +438,7 @@ void func_8025A788(enum comusic_e comusic_id, f32 delay1, f32 delay2){ void func_8025A7DC(enum comusic_e track_id){ CoMusic *trackPtr; - trackPtr = __find_track(track_id); + trackPtr = findTrack(track_id); if (trackPtr != NULL && trackPtr->track_id >= 0){ func_802599B4(trackPtr); } @@ -454,7 +455,7 @@ s32 func_8025A818(void){ s32 func_8025A864(enum comusic_e track_id){ CoMusic *trackPtr; - trackPtr = __find_track(track_id); + trackPtr = findTrack(track_id); if (trackPtr != NULL && trackPtr->unkC == 0 && trackPtr->volume <= 0){ func_802599B4(trackPtr); return 1; @@ -465,7 +466,7 @@ s32 func_8025A864(enum comusic_e track_id){ void func_8025A8B8(enum comusic_e track_id, s32 arg1){ CoMusic *trackPtr; - trackPtr = __find_track(track_id); + trackPtr = findTrack(track_id); if (trackPtr != NULL){ trackPtr->unk14 = arg1; } @@ -525,7 +526,7 @@ void func_8025AA48(void){ void func_8025AABC(enum comusic_e track_id){ CoMusic *trackPtr; - if(trackPtr = __find_track(track_id)){ + if(trackPtr = findTrack(track_id)){ trackPtr->unk15 = 1; if(!trackPtr->volume) func_802599B4(trackPtr); @@ -545,17 +546,17 @@ void comusic_8025AB44(enum comusic_e comusic_id, s32 arg1, s32 arg2){ } void comusic_8025AB78(enum comusic_e comusic_id, s32 arg1, s32 arg2, s32 arg3){ - CoMusic *track = __find_track(comusic_id); + CoMusic *track = findTrack(comusic_id); if (!track) return; func_8025AC7C(comusic_id, arg1, arg2, 0.0f, &track->unk1C[arg3], "comusic.c", VER_SELECT(0x3a3, 0x3a4, 0, 0)); } void func_8025ABB8(enum comusic_e comusic_id, s32 arg1, s32 arg2, s32 arg3){ - func_8025AC7C(comusic_id, arg1, arg2, 0.0f, &(__find_track(comusic_id)->unk1C[arg3]), "comusic.c", VER_SELECT(0x3aa, 0x3ab,0,0)); + func_8025AC7C(comusic_id, arg1, arg2, 0.0f, &(findTrack(comusic_id)->unk1C[arg3]), "comusic.c", VER_SELECT(0x3aa, 0x3ab,0,0)); } void func_8025AC20(enum comusic_e comusic_id, s32 arg1, s32 arg2, f32 arg3, char* arg4, s32 char5){ - func_8025AC7C(comusic_id, arg1, arg2, 0.0f, __find_track(comusic_id)->unk1C, "comusic.c", VER_SELECT(0x3b1, 0x3b2,0,0)); + func_8025AC7C(comusic_id, arg1, arg2, 0.0f, findTrack(comusic_id)->unk1C, "comusic.c", VER_SELECT(0x3b1, 0x3b2,0,0)); } void func_8025AC7C(enum comusic_e comusic_id, s32 arg1, s32 arg2, f32 arg3, void *arg4, char* arg5, s32 arg6){ @@ -564,7 +565,7 @@ void func_8025AC7C(enum comusic_e comusic_id, s32 arg1, s32 arg2, f32 arg3, void s32 *fadeSlot = (s32 *)arg4; //get track location - trackPtr = __find_track(comusic_id); + trackPtr = findTrack(comusic_id); if(trackPtr == NULL) return; @@ -590,7 +591,7 @@ void func_8025AC7C(enum comusic_e comusic_id, s32 arg1, s32 arg2, f32 arg3, void //comusic_trackQueued int func_8025AD7C(enum comusic_e arg0){ - CoMusic * trackPtr = __find_track(arg0); + CoMusic * trackPtr = findTrack(arg0); return (trackPtr == NULL || trackPtr->track_id == -1)? 0 : 1; } @@ -600,7 +601,7 @@ int func_8025ADBC(enum comusic_e arg0){ } s32 func_8025ADD4(enum comusic_e id){ - CoMusic * ptr = __find_track(id); + CoMusic * ptr = findTrack(id); return ptr - D_80276E30; } @@ -615,7 +616,7 @@ void func_8025AE50(s32 arg0, f32 arg1){ } void func_8025AEA0(enum comusic_e track_id, s32 arg1){ - CoMusic *ptr = __find_track(track_id); + CoMusic *ptr = findTrack(track_id); if(!ptr) return; func_8024FDDC(ptr - D_80276E30, arg1); diff --git a/src/core1/musicplayer.h b/src/core1/musicplayer.h new file mode 100644 index 000000000..1fd913058 --- /dev/null +++ b/src/core1/musicplayer.h @@ -0,0 +1,7 @@ +// BanjoDecomp: core1/musicplayer.h +#ifndef BANJO_KAZOOIE_MUSICPLAYER_H +#define BANJO_KAZOOIE_MUSICPLAYER_H + +#define MAX_MUSIC_STRUCT_COUNT 6 + +#endif // BANJO_KAZOOIE_MUSICPLAYER_H diff --git a/src/core1/overlay.c b/src/core1/overlay.c index a727190ae..c5a76f83e 100644 --- a/src/core1/overlay.c +++ b/src/core1/overlay.c @@ -2,8 +2,7 @@ #include #include "boot/overlaytable.h" #include "core1/core1.h" -#include "functions.h" -#include "variables.h" +#include "checksums.h" extern u8 gHeapBase; extern u32 D_8027BF2C; @@ -20,7 +19,7 @@ void overlay_load( #if 0 void *compressed_buffer; u32 crc2, crc1; - u32 *tmp; + struct overlay_checksums_s *checksums; osWritebackDCacheAll(); osInvalDCache(ram_start, ram_end - ram_start); @@ -50,11 +49,11 @@ void overlay_load( bzero(bss_start, bss_end - bss_start); osWritebackDCacheAll(); - tmp = (u32*) bss_start; - tmp[0] = crc1; - tmp[1] = crc2; - tmp[2] = D_8027BF2C; - tmp[3] = D_8027BF30; + checksums = (struct overlay_checksums_s *) bss_start; + checksums->text_checksum1 = crc1; + checksums->text_checksum2 = crc2; + checksums->data_checksum1 = D_8027BF2C; + checksums->data_checksum2 = D_8027BF30; } #endif } diff --git a/src/core1/io/pfsmanager.c b/src/core1/pfsmanager.c similarity index 97% rename from src/core1/io/pfsmanager.c rename to src/core1/pfsmanager.c index 30afe7642..1d06ee4cc 100644 --- a/src/core1/io/pfsmanager.c +++ b/src/core1/pfsmanager.c @@ -7,29 +7,17 @@ #include "core1/pfsmanager.h" #include "version.h" +#include "checksums.h" #include "port/Patches/Patches.h" #define PFSMANAGER_THREAD_STACK_SIZE 0x200 -extern struct { - u8 pad0[4]; - s32 unk4; - u8 pad8[4]; - s32 unkC; -} D_80379B90; - extern s32 D_803727F4; extern s32 D_80276574; -/* .data */ -#if VERSION == VERSION_USA_1_0 - s32 D_80275D30 = 0xC3A68832; //WHAT IS THIS? - s32 D_80275D34 = 0xDDC3A724; //WHAT IS THIS? -#elif VERSION == VERSION_PAL - s32 D_80275D30 = 0xED7BCDB7; //WHAT IS THIS? - s32 D_80275D34 = 0xF82DC7AC; //WHAT IS THIS? -#endif +s32 D_80275D30 = VER_SELECT(0xC3A68832, 0xED7BCDB7, 0, 0); // CCW_DATA_CRC2 +s32 D_80275D34 = VER_SELECT(0xDDC3A724, 0xF82DC7AC, 0, 0); // FIGHT_DATA_CRC2 static s32 D_80275D38 = 0; @@ -66,7 +54,7 @@ f32 func_8024E420(s32 arg0, s32 arg1, s32 arg2) { // instead of 1.0), making it impossible to reach the 0.7 threshold used by // gameSelect.c and other input consumers. Bypassed. #if ANTI_TAMPER - if ((D_80379B90.unk4 != D_803727F4) || (D_80379B90.unkC != D_80276574)) { + if ((gChecksumsCore2.text_checksum2 != D_803727F4) || (gChecksumsCore2.data_checksum2 != D_80276574)) { phi_f2 = 0.00625f; } #endif diff --git a/src/core1/stopnswop_payload.c b/src/core1/sns.c similarity index 99% rename from src/core1/stopnswop_payload.c rename to src/core1/sns.c index 2168c8848..6c0e115c9 100644 --- a/src/core1/stopnswop_payload.c +++ b/src/core1/sns.c @@ -1,4 +1,4 @@ -// BanjoDecomp: sns.c +// BanjoDecomp: core1/sns.c #include #include "core1/core1.h" #include "functions.h" diff --git a/src/core1/stopnswop.c b/src/core1/stopnswop.c index 4564357f4..e5165fac8 100644 --- a/src/core1/stopnswop.c +++ b/src/core1/stopnswop.c @@ -1,4 +1,4 @@ -// BanjoDecomp: sns.c +// BanjoDecomp: core1/code_1D5D0.c #include #include "core1/core1.h" #include "functions.h" @@ -217,7 +217,7 @@ void sns_generate_payload(struct SnsPayload *payload) void sns_write_payload_over_heap(void) { // [port] SNS writes payload to hardcoded N64 RDRAM for cartridge-swap. - // Non-functional on PC — all base payload pointers are NULL. + // Non-functional on PC. #if 0 s32 val2; u32 i; diff --git a/src/core1/syncprintf.c b/src/core1/syncprintf.c deleted file mode 100644 index ae7baf1de..000000000 --- a/src/core1/syncprintf.c +++ /dev/null @@ -1,17 +0,0 @@ -// BanjoDecomp: (unknown decomp origin) -#include -// Lighthouse [port] These functions aren't used so we can remove these includes -//#include -//#include - -void osSyncPrintf(const char *fmt, ...) -{ - int ans; - va_list ap; - // these functions intentionally left blank. ifdeffed out in rom release -} -void rmonPrintf(const char *fmt, ...) -{ - int ans; - va_list ap; -} diff --git a/src/core1/viewport.c b/src/core1/viewport.c index bf5591aed..04a1e2976 100644 --- a/src/core1/viewport.c +++ b/src/core1/viewport.c @@ -45,7 +45,7 @@ f32 viewport_getDistance(f32 arg0[3]) { return ml_vec3f_distance(arg0, sViewportPosition); } -void viewport_getLookbk_vector(f32 arg0[3]) { +void viewport_getLookVector(f32 arg0[3]) { ml_vec3f_copy(arg0, sViewportLookbk_vector); } @@ -100,12 +100,12 @@ void viewport_setRenderPerspectiveMatrix(Gfx **gfx, Mtx **mtx, f32 near, f32 far near = MAX(sViewportNear, near); far = MIN(sViewportFar, far); - // [port] This is either anti-tamper or a legit camera adjustment - // based on NTSC or PAL, because PAL runs at 50Hz instead of 60Hz - // if(*(u32*)OS_PHYSICAL_TO_K1(0x1D8) + 0x53D4FFF0) { - // near = 750.0f; - // far = 1250.0f; - // } +#if ANTI_TAMPER + if ((*(u32*) OS_PHYSICAL_TO_K1(0x000001D8)) + 0x53D4FFF0) { + near = 750.0f; + far = 1250.0f; + } +#endif guPerspective(*mtx, &perspNorm, sViewportFOVy, sViewportAspect, near, far, 0.5f); gSPPerspNormalize((*gfx)++, perspNorm); @@ -490,7 +490,7 @@ f32 viewport_transformCoordinate(f32 x, f32 y, f32 viewport_translation[3], f32 f32 sViewportBackupPosition[3]; f32 sViewportBackupRotation[3]; f32 sViewportBackupFrustumPlanes[4][4]; -f32 sViewportBackupLookbk_vector[3]; +f32 sViewportBackupLookVector[3]; MtxF sViewportBackupMatrix; // ?? @@ -537,7 +537,7 @@ void viewport_backupState(void) { viewport_getPosition_vec3f(sViewportBackupPosition); viewport_getRotation_vec3f(sViewportBackupRotation); viewport_getFrustumPlanes(sViewportBackupFrustumPlanes[0], sViewportBackupFrustumPlanes[1], sViewportBackupFrustumPlanes[2], sViewportBackupFrustumPlanes[3]); - viewport_getLookbk_vector(sViewportBackupLookbk_vector); + viewport_getLookVector(sViewportBackupLookVector); for(i = 0; i < 4; i++){ for(j = 0; j < 4; j++){ @@ -552,7 +552,7 @@ void viewport_restoreState(void) { viewport_setPosition_vec3f(sViewportBackupPosition); viewport_setRotation_vec3f(sViewportBackupRotation); viewport_setFrustumPlanes(sViewportBackupFrustumPlanes[0], sViewportBackupFrustumPlanes[1], sViewportBackupFrustumPlanes[2], sViewportBackupFrustumPlanes[3]); - ml_vec3f_copy(sViewportLookbk_vector, sViewportBackupLookbk_vector); + ml_vec3f_copy(sViewportLookbk_vector, sViewportBackupLookVector); for(i = 0; i < 4; i++){ for(j = 0; j < 4; j++){ diff --git a/src/core1/vimgr.c b/src/core1/vimgr.c index dec23b0aa..24c3aa90b 100644 --- a/src/core1/vimgr.c +++ b/src/core1/vimgr.c @@ -180,7 +180,7 @@ void viMgr_func_8024BFD8(s32 arg0){ osSetThreadPri(NULL, 0x7f); defragManager_setPriority(DEFRAGMANAGER_THREAD_PRIORITY_HIGH); - defragManager_80240874(); + defragManager_resume(); if(arg0){ osRecvMesg(&sMesgQueue2, NULL, OS_MESG_BLOCK); } @@ -201,7 +201,7 @@ void viMgr_func_8024BFD8(s32 arg0){ }//L8024C178 D_80280724 = D_802808D8; D_802808D8 = 0; - defragManager_802408B0(); + defragManager_pause(); osSetThreadPri(NULL, 0x14); defragManager_setPriority(DEFRAGMANAGER_THREAD_PRIORITY); #endif diff --git a/src/core2/actor_array.c b/src/core2/actor_array.c index 5fdf09026..4c58c688b 100644 --- a/src/core2/actor_array.c +++ b/src/core2/actor_array.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_9E370.c #include #include "core1/core1.h" #include "functions.h" @@ -192,13 +193,13 @@ void func_803255FC(Actor *this) { } break; } - func_8033A45C(1, this->unk124_3 + 1); - func_8033A45C(2, this->unk124_3 + 1); + modelRender_setAppendageVisibility(1, this->unk124_3 + 1); + modelRender_setAppendageVisibility(2, this->unk124_3 + 1); } void func_80325760(Actor *this) { - func_8033A45C(1, 4); - func_8033A45C(2, 4); + modelRender_setAppendageVisibility(1, 4); + modelRender_setAppendageVisibility(2, 4); } // [port] In widescreen, actors outside the 4:3 frustum are still drawn but @@ -376,6 +377,7 @@ Actor *func_80325F2C(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx) { return actor_drawFullDepth(marker, gfx, mtx, vtx); } +// CCW Unknown Update Function void func_80325F84(Actor *this){} void func_80325F8C(void) { @@ -1540,14 +1542,14 @@ bool func_803292E0(Actor *this){ return 1; } - _player_getPosition(player_position); + playerPosition_get(player_position); return func_80307258(player_position, this->unk10_25 - 1, this->unk10_18 - 1) != -1; } bool func_80329354(Actor *this){ f32 sp1C[3]; - _player_getPosition(sp1C); + playerPosition_get(sp1C); return func_80329260(this, sp1C); } @@ -1557,7 +1559,7 @@ bool func_80329384(Actor *this, f32 arg1){ if(this->unk10_25 == 0) return true; - _player_getPosition(sp1C); + playerPosition_get(sp1C); return func_80307258(sp1C, this->unk10_25 - 1, this->unk10_18 - 1) != -1 && (sp1C[1] < (this->position[1] + arg1)) @@ -1604,14 +1606,14 @@ bool subaddie_playerIsWithinSphereAndActive(Actor *this, s32 dist){ bool subaddie_playerIsWithinSphere(Actor *this, s32 dist){ f32 sp24[3]; - f32 sp18[3]; + f32 player_position[3]; func_8028E964(sp24); - _player_getPosition(sp18); - sp24[1] = sp18[1]; - if( ( (this->position_x - sp24[0])*(this->position_x - sp24[0]) - + (this->position_y - sp24[1])*(this->position_y - sp24[1]) - + (this->position_z - sp24[2])*(this->position_z - sp24[2]) + playerPosition_get(player_position); + sp24[1] = player_position[1]; + if( ( (this->position_x - sp24[0]) * (this->position_x - sp24[0]) + + (this->position_y - sp24[1]) * (this->position_y - sp24[1]) + + (this->position_z - sp24[2]) * (this->position_z - sp24[2]) ) < dist*dist ){ return true; @@ -1650,7 +1652,7 @@ s32 func_8032970C(Actor *this){ f32 plyr_pos[3]; func_8028E964(sp24); - _player_getPosition(plyr_pos); + playerPosition_get(plyr_pos); sp24[1] = plyr_pos[1]; return (s32) DIST_SQ_VEC3F(this->position, sp24); } @@ -1667,12 +1669,12 @@ s32 subaddie_getYawToPosition(Actor *arg0, f32 arg1[3]){ } void func_803297FC(Actor *arg0, f32 *o1, f32 *o2){ - f32 sp2C[3]; + f32 player_pos[3]; - _player_getPosition(sp2C); - func_8025727C( + playerPosition_get(player_pos); + ml_horizontal_and_vertical_angles( arg0->position[0], arg0->position[1], arg0->position[2], - sp2C[0], sp2C[1], sp2C[2], + player_pos[0], player_pos[1], player_pos[2], o1, o2 ); *o1 = 360.0f - *o1; @@ -2008,7 +2010,7 @@ void func_8032A82C(Actor *arg0, s32 arg1) { sp1C = (Actorlocal_Core2_9E370 *)arg0->local; sp24 = nodeprop_findByActorIdAndActorPosition(arg1, arg0); if (sp24 != NULL) { - sp1C->unkC = nodeprop_getYaw(sp24); + sp1C->unkC = nodeProp_getYaw(sp24); nodeprop_getPosition(sp24, sp1C->unk0); sp1C->unkE = func_80341EC4(sp1C->unk0); } diff --git a/src/core2/actor_cleanup.c b/src/core2/actor_cleanup.c index 152b831b7..8b0a8f89d 100644 --- a/src/core2/actor_cleanup.c +++ b/src/core2/actor_cleanup.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_DC4B0.c #include #include "functions.h" #include "variables.h" @@ -5,7 +6,9 @@ void func_80363500(Actor *this); /* .data */ -ActorInfo D_80373DC0= { +// Next To SM Bridge Bottles +// Gets removed when player learns all SM Moves +ActorInfo D_80373DC0 = { 0x1EE, ACTOR_3BA_UNKNOWN, 0, 0, NULL, func_80363500, actor_update_func_80326224, func_80325340, diff --git a/src/core2/actor_cubepropsystem.c b/src/core2/actor_cubepropsystem.c index 466e31455..77c0c5bc1 100644 --- a/src/core2/actor_cubepropsystem.c +++ b/src/core2/actor_cubepropsystem.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_A5BC0.c #include #include "core1/core1.h" #include "functions.h" @@ -28,7 +29,7 @@ extern BKCollisionTriangle *collisionList_func_802E805C(BKCollisionList *, BKVer extern NodeProp *func_803080C8(s32 arg0); extern Cube *func_80308224(void); extern Cube *func_8030364C(void); -extern Cube *cube_atPosition_s32(s32 position[3]); +extern Cube *cubeList_GetCubeAtPosition_s32(s32 position[3]); extern f32 propModelList_getScale(Prop *); extern void propModelList_setScale(Prop *, f32); @@ -275,8 +276,7 @@ void func_8032CD60(Prop *prop) { } else { sp3C = prop->spriteProp.isMirrored; } - if (1); - break; + if (1) break; } break; @@ -364,17 +364,19 @@ void func_8032D3A8(void){ bk_vector_clear(D_80383554); } -void func_8032D3D8(Gfx **gdl, Mtx **mptr, Vtx **vptr){ +void core2_A5BC0_drawUnknownMarkers(Gfx **gfx, Mtx **mtx, Vtx **vtx) { // further investigation needed what's drawn here int i; - for(i = 0; i < bk_vector_size(D_80383550); i++){ - __marker_draw(*(ActorMarker **) bk_vector_at(D_80383550, i), gdl, mptr, vptr); + + for (i = 0; i < bk_vector_size(D_80383550); i++) { + __marker_draw(*(ActorMarker **) bk_vector_at(D_80383550, i), gfx, mtx, vtx); } } -void func_8032D474(Gfx **gdl, Mtx **mptr, Vtx **vptr){ +void core2_A5BC0_drawScreenOverlayMarkers(Gfx **gfx, Mtx **mtx, Vtx **vtx) { int i; - for(i = 0; i < bk_vector_size(D_80383554); i++){ - __marker_draw(*(ActorMarker **) bk_vector_at(D_80383554, i), gdl, mptr, vptr); + + for (i = 0; i < bk_vector_size(D_80383554); i++) { + __marker_draw(*(ActorMarker **) bk_vector_at(D_80383554, i), gfx, mtx, vtx); } } @@ -1220,7 +1222,7 @@ void func_8032F21C(Cube *cube, s32 position[3], ActorMarker *marker, bool arg3) } void func_8032F3D4(s32 arg0[3], ActorMarker *marker, s32 arg2){ - func_8032F21C((marker->unk40_23)? func_8030364C() : cube_atPosition_s32(arg0), arg0, marker, arg2); + func_8032F21C((marker->unk40_23)? func_8030364C() : cubeList_GetCubeAtPosition_s32(arg0), arg0, marker, arg2); } void marker_free(ActorMarker *this){ @@ -1235,7 +1237,7 @@ void func_8032F464(bool arg0){ void func_8032F470(s32 *pos, ActorMarker *arg1){ Cube *cubePtr; - cubePtr = (arg1->unk40_23)? func_8030364C(): cube_atPosition_s32(pos); + cubePtr = (arg1->unk40_23)? func_8030364C(): cubeList_GetCubeAtPosition_s32(pos); if(cubePtr == arg1->cubePtr){ arg1->propPtr->x = pos[0]; @@ -1805,19 +1807,19 @@ BKSprite *func_80330F50(ActorMarker * marker){ return sp1C; } -s32 codeA5BC0_getNodePropUnkA(NodeProp *arg0){ +s32 codeA5BC0_getNodePropMarkerId(NodeProp *arg0){ return arg0->unkA; //marker_id } -s32 codeA5BC0_getNodePropBit6(NodeProp *arg0){ +s32 codeA5BC0_getNodePropCategory(NodeProp *arg0){ return arg0->bit6; } -s32 codeA5BC0_getNodePropUnk8(NodeProp *arg0){ +s32 codeA5BC0_getNodePropActorId(NodeProp *arg0){ return arg0->unk8; } -s32 codeA5BC0_getPositionAndReturnRadius(void *arg0_, s32 arg1[3]){ +s32 codeA5BC0_getPositionAndSelectorOrRadius(void *arg0_, s32 arg1[3]){ NodeProp *arg0 = (NodeProp *)arg0_; arg1[0] = arg0->x; arg1[1] = arg0->y; @@ -2426,8 +2428,8 @@ void func_80332894(void) { s32 size; s32 i; - size = 0x579; - D_8036E7C4 = bk_malloc(size); + size = VER_SELECT(0x579, 0x391, 0, 0); + D_8036E7C4 = malloc(size); i = 0; do{ D_8036E7C4[i] = 0; diff --git a/src/core2/actor_motioncurve.c b/src/core2/actor_motioncurve.c index 128b91d04..eb3518980 100644 --- a/src/core2/actor_motioncurve.c +++ b/src/core2/actor_motioncurve.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_EF50.c #include #include "functions.h" #include "variables.h" @@ -82,15 +83,15 @@ enum bs_e func_80295EE0(enum bs_e arg0){ enum bs_e __get_rebound_state_id(void){ switch(bsStoredState_getTransformation()){ case TRANSFORM_3_PUMPKIN:// L8029606C - return BS_PUMPKIN_BOUNCE; + return BS_A0_ANT_BOUNCE; case TRANSFORM_2_TERMITE:// L80296074 - return BS_ANT_BOUNCE; + return BS_9F_ANT_BOUNCE; case TRANSFORM_5_CROC:// L8029607C - return BS_CROC_BOUNCE; + return BS_A1_CROC_BOUNCE; case TRANSFORM_4_WALRUS:// L80296084 - return BS_WALRUS_BOUNCE; + return BS_A2_WALRUS_BOUNCE; case TRANSFORM_6_BEE:// L8029608C - return BS_BEE_BOUNCE; + return BS_A3_BEE_BOUNCE; case TRANSFORM_1_BANJO:// L80296094 default: if(player_movementGroup() == BSGROUP_A_FLYING) @@ -147,7 +148,7 @@ void func_8029622C(void){ f32 sp34[3]; f32 sp28[3]; - _player_getPosition(sp28); + playerPosition_get(sp28); func_80256E24(sp34, 0.0f, yaw_get(), 0.0f, 0.0f, 100.0f); sp28[0] += sp34[0]; sp28[1] += sp34[1]; @@ -175,29 +176,29 @@ enum bs_e func_802962BC(u32 arg0){ return BS_4E_PUMPKIN_DIE; case TRANSFORM_5_CROC: //L80296344 if(sp1C) - return BS_CROC_OW; + return BS_63_CROC_OW; else - return BS_CROC_OW; + return BS_63_CROC_OW; case TRANSFORM_4_WALRUS: //L8029635C if(sp1C) - return BS_WALRUS_OW; + return BS_6C_WALRUS_OW; else - return BS_WALRUS_DIE; + return BS_6D_WALRUS_DIE; case TRANSFORM_6_BEE: //L80296374 if(sp1C) - return BS_BEE_OW; - return BS_BEE_DIE; + return BS_89_BEE_OW; + return BS_8A_BEE_DIE; case TRANSFORM_1_BANJO: //L8029638C default: if(sp1C){ if(bsbtrot_inSet(bs_getState())) - return BS_BTROT_OW; + return BS_7B_BTROT_OW; if(player_getWaterState() == BSWATERGROUP_2_UNDERWATER) return BS_7F_DIVE_OW; if(player_movementGroup() == BSGROUP_A_FLYING) - return BS_FLY_OW; + return BS_91_FLY_OW; return BS_E_OW; } return BS_41_DIE; diff --git a/src/core2/actor_updatestub.c b/src/core2/actor_updatestub.c index 7a58ba2f1..d9717b32e 100644 --- a/src/core2/actor_updatestub.c +++ b/src/core2/actor_updatestub.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_4BE10.c #include #include "functions.h" #include "variables.h" @@ -6,13 +7,23 @@ void func_802D2DA0(Actor *this); /* .data */ ActorInfo D_803675F0 = { - 0x16, 0x6A, 0x0, + MARKER_16_UNKNOWN, ACTOR_6A_UNKNOWN, 0x0, 0x1, NULL, func_802D2DA0, func_80326244, func_80325340, 0, 0, 0.0f, 0 }; + s16 D_80367614[] = {3,2,3,4,3,5,3,0}; -ParticleScaleAndLifetimeRanges D_80367624 = {{0.7f, 0.3f}, {0.01f, 0.01f}, {0.05f, 0.05f}, {0.2f, 0.2f}, 0.0f, 0.01f}; + +ParticleScaleAndLifetimeRanges D_80367624 = { + {0.7f, 0.3f}, // particle_starting_scale_range + {0.01f, 0.01f}, // particle_starting_scale_range + {0.05f, 0.05f}, // particle_spawn_interval_range + {0.2f, 0.2f}, // particle_lifetime_range + 0.0f, // particle_fade_in + 0.01f // particle_fade_in +}; + ParticleSettingsVelocityPosition D_8036764C = { {{-100.0f, 400.0f, -100.0f}, { 100.0f, 800.0f, 100.0f}}, {{-100.0f, 0.0f, -100.0f}, { 100.0f, 0.0f, 100.0f}} diff --git a/src/core2/anim/controller.c b/src/core2/anim/anctrl.c similarity index 99% rename from src/core2/anim/controller.c rename to src/core2/anim/anctrl.c index ddfe5013a..0f6a95404 100644 --- a/src/core2/anim/controller.c +++ b/src/core2/anim/anctrl.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/anctrl.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/anim/anim_bonetransform.c b/src/core2/anim/anim_bonetransform.c index 6cda545db..f9a2d5f62 100644 --- a/src/core2/anim/anim_bonetransform.c +++ b/src/core2/anim/anim_bonetransform.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_B3A80.c #include #include "functions.h" #include "variables.h" @@ -230,8 +231,13 @@ void func_8033B1BC(void){ } void func_8033B268(void){ +#if VERSION == VERSION_USA_1_0 D_80383CE0[0] = (bk_vector(struct21s) *)defrag(D_80383CE0[0]); D_80383CE0[1] = (bk_vector(struct21s) *)defrag(D_80383CE0[1]); +#else + D_80383CE0[0] = (bk_vector(struct21s) *)bk_vector_defrag(D_80383CE0[0]); + D_80383CE0[1] = (bk_vector(struct21s) *)bk_vector_defrag(D_80383CE0[1]); +#endif } void func_8033B2A4(s32 arg0) { diff --git a/src/core2/anim/anim_buffer.c b/src/core2/anim/anim_buffer.c index 7bdeb906e..563e0aeca 100644 --- a/src/core2/anim/anim_buffer.c +++ b/src/core2/anim/anim_buffer.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_2240.c #include #include "functions.h" #include "port/ShipUtils.h" // BK_LOG_*, port_shapeControllerInput diff --git a/src/core2/anim/anim_defrag.c b/src/core2/anim/anim_defrag.c index f364a2353..10767a17d 100644 --- a/src/core2/anim/anim_defrag.c +++ b/src/core2/anim/anim_defrag.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_630D0.c #include #include "functions.h" #include "port/ShipUtils.h" // BK_LOG_*, port_shapeControllerInput diff --git a/src/core2/anim/anim_driver.c b/src/core2/anim/anim_driver.c index fdba789b0..7baf7ebe9 100644 --- a/src/core2/anim/anim_driver.c +++ b/src/core2/anim/anim_driver.c @@ -1,66 +1,88 @@ +// BanjoDecomp: core2/code_DA760.c #include #include "functions.h" #include "variables.h" -void func_80361870(Actor *this); +void lairBottlesDialog_update(Actor *this); /* .data */ -ActorInfo D_803731B0 = { +ActorInfo lairBottlesDialog = { 0x1E4, 0x373, 0, 0, NULL, - func_80361870, actor_update_func_80326224, func_80325340, + lairBottlesDialog_update, actor_update_func_80326224, func_80325340, 0, 0, 0.0f, 0 -}; +}; + +enum lairbottlesdialog_specificfield_e { + LAIR_BOTTLES_DIALOG_SPECIFIC_FIELD_1_MM = 1, + LAIR_BOTTLES_DIALOG_SPECIFIC_FIELD_2_TTC, + LAIR_BOTTLES_DIALOG_SPECIFIC_FIELD_3_CC, + LAIR_BOTTLES_DIALOG_SPECIFIC_FIELD_4_BGS, + LAIR_BOTTLES_DIALOG_SPECIFIC_FIELD_5_FP, + LAIR_BOTTLES_DIALOG_SPECIFIC_FIELD_6_GV +}; /* .code */ -int func_803616F0(Actor *this){ +bool lairBottlesDialog_levelOpenedAndNotLearnedAllMoves(Actor *this){ switch(this->actorTypeSpecificField){ - case 1:// L80361728 + case LAIR_BOTTLES_DIALOG_SPECIFIC_FIELD_1_MM:// L80361728 return fileProgressFlag_get(FILEPROG_31_MM_OPEN) && !chmole_learnedAllLevelAbilities(LEVEL_1_MUMBOS_MOUNTAIN); - case 2:// L80361750 + case LAIR_BOTTLES_DIALOG_SPECIFIC_FIELD_2_TTC:// L80361750 return fileProgressFlag_get(FILEPROG_32_TTC_OPEN) && !chmole_learnedAllLevelAbilities(LEVEL_2_TREASURE_TROVE_COVE); - case 3:// L80361778 + case LAIR_BOTTLES_DIALOG_SPECIFIC_FIELD_3_CC:// L80361778 return fileProgressFlag_get(FILEPROG_33_CC_OPEN) && !chmole_learnedAllLevelAbilities(LEVEL_3_CLANKERS_CAVERN); - case 4:// L803617A0 + case LAIR_BOTTLES_DIALOG_SPECIFIC_FIELD_4_BGS:// L803617A0 return fileProgressFlag_get(FILEPROG_34_BGS_OPEN) && !chmole_learnedAllLevelAbilities(LEVEL_4_BUBBLEGLOOP_SWAMP); - case 5:// L803617C8 + case LAIR_BOTTLES_DIALOG_SPECIFIC_FIELD_5_FP:// L803617C8 return fileProgressFlag_get(FILEPROG_35_FP_OPEN) && !chmole_learnedAllLevelAbilities(LEVEL_5_FREEZEEZY_PEAK); - case 6:// L803617F0 + case LAIR_BOTTLES_DIALOG_SPECIFIC_FIELD_6_GV:// L803617F0 return fileProgressFlag_get(FILEPROG_36_GV_OPEN) && !chmole_learnedAllLevelAbilities(LEVEL_7_GOBIS_VALLEY); default: return false; } } -void func_80361828(Actor *this){ - if(volatileFlag_get(VOLATILE_FLAG_16) && level_get() == LEVEL_6_LAIR){ +void lairBottlesDialog_free(Actor *this){ + if(volatileFlag_get(VOLATILE_FLAG_16) + && level_get() == LEVEL_6_LAIR) + { volatileFlag_set(VOLATILE_FLAG_16, 0); } } -void func_80361870(Actor *this){ - s32 text_id; - s32 sp28; +void lairBottlesDialog_update(Actor *this){ + s32 podium_text_id; + s32 didnt_learn_moves_text_id; if(!this->volatile_initialized){ - marker_setFreeMethod(this->marker, func_80361828); - this->volatile_initialized = true; + marker_setFreeMethod(this->marker, lairBottlesDialog_free); + this->volatile_initialized = TRUE; } - if(!this->has_met_before && subaddie_playerIsWithinSphereAndActive(this, 400) && !subaddie_playerIsWithinSphereAndActive(this, 50)){ - if(this->actorTypeSpecificField == 1 && !fileProgressFlag_get(FILEPROG_31_MM_OPEN) && level_get() == LEVEL_6_LAIR){ - text_id = fileProgressFlag_get(FILEPROG_A7_NEAR_PUZZLE_PODIUM_TEXT)? 0xF80 : 0xF7F; - if(gcdialog_showDialog(text_id, 0, 0, 0, 0, 0)){ - this->has_met_before = true; + if(!this->has_met_before + && subaddie_playerIsWithinSphereAndActive(this, 400) + && !subaddie_playerIsWithinSphereAndActive(this, 50)) + { + if(this->actorTypeSpecificField == 1 + && !fileProgressFlag_get(FILEPROG_31_MM_OPEN) + && level_get() == LEVEL_6_LAIR) + { + podium_text_id = fileProgressFlag_get(FILEPROG_A7_NEAR_PUZZLE_PODIUM_TEXT) ? + VER_SELECT(ASSET_F80_DIALOG_BOTTLES_MM_ENTRANCE_BEFORE_OPENING_AFTER_PODIUM, 0x0AE6, 0, 0) : VER_SELECT(ASSET_F7F_DIALOG_BOTTLES_MM_ENTRANCE_BEFORE_OPENING_BEFORE_PODIUM, 0x0AE5, 0, 0); + if(gcdialog_showDialog(podium_text_id, 0, 0, 0, 0, 0)){ + this->has_met_before = TRUE; } } - else if(func_803616F0(this)){ - sp28 = (volatileFlag_get(VOLATILE_FLAG_16)?0xf6e:0xf68) + this->actorTypeSpecificField - 1; - if(!volatileFlag_get(VOLATILE_FLAG_16) && level_get() == LEVEL_6_LAIR){ - this->has_met_before = true; + else if(lairBottlesDialog_levelOpenedAndNotLearnedAllMoves(this)){ + didnt_learn_moves_text_id = (volatileFlag_get(VOLATILE_FLAG_16) ? VER_SELECT(ASSET_F6E_DIALOG_DIDNT_LEARN_ALL_MOVES_FROM_MM, 0xAD4, 0, 0) : VER_SELECT(ASSET_F68_DIALOG_MM_THREE_NEW_MOVES_TO_LEARN, 0x0ACE, 0, 0)) + this->actorTypeSpecificField - 1; + if(!volatileFlag_get(VOLATILE_FLAG_16) + && level_get() == LEVEL_6_LAIR) + { + this->has_met_before = TRUE; } - else{ - if(gcdialog_showDialog(sp28, 0, 0, 0, 0, 0)){ - this->has_met_before = true; + else{ + if(gcdialog_showDialog(didnt_learn_moves_text_id, 0, 0, 0, 0, 0)) + { + this->has_met_before = TRUE; volatileFlag_set(VOLATILE_FLAG_16, 0); } } diff --git a/src/core2/anim/anim_sequencehandler.c b/src/core2/anim/anim_sequencehandler.c index f82bb92a9..77a79ed2d 100644 --- a/src/core2/anim/anim_sequencehandler.c +++ b/src/core2/anim/anim_sequencehandler.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_DAAA0.c #include #include "core1/core1.h" #include "functions.h" diff --git a/src/core2/anim/anim_cache.c b/src/core2/anim/animcache.c similarity index 98% rename from src/core2/anim/anim_cache.c rename to src/core2/anim/animcache.c index b617f2341..ee7d459d5 100644 --- a/src/core2/anim/anim_cache.c +++ b/src/core2/anim/animcache.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/animcache.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/anim/anim_texturecache.c b/src/core2/anim/animtexturecache.c similarity index 98% rename from src/core2/anim/anim_texturecache.c rename to src/core2/anim/animtexturecache.c index 306efc82c..268aa0270 100644 --- a/src/core2/anim/anim_texturecache.c +++ b/src/core2/anim/animtexturecache.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/animtexturecache.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/anim/sequence.c b/src/core2/anim/anseq.c similarity index 99% rename from src/core2/anim/sequence.c rename to src/core2/anim/anseq.c index b686aaba4..cd53ced72 100644 --- a/src/core2/anim/sequence.c +++ b/src/core2/anim/anseq.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/anseq.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/anim/anim_sequencestruct.c b/src/core2/anim/betavent.c similarity index 88% rename from src/core2/anim/anim_sequencestruct.c rename to src/core2/anim/betavent.c index 197d87cd7..823d85860 100644 --- a/src/core2/anim/anim_sequencestruct.c +++ b/src/core2/anim/betavent.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/ch/betavent.c #include #include "core1/core1.h" #include "functions.h" @@ -8,22 +9,22 @@ typedef struct { f32 unk4; } ActorLocal_Core2_DA3A0; -void func_8036158C(Actor *this); +void chBetaVent_update(Actor *this); /* .data */ u8 D_80373130[] = {0, 1, 0, 0}; -ActorInfo D_80373134 = { - 0x1a6, 0x289, 0x431, +ActorInfo chBetaVent1 = { + MARKER_1A6_BETA_VENT, ACTOR_289_BETA_VENT, ASSET_431_MODEL_BETA_VENT, 0x0, NULL, - func_8036158C, NULL, actor_draw, + chBetaVent_update, NULL, actor_draw, 0, 0, 0.0f, 0 }; -ActorInfo D_80373158 = { - 0x1a6, 0x28f, 0x431, +ActorInfo chBetaVent2 = { + MARKER_1A6_BETA_VENT, ACTOR_28F_BETA_VENT, ASSET_431_MODEL_BETA_VENT, 0x0, NULL, - func_8036158C, NULL, actor_draw, + chBetaVent_update, NULL, actor_draw, 0, 0, 0.0f, 0 }; @@ -76,7 +77,7 @@ void func_80361330(Actor *this, s32 next_state){ this->state = next_state; } -void func_8036158C(Actor *this){ +void chBetaVent_update(Actor *this){ ActorLocal_Core2_DA3A0 *local = (ActorLocal_Core2_DA3A0 *)&this->local; f32 sp30; f32 sp24[3]; diff --git a/src/core2/anim/bonetransformlist.c b/src/core2/anim/bonetransformlist.c index 011bc75a4..1465fbc12 100644 --- a/src/core2/anim/bonetransformlist.c +++ b/src/core2/anim/bonetransformlist.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_B3580.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/anim/anim_spriteframe.c b/src/core2/anim/chumpfish.c similarity index 99% rename from src/core2/anim/anim_spriteframe.c rename to src/core2/anim/chumpfish.c index 92872bd6c..ca6bdc710 100644 --- a/src/core2/anim/anim_spriteframe.c +++ b/src/core2/anim/chumpfish.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/ch/chumpfish.c #include #include "functions.h" #include "variables.h" @@ -27,7 +28,7 @@ ActorAnimationInfo D_80372EA0[] = { {0x2C0, 1.5f} }; -ActorInfo D_80372EE0 = { +ActorInfo chChumpFish = { MARKER_69_CHUMP_FISH, ACTOR_A_CHUMP_FISH, ASSET_36B_CHUMP_FISH, 0x2, D_80372EA0, chchumpfish_update, actor_update_func_80326224, actor_draw, diff --git a/src/core2/anim/skeletal.c b/src/core2/anim/skeletalanim.c similarity index 99% rename from src/core2/anim/skeletal.c rename to src/core2/anim/skeletalanim.c index 04cbd309f..493db4e50 100644 --- a/src/core2/anim/skeletal.c +++ b/src/core2/anim/skeletalanim.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/skeletalanim.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/anim/sprite.c b/src/core2/anim/sprite.c index eb0542a28..778bbd349 100644 --- a/src/core2/anim/sprite.c +++ b/src/core2/anim/sprite.c @@ -3,11 +3,11 @@ #include "functions.h" #include "variables.h" +#include "checksums.h" /* .bss */ -u8 D_80379B90[0x10]; static AnimSprite s_animsprite_list[40]; /* .code */ diff --git a/src/core2/ba/ba_anim.c b/src/core2/ba/anim.c similarity index 98% rename from src/core2/ba/ba_anim.c rename to src/core2/ba/anim.c index 560822412..6c639148d 100644 --- a/src/core2/ba/ba_anim.c +++ b/src/core2/ba/anim.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/ba/anim.c #include #include "functions.h" #include "variables.h" @@ -131,10 +132,10 @@ void __baanim_applyBottlesBonus(uintptr_t arg0, uintptr_t arg1) { baanim_applyBottlesBonusMask(arg0, mask); if ((mask & BAANIM_WISHYWASHY) && (player_getTransformation() == TRANSFORM_1_BANJO)) { - func_8028FB88(TRANSFORM_7_WISHWASHY); + player_transform(TRANSFORM_7_WISHWASHY); } if (!(mask & BAANIM_WISHYWASHY) && (player_getTransformation() == TRANSFORM_7_WISHWASHY)) { - func_8028FB88(TRANSFORM_1_BANJO); + player_transform(TRANSFORM_1_BANJO); } if (baAnimModifyFunction != NULL) { baAnimModifyFunction(arg0, arg1); @@ -236,7 +237,7 @@ void baanim_setUpdateType(enum baanim_update_type_e arg0){ void baanim_80289F30(void){ f32 sp1C[3]; - _player_getPosition(sp1C); + playerPosition_get(sp1C); anctrl_drawSetup(playerAnimCtrl, sp1C, 1); } diff --git a/src/core2/ba/ba_animcache.c b/src/core2/ba/ba_animcache.c index ee2f4f126..feebc996a 100644 --- a/src/core2/ba/ba_animcache.c +++ b/src/core2/ba/ba_animcache.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_1550.c /** * @file anim/commoncache.c * @brief This file controls a cache of common animations consisting of diff --git a/src/core2/ba/ba_animstate.c b/src/core2/ba/ba_animstate.c deleted file mode 100644 index 9b5527b17..000000000 --- a/src/core2/ba/ba_animstate.c +++ /dev/null @@ -1,197 +0,0 @@ -#include -#include "functions.h" -#include "variables.h" - -void func_8029E070(bool); -void func_8029E064(bool); -void func_8029E058(bool); -void func_8029E0C4(f32); -void func_8029E0D0(f32); -void func_8029E0DC(bool); -void func_8029E0F4(bool); -void func_8029E0E8(bool); - -/* .bss */ -f32 D_8037D230; -u8 D_8037D234; -u8 D_8037D235; -u8 D_8037D236; -u8 D_8037D237; -u8 D_8037D238; -u8 D_8037D239; -u8 D_8037D23A; -f32 D_8037D23C; -f32 D_8037D240; - -/* .code */ -void func_8029DBF0(void){ - s32 temp_s0; - switch(baModel_getModelId()){ - case ASSET_34D_MODEL_BANJOKAZOOIE_LOW_POLY: //L8029DC24 - case ASSET_34E_MODEL_BANJOKAZOOIE_HIGH_POLY: //L8029DC24 - temp_s0 = (s32) ml_interpolate_f(D_8037D23C, 1.0f, 8.0f); - func_8033A45C(0x1B, temp_s0); - func_8033A45C(0x1D, temp_s0); - func_8033A45C(0x1F, temp_s0); - func_8033A45C(0x21, temp_s0); - temp_s0 = (s32) ml_interpolate_f(D_8037D240, 1.0f, 8.0f); - func_8033A45C(0x1A, temp_s0); - func_8033A45C(0x1C, temp_s0); - func_8033A45C(0x1E, temp_s0); - func_8033A45C(0x20, temp_s0); - break; - - case ASSET_34F_MODEL_BANJO_TERMITE: //L8029DCCC - case ASSET_359_MODEL_BANJO_WALRUS: //L8029DCCC - case ASSET_36F_MODEL_BANJO_PUMPKIN: //L8029DCCC - case ASSET_374_MODEL_BANJO_CROC: //L8029DCCC - func_8033A45C(0x1B, (s32) ml_interpolate_f(D_8037D23C, 1.0f, 6.0f)); - func_8033A45C(0x1A, (s32) ml_interpolate_f(D_8037D240, 1.0f, 6.0f)); - break; - - case ASSET_356_MODEL_BANJO_WISHYWASHY: //L8029DD2C - func_8033A45C(1, (s32) ml_interpolate_f(D_8037D240, 1.0f, 4.0f)); - break; - } -} - -void func_8029DD6C(void) { - s32 temp_s0; // [port] must hold values > 1 for geo selector branches - - modelRender_func_8033A1FC(); - switch (baModel_getModelId()) { - case ASSET_34D_MODEL_BANJOKAZOOIE_LOW_POLY: - case ASSET_34E_MODEL_BANJOKAZOOIE_HIGH_POLY: - func_8033A45C(1, D_8037D238); - func_8033A45C(9, D_8037D238); - func_8033A45C(0xC, D_8037D238); - func_8033A45C(0xF, D_8037D238); - func_8033A45C(2, D_8037D236); - func_8033A45C(0xA, D_8037D236); - func_8033A45C(0xD, D_8037D236); - func_8033A45C(0x10, D_8037D236); - func_8033A45C(8, D_8037D235); - func_8033A45C(0xB, D_8037D235); - func_8033A45C(0xE, D_8037D235); - func_8033A45C(0x11, D_8037D235); - temp_s0 = D_8037D237 + 1; - func_8033A45C(0x12, temp_s0); - func_8033A45C(0x14, temp_s0); - func_8033A45C(0x16, temp_s0); - func_8033A45C(0x18, temp_s0); - func_8033A45C(0x13, temp_s0); - func_8033A45C(0x15, temp_s0); - func_8033A45C(0x17, temp_s0); - func_8033A45C(0x19, temp_s0); - temp_s0 = D_8037D239 + 1; - func_8033A45C(0x22, temp_s0); - func_8033A45C(0x24, temp_s0); - func_8033A45C(0x26, temp_s0); - func_8033A45C(0x28, temp_s0); - func_8033A45C(0x23, temp_s0); - func_8033A45C(0x25, temp_s0); - func_8033A45C(0x27, temp_s0); - func_8033A45C(0x29, temp_s0); - break; - case ASSET_359_MODEL_BANJO_WALRUS: - func_8033A45C(3, D_8037D23A); - break; - case ASSET_374_MODEL_BANJO_CROC: - temp_s0 = D_8037D237 + 1; - func_8033A45C(4, temp_s0); - func_8033A45C(5, temp_s0); - func_8033A45C(6, temp_s0); - func_8033A45C(7, temp_s0); - break; - } - func_8029DBF0(); -} - -bool func_8029DFA4(void){ - return D_8037D235; -} - -bool func_8029DFB0(void){ - return D_8037D236; -} - -bool func_8029DFBC(void){ - return D_8037D238; -} - -f32 func_8029DFC8(void){ - return D_8037D23C; -} - -f32 func_8029DFD4(void){ - return D_8037D240; -} - -bool func_8029DFE0(void){ - return D_8037D237; -} - -bool func_8029DFEC(void){ - return D_8037D239; -} - -void func_8029DFF8(void) { - func_8029E070(0); - func_8029E064(0); - func_8029E058(0); - func_8029E0C4(0.0f); - func_8029E0D0(0.0f); - func_8029E0DC(0); - func_8029E0F4(0); - func_8029E0E8(0); - CALL_EVENT(OnPlayerAnimReset); -} - -void func_8029E058(bool arg0){ - D_8037D235 = arg0; -} - -void func_8029E064(bool arg0){ - D_8037D236 = arg0; -} - -void func_8029E070(bool arg0) { - func_8029E090(arg0, 0.0f); -} - -void func_8029E090(bool arg0, f32 arg1) { - D_8037D230 = arg1; - D_8037D234 = arg0; - if (arg1 == 0.0f) { - D_8037D238 = arg0; - } -} - -void func_8029E0C4(f32 arg0){ - D_8037D23C = arg0; -} - -void func_8029E0D0(f32 arg0){ - D_8037D240 = arg0; -} - -void func_8029E0DC(bool arg0){ - D_8037D237 = arg0; -} - -void func_8029E0E8(bool arg0){ - D_8037D23A = arg0; -} - -void func_8029E0F4(bool arg0){ - D_8037D239 = arg0; -} - -void func_8029E100(void) { - if (D_8037D230 != 0.0f) { - D_8037D230 -= time_getDelta(); - if (D_8037D230 <= 0.0f) { - D_8037D238 = D_8037D234; - } - } -} diff --git a/src/core2/ba/ba_camera.c b/src/core2/ba/ba_camera.c index 71bf5d378..d91fcd45b 100644 --- a/src/core2/ba/ba_camera.c +++ b/src/core2/ba/ba_camera.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_9BD0.c #include #include "functions.h" #include "variables.h" @@ -112,7 +113,7 @@ int func_80290E8C(void){ ncDynamicCamera_setState(3); func_80291488(0xB); if( gsworld_getMap() == MAP_B_CC_CLANKERS_CAVERN - && player_getYPosition() < 1201.0f + && playerPosition_getY() < 1201.0f ){ func_802C1B20(1100.0f); } diff --git a/src/core2/ba/ba_eyeblink_data.c b/src/core2/ba/ba_eyeblink_data.c index 0c959a60f..7d4179659 100644 --- a/src/core2/ba/ba_eyeblink_data.c +++ b/src/core2/ba/ba_eyeblink_data.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_90E0.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/ba/ba_eyemouth_data.c b/src/core2/ba/ba_eyemouth_data.c index 4d9c9b6f7..bbc2c81ca 100644 --- a/src/core2/ba/ba_eyemouth_data.c +++ b/src/core2/ba/ba_eyemouth_data.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_400F0.c #include #include "functions.h" #include "variables.h" @@ -101,16 +102,16 @@ void func_802C71F0(Actor *actor){ case 0x8E: case 0xAC: case 0xB8://L802C7254 - func_8033A45C(0x1, (s32)ml_interpolate_f(local->unk0[0], 1.0f, 6.0f)); - func_8033A45C(0x2, (s32)ml_interpolate_f(local->unk0[1], 1.0f, 6.0f)); + modelRender_setAppendageVisibility(0x1, (s32)ml_interpolate_f(local->unk0[0], 1.0f, 6.0f)); + modelRender_setAppendageVisibility(0x2, (s32)ml_interpolate_f(local->unk0[1], 1.0f, 6.0f)); break; case 0x195: case 0x196: case 0x197://L802C72B0 case 0x2FB://L802C72B4 - func_8033A45C(0x1C, (s32)ml_interpolate_f(local->unk0[0], 1.0f, 8.0f)); - func_8033A45C(0x1D, (s32)ml_interpolate_f(local->unk0[1], 1.0f, 8.0f)); + modelRender_setAppendageVisibility(0x1C, (s32)ml_interpolate_f(local->unk0[0], 1.0f, 8.0f)); + modelRender_setAppendageVisibility(0x1D, (s32)ml_interpolate_f(local->unk0[1], 1.0f, 8.0f)); break; } } diff --git a/src/core2/ba/ba_falling.c b/src/core2/ba/ba_falling.c index 4c7df9dc4..ed93cf78f 100644 --- a/src/core2/ba/ba_falling.c +++ b/src/core2/ba/ba_falling.c @@ -1,8 +1,8 @@ +// BanjoDecomp: core2/code_C97F0.c #include #include "core1/core1.h" #include "functions.h" #include "variables.h" - #include "port/Interpolation/FrameInterpolation.h" @@ -211,7 +211,7 @@ void func_80350CA4(void) { sp24[0] = sp30[0] + sp48[0]; sp24[1] = sp30[1] + sp48[1]; sp24[2] = sp30[2] + sp48[2]; - if (func_8028F170()) { // [port] decomp passed sp48[1],sp48[2] but actual def is (void) + if (player_isInFirstPersonView()) { // [port] decomp passes sp48[1],sp48[2]; actual def takes none var_v0 = func_80320B98(sp30, sp24, sp3C, 0x01000000); } else { var_v0 = func_80309B48(sp30, sp24, sp3C, 0x01000000); diff --git a/src/core2/ba/ba_health.c b/src/core2/ba/ba_health.c index 0e8864f5d..31f21e56f 100644 --- a/src/core2/ba/ba_health.c +++ b/src/core2/ba/ba_health.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_9290.c #include #include "functions.h" #include "variables.h" @@ -15,7 +16,7 @@ void func_80290220(void){ D_8037C010 = D_8037C014 = -1; D_8037C02C = 0; D_8037C018 = -1; - _player_getPosition(D_8037C020); + playerPosition_get(D_8037C020); } void func_8029026C(s32 arg0, s32 arg1){ @@ -36,7 +37,7 @@ void func_80290298(void) { sp30 = (func_8028B528() && !is_pumpkin) ? 6 : 1; sp24 = func_8028B528() && !is_pumpkin; if (D_8037C02C || player_isStable() || sp24 || player_movementGroup() == BSGROUP_5_CLIMB || bs_getState() == BS_B_UNKOWN) { - _player_getPosition(D_8037C020); + playerPosition_get(D_8037C020); } if (player_movementGroup() == BSGROUP_A_FLYING) { diff --git a/src/core2/ba/ba_hitbox.c b/src/core2/ba/ba_hitbox.c index 56c0c35a0..74f7889f0 100644 --- a/src/core2/ba/ba_hitbox.c +++ b/src/core2/ba/ba_hitbox.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_6B30.c #include #include "functions.h" #include "variables.h" @@ -36,19 +37,19 @@ enum hitbox_e hitbox_getHitboxForActor(ActorMarker *arg0){ switch(bs_getState()){ case BS_F_BBUSTER: //8028DBA4 - return __maybe(bsbbuster_hitboxActive(),HITBOX_1_BEAK_BUSTER); + return __maybe(bsbbuster_hitboxActive(), HITBOX_1_BEAK_BUSTER); break; - case BS_BBARGE://8028DBC0 - return __maybe(bsbbarge_hitboxActive(),HITBOX_2_BEAK_BARGE); + case BS_13_BBARGE://8028DBC0 + return __maybe(bsbbarge_hitboxActive(), HITBOX_2_BEAK_BARGE); break; - case BS_BOMB://8028DBDC - return __maybe(bsbfly_bombHitboxActive(),HITBOX_3_BEAK_BOMB); + case BS_2A_BOMB://8028DBDC + return __maybe(bsbfly_bombHitboxActive(), HITBOX_3_BEAK_BOMB); break; - case BS_CLAW://8028DBF8 + case BS_6_CLAW://8028DBF8 if(arg0 && !func_8028AED4(marker_getActor(arg0)->position, 90.0f)) return HITBOX_0_NONE; - retVal = __maybe(bsclaw_hitboxActive(),HITBOX_4_CLAW); + retVal = __maybe(bsclaw_hitboxActive(), HITBOX_4_CLAW); if(retVal != 0) return retVal; return HITBOX_8_CLAW_DOWN; @@ -68,7 +69,7 @@ enum hitbox_e hitbox_getHitboxForActor(ActorMarker *arg0){ return HITBOX_6_WONDERWING; break; //8028DCA0 - case BS_ROLL: + case BS_31_ROLL: return __maybe(bstwirl_hitboxActive(),HITBOX_7_ROLL); break; case BS_6E_CROC_BITE://L8028DCBC diff --git a/src/core2/ba/ba_intensity.c b/src/core2/ba/ba_intensity.c index a09751769..bb0f5d7d7 100644 --- a/src/core2/ba/ba_intensity.c +++ b/src/core2/ba/ba_intensity.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_A600.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/ba/ba_lookdir.c b/src/core2/ba/ba_lookdir.c index 9200a4068..c9c114fe0 100644 --- a/src/core2/ba/ba_lookdir.c +++ b/src/core2/ba/ba_lookdir.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_7060.c #include #include "functions.h" #include "variables.h" @@ -11,10 +12,10 @@ #include "core2/snackerctl.h" -extern int player_isInHorizontalRadius(f32[3], f32); +extern bool player_isInHorizontalRadius(f32[3], f32); extern bool player_isInVerticalRange(f32[3], f32); extern void func_80295A8C(void); -extern void climbSet(f32[3], f32[3], f32, u32); +extern void climb_set(f32[3], f32[3], f32, u32); extern void func_80296C90(f32); extern void func_80296C9C(f32); extern void func_8029B73C(f32 arg0[3], f32 arg1, f32 arg2, f32 arg3, f32 arg4); @@ -185,10 +186,10 @@ void func_8028E4B0(void) { D_8037BFBA = true; D_8037BFB9 = false; - func_80295914(); + bsmethods_reset(); sp20 = gsworld_getExit(); D_8037BFB8 = 0; - player_setPosition(D_803636C0); + playerPosition_set(D_803636C0); if (volatileFlag_get(VOLATILE_FLAG_E) || func_802D686C() || (sp20 == 0x65)){ return; } @@ -270,7 +271,7 @@ u32 player_getTransformation(void){ } void func_8028E7EC(f32 arg0[3]){ - climbGetBottom(arg0); + climb_getBottom(arg0); } f32 player_stateTimer_get(enum state_timer_e timer_id){ @@ -285,14 +286,14 @@ void func_8028E84C(f32 arg0[3]){ func_80294480(arg0); } -ActorMarker *func_8028E86C(void){ - return bacarry_get_marker(); +ActorMarker *bacarry_getMarkerWithExtraSteps(void){ + return bacarry_getMarker(); } -enum marker_e bacarry_get_markerId(void){ +enum marker_e bacarry_getMarkerId(void){ ActorMarker *marker; - marker = bacarry_get_marker(); + marker = bacarry_getMarker(); if(marker){ return marker->id; } @@ -303,7 +304,7 @@ enum actor_e carriedObj_getActorId(void){ ActorMarker *marker; Actor *actor; - marker = bacarry_get_marker(); + marker = bacarry_getMarker(); if(marker != NULL){ actor = marker_getActor(marker); @@ -333,7 +334,7 @@ f32 func_8028E984(void){ } void player_getPosition(f32 dst[3]){ - _player_getPosition(dst); + playerPosition_get(dst); } void func_8028E9C4(s32 arg0, f32 arg1[3]) { @@ -355,7 +356,7 @@ void func_8028E9C4(s32 arg0, f32 arg1[3]) { break; case 5: //L8028EA2C - _player_getPosition(arg1); + playerPosition_get(arg1); switch(bsStoredState_getTransformation()){ case TRANSFORM_3_PUMPKIN: //L8028EA68 if(gsworld_getMap() == MAP_1B_MMM_MAD_MONSTER_MANSION){ @@ -397,12 +398,12 @@ void func_8028E9C4(s32 arg0, f32 arg1[3]) { } -void player_getPosition_s32(s32 arg0[3]){ +void player_getPosition_s32(s32 position_s32[3]){ f32 plyr_pos[3]; player_getPosition(plyr_pos); - arg0[0] = (s32)plyr_pos[0]; - arg0[1] = (s32)plyr_pos[1]; - arg0[2] = (s32)plyr_pos[2]; + position_s32[0] = (s32)plyr_pos[0]; + position_s32[1] = (s32)plyr_pos[1]; + position_s32[2] = (s32)plyr_pos[2]; } f32 player_getYaw(void){ @@ -431,7 +432,7 @@ f32 func_8028EC64(f32 arg0[3]){ f32 sp1C; f32 sp18; func_80293D2C(&sp18, &sp1C); - _player_getPosition(arg0); + playerPosition_get(arg0); arg0[1] += sp18; return sp1C; } @@ -466,7 +467,7 @@ enum bsgroup_e player_movementGroup(void) { case BS_E_OW: //L8028EE00 case BS_34_JIG_NOTEDOOR: //L8028EE00 case BS_3C_TALK: //L8028EE00 - case BS_3F: //L8028EE00 + case BS_3F_UNKNOWN: //L8028EE00 case BS_41_DIE: //L8028EE00 case BS_44_JIG_JIGGY: //L8028EE00 return BSGROUP_1_INTR; @@ -548,7 +549,7 @@ f32 func_8028EF88(void){ if(floor_isCurrentFloorunk59()){ return floor_getCurrentFloorYPosition(); } - return player_getYPosition(); + return playerPosition_getY(); } bool func_8028EFC8(void){ @@ -559,15 +560,15 @@ bool func_8028EFEC(void){ return bakey_getAndSetState(BUTTON_A, 2); } -void func_8028F010(enum actor_e actor_id){ +void bacarriedobj_decWithExtraSteps(enum actor_e actor_id){ bacarriedobj_dec(actor_id); } -void func_8028F030(enum actor_e actor_id){ +void bacarriedobj_incWithExtraSteps(enum actor_e actor_id){ bacarriedobj_inc(actor_id); } -void func_8028F050(enum actor_e actor_id){ +void bacarriedobj_displayOnHudWithExtraSteps(enum actor_e actor_id){ bacarriedobj_displayOnHud(actor_id); } @@ -588,7 +589,7 @@ bool func_8028F098(void){ } } -bool func_8028F0D4(void){ +bool player_isBanjoOrWishywashy(void){ enum transformation_e xform_id; xform_id = bsStoredState_getTransformation(); @@ -608,11 +609,11 @@ bool func_8028F150(void){ return baModel_isVisible(); } -bool func_8028F170(void){ +bool player_isInFirstPersonView(void){ return baflag_isTrue(BA_FLAG_17_FIRST_PERSON_VIEW); } -int ability_isUnlocked(enum ability_e uid){ +bool ability_isUnlocked(enum ability_e uid){ return ability_hasLearned(uid); } @@ -628,7 +629,7 @@ bool func_8028F1E0(void){ return bsList_getInterruptMethod(bs_getState()) != NULL; } -bool func_8028F20C(void){ +bool player_isStableWithExtraSteps(void){ return player_isStable(); } @@ -776,7 +777,7 @@ void player_stateTimer_set(enum state_timer_e timer_id, f32 value){ } void player_setClimbParams(f32 bottom[3], f32 top[3], f32 radius, u32 arg3){ - climbSet(bottom, top, radius, arg3); + climb_set(bottom, top, radius, arg3); } void func_8028F760(s32 arg0, f32 arg1, f32 arg2){ @@ -884,7 +885,7 @@ void func_8028FA74(f32 dst[3]){ f32 plyr_pos[3]; f32 sp18[3]; - _player_getPosition(plyr_pos); + playerPosition_get(plyr_pos); playerPosition_getOffset(sp18); ml_vec3f_add(dst, plyr_pos, sp18); } @@ -893,7 +894,7 @@ void func_8028FAB0(f32 arg0[3]){ f32 plyr_pos[3]; f32 diff[3]; - _player_getPosition(plyr_pos); + playerPosition_get(plyr_pos); ml_vec3f_diff_copy(diff, arg0, plyr_pos); playerPosition_setOffset(diff); } @@ -916,7 +917,7 @@ void func_8028FB68(void){ func_80295D74(); } -bool func_8028FB88(enum transformation_e xform_id) { +bool player_transform(enum transformation_e xform_id) { if (wishyWashyFlag_get() && xform_id == TRANSFORM_1_BANJO) { xform_id = TRANSFORM_7_WISHWASHY; } @@ -935,7 +936,7 @@ bool func_8028FBD4(f32 arg0[3]) { } bool player_throwCarriedObject(void){ - if (func_8028E86C() && bscarry_inSet(bs_getState())) { + if (bacarry_getMarkerWithExtraSteps() && bscarry_inSet(bs_getState())) { return bs_checkInterrupt(BS_INTR_16_THROW_CARRIED_OBJ) == 2; } diff --git a/src/core2/ba/ba_momentum.c b/src/core2/ba/ba_momentum.c index 8d005015a..1ba3f16cf 100644 --- a/src/core2/ba/ba_momentum.c +++ b/src/core2/ba/ba_momentum.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_9450.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/ba/ba_musicstate.c b/src/core2/ba/ba_musicstate.c index 825ff4e2c..b6dcfd3bf 100644 --- a/src/core2/ba/ba_musicstate.c +++ b/src/core2/ba/ba_musicstate.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_9A9D0.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/ba/ba_recoil.c b/src/core2/ba/ba_recoil.c index db60a03ea..ed23a9804 100644 --- a/src/core2/ba/ba_recoil.c +++ b/src/core2/ba/ba_recoil.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_D9B0.c #include #include "functions.h" #include "variables.h" @@ -101,7 +102,7 @@ void func_80294B00(int arg0){ } void func_80294B0C(void){ - f32 sp1C = player_getYPosition(); + f32 sp1C = playerPosition_getY(); enum bsgroup_e player_movement_group = player_movementGroup(); if( player_isStable() || player_inWater() @@ -173,12 +174,12 @@ void func_80294BDC(void) { void func_80294DD8(void){ ml_vec3f_clear(D_8037C2A0); ml_vec3f_clear(D_8037C2B0); - _player_getPosition(D_8037C2D8); + playerPosition_get(D_8037C2D8); D_8037C2ED = 0; D_8037C2E4 = 0.0f; D_8037C2EC = 1; D_8037C2F0.unk8 = 0; - D_8037C2F0.unk4 = D_8037C2F0.unk0 = player_getYPosition(); + D_8037C2F0.unk4 = D_8037C2F0.unk0 = playerPosition_getY(); } void func_80294E54(int arg0){ @@ -187,7 +188,7 @@ void func_80294E54(int arg0){ void func_80294E60(void){ if(player_isStable()){ - _player_getPosition(D_8037C2D8); + playerPosition_get(D_8037C2D8); } if(player_isStable() || bsclimb_inSet(bs_getState())){ diff --git a/src/core2/ba/ba_state.c b/src/core2/ba/ba_state.c deleted file mode 100644 index 43a6c6abe..000000000 --- a/src/core2/ba/ba_state.c +++ /dev/null @@ -1,331 +0,0 @@ -#include -#include "functions.h" -#include "variables.h" -#include "bsint.h" -#include "bs_funcs.h" -#include "core2/statetimer.h" -#include "core2/ba/physics.h" -#include "core2/snackerctl.h" - -u8 D_80363820 = 0; -bsMap D_80363824[] ={ - {BS_1_IDLE, bsstand_init, bsstand_update, bsstand_end, func_802B5350}, - {BS_2_WALK_SLOW, bswalk_slow_init, bswalk_slow_upate, NULL, func_802B5350}, - {BS_WALK, bswalk_init, bswalk_update, NULL, func_802B5350}, - {BS_4_WALK_FAST, bswalk_fast_init, bswalk_fast_update, bswalk_fast_end, func_802B5350}, - {BS_5_JUMP, bsjump_init, bsjump_update, bsjump_end, func_80296608}, - {BS_CLAW, bsclaw_init, bsclaw_update, bsclaw_end, func_80296608}, - {BS_CROUCH, bscrouch_init, bscrouch_update, bscrouch_end, func_802B5350}, - {BS_8_BTROT_JUMP, bsbtrot_jump_init, bsbtrot_jump_update,bsbtrot_jump_end, func_802B5350}, - {BS_SKID, bsturn_init, bsturn_update, bsturn_end, func_802B5350}, - {BS_D_TIMEOUT, func_802B63F8, func_802B64D0, func_802B6500, func_80296590}, - {BS_E_OW, bsow_init, bsow_update, bsow_end, func_80296590}, - {BS_F_BBUSTER, bsbbuster_init, bsbbuster_update, bsbbuster_end, func_80296608}, - {BS_BFLAP, bsbflap_init, bsbflap_update, bsbflap_end, func_80296608}, - {BS_11_BPECK, bsbpeck_init, bsbpeck_update, bsbpeck_end, func_80296608}, - {BS_12_BFLIP, bsbflip_init, bsbflip_update, bsbflip_end, func_80296608}, - {BS_BBARGE, bsbarge_init, bsbarge_update, bsbarge_end, func_80296608}, - {BS_14_BTROT_ENTER, bsbtrot_enter_init, bsbtrot_enter_update, bsbtrot_enter_end, func_802B5350}, - {BS_15_BTROT_IDLE, bsbtrot_stand_init, bsbtrot_stand_update, bsbtrot_stand_end, func_802B5350}, - {BS_16_BTROT_WALK, bsbtrot_walk_init, bsbtrot_walk_update, bsbtrot_walk_end, func_802B5350}, - {BS_17_BTROT_EXIT, bsbtrot_exit_init, bsbtrot_exit_update, bsbtrot_exit_end, func_802B5350}, - {BS_18_FLY_KNOCKBACK, func_802A4D90, func_802A4EC8, func_802A4F44, func_80296608}, - {BS_1A_WONDERWING_ENTER, bsbwhirl_enter_init, bsbwhirl_enter_update, bsbwhirl_enter_end, func_80296608}, - {BS_1B_WONDERWING_IDLE, bsbwhirl_stand_init, bsbwhirl_stand_update, bsbwhirl_stand_end, func_80296608}, - {BS_1C_WONDERWING_WALK, bsbwhirl_walk_init, bsbwhirl_walk_update, bsbwhirl_walk_end, func_80296608}, - {BS_1D_WONDERWING_JUMP, bsbwhirl_jump_init, bsbwhirl_jump_update, bsbwhirl_jump_end, func_80296608}, - {BS_1E_WONDERWING_EXIT, bsbwhirl_exit_init, bsbwhirl_exit_update, bsbwhirl_exit_end, func_80296608}, - {BS_9_EGG_HEAD, bsegghead_init, bsegghead_update, bsegghead_end, func_802B5350}, - {BS_A_EGG_ASS, bseggass_init, bseggass_update, bseggass_end, func_802B5350}, - {BS_WALK_CREEP, bswalk_creep_init, bswalk_creep_update, NULL, func_802B5350}, - {BS_20_LANDING, bsstand_landing_init, bsstand_landing_update, NULL, func_802B5350}, - {BS_BSHOCK_CHARGE, bsbshock_charge_init, bsbshock_charge_update, bsbshock_charge_end, func_80296608}, - {BS_BSHOCK_JUMP, bsbshock_init, bsbshock_update, bsbshock_end, func_80296608}, - {BS_23_FLY_ENTER, bsbfly_enter_init, bsbfly_enter_update, bsbfly_enter_end, func_802A505C}, - {BS_24_FLY, bsbfly_init, bsbfly_update, func_802A3F70, func_802A505C}, - {BS_25_LONGLEG_ENTER, bsblongleg_enter_init, bsblongleg_enter_update, bsblongleg_enter_end, func_802B5350}, - {BS_26_LONGLEG_IDLE, bsblongleg_stand_enter, bsblongleg_stand_update, bsblongleg_stand_end, func_802B5350}, - {BS_LONGLEG_WALK, bsblongleg_walk_init, bsblongleg_walk_update, bsblongleg_walk_end, func_802B5350}, - {BS_LONGLEG_JUMP, bsblongleg_jump_init, bsblongleg_jump_update, bsblongleg_jump_end, func_80296608}, - {BS_LONGLEG_EXIT, bsblongleg_exit_init, bsblongleg_exit_update, bsblongleg_exit_end, func_802B5350}, - {BS_BOMB, func_802A3F9C, func_802A411C, func_802A4404, func_802A505C}, - {BS_2B_DIVE_IDLE, func_802A762C, func_802A7674, func_802A7718, func_80296608}, - {BS_2C_DIVE_B, func_802A7738, func_802A7838, func_802A7A2C, func_80296608}, - {BS_2D_SWIM_IDLE, bsswim_idle_init, bsswim_idle_update, bsswim_idle_end, func_80296608}, - {BS_2E_SWIM, bsswim_swim_init, bsswim_swim_update, bsswim_swim_end, func_80296608}, - {BS_2F_FALL, bsjump_fall_init, bsjump_fall_update, bsjump_fall_end, func_80296608}, - {BS_30_DIVE_ENTER, bsSwim_dive_init, func_802A7E2C, func_802A7F4C, func_80296608}, - {BS_ROLL, bstwirl_init, bstwirl_update, bstwirl_end, func_802B5350}, - {BS_SLIDE, bsslide_init, bsslide_update, bsslide_end, func_802B5350}, - {0x33, func_802B9ACC, func_802B9B14, func_802B9AAC, func_802B9D00}, - {BS_34_JIG_NOTEDOOR, bsjig_notedoor_init, bsjig_notedoor_update, bsjig_notedoor_end, func_80296590}, - {BS_35_ANT_IDLE, bsant_idle_init, bsant_idle_update, bsant_idle_end, func_802B5350}, - {BS_ANT_WALK, bsant_walk_init, bsant_walk_update, bsant_walk_end, func_802B5350}, - {BS_ANT_JUMP, bsant_jump_init, bsant_jump_update, bsant_jump_end, func_802B5350}, - {BS_39_DIVE_A, func_802A7A54, func_802A7AB0, func_802A7BA8, func_80296608}, - {BS_3A_CARRY_IDLE, bscarry_idle_init, bscarry_idle_update, bscarry_idle_end, bscarry_interrupt}, - {BS_3B_CARRY_WALK, bscarry_walk_init, bscarry_walk_update, bscarry_walk_end, bscarry_interrupt}, - {BS_3C_TALK, bstalk_init, bstalk_update, bstalk_end, bstalk_interrupt}, - {BS_3D_FALL_TUMBLING, bsjump_tumble_init, bsjump_tumble_update, bsjump_tumble_end, func_80296608}, - {BS_38_ANT_FALL, bsant_fall_init, bsant_fall_update, bsant_fall_end, func_80296590}, - {BS_3E_ANT_OW, bsant_ow_init, bsant_ow_update, bsant_ow_end, func_80296590}, - {0x3F, func_802B1BF4, func_802B1CF8, func_802B1DA4, func_80296590}, - {BS_40_PUMPKIN_FLUSH, func_802B2BF0, func_802B2C58, func_802B2D50, func_80296590}, - {BS_41_DIE, bsdie_init, bsdie_update, bsdie_end, func_80296590}, - {BS_42_DINGPOT, func_802A5120, func_802A5190, func_802A51C0, func_80296590}, - {BS_43_ANT_DIE, bsant_die_init, bsant_die_update, bsant_die_end, func_80296590}, - {BS_44_JIG_JIGGY, bsjig_jiggy_init, bsjig_jiggy_update, bsjig_jiggy_end, bsjig_jiggy_interrupt}, - {BS_45_BTROT_SLIDE, bsbtrot_slide_init, bsbtrot_slide_update, bsbtrot_slide_end, func_802B5350}, - {0x46, func_802A2098, func_802A2130, func_802A2054, func_80296590}, - {BS_48_PUMPKIN_IDLE, bspumpkin_idle_init, bspumpkin_idle_update, bspumpkin_idle_end, func_802B5350}, - {BS_49_PUMPKIN_WALK, bspumpkin_walk_init, bspumpkin_walk_update, bspumpkin_walk_end, func_802B5350}, - {BS_4A_PUMPKIN_JUMP, bspumpkin_jump_init, bspumpkin_jump_update, bspumpkin_jump_end, func_802B5350}, - {BS_4B_PUMPKIN_FALL, bspumpkin_fall_init, bspumpkin_fall_update, bspumpkin_fall_end, func_802B5350}, - {BS_4C_LANDING_IN_WATER, func_802A846C, func_802A85EC, func_802A872C, func_80296608}, - {BS_4D_PUMPKIN_OW, __bspumpkin_ow_init, __bspumpkin_ow_update, __bspumpkin_ow_end, func_80296590}, - {BS_4E_PUMPKIN_DIE, bspumpkin_die_init, bspumpkin_die_update, bspumpkin_die_end, func_80296590}, - {BS_4F_CLIMB_IDLE, bsclimb_idle_init, bsclimb_idle_update, bsclimb_idle_end, func_802ABD60}, - {BS_50_CLIMB_MOVE, bsclimb_move_init, bsclimb_move_update, bsclimb_move_end, func_802ABD60}, - {BS_51_CLIMB_EXIT, func_802B1928, func_802B1A54, func_802B1BCC, func_80296608}, - {0x52, func_802B5FD0, func_802B6064, func_802B60D0, func_802B60D8}, - {BS_53_TIMEOUT, func_802B6270, func_802B6314, func_802B63C8, func_80296590}, - {BS_LONGLEG_SLIDE, bsblongleg_slide_init, bsblongleg_slide_update, bsblongleg_slide_end, func_802B5350}, - {BS_56_RECOIL, func_802B3868, func_802B3954, func_802B3A20, func_80296590}, - {BS_57_BOMB_END, func_802A4430, func_802A4548, func_802A4664, func_802A505C}, - {BS_58_BEAKBOMB_CRASH, bsbfly_beakbomb_crash_init, func_802A48B4, func_802A4A40, func_80296590}, - {0x59, func_802A4CD0, func_802A4CF0, func_802A4D10, func_802A505C}, - {BS_54_SWIM_DIE, func_802A7F6C, func_802A8098, func_802A82D4, func_80296590}, - {BS_CARRY_THROW, bsthrow_init, bsthrow_update, bsthrow_end, bsthrow_interrupt}, - {BS_5E_CROC_IDLE, bscroc_idle_init, bscroc_idle_update, bscroc_idle_end, func_802B5350}, - {BS_CROC_WALK, bscroc_walk_init, bscroc_walk_update, bscroc_walk_end, func_802B5350}, - {BS_CROC_JUMP, bscroc_jump_init, bscroc_jump_update, bscroc_jump_end, func_802B5350}, - {BS_61_CROC_FALL, bscroc_fall_init, bscroc_fall_update, bscroc_fall_end, func_802B5350}, - {BS_62_LONGLEG_LOCKED, func_802A6394, func_802A63F0, func_802A6450, func_80296608}, - {BS_CROC_OW, bscroc_ow_init, bscroc_ow_update, bscroc_ow_end, func_80296590}, - {BS_CROC_OW, bscroc_die_init, bscroc_die_update, bscroc_die_end, func_80296590}, - {BS_67_WALRUS_IDLE, bswalrus_idle_init, bswalrus_idle_update, bswalrus_idle_end, func_802B5350}, - {BS_WALRUS_WALK, bswalrus_walk_init, bswalrus_walk_update, bswalrus_walk_end, func_802B5350}, - {BS_WALRUS_JUMP, bswalrus_jump_init, bswalrus_jump_update, bswalrus_jump_end, func_802B5350}, - {BS_6A_WALRUS_FALL, bswalrus_fall_init, bswalrus_fall_update, bswalrus_fall_end, func_802B5350}, - {0x6B, func_802A1F6C, func_802A1FC8, func_802A2014, func_80296608}, - {BS_WALRUS_OW, bswalrus_ow_init, bswalrus_ow_update, bswalrus_ow_end, func_80296590}, - {BS_WALRUS_DIE, bswalrus_die_init, bswalrus_die_update, bswalrus_die_end, func_80296590}, - {BS_6E_CROC_BITE, bscroc_bite_init, bscroc_bite_update, bscroc_bite_end, func_802B5350}, - {BS_CROC_EAT_BAD, bscroc_eat_bad_init, bscroc_eat_bad_update, bscroc_eat_bad_end, func_802B5350}, - {BS_70_CROC_EAT_GOOD, bscroc_eat_good_init, bscroc_eat_good_update, bscroc_eat_good_end, func_802B5350}, - {BS_71_BTROT_FALL, bsbtrot_fall_init, bsbtrot_fall_update, bsbtrot_fall_end, func_80296608}, - {BS_SPLAT, bssplat_init, bssplat_update, bssplat_end, func_80296590}, - {0x00000073, func_802B3CEC, func_802B3D1C, func_802B3D6C, func_80296608}, - {0x00000074, func_802B3E2C, func_802B3E64, func_802B3EF4, func_80296608}, - {0x00000075, func_802B3D8C, func_802B3DBC, func_802B3E0C, func_80296608}, - {0x00000076, func_802A4F74, func_802A4FC8, func_802A503C, func_80296608}, - {0x00000077, bsswim_lookat_init, bsswim_lookat_update, bsswim_lookat_end, func_80296608}, - {0x00000078, bsbswim_lookat_init, bsbswim_lookat_update, bsbswim_lookat_end, func_80296608}, - {0x00000079, bsbtrot_unk79_init, bsbtrot_unk79_update, bsbtrot_unk79_end, func_80296608}, - {BS_WALK_MUD, bswalk_mud_init, bswalk_mud_update, NULL, func_80296608}, - {BS_BTROT_OW, bsbtrot_ow_init, bsbtrot_ow_update, bsbtrot_ow_end, func_80296590}, - {BS_7C_SLED, bssled_init, bssled_update, bssled_end, bssled_interrupt}, - {BS_7D_WALRUS_SLED, bswalrus_sled_init, bswalrus_sled_update, bswalrus_sled_end, func_802B98C0}, - {BS_7E_WALRUS_SLED, bswalrus_sled_jump_init, bswalrus_sled_jump_update, bswalrus_sled_jump_end, func_802B98C0}, - {BS_7F_DIVE_OW, func_802A7BD0, func_802A7CA8, func_802A7D74, func_80296590}, - {0x00000080, bswalrus_timeout_init, func_802B9830, func_802B9880, func_80296590}, - {0x00000081, func_802B90D0, func_802B9130, func_802B917C, func_802B98C0}, - {0x00000082, func_802B95A0, func_802B963C, func_802B976C, func_802B98C0}, - {BS_85_BEE_IDLE, func_802A1080, func_802A10D4, func_802A117C, func_802B5350}, - {BS_BEE_WALK, func_802A11A4, func_802A1214, func_802A12D4, func_802B5350}, - {BS_BEE_JUMP, func_802A12FC, func_802A1438, func_802A163C, func_802B5350}, - {BS_88_BEE_FALL, func_802A1664, func_802A170C, func_802A18C8, func_802B5350}, - {BS_BEE_OW, func_802A1B68, func_802A1B88, func_802A1BA8, func_802B5350}, - {BS_BEE_DIE, bsbeemain_die_init, func_802A1DD8, func_802A1F2C, func_80296590}, - {0x0000008B, func_802A0590, func_802A0630, func_802A0704, func_802B5350}, - {BS_BEE_FLY, bsbeefly_enter, bsbeefly_update, bsbeefly_end, func_802B5350}, - {BS_8D_CROC_LOCKED, bscroc_locked_enter, bscroc_locked_update, bscroc_locked_end, func_802B5350}, - {0x0000008E, func_8029F398, func_8029F3F4, func_8029F440, func_802B5350}, - {BS_8F_PUMPKIN_LOCKED, func_802B34A0, func_802B34F8, func_802B353C, func_802B5350}, - {BS_FLY_OW, func_802A4D30, func_802A4D50, func_802A4D70, func_802A505C}, - {BS_92_ANT_DRONE, bsant_drone_init, bsant_drone_update, bsant_drone_end, bsdrone_interrupt}, - {BS_93_PUMPKIN_DRONE, bspumpkin_drone_init, bspumpkin_drone_update, bspumpkin_drone_end, bsdrone_interrupt}, - {BS_94_CROC_DRONE, bscroc_drone_init, bscroc_drone_update, bscroc_drone_end, bsdrone_interrupt}, - {BS_95_WALRUS_DRONE, bswalrus_drone_init, bswalrus_drone_update, bswalrus_drone_end, bsdrone_interrupt}, - {BS_96_SWIM_DRONE, bsswim_drone_init, bsswim_drone_update, bsswim_drone_end, bsdrone_interrupt}, - {BS_97_DIVE_DRONE, bsbswim_drone_init, bsbswim_drone_update, bsbswim_drone_end, bsdrone_interrupt}, - {BS_98_WALK_DRONE, bswalk_drone_init, bswalk_drone_update, bswalk_drone_end, bsdrone_interrupt}, - {0x00000099, func_802A50B0, func_802A50D8, func_802A50F8, bsdrone_interrupt}, - {BS_9A_BTROT_DRONE, bsbtrot_drone_init, bsbtrot_drone_update, bsbtrot_drone_end, bsdrone_interrupt}, - {BS_9B_LONGLEG_DRONE, bsblongleg_drone_init, bsblongleg_drone_update, bsblongleg_drone_end, bsdrone_interrupt}, - {0x0000009C, bswalrus_sled_drone_init, bswalrus_sled_drone_update, bswalrus_sled_drone_end, bsdrone_interrupt}, - {BS_9D_BEE_DRONE, bsbee_drone_init, bsbee_drone_update, bsbee_drone_end, bsdrone_interrupt}, - {0x0000009E, func_802ABCCC, func_802ABD0C, func_802ABD40, func_802ABD60}, - {BS_ANT_BOUNCE, bsant_bounce_init, bsant_bounce_update, bsant_bounce_end, func_80296590}, - {BS_PUMPKIN_BOUNCE, bspumpkin_rebound_init, bspumpkin_rebound_update, bspumpkin_rebound_end, func_80296590}, - {BS_CROC_BOUNCE, bscroc_bounce_init, bscroc_bounce_update, bscroc_bounce_end, func_80296590}, - {BS_WALRUS_BOUNCE, bswalrus_bounce_init, bswalrus_bounce_update, bswalrus_bounce_end, func_80296590}, - {BS_BEE_BOUNCE, func_802A1BC8, func_802A1BE8, func_802A1C08, func_80296590}, - {BS_A4_WONDERWING_DRONE, bsbwhirl_drone_init, bsbwhirl_drone_update, bsbwhirl_drone_end, func_80296608}, - {BS_A5_WONDERWING_UNKA5, func_802AADBC, func_802AAE08, func_802AAE4C, func_80296608}, - {0} -}; - -/* .bss */ -void (*D_8037C3B0)(); - -/* .code */ -void func_802958A0(void){ - s32 i; - bsMap *iPtr; - - for(i = 0; D_80363824[i].uid != 0; i++){ - bsList_setInitMethod(D_80363824[i].uid, D_80363824[i].behavior.init_func); - bsList_setUpdateMethod(D_80363824[i].uid, D_80363824[i].behavior.update_func); - bsList_setEndMethod(D_80363824[i].uid, D_80363824[i].behavior.end_func); - bsList_setInterruptMethod(D_80363824[i].uid, D_80363824[i].behavior.interrupt_func); - } -} - -void func_80295914(void){ - D_80363820 = 1; - D_8037C3B0 = NULL; - update_void_return_Location(); - playerPosition_init(); - snackerctl_reset(); - func_80291910(); - badrone_init(); - bafalldamage_init(); - baflag_clearAll(); - func_8028B6FC(); - func_80291590(); - bakey_reset(); - bastick_reset(); - bainput_reset(); - bsList_clearAll(); - bs_clearState(); - babounds_init(); - func_80296C30(); - baphysics_init(); - baiFrame_reset(); - pitch_reset(); - climbClear(); - balookat_init(); - roll_reset(); - func_802992F0(); - func_80294DD8(); - func_8029CF6C(); - func_8029DFF8(); - func_80290B6C(); - baeyes_reset(); - func_80290070(); - func_80290664(); - stateTimer_init(); - eggShatter_init(); - bacarry_init(); - func_80293DA4(); - baAnim_init(); - baModel_reset(); - baMarker_init(); - basfx_reset(); - func_8029A4D0(); - func_8029ADCC(); - hazards_reset(); - func_802958A0(); -} - -void func_80295A8C(void){ - - stateTimer_set(STATE_TIMER_2_LONGLEG, bsStoredState_getLongLegTimer()); - stateTimer_set(STATE_TIMER_3_TURBO_TALON, bsStoredState_getTurboTimer()); - if(func_8028ADB4()) - bs_setState(badrone_enter()); - else - bs_setState(bs_getIdleState()); - -} - -void func_80295B04(void){ - f32 sp24; - enum bs_e sp20 = bs_getState(); - bool is_in_talon_trot; - - sp24 = (bslongleg_inSet(sp20)) ? stateTimer_get(STATE_TIMER_2_LONGLEG) : 0.0f; - bsStoredState_setLongLegTimer(sp24); - sp24 = 0.0f; - is_in_talon_trot = false; - if(bsbtrot_inSet(sp20)){ - sp24 = stateTimer_get(STATE_TIMER_3_TURBO_TALON); - is_in_talon_trot = true; - } - - bsStoredState_setTrot(is_in_talon_trot); - bsStoredState_setTurboTimer(sp24); - bs_setState(BS_5A_LOADZONE); - baMarker_free(); - func_8029065C(); - stateTimer_free(); - eggShatter_free(); - baModel_free(); - baAnim_free(); - func_80293E88(); - bacarry_end(); - basfx_free(); - func_8029A54C(); - func_8029ADA8(); - freeHazardSfxId(); - D_80363820 = 0; -} - -void func_80295C08(void (* arg0)(void)){ - D_8037C3B0 = arg0; -} - -void func_80295C14(void){ - func_802964B8(); - balookat_update(); - stateTimer_update(); - func_8029E100(); - pfsManager_update();//controller_update - disableInput_set(); - bakey_update(); - bastick_update(); - bainput_update(); //dive_cooldown_update - bs_updateState(); - baphysics_update(); - playerPosition_applyOffset(); - bafalldamage_update(); - func_80293F0C(); - pitch_update(); - roll_update(); - func_802993C8();//yaw update - func_802906D8(); - baAnim_update(); - func_8029A554(); - func_80298344(); //climb_cooldown_update - func_80290108(); - eggShatter_update(); - baeyes_update(); - baModel_update(); - playerPosition_func_8029842C(); - baMarker_update(); - bacarry_update(); - snackerctl_update(); - func_8028B71C(); - hazards_update(); - baiFrame_update(); - func_80294E60(); - cameraMode_update(); - func_802919A0(); - if(D_8037C3B0){ - D_8037C3B0(); - D_8037C3B0 = NULL; - } - basfx_update(); - babounds_update();//voidOut_update -} - -void func_80295D74(void){ - if(D_80363820){ - baAnim_defrag(); - baModel_defrag(); - eggShatter_defrag(); - func_80294750(); - func_8029AF1C(); - } -} diff --git a/src/core2/ba/ba_statusflags.c b/src/core2/ba/ba_statusflags.c index c0707812e..866f0e15d 100644 --- a/src/core2/ba/ba_statusflags.c +++ b/src/core2/ba/ba_statusflags.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_9C170.c #include #include "functions.h" #include "variables.h" @@ -329,7 +330,7 @@ void func_8032417C(struct56s *arg0, f32 arg1, f32 arg2[3], f32 arg3[3]) { func_80341180(var_f0, sp64, 3, sp60, sp44); ml_vec3f_diff_copy(arg2, sp44, sp50); ml_vec3f_normalize(arg2); - func_8025727C(sp44[0], sp44[1], sp44[2], sp50[0], sp50[1], sp50[2], &arg3[0], &arg3[1]); + ml_horizontal_and_vertical_angles(sp44[0], sp44[1], sp44[2], sp50[0], sp50[1], sp50[2], &arg3[0], &arg3[1]); arg3[0] = mlNormalizeAngle(-arg3[0]); arg3[2] = 0.0f; } diff --git a/src/core2/ba/ba_stickinterp.c b/src/core2/ba/ba_stickinterp.c index f1c65a47f..1090b41fa 100644 --- a/src/core2/ba/ba_stickinterp.c +++ b/src/core2/ba/ba_stickinterp.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_11040.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/ba/ba_underwater.c b/src/core2/ba/ba_underwater.c index 00febdde0..b5f0b42b9 100644 --- a/src/core2/ba/ba_underwater.c +++ b/src/core2/ba/ba_underwater.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_15F20.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/ba/ba_yaw.c b/src/core2/ba/ba_yaw.c index dc08799af..1fd1402d2 100644 --- a/src/core2/ba/ba_yaw.c +++ b/src/core2/ba/ba_yaw.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_12360.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/ba/ba_bounds.c b/src/core2/ba/babounds.c similarity index 93% rename from src/core2/ba/ba_bounds.c rename to src/core2/ba/babounds.c index ebf619b7e..45bdd0a39 100644 --- a/src/core2/ba/ba_bounds.c +++ b/src/core2/ba/babounds.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/babounds.c #include #include "functions.h" #include "variables.h" @@ -32,7 +33,7 @@ void babounds_init(void){ void babounds_update(void){ f32 sp1C[3]; - _player_getPosition(sp1C); + playerPosition_get(sp1C); if(!ml_vec3f_inside_box_vec3f(sp1C, D_8037C3C0.unkC, D_8037C3C0.unk0)){ if(D_8037C3C0.unk18 == 0){ D_8037C3C0.unk18 = 1; diff --git a/src/core2/ba/ba_buzz.c b/src/core2/ba/babuzz.c similarity index 98% rename from src/core2/ba/ba_buzz.c rename to src/core2/ba/babuzz.c index 216cf5abb..87e6371cb 100644 --- a/src/core2/ba/ba_buzz.c +++ b/src/core2/ba/babuzz.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/babuzz.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/ba/ba_eyes.c b/src/core2/ba/baeyes.c similarity index 88% rename from src/core2/ba/ba_eyes.c rename to src/core2/ba/baeyes.c index 18e972bd4..ac8d357e0 100644 --- a/src/core2/ba/ba_eyes.c +++ b/src/core2/ba/baeyes.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/baeyes.c #include #include "functions.h" #include "variables.h" @@ -13,9 +14,9 @@ BaEyes baEyes[4]; f32 baeyes_getEyePosition(s32 id){ switch (id) { case 0: - return func_8029DFC8(); + return modelAppendages_showBanjosLeftEye(); case 1: - return func_8029DFD4(); + return modelAppendages_showBanjosRightEye(); case 2: return 0.0f; case 3: @@ -29,10 +30,10 @@ f32 baeyes_getEyePosition(s32 id){ void baeyes_setEyePosition(s32 id, f32 position){ switch(id){ case 0: - func_8029E0C4(position); + modelAppendages_setBanjosLeftEyeVisibility(position); break; case 1: - func_8029E0D0(position); + modelAppendages_setBanjosRightEyeVisibility(position); break; case 2: break; @@ -99,7 +100,7 @@ void baeyes_update(void){ break; case 3://L80292FBC case 4://L80292FBC - eye_position -= dt/baEyes[i].duration; + eye_position -= dt / baEyes[i].duration; if(eye_position < 0.0){ eye_position = 0.0f; baEyes[i].state = 0; diff --git a/src/core2/ba/ba_flag.c b/src/core2/ba/baflag.c similarity index 95% rename from src/core2/ba/ba_flag.c rename to src/core2/ba/baflag.c index 0ada884b8..64dc73ede 100644 --- a/src/core2/ba/ba_flag.c +++ b/src/core2/ba/baflag.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/baflag.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/ba/ba_input.c b/src/core2/ba/bainput.c similarity index 98% rename from src/core2/ba/ba_input.c rename to src/core2/ba/bainput.c index e87349cb0..b85165166 100644 --- a/src/core2/ba/ba_input.c +++ b/src/core2/ba/bainput.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/bainput.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/ba/ba_key.c b/src/core2/ba/bakey.c similarity index 98% rename from src/core2/ba/ba_key.c rename to src/core2/ba/bakey.c index 2100bb0eb..605791360 100644 --- a/src/core2/ba/ba_key.c +++ b/src/core2/ba/bakey.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/bakey.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/ba/ba_lookat.c b/src/core2/ba/balookat.c similarity index 98% rename from src/core2/ba/ba_lookat.c rename to src/core2/ba/balookat.c index afd917717..ba4281efa 100644 --- a/src/core2/ba/ba_lookat.c +++ b/src/core2/ba/balookat.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/balookat.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/ba/ba_sfx.c b/src/core2/ba/basfx.c similarity index 99% rename from src/core2/ba/ba_sfx.c rename to src/core2/ba/basfx.c index c7c10fe34..d091e2a98 100644 --- a/src/core2/ba/ba_sfx.c +++ b/src/core2/ba/basfx.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/basfx.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/ba/ba_stick.c b/src/core2/ba/bastick.c similarity index 98% rename from src/core2/ba/ba_stick.c rename to src/core2/ba/bastick.c index 63b2ce6e2..4e56e29ff 100644 --- a/src/core2/ba/ba_stick.c +++ b/src/core2/ba/bastick.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/bastick.c #include #include "core1/core1.h" #include "functions.h" @@ -139,7 +140,7 @@ void bastick_setZoneMax(s32 zone_id, f32 value){ f32 bastick_getAngleRelativeToBanjo(void){ f32 sp1C[3]; - _player_getPosition(sp1C); + playerPosition_get(sp1C); return viewport_adjustAngleToRight(sp1C, bastick_getAngle()); } diff --git a/src/core2/ba/ba_timer.c b/src/core2/ba/batimer.c similarity index 93% rename from src/core2/ba/ba_timer.c rename to src/core2/ba/batimer.c index eec243169..87cc37caa 100644 --- a/src/core2/ba/ba_timer.c +++ b/src/core2/ba/batimer.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/batimer.c #include #include "functions.h" #include "variables.h" @@ -15,10 +16,10 @@ void batimer_incrementBy(s32 id, f32 inc_value_sec){ s_batimer.value[id] += inc_value_sec; } -int batimer_decrement(s32 id){ +bool batimer_decrement(s32 id){ s_batimer.last[id] = s_batimer.value[id]; if(0.0f == s_batimer.value[id]){ - return 0; + return false; } s_batimer.value[id] = ml_max_f(0.0f, s_batimer.value[id] - time_getDelta()); return s_batimer.value[id] == 0.0f; diff --git a/src/core2/ba/bsmethods.c b/src/core2/ba/bsmethods.c new file mode 100644 index 000000000..25e520266 --- /dev/null +++ b/src/core2/ba/bsmethods.c @@ -0,0 +1,335 @@ +// BanjoDecomp: core2/bsmethods.c +#include +#include "functions.h" +#include "variables.h" +#include "bsint.h" +#include "bs_funcs.h" +#include "core2/statetimer.h" +#include "core2/ba/physics.h" +#include "core2/snackerctl.h" + +u8 D_80363820 = 0; + +bsMap bsMethodsTable[] = { + //Banjo States Initialize Funcitons Update Functions End Functions Interrupt Functions + {BS_1_IDLE, bsstand_init, bsstand_update, bsstand_end, func_802B5350}, + {BS_2_WALK_SLOW, bswalk_slow_init, bswalk_slow_upate, NULL, func_802B5350}, + {BS_3_WALK, bswalk_init, bswalk_update, NULL, func_802B5350}, + {BS_4_WALK_FAST, bswalk_fast_init, bswalk_fast_update, bswalk_fast_end, func_802B5350}, + {BS_5_JUMP, bsjump_init, bsjump_update, bsjump_end, func_80296608}, + {BS_6_CLAW, bsclaw_init, bsclaw_update, bsclaw_end, func_80296608}, + {BS_7_CROUCH, bscrouch_init, bscrouch_update, bscrouch_end, func_802B5350}, + {BS_8_BTROT_JUMP, bsbtrot_jump_init, bsbtrot_jump_update, bsbtrot_jump_end, func_802B5350}, + {BS_C_SKID, bsturn_init, bsturn_update, bsturn_end, func_802B5350}, + {BS_D_TIMEOUT_TRANSFORMATION, timeout_transformation_init, timeout_transformation_update, timeout_transformation_end, func_80296590}, + {BS_E_OW, bsow_init, bsow_update, bsow_end, func_80296590}, + {BS_F_BBUSTER, bsbbuster_init, bsbbuster_update, bsbbuster_end, func_80296608}, + {BS_10_BFLAP, bsbflap_init, bsbflap_update, bsbflap_end, func_80296608}, + {BS_11_BPECK, bsbpeck_init, bsbpeck_update, bsbpeck_end, func_80296608}, + {BS_12_BFLIP, bsbflip_init, bsbflip_update, bsbflip_end, func_80296608}, + {BS_13_BBARGE, bsbarge_init, bsbarge_update, bsbarge_end, func_80296608}, + {BS_14_BTROT_ENTER, bsbtrot_enter_init, bsbtrot_enter_update, bsbtrot_enter_end, func_802B5350}, + {BS_15_BTROT_IDLE, bsbtrot_stand_init, bsbtrot_stand_update, bsbtrot_stand_end, func_802B5350}, + {BS_16_BTROT_WALK, bsbtrot_walk_init, bsbtrot_walk_update, bsbtrot_walk_end, func_802B5350}, + {BS_17_BTROT_EXIT, bsbtrot_exit_init, bsbtrot_exit_update, bsbtrot_exit_end, func_802B5350}, + {BS_18_FLY_KNOCKBACK, bsbfly_knockback_init, bsbfly_knockback_update, bsbfly_knockback_end, func_80296608}, + {BS_1A_WONDERWING_ENTER, bsbwhirl_enter_init, bsbwhirl_enter_update, bsbwhirl_enter_end, func_80296608}, + {BS_1B_WONDERWING_IDLE, bsbwhirl_stand_init, bsbwhirl_stand_update, bsbwhirl_stand_end, func_80296608}, + {BS_1C_WONDERWING_WALK, bsbwhirl_walk_init, bsbwhirl_walk_update, bsbwhirl_walk_end, func_80296608}, + {BS_1D_WONDERWING_JUMP, bsbwhirl_jump_init, bsbwhirl_jump_update, bsbwhirl_jump_end, func_80296608}, + {BS_1E_WONDERWING_EXIT, bsbwhirl_exit_init, bsbwhirl_exit_update, bsbwhirl_exit_end, func_80296608}, + {BS_9_EGG_HEAD, bsegghead_init, bsegghead_update, bsegghead_end, func_802B5350}, + {BS_A_EGG_ASS, bseggass_init, bseggass_update, bseggass_end, func_802B5350}, + {BS_1F_WALK_CREEP, bswalk_creep_init, bswalk_creep_update, NULL, func_802B5350}, + {BS_20_LANDING, bsstand_landing_init, bsstand_landing_update, NULL, func_802B5350}, + {BS_21_BSHOCK_CHARGE, bsbshock_charge_init, bsbshock_charge_update, bsbshock_charge_end, func_80296608}, + {BS_22_BSHOCK_JUMP, bsbshock_init, bsbshock_update, bsbshock_end, func_80296608}, + {BS_23_FLY_ENTER, bsbfly_enter_init, bsbfly_enter_update, bsbfly_enter_end, func_802A505C}, + {BS_24_FLY, bsbfly_init, bsbfly_update, bsbfly_end, func_802A505C}, + {BS_25_LONGLEG_ENTER, bsblongleg_enter_init, bsblongleg_enter_update, bsblongleg_enter_end, func_802B5350}, + {BS_26_LONGLEG_IDLE, bsblongleg_stand_enter, bsblongleg_stand_update, bsblongleg_stand_end, func_802B5350}, + {BS_27_LONGLEG_WALK, bsblongleg_walk_init, bsblongleg_walk_update, bsblongleg_walk_end, func_802B5350}, + {BS_28_LONGLEG_JUMP, bsblongleg_jump_init, bsblongleg_jump_update, bsblongleg_jump_end, func_80296608}, + {BS_29_LONGLEG_EXIT, bsblongleg_exit_init, bsblongleg_exit_update, bsblongleg_exit_end, func_802B5350}, + {BS_2A_BOMB, bsbfly_bomb_init, bsbfly_bomb_update, bsbfly_bomb_end, func_802A505C}, + {BS_2B_DIVE_IDLE, bsbdive_idle_init, bsbdive_idle_update, bsbdive_idle_end, func_80296608}, + {BS_2C_DIVE_B, bsbdiveb_init, bsbdiveb_update, bsbdiveb_end, func_80296608}, + {BS_2D_SWIM_IDLE, bsswim_idle_init, bsswim_idle_update, bsswim_idle_end, func_80296608}, + {BS_2E_SWIM, bsswim_swim_init, bsswim_swim_update, bsswim_swim_end, func_80296608}, + {BS_2F_FALL, bsjump_fall_init, bsjump_fall_update, bsjump_fall_end, func_80296608}, + {BS_30_DIVE_ENTER, bsSwim_dive_init, bsSwim_dive_update, bsSwim_dive_end, func_80296608}, + {BS_31_ROLL, bstwirl_init, bstwirl_update, bstwirl_end, func_802B5350}, + {BS_32_SLIDE, bsslide_init, bsslide_update, bsslide_end, func_802B5350}, + {BS_33_WASHY_UNKNOWN, bswashy_init, bswashy_update, bswashy_end, func_802B9D00}, + {BS_34_JIG_NOTEDOOR, bsjig_notedoor_init, bsjig_notedoor_update, bsjig_notedoor_end, func_80296590}, + {BS_35_ANT_IDLE, bsant_idle_init, bsant_idle_update, bsant_idle_end, func_802B5350}, + {BS_36_ANT_WALK, bsant_walk_init, bsant_walk_update, bsant_walk_end, func_802B5350}, + {BS_37_ANT_WALK, bsant_jump_init, bsant_jump_update, bsant_jump_end, func_802B5350}, + {BS_39_DIVE_A, bsswim_divea_init, bsswim_divea_update, bsswim_divea_end, func_80296608}, + {BS_3A_CARRY_IDLE, bscarry_idle_init, bscarry_idle_update, bscarry_idle_end, bscarry_interrupt}, + {BS_3B_CARRY_WALK, bscarry_walk_init, bscarry_walk_update, bscarry_walk_end, bscarry_interrupt}, + {BS_3C_TALK, bstalk_init, bstalk_update, bstalk_end, bstalk_interrupt}, + {BS_3D_FALL_TUMBLING, bsjump_tumble_init, bsjump_tumble_update, bsjump_tumble_end, func_80296608}, + {BS_38_ANT_FALL, bsant_fall_init, bsant_fall_update, bsant_fall_end, func_80296590}, + {BS_3E_ANT_OW, bsant_ow_init, bsant_ow_update, bsant_ow_end, func_80296590}, + {BS_3F_UNKNOWN, func_802B1BF4, func_802B1CF8, func_802B1DA4, func_80296590}, + {BS_40_PUMPKIN_FLUSH, bspumpkin_flush_init, bspumpkin_flush_update, bspumpkin_flush_end, func_80296590}, + {BS_41_DIE, bsdie_init, bsdie_update, bsdie_end, func_80296590}, + {BS_42_DINGPOT, bsfly_dingpotLaunch_init, bsfly_dingpotLaunch_update, bsfly_dingpotLaunch_end, func_80296590}, + {BS_43_ANT_DIE, bsant_die_init, bsant_die_update, bsant_die_end, func_80296590}, + {BS_44_JIG_JIGGY, bsjig_jiggy_init, bsjig_jiggy_update, bsjig_jiggy_end, bsjig_jiggy_interrupt}, + {BS_45_BTROT_SLIDE, bsbtrot_slide_init, bsbtrot_slide_update, bsbtrot_slide_end, func_802B5350}, + {BS_46_UNKNOWN, func_802A2098, func_802A2130, func_802A2054, func_80296590}, + {BS_48_PUMPKIN_IDLE, bspumpkin_idle_init, bspumpkin_idle_update, bspumpkin_idle_end, func_802B5350}, + {BS_49_PUMPKIN_WALK, bspumpkin_walk_init, bspumpkin_walk_update, bspumpkin_walk_end, func_802B5350}, + {BS_4A_PUMPKIN_JUMP, bspumpkin_jump_init, bspumpkin_jump_update, bspumpkin_jump_end, func_802B5350}, + {BS_4B_PUMPKIN_FALL, bspumpkin_fall_init, bspumpkin_fall_update, bspumpkin_fall_end, func_802B5350}, + {BS_4C_LANDING_IN_WATER, bsbswim_landingInWater_init, bsbswim_landingInWater_update, bsbswim_landingInWater_end, func_80296608}, + {BS_4D_PUMPKIN_OW, __bspumpkin_ow_init, __bspumpkin_ow_update, __bspumpkin_ow_end, func_80296590}, + {BS_4E_PUMPKIN_DIE, bspumpkin_die_init, bspumpkin_die_update, bspumpkin_die_end, func_80296590}, + {BS_4F_CLIMB_IDLE, bsclimb_idle_init, bsclimb_idle_update, bsclimb_idle_end, func_802ABD60}, + {BS_50_CLIMB_MOVE, bsclimb_move_init, bsclimb_move_update, bsclimb_move_end, func_802ABD60}, + {BS_51_CLIMB_EXIT, bsjump_climbExit_init, bsjump_climbExit_update, bsjump_climbExit_end, func_80296608}, + {BS_52_SURF, bssurf_init, bssurf_update, bssurf_end, func_802B60D8}, + {BS_53_TIMEOUT_BANJO, timeout_banjo_init, timeout_banjo_update, timeout_banjo_end, func_80296590}, + {BS_55_LONGLEG_SLIDE, bsblongleg_slide_init, bsblongleg_slide_update, bsblongleg_slide_end, func_802B5350}, + {BS_56_RECOIL, rebound_init, rebound_update, rebound_end, func_80296590}, + {BS_57_BOMB_END, bsbfly_beakbombend_init, bsbfly_beakbombend_update, bsbfly_beakbombend_end, func_802A505C}, + {BS_58_BEAKBOMB_CRASH, bsbfly_beakbomb_crash_init, func_802A48B4, func_802A4A40, func_80296590}, + {BS_59_BFLY_UNK59, func_802A4CD0, func_802A4CF0, func_802A4D10, func_802A505C}, + {BS_54_SWIM_DIE, bsbswim_die_init, bsbswim_die_update, bsbswim_die_end, func_80296590}, + {BS_5B_CARRY_THROW, bsthrow_init, bsthrow_update, bsthrow_end, bsthrow_interrupt}, + {BS_5E_CROC_IDLE, bscroc_idle_init, bscroc_idle_update, bscroc_idle_end, func_802B5350}, + {BS_5F_CROC_WALK, bscroc_walk_init, bscroc_walk_update, bscroc_walk_end, func_802B5350}, + {BS_60_CROC_JUMP, bscroc_jump_init, bscroc_jump_update, bscroc_jump_end, func_802B5350}, + {BS_61_CROC_FALL, bscroc_fall_init, bscroc_fall_update, bscroc_fall_end, func_802B5350}, + {BS_62_LONGLEG_LOCKED, bsblongleg_locked_init, bsblongleg_locked_update, bsblongleg_locked_end, func_80296608}, + {BS_63_CROC_OW, bscroc_ow_init, bscroc_ow_update, bscroc_ow_end, func_80296590}, + {BS_64_CROC_DIE, bscroc_die_init, bscroc_die_update, bscroc_die_end, func_80296590}, + {BS_67_WALRUS_IDLE, bswalrus_idle_init, bswalrus_idle_update, bswalrus_idle_end, func_802B5350}, + {BS_68_WALRUS_WALK, bswalrus_walk_init, bswalrus_walk_update, bswalrus_walk_end, func_802B5350}, + {BS_69_WALRUS_JUMP, bswalrus_jump_init, bswalrus_jump_update, bswalrus_jump_end, func_802B5350}, + {BS_6A_WALRUS_FALL, bswalrus_fall_init, bswalrus_fall_update, bswalrus_fall_end, func_802B5350}, + {BS_6B_BEE_LOCKED, bsbee_locked_init, bsbee_locked_update, bsbee_locked_end, func_80296608}, + {BS_6C_WALRUS_OW, bswalrus_ow_init, bswalrus_ow_update, bswalrus_ow_end, func_80296590}, + {BS_6D_WALRUS_DIE, bswalrus_die_init, bswalrus_die_update, bswalrus_die_end, func_80296590}, + {BS_6E_CROC_BITE, bscroc_bite_init, bscroc_bite_update, bscroc_bite_end, func_802B5350}, + {BS_6F_CROC_EAT_BAD, bscroc_eat_bad_init, bscroc_eat_bad_update, bscroc_eat_bad_end, func_802B5350}, + {BS_70_CROC_EAT_GOOD, bscroc_eat_good_init, bscroc_eat_good_update, bscroc_eat_good_end, func_802B5350}, + {BS_71_BTROT_FALL, bsbtrot_fall_init, bsbtrot_fall_update, bsbtrot_fall_end, func_80296608}, + {BS_72_SPLAT, bssplat_init, bssplat_update, bssplat_end, func_80296590}, + {BS_73_UNKNOWN, bsrest_bs73unknown_init, bsrest_bs73unknown_update, bsrest_bs73unknown_end, func_80296608}, + {BS_74_UNKNOWN, bsrest_bs74unknown_init, bsrest_bs74unknown_update, bsrest_bs74unknown_end, func_80296608}, + {BS_75_UNKNOWN, bsrest_bs75unknown_init, bsrest_bs75unknown_update, bsrest_bs75unknown_end, func_80296608}, + {BS_76_BFLY_LOCKED, bsbfly_locked_init, bsbfly_locked_update, bsbfly_locked_end, func_80296608}, + {BS_77_SWIM_LOOKAT_DRONE, bsswim_lookat_init, bsswim_lookat_update, bsswim_lookat_end, func_80296608}, + {BS_78_DIVE_LOOKAT_DRONE, bsbswim_lookat_init, bsbswim_lookat_update, bsbswim_lookat_end, func_80296608}, + {BS_79_BTROT_LOCKED, bsbtrot_locked_init, bsbtrot_locked_update, bsbtrot_locked_end, func_80296608}, + {BS_7A_WALK_MUD, bswalk_mud_init, bswalk_mud_update, NULL, func_80296608}, + {BS_7B_BTROT_OW, bsbtrot_ow_init, bsbtrot_ow_update, bsbtrot_ow_end, func_80296590}, + {BS_7C_SLED, bssled_init, bssled_update, bssled_end, bssled_interrupt}, + {BS_7D_WALRUS_SLED, bswalrus_sled_init, bswalrus_sled_update, bswalrus_sled_end, func_802B98C0}, + {BS_7E_WALRUS_SLED, bswalrus_sled_jump_init, bswalrus_sled_jump_update, bswalrus_sled_jump_end, func_802B98C0}, + {BS_7F_DIVE_OW, bsbswim_ow_init, bsbswim_ow_update, bsbswim_ow_end, func_80296590}, + {BS_80_WALRUS_SLED_LOSE, bswalrus_timeout_init, bswalrus_timeout_update, bswalrus_timeout_end, func_80296590}, + {BS_81_WALRUS_SLED_LOCKED, bswalrus_sledlocked_init, bswalrus_sledlocked_update, bswalrus_sledlocked_end, func_802B98C0}, + {BS_82_WALRUS_SLED_LOSE_IN_AIR,bswalrus_sledloseinair_init, bswalrus_sledloseinair_update, bswalrus_sledloseinair_end, func_802B98C0}, + {BS_85_BEE_IDLE, bsbeemain_idle_init, bsbeemain_idle_update, bsbeemain_idle_end, func_802B5350}, + {BS_86_BEE_WALK, bsbeemain_walk_init, bsbeemain_walk_update, bsbeemain_walk_end, func_802B5350}, + {BS_87_BEE_JUMP, bsbeemain_jump_init, bsbeemain_jump_update, bsbeemain_jump_end, func_802B5350}, + {BS_88_BEE_FALL, bsbeemain_fall_init, bsbeemain_fall_update, bsbeemain_fall_end, func_802B5350}, + {BS_89_BEE_OW, bsbeemain_ow_init, bsbeemain_ow_update, bsbeemain_ow_end, func_802B5350}, + {BS_8A_BEE_DIE, bsbeemain_die_init, bsbeemain_die_update, bsbeemain_die_end, func_80296590}, + {BS_8B_UNKNOWN, bsbeefly_bs8Bunknown_init, bsbeefly_bs8Bunknown_update, bsbeefly_bs8Bunknown_end, func_802B5350}, + {BS_8C_BEE_FLY, bsbeefly_enter, bsbeefly_update, bsbeefly_end, func_802B5350}, + {BS_8D_CROC_LOCKED, bscroc_locked_enter, bscroc_locked_update, bscroc_locked_end, func_802B5350}, + {BS_8E_ANT_LOCKED, bsant_locked_init, bsant_locked_update, bsant_locked_end, func_802B5350}, + {BS_8F_PUMPKIN_LOCKED, bspumpkin_locked_init, bspumpkin_locked_update, bspumpkin_locked_end, func_802B5350}, + {BS_91_FLY_OW, bsbfly_ow_init, bsbfly_ow_update, bsbfly_ow_end, func_802A505C}, + {BS_92_ANT_DRONE, bsant_drone_init, bsant_drone_update, bsant_drone_end, bsdrone_interrupt}, + {BS_93_PUMPKIN_DRONE, bspumpkin_drone_init, bspumpkin_drone_update, bspumpkin_drone_end, bsdrone_interrupt}, + {BS_94_CROC_DRONE, bscroc_drone_init, bscroc_drone_update, bscroc_drone_end, bsdrone_interrupt}, + {BS_95_WALRUS_DRONE, bswalrus_drone_init, bswalrus_drone_update, bswalrus_drone_end, bsdrone_interrupt}, + {BS_96_SWIM_DRONE, bsswim_drone_init, bsswim_drone_update, bsswim_drone_end, bsdrone_interrupt}, + {BS_97_DIVE_DRONE, bsbswim_drone_init, bsbswim_drone_update, bsbswim_drone_end, bsdrone_interrupt}, + {BS_98_WALK_DRONE, bswalk_drone_init, bswalk_drone_update, bswalk_drone_end, bsdrone_interrupt}, + {BS_99_BFLY_DRONE, bsbfly_drone_init, bsbfly_drone_update, bsbfly_drone_end, bsdrone_interrupt}, + {BS_9A_BTROT_DRONE, bsbtrot_drone_init, bsbtrot_drone_update, bsbtrot_drone_end, bsdrone_interrupt}, + {BS_9B_LONGLEG_DRONE, bsblongleg_drone_init, bsblongleg_drone_update, bsblongleg_drone_end, bsdrone_interrupt}, + {BS_9C_WALRUS_SLED_DRONE, bswalrus_sled_drone_init, bswalrus_sled_drone_update, bswalrus_sled_drone_end, bsdrone_interrupt}, + {BS_9D_BEE_DRONE, bsbee_drone_init, bsbee_drone_update, bsbee_drone_end, bsdrone_interrupt}, + {BS_9E_CLIMB_LOCKED, bsclimb_locked_init, bsclimb_locked_update, bsclimb_locked_end, func_802ABD60}, + {BS_9F_ANT_BOUNCE, bsant_bounce_init, bsant_bounce_update, bsant_bounce_end, func_80296590}, + {BS_A0_ANT_BOUNCE, bspumpkin_rebound_init, bspumpkin_rebound_update, bspumpkin_rebound_end, func_80296590}, + {BS_A1_CROC_BOUNCE, bscroc_bounce_init, bscroc_bounce_update, bscroc_bounce_end, func_80296590}, + {BS_A2_WALRUS_BOUNCE, bswalrus_bounce_init, bswalrus_bounce_update, bswalrus_bounce_end, func_80296590}, + {BS_A3_BEE_BOUNCE, bsbeemain_bounce_init, bsbeemain_bounce_update, bsbeemain_bounce_end, func_80296590}, + {BS_A4_WONDERWING_DRONE, bsbwhirl_drone_init, bsbwhirl_drone_update, bsbwhirl_drone_end, func_80296608}, + {BS_A5_WONDERWING_UNKA5, bsbwhirl_bsA5unknown_init, bsbwhirl_bsA5unknown_update, bsbwhirl_bsA5unknown_end, func_80296608}, + {0} +}; + +/* .bss */ +void (*D_8037C3B0)(); + +/* .code */ +void bsmethods_setMethods(void){ + s32 index; + bsMap *iPtr; + + for(index = 0; bsMethodsTable[index].uid != 0; index++){ + bsList_setInitMethod(bsMethodsTable[index].uid, bsMethodsTable[index].behavior.init_func); + bsList_setUpdateMethod(bsMethodsTable[index].uid, bsMethodsTable[index].behavior.update_func); + bsList_setEndMethod(bsMethodsTable[index].uid, bsMethodsTable[index].behavior.end_func); + bsList_setInterruptMethod(bsMethodsTable[index].uid, bsMethodsTable[index].behavior.interrupt_func); + } +} + +void bsmethods_reset(void){ + D_80363820 = 1; + D_8037C3B0 = NULL; + update_void_return_Location(); + playerPosition_init(); + snackerctl_reset(); + func_80291910(); + badrone_init(); + bafalldamage_init(); + baflag_clearAll(); + func_8028B6FC(); + func_80291590(); + bakey_reset(); + bastick_reset(); + bainput_reset(); + bsList_clearAll(); + bs_clearState(); + babounds_init(); + func_80296C30(); + baphysics_init(); + baiFrame_reset(); + pitch_reset(); + climb_clear(); + balookat_init(); + roll_reset(); + func_802992F0(); + func_80294DD8(); + func_8029CF6C(); + modelAppendages_reset(); + func_80290B6C(); + baeyes_reset(); + func_80290070(); + func_80290664(); + stateTimer_init(); + eggShatter_init(); + bacarry_init(); + func_80293DA4(); + baAnim_init(); + baModel_reset(); + baMarker_init(); + basfx_reset(); + func_8029A4D0(); + func_8029ADCC(); + hazards_reset(); + bsmethods_setMethods(); +} + +void func_80295A8C(void) +{ + stateTimer_set(STATE_TIMER_2_LONGLEG, bsStoredState_getLongLegTimer()); + stateTimer_set(STATE_TIMER_3_TURBO_TALON, bsStoredState_getTurboTimer()); + if(func_8028ADB4()) + bs_setState(badrone_enter()); + else + bs_setState(bs_getIdleState()); + +} + +void func_80295B04(void){ + f32 longleg_timer; + enum bs_e current_state = bs_getState(); + bool is_in_talon_trot; + + longleg_timer = (bslongleg_inSet(current_state)) ? stateTimer_get(STATE_TIMER_2_LONGLEG) : 0.0f; + bsStoredState_setLongLegTimer(longleg_timer); + longleg_timer = 0.0f; + is_in_talon_trot = false; + + if (bsbtrot_inSet(current_state)) { + longleg_timer = stateTimer_get(STATE_TIMER_3_TURBO_TALON); + is_in_talon_trot = true; + } + + bsStoredState_setTrot(is_in_talon_trot); + bsStoredState_setTurboTimer(longleg_timer); + bs_setState(BS_5A_LOADZONE); + baMarker_free(); + func_8029065C(); + stateTimer_free(); + eggShatter_free(); + baModel_free(); + baAnim_free(); + func_80293E88(); + bacarry_end(); + basfx_free(); + func_8029A54C(); + func_8029ADA8(); + freeHazardSfxId(); + D_80363820 = 0; +} + +void func_80295C08(void (* arg0)(void)){ + D_8037C3B0 = arg0; +} + +void func_80295C14(void){ + func_802964B8(); + balookat_update(); + stateTimer_update(); + modelAppendages_kazooiesUpperHalfVisibilityTimer(); + pfsManager_update();//controller_update + disableInput_set(); + bakey_update(); + bastick_update(); + bainput_update(); //dive_cooldown_update + bs_updateState(); + baphysics_update(); + playerPosition_applyOffset(); + bafalldamage_update(); + func_80293F0C(); + pitch_update(); + roll_update(); + func_802993C8();//yaw update + func_802906D8(); + baAnim_update(); + func_8029A554(); + climb_regrab_update(); + func_80290108(); + eggShatter_update(); + baeyes_update(); + baModel_update(); + playerPosition_func_8029842C(); + baMarker_update(); + bacarry_update(); + snackerctl_update(); + func_8028B71C(); + hazards_update(); + baiFrame_update(); + func_80294E60(); + cameraMode_update(); + func_802919A0(); + if(D_8037C3B0){ + D_8037C3B0(); + D_8037C3B0 = NULL; + } + basfx_update(); + babounds_update();//voidOut_update +} + +void func_80295D74(void){ + if(D_80363820){ + baAnim_defrag(); + baModel_defrag(); + eggShatter_defrag(); + func_80294750(); + func_8029AF1C(); + } +} diff --git a/src/core2/ba/ba_carriedobj.c b/src/core2/ba/carriedobj.c similarity index 93% rename from src/core2/ba/ba_carriedobj.c rename to src/core2/ba/carriedobj.c index 9d39a7c57..3d666a454 100644 --- a/src/core2/ba/ba_carriedobj.c +++ b/src/core2/ba/carriedobj.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/ba/carriedobj.c #include #include "functions.h" #include "variables.h" @@ -9,7 +10,7 @@ bool player_setCarryObjectPose(enum actor_e actor_id, Actor **arg1){ Actor *actor; m1 = (*arg1)->marker; - m2 = bacarry_get_marker(); + m2 = bacarry_getMarker(); if(m2){ actor = marker_getActor(m2); } @@ -40,7 +41,7 @@ void bacarriedobj_spawn(enum actor_e actor_id){ ActorMarker *marker; Actor *actor; - marker = bacarry_get_marker(); + marker = bacarry_getMarker(); if(marker){ actor = marker_getActor(marker); } @@ -68,7 +69,7 @@ void bacarriedobj_dec(enum actor_e actor_id){ ActorMarker *marker; Actor* actor; - marker = bacarry_get_marker(); + marker = bacarry_getMarker(); if(marker) actor = marker_getActor(marker); diff --git a/src/core2/ba/ba_carry.c b/src/core2/ba/carry.c similarity index 95% rename from src/core2/ba/ba_carry.c rename to src/core2/ba/carry.c index 3f71a39a8..d15cff986 100644 --- a/src/core2/ba/ba_carry.c +++ b/src/core2/ba/carry.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/ba/carry.c #include "functions.h" #include "core2/ba/carry.h" @@ -61,7 +62,7 @@ void bacarry_reset_marker(void){ baCarry_marker = NULL; } -ActorMarker *bacarry_get_marker(void){ +ActorMarker *bacarry_getMarker(void){ return baCarry_marker; } diff --git a/src/core2/ba/ba_scripted.c b/src/core2/ba/drone.c similarity index 98% rename from src/core2/ba/ba_scripted.c rename to src/core2/ba/drone.c index 403b48de5..9ebae29a8 100644 --- a/src/core2/ba/ba_scripted.c +++ b/src/core2/ba/drone.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/ba/drone.c #include #include "functions.h" diff --git a/src/core2/ba/ba_falldamage.c b/src/core2/ba/falldamage.c similarity index 96% rename from src/core2/ba/ba_falldamage.c rename to src/core2/ba/falldamage.c index 0b17f17ab..a39d52212 100644 --- a/src/core2/ba/ba_falldamage.c +++ b/src/core2/ba/falldamage.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/ba/falldamage.c #include #include "functions.h" #include "variables.h" @@ -114,7 +115,7 @@ void bafalldamage_set_start_position(f32 arg0[3]){ } void bafalldamage_init(void){ - _player_getPosition(bafalldamage_start_position); + playerPosition_get(bafalldamage_start_position); bafalldamage_state = 0; bafalldamage_set_state(1); D_8037C1C0.damage = 0; @@ -134,6 +135,6 @@ void bafalldamage_update(void){ void bafalldamage_start(void){ f32 player_position[3]; - _player_getPosition(player_position); + playerPosition_get(player_position); bafalldamage_set_start_position(player_position); } diff --git a/src/core2/ba/ba_flap.c b/src/core2/ba/flap.c similarity index 98% rename from src/core2/ba/ba_flap.c rename to src/core2/ba/flap.c index c35f93134..5647fae92 100644 --- a/src/core2/ba/ba_flap.c +++ b/src/core2/ba/flap.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/ba/flap.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/ba/ba_groundsurface.c b/src/core2/ba/hazards.c similarity index 99% rename from src/core2/ba/ba_groundsurface.c rename to src/core2/ba/hazards.c index 506846ce4..402aab5ac 100644 --- a/src/core2/ba/ba_groundsurface.c +++ b/src/core2/ba/hazards.c @@ -1,6 +1,8 @@ +// BanjoDecomp: core2/hazards.c #include #include "functions.h" #include "variables.h" +#include "iFrame.h" #include "core2/ba/timer.h" #include "core2/statetimer.h" @@ -14,7 +16,7 @@ f32 D_8037D224; /*.code */ bool isOnFloor(void){ - return floor_isCurrentFloorunk59() && floor_getCurrentFloorYPosition() > player_getYPosition(); + return floor_isCurrentFloorunk59() && floor_getCurrentFloorYPosition() > playerPosition_getY(); } void freeHazardSfxId(void){ diff --git a/src/core2/ba/ba_eyeblink.c b/src/core2/ba/iFrame.c similarity index 92% rename from src/core2/ba/ba_eyeblink.c rename to src/core2/ba/iFrame.c index 33803e3ee..ed3bd4e9d 100644 --- a/src/core2/ba/ba_eyeblink.c +++ b/src/core2/ba/iFrame.c @@ -1,6 +1,8 @@ +// BanjoDecomp: core2/ba/iFrame.c #include #include "functions.h" #include "variables.h" +#include "iFrame.h" #include "core2/statetimer.h" /* .bss */ diff --git a/src/core2/ba/iFrame.h b/src/core2/ba/iFrame.h new file mode 100644 index 000000000..41798abb8 --- /dev/null +++ b/src/core2/ba/iFrame.h @@ -0,0 +1,10 @@ +// BanjoDecomp: core2/ba/iFrame.h +#ifndef BANJO_KAZOOIE_BA_IFRAME_H +#define BANJO_KAZOOIE_BA_IFRAME_H + +typedef enum { + IFRAME_NONE = 1, + IFRAME_INVICIBLE = 3 +} IFrameState; + +#endif // BANJO_KAZOOIE_BA_IFRAME_H diff --git a/src/core2/ba/ba_marker.c b/src/core2/ba/marker.c similarity index 98% rename from src/core2/ba/ba_marker.c rename to src/core2/ba/marker.c index 8bacbfccd..eb5197d37 100644 --- a/src/core2/ba/ba_marker.c +++ b/src/core2/ba/marker.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/ba/marker.c #include #include "core1/core1.h" #include "functions.h" @@ -631,7 +632,7 @@ void __baMarker_resolveCollision(Prop *other_prop){ && volatileFlag_get(VOLATILE_FLAG_0_IN_FURNACE_FUN_QUIZ) && !fileProgressFlag_get(FILEPROG_A6_FURNACE_FUN_COMPLETE) ) { - volatileFlag_setAndTriggerDialog_4(VOLATILE_FLAG_A6_FF_FOUND_HONEYCOMB); + progressDialog_setAndTriggerDialog_4(VOLATILE_FLAG_A6_FF_FOUND_HONEYCOMB); func_8030E6D4(SFX_126_AUDIENCE_BOOING); } @@ -746,7 +747,7 @@ void __baMarker_resolveCollision(Prop *other_prop){ && volatileFlag_get(VOLATILE_FLAG_0_IN_FURNACE_FUN_QUIZ) && !fileProgressFlag_get(FILEPROG_A6_FURNACE_FUN_COMPLETE) ) { - volatileFlag_setAndTriggerDialog_4(VOLATILE_FLAG_A7_FF_FOUND_EXTRALIFE); + progressDialog_setAndTriggerDialog_4(VOLATILE_FLAG_A7_FF_FOUND_EXTRALIFE); func_8030E6D4(SFX_127_AUDIENCE_MIXED); } coMusicPlayer_playMusic(COMUSIC_15_EXTRA_LIFE_COLLECTED, 0x7FFF); @@ -786,7 +787,7 @@ void __baMarker_resolveCollision(Prop *other_prop){ return; if (bsStoredState_getTransformation() != TRANSFORM_1_BANJO) return; - if (func_8028F170()) + if(player_isInFirstPersonView()) return; if (func_8028F25C()) return; @@ -811,7 +812,7 @@ void __baMarker_resolveCollision(Prop *other_prop){ if (func_8028F25C()) return; - if (func_8028F170()) + if(player_isInFirstPersonView()) return; if (!chtrainers_canUse(actor)) @@ -909,7 +910,7 @@ void __baMarker_resolveCollision(Prop *other_prop){ void baMarker_init(void){ f32 sp1C[3]; - _player_getPosition(sp1C); + playerPosition_get(sp1C); playerMarker = func_8032FBE4(sp1C, baModel_80291AAC, 1, 0); playerMarker->unk2C_1 = 1; marker_setCollisionScripts(playerMarker, NULL, func_80291634, func_80291610); @@ -942,7 +943,7 @@ void baMarker_update(void){ if ((D_8037BF88 != 0)){ temp_s0 = func_8024FEEC(func_8025ADD4(COMUSIC_30_5TH_JINJO_COLLECTED) & 0xFF); - if((comusic_active_track_count() < 4 && temp_s0 >= 0xBB9) || !func_8025AD7C(COMUSIC_30_5TH_JINJO_COLLECTED)){ + if((coMusicPlayer_getTrackCount() < 4 && temp_s0 >= 0xBB9) || !func_8025AD7C(COMUSIC_30_5TH_JINJO_COLLECTED)){ func_8028F918(0); D_8037BF88 = 0; } @@ -952,7 +953,7 @@ void baMarker_update(void){ temp_s0_2 = __baMarker_8028B750(); baflag_clear(BA_FLAG_1_ON_FLIGHT_PAD); baflag_clear(BA_FLAG_2_ON_SPRING_PAD); - _player_getPosition(sp168); + playerPosition_get(sp168); func_8032F64C(sp168, playerMarker); for(D_8037BF8C = NULL, i = 0, temp_s2 = 0; i < 2;i++){//L8028D3DC D_8037BF90 = i; diff --git a/src/core2/ba/ba_model.c b/src/core2/ba/model.c similarity index 96% rename from src/core2/ba/ba_model.c rename to src/core2/ba/model.c index 4c2fc13d1..4b16065fd 100644 --- a/src/core2/ba/ba_model.c +++ b/src/core2/ba/model.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/ba/model.c #include #include "functions.h" #include "variables.h" @@ -54,7 +55,7 @@ static void _baModel_updateModelYaw(void){ void baModel_80291A50(s32 arg0, f32 dst[3]){ vec3fArray_get_vec3f(D_80363780, arg0, dst); if(ml_isZero_vec3f(dst)){ - _player_getPosition(dst); + playerPosition_get(dst); } } @@ -78,7 +79,7 @@ void baModel_draw(Gfx **gfx, Mtx **mtx, Vtx **vtx){ _baModel_updateModelYaw(); baModelRoll = roll_get(); baModelPitch = pitch_get(); - _player_getPosition(plyr_pos); + playerPosition_get(plyr_pos); plyr_pos[1] += 2.0f; ml_vec3f_assign(rotation, baModelPitch, baModelYaw, baModelRoll); func_8029A47C(env_color); @@ -94,7 +95,7 @@ void baModel_draw(Gfx **gfx, Mtx **mtx, Vtx **vtx){ if(baModelBin){ baanim_80289F30(); - func_8029DD6C(); + modelAppendages_loadAppendage(); modelRender_setEnvColor(env_color[0], env_color[1], env_color[2], baModelEnvAlpha); modelRender_func_8033A280(2.0f); modelRender_setPreDrawCallback((model_render_pre_draw_callback_f)_baModel_preDraw, 0); @@ -115,7 +116,7 @@ void baModel_draw(Gfx **gfx, Mtx **mtx, Vtx **vtx){ } void baModel_updateModel(void){ - baModel_set(func_802985F0()); + baModel_set(playerModel_get()); } void baModel_reset(void){ @@ -304,7 +305,7 @@ void baModel_80292284(f32 arg0[3], s32 arg1){ case ASSET_374_MODEL_BANJO_CROC: vec3fArray_get_vec3f(D_80363780, arg1 + 1, arg0); if(ml_isZero_vec3f(arg0)){ - _player_getPosition(arg0); + playerPosition_get(arg0); } arg0[1] += D_8037C130[arg1][0]; @@ -320,12 +321,12 @@ void baModel_80292284(f32 arg0[3], s32 arg1){ arg0[2] = arg0[2] + sp38[2]; break; default: ////80292400 - _player_getPosition(arg0); + playerPosition_get(arg0); break; } } else{//L80292410 - _player_getPosition(arg0); + playerPosition_get(arg0); if(arg1){ arg0[1] += 33.0f; } diff --git a/src/core2/ba/modelappendages.c b/src/core2/ba/modelappendages.c new file mode 100644 index 000000000..b02da560a --- /dev/null +++ b/src/core2/ba/modelappendages.c @@ -0,0 +1,209 @@ +// BanjoDecomp: core2/modelappendages.c +#include +#include "functions.h" +#include "variables.h" + +void modelAppendages_setKazooiesUpperHalfVisibility(bool); +void modelAppendages_setKazooiesFeetAndShoesVisibility(bool); +void modelAppendages_setKazooiesAssVisibility(bool); +void modelAppendages_setBanjosLeftEyeVisibility(f32); +void modelAppendages_setBanjosRightEyeVisibility(f32); +void modelAppendages_setTurboTrainersVisibility(bool); +void modelAppendages_setWadingBootsVisibility(bool); +void modelAppendages_setSledVisibility(bool); + +/* .bss */ +f32 showKazooiesUpperHalfModelTimer; // Only used in bFlap +u8 showKazooiesUpperHalfModelNext; // Only used in bFlap +u8 showKazooieAssModel; +u8 showKazooieFeetAndShoesModel; +u8 hideTurboTrainersModel; +u8 showKazooiesUpperHalfModel; +u8 hideWadingBootsModel; +u8 showSledModel; +f32 showBanjosLeftEye; +f32 showBanjosRightEye; + +/* .code */ +// Kazooie & Bee do not blink +// Wishywashy's eyes blink together +void modelAppendages_loadBlinkingEyes(void){ + s32 is_model_visible; + switch(baModel_getModelId()){ + case ASSET_34D_MODEL_BANJOKAZOOIE_LOW_POLY: //L8029DC24 + case ASSET_34E_MODEL_BANJOKAZOOIE_HIGH_POLY: //L8029DC24 + is_model_visible = (s32) ml_interpolate_f(showBanjosLeftEye, 1.0f, 8.0f); + modelRender_setAppendageVisibility(0x1B, is_model_visible); + modelRender_setAppendageVisibility(0x1D, is_model_visible); + modelRender_setAppendageVisibility(0x1F, is_model_visible); + modelRender_setAppendageVisibility(0x21, is_model_visible); + is_model_visible = (s32) ml_interpolate_f(showBanjosRightEye, 1.0f, 8.0f); + modelRender_setAppendageVisibility(0x1A, is_model_visible); + modelRender_setAppendageVisibility(0x1C, is_model_visible); + modelRender_setAppendageVisibility(0x1E, is_model_visible); + modelRender_setAppendageVisibility(0x20, is_model_visible); + break; + + case ASSET_34F_MODEL_BANJO_TERMITE: //L8029DCCC + case ASSET_359_MODEL_BANJO_WALRUS: //L8029DCCC + case ASSET_36F_MODEL_BANJO_PUMPKIN: //L8029DCCC + case ASSET_374_MODEL_BANJO_CROC: //L8029DCCC + modelRender_setAppendageVisibility(0x1B, (s32) ml_interpolate_f(showBanjosLeftEye, 1.0f, 6.0f)); + modelRender_setAppendageVisibility(0x1A, (s32) ml_interpolate_f(showBanjosRightEye, 1.0f, 6.0f)); + break; + + case ASSET_356_MODEL_BANJO_WISHYWASHY: //L8029DD2C + modelRender_setAppendageVisibility(1, (s32) ml_interpolate_f(showBanjosRightEye, 1.0f, 4.0f)); + break; + } +} + +// This includes Kazooie, the shoes, and the sled +void modelAppendages_loadAppendage(void) { + s32 is_model_visible; // [port] must hold values > 1 for geo selector branches + + modelRender_func_8033A1FC(); + switch (baModel_getModelId()) { + case ASSET_34D_MODEL_BANJOKAZOOIE_LOW_POLY: + case ASSET_34E_MODEL_BANJOKAZOOIE_HIGH_POLY: + /* Kazooie's Upper Half */ + modelRender_setAppendageVisibility(0x1, showKazooiesUpperHalfModel); + modelRender_setAppendageVisibility(0x9, showKazooiesUpperHalfModel); + modelRender_setAppendageVisibility(0xC, showKazooiesUpperHalfModel); + modelRender_setAppendageVisibility(0xF, showKazooiesUpperHalfModel); + /* Kazooie's Legs & Shoes */ + modelRender_setAppendageVisibility(0x2, showKazooieFeetAndShoesModel); + modelRender_setAppendageVisibility(0xA, showKazooieFeetAndShoesModel); + modelRender_setAppendageVisibility(0xD, showKazooieFeetAndShoesModel); + modelRender_setAppendageVisibility(0x10, showKazooieFeetAndShoesModel); + /* Kazooie's Ass */ + modelRender_setAppendageVisibility(0x8, showKazooieAssModel); + modelRender_setAppendageVisibility(0xB, showKazooieAssModel); + modelRender_setAppendageVisibility(0xE, showKazooieAssModel); + modelRender_setAppendageVisibility(0x11, showKazooieAssModel); + /* Turbo Talon Trainer */ + is_model_visible = hideTurboTrainersModel + 1; + modelRender_setAppendageVisibility(0x12, is_model_visible); + modelRender_setAppendageVisibility(0x14, is_model_visible); + modelRender_setAppendageVisibility(0x16, is_model_visible); + modelRender_setAppendageVisibility(0x18, is_model_visible); + modelRender_setAppendageVisibility(0x13, is_model_visible); + modelRender_setAppendageVisibility(0x15, is_model_visible); + modelRender_setAppendageVisibility(0x17, is_model_visible); + modelRender_setAppendageVisibility(0x19, is_model_visible); + /* Wading Boots */ + is_model_visible = hideWadingBootsModel + 1; + modelRender_setAppendageVisibility(0x22, is_model_visible); + modelRender_setAppendageVisibility(0x24, is_model_visible); + modelRender_setAppendageVisibility(0x26, is_model_visible); + modelRender_setAppendageVisibility(0x28, is_model_visible); + modelRender_setAppendageVisibility(0x23, is_model_visible); + modelRender_setAppendageVisibility(0x25, is_model_visible); + modelRender_setAppendageVisibility(0x27, is_model_visible); + modelRender_setAppendageVisibility(0x29, is_model_visible); + break; + case ASSET_359_MODEL_BANJO_WALRUS: + /* Sled */ + modelRender_setAppendageVisibility(0x3, showSledModel); + break; + case ASSET_374_MODEL_BANJO_CROC: + /* Turbo Talon Trainer */ + is_model_visible = hideTurboTrainersModel + 1; + modelRender_setAppendageVisibility(0x4, is_model_visible); + modelRender_setAppendageVisibility(0x5, is_model_visible); + modelRender_setAppendageVisibility(0x6, is_model_visible); + modelRender_setAppendageVisibility(0x7, is_model_visible); + break; + } + modelAppendages_loadBlinkingEyes(); +} + +bool modelAppendages_showKazooiesAss(void){ + return showKazooieAssModel; +} + +bool modelAppendages_showKazooiesFeetAndShoes(void){ + return showKazooieFeetAndShoesModel; +} + +bool modelAppendages_showKazooiesUpperHalf(void){ + return showKazooiesUpperHalfModel; +} + +f32 modelAppendages_showBanjosLeftEye(void){ + return showBanjosLeftEye; +} + +f32 modelAppendages_showBanjosRightEye(void){ + return showBanjosRightEye; +} + +bool modelAppendages_hideTurboTrainers(void){ + return hideTurboTrainersModel; +} + +bool modelAppendages_hideWadingBoots(void){ + return hideWadingBootsModel; +} + +void modelAppendages_reset(void) { + modelAppendages_setKazooiesUpperHalfVisibility(false); + modelAppendages_setKazooiesFeetAndShoesVisibility(false); + modelAppendages_setKazooiesAssVisibility(false); + modelAppendages_setBanjosLeftEyeVisibility(0.0f); + modelAppendages_setBanjosRightEyeVisibility(0.0f); + modelAppendages_setTurboTrainersVisibility(false); + modelAppendages_setWadingBootsVisibility(false); + modelAppendages_setSledVisibility(false); + CALL_EVENT(OnPlayerAnimReset); +} + +void modelAppendages_setKazooiesAssVisibility(bool show_model){ + showKazooieAssModel = show_model; +} + +void modelAppendages_setKazooiesFeetAndShoesVisibility(bool show_model){ + showKazooieFeetAndShoesModel = show_model; +} + +void modelAppendages_setKazooiesUpperHalfVisibility(bool show_model) { + modelAppendages_setKazooiesUpperHalfVisibilityAndTimer(show_model, 0.0f); +} + +// Timer only set in bFlap +void modelAppendages_setKazooiesUpperHalfVisibilityAndTimer(bool show_model, f32 timer) { + showKazooiesUpperHalfModelTimer = timer; + showKazooiesUpperHalfModelNext = show_model; + if (timer == 0.0f) { + showKazooiesUpperHalfModel = show_model; + } +} + +void modelAppendages_setBanjosLeftEyeVisibility(f32 show_model){ + showBanjosLeftEye = show_model; +} + +void modelAppendages_setBanjosRightEyeVisibility(f32 show_model){ + showBanjosRightEye = show_model; +} + +void modelAppendages_setTurboTrainersVisibility(bool hide_model){ + hideTurboTrainersModel = hide_model; +} + +void modelAppendages_setSledVisibility(bool show_model){ + showSledModel = show_model; +} + +void modelAppendages_setWadingBootsVisibility(bool hide_model){ + hideWadingBootsModel = hide_model; +} + +void modelAppendages_kazooiesUpperHalfVisibilityTimer(void) { + if (showKazooiesUpperHalfModelTimer != 0.0f) { + showKazooiesUpperHalfModelTimer -= time_getDelta(); + if (showKazooiesUpperHalfModelTimer <= 0.0f) { + showKazooiesUpperHalfModel = showKazooiesUpperHalfModelNext; + } + } +} diff --git a/src/core2/ba/ba_physics.c b/src/core2/ba/physics.c similarity index 96% rename from src/core2/ba/ba_physics.c rename to src/core2/ba/physics.c index b61b4c703..c5ff222b4 100644 --- a/src/core2/ba/ba_physics.c +++ b/src/core2/ba/physics.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/ba/physics.c #include "core2/ba/physics.h" #include "functions.h" #include "variables.h" @@ -5,7 +6,7 @@ #include -extern f32 climbGetRadius(void); +extern f32 climb_getRadius(void); extern f32 func_8029CED0(void); /* .data */ @@ -153,10 +154,10 @@ void __baphysics_update_climb(void){ f32 sp34[3]; f32 sp28[3]; - climbGetBottom(sp28); + climb_getBottom(sp28); s_next_position[0] = sp28[0]; s_next_position[2] = sp28[2]; - func_80256E24(sp34, 0.0f, yaw_get(), 0.0f, 0.0f, -climbGetRadius()); + func_80256E24(sp34, 0.0f, yaw_get(), 0.0f, 0.0f, -climb_getRadius()); s_player_velocity[2] = 0.0f; s_next_position[0] += sp34[0];\ @@ -197,7 +198,7 @@ void __baphysics_update_goto(void){ break; case 1: //L802974E8 baphysics_goto.state = 2; - _player_getPosition(baphysics_goto.start_position); + playerPosition_get(baphysics_goto.start_position); baphysics_goto.elapsed_time = 0.0f; baphysics_set_velocity(0); break; @@ -225,8 +226,8 @@ void __baphysics_update_transform(void){ D_8037C500 += time_getDelta(); temp_f0 = func_80257A44(D_8037C500, 1.2f); - temp_f0 = ml_sin_deg(temp_f0*360.0f); - s_next_position[1] = 5.0*temp_f0 + D_8037C4FC; + temp_f0 = ml_sin_deg(temp_f0 * 360.0f); + s_next_position[1] = 5.0 * temp_f0 + D_8037C4FC; } void baphysics_get_position_change(f32 arg0[3]){ @@ -244,7 +245,7 @@ void baphysics_init(void){ } void baphysics_update(void){ - _player_getPosition(s_next_position); + playerPosition_get(s_next_position); switch(baphysics_type){ case BA_PHYSICS_GOTO: //L80297780 __baphysics_update_goto(); @@ -289,7 +290,7 @@ void baphysics_update(void){ default: break; } - player_setPosition(s_next_position); + playerPosition_set(s_next_position); } void baphysics_reset_horizontal_velocity(void){ diff --git a/src/core2/ba/ba_modelselect.c b/src/core2/ba/playermodel.c similarity index 87% rename from src/core2/ba/ba_modelselect.c rename to src/core2/ba/playermodel.c index eeedd3ccb..7c05e884c 100644 --- a/src/core2/ba/ba_modelselect.c +++ b/src/core2/ba/playermodel.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/playermodel.c #include #include "functions.h" #include "variables.h" @@ -5,10 +6,10 @@ #include "port/Patches/Patches.h" /* .bss */ -void *D_8037C5D0; +void *PlayerModelAssetId; /* .code */ -s32 func_802985F0(void){ +enum asset_e playerModel_get(void){ switch(bsStoredState_getTransformation()) { case TRANSFORM_2_TERMITE: //80298624 @@ -75,21 +76,22 @@ s32 func_802985F0(void){ } } -void func_802986D0(void){ - if(D_8037C5D0){ - assetcache_release(D_8037C5D0); +void playerModel_free(void){ + if(PlayerModelAssetId){ + assetcache_release(PlayerModelAssetId); } } -void func_80298700(void){ - s32 sp1C = func_802985F0(); +void playerModel_set(void){ + enum asset_e model_id = playerModel_get(); + if(func_8028ADB4()){ - D_8037C5D0 = 0; + PlayerModelAssetId = 0; } - else if(sp1C){ - D_8037C5D0 = assetcache_get(sp1C); + else if(model_id){ + PlayerModelAssetId = assetcache_get(model_id); } else{ - D_8037C5D0 = NULL; + PlayerModelAssetId = NULL; } } diff --git a/src/core2/ba/ba_position.c b/src/core2/ba/playerposition.c similarity index 87% rename from src/core2/ba/ba_position.c rename to src/core2/ba/playerposition.c index ff7109717..95c04692c 100644 --- a/src/core2/ba/ba_position.c +++ b/src/core2/ba/playerposition.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/playerposition.c #include #include "functions.h" #include "variables.h" @@ -24,19 +25,19 @@ void playerPosition_func_80298464(f32 arg0[3]){ ml_vec3f_copy(D_8037C5B0, arg0); } -void player_setPosition(f32 arg0[3]){ +void playerPosition_set(f32 arg0[3]){ ml_vec3f_copy(player_position, arg0); } -void player_setYPosition(f32 arg0){ +void playerPosition_setY(f32 arg0){ player_position[1] = arg0; } -void _player_getPosition(f32 arg0[3]){ +void playerPosition_get(f32 arg0[3]){ ml_vec3f_copy(arg0, player_position); } -f32 player_getYPosition(void){ +f32 playerPosition_getY(void){ return player_position[1]; } diff --git a/src/core2/bs/ant.c b/src/core2/bs/ant.c index 7ccf6ec65..f00639615 100644 --- a/src/core2/bs/ant.c +++ b/src/core2/bs/ant.c @@ -50,11 +50,11 @@ void func_8029E48C(void){ } } -void func_8029E4EC(void){ +void bsant_end(void){ if(!bsant_inSet(bs_getNextState())){ bastick_resetZones(); - func_8029E070(0); - func_8029E064(0); + modelAppendages_setKazooiesUpperHalfVisibility(false); + modelAppendages_setKazooiesFeetAndShoesVisibility(false); baflag_clear(BA_FLAG_3); baflag_clear(BA_FLAG_4); func_80293D74(); @@ -69,8 +69,8 @@ void func_8029E554(void){ int bsant_inSet(s32 move_indx){ return (move_indx == BS_35_ANT_IDLE) - || (move_indx == BS_ANT_WALK) - || (move_indx == BS_ANT_JUMP) + || (move_indx == BS_36_ANT_WALK) + || (move_indx == BS_37_ANT_WALK) || (move_indx == BS_38_ANT_FALL) || (move_indx == BS_3E_ANT_OW) || (move_indx == BS_43_ANT_DIE) @@ -81,7 +81,7 @@ int bsant_inSet(s32 move_indx){ void bsant_idle_init(void){ func_8029E554(); baanim_playForDuration_loopSmooth(ASSET_5E_ANIM_BSANT_IDLE, 1.2f); - func_8029C7F4(1,YAW_STATE_1_DEFAULT,1,BA_PHYSICS_NORMAL); + code_14420_setUpdateTypes(1, YAW_STATE_1_DEFAULT, 1, BA_PHYSICS_NORMAL); baphysics_set_target_horizontal_velocity(0.0f); pitch_setAngVel(1000.0f, 12.0f); roll_setAngularVelocity(1000.0f, 12.0f); @@ -101,23 +101,23 @@ void bsant_idle_update(void){ new_state = badrone_look(); if(bastick_getZone() > 0) - new_state = BS_ANT_WALK; + new_state = BS_36_ANT_WALK; if(bakey_pressed(BUTTON_A)) - new_state = BS_ANT_JUMP; + new_state = BS_37_ANT_WALK; bs_setState(new_state); } void bsant_idle_end(void){ func_802900FC(); - func_8029E4EC(); + bsant_end(); } void bsant_walk_init(void){ func_8029E554(); baanim_playForDuration_loopSmooth(ASSET_5F_ANIM_BSANT_WALK, 0.8f); - func_8029C7F4(2, YAW_STATE_1_DEFAULT,1, BA_PHYSICS_NORMAL); + code_14420_setUpdateTypes(2, YAW_STATE_1_DEFAULT, 1, BA_PHYSICS_NORMAL); baanim_setVelocityMapRanges(D_80364960, D_80364964, D_80364968, D_8036496C); func_802900B4(); } @@ -142,13 +142,13 @@ void bsant_walk_update(void){ sp1C = BS_38_ANT_FALL; if(bakey_pressed(BUTTON_A)) - sp1C = BS_ANT_JUMP; + sp1C = BS_37_ANT_WALK; bs_setState(sp1C); } void bsant_walk_end(void){ - func_8029E4EC(); + bsant_end(); func_802900FC(); } @@ -163,7 +163,7 @@ void bsant_jump_init(void){ anctrl_setSubRange(aCtrl, 0.0f, 0.4423f); anctrl_setPlaybackType(aCtrl, ANIMCTRL_ONCE); anctrl_start(aCtrl, "bsant.c", 0x17c); - func_8029C7F4(1, YAW_STATE_1_DEFAULT, 3, BA_PHYSICS_AIRBORN); + code_14420_setUpdateTypes(1, YAW_STATE_1_DEFAULT, 3, BA_PHYSICS_AIRBORN); if(bastick_distance() != 0.0f) yaw_setIdeal(bastick_getAngleRelativeToBanjo()); baphysics_set_target_yaw(yaw_getIdeal()); @@ -217,10 +217,10 @@ void bsant_jump_update(void){ if(player_isStable()){ baphysics_set_target_horizontal_velocity(0.0f); if(bastick_getZone() > 0) - sp2C = BS_ANT_WALK; + sp2C = BS_36_ANT_WALK; if(bakey_pressed(BUTTON_A)) - sp2C = BS_ANT_JUMP; + sp2C = BS_37_ANT_WALK; } bs_setState(sp2C); @@ -228,7 +228,7 @@ void bsant_jump_update(void){ void bsant_jump_end(void){ baphysics_reset_gravity(); - func_8029E4EC(); + bsant_end(); } void bsant_fall_init(void){ @@ -241,7 +241,7 @@ void bsant_fall_init(void){ anctrl_setStart(aCtrl, 0.4423f); anctrl_setPlaybackType(aCtrl, ANIMCTRL_STOPPED); anctrl_start(aCtrl, "bsant.c", 0x208); - func_8029C7F4(1, YAW_STATE_1_DEFAULT, 3, BA_PHYSICS_AIRBORN); + code_14420_setUpdateTypes(1, YAW_STATE_1_DEFAULT, 3, BA_PHYSICS_AIRBORN); bsant_substate = 0; } @@ -276,7 +276,7 @@ void bsant_fall_update(void){ } void bsant_fall_end(void){ - func_8029E4EC(); + bsant_end(); } static void __bsant_recoil_init(int take_damage){ @@ -297,7 +297,7 @@ static void __bsant_recoil_init(int take_damage){ else func_8030E58C(SFX_56_BANJO_HUI, 1.8f); - _player_getPosition(sp2C); + playerPosition_get(sp2C); func_80294980(sp20); func_80257F18(sp20, sp2C, &sp38); yaw_setIdeal(mlNormalizeAngle(sp38 + 180.0f)); @@ -305,7 +305,7 @@ static void __bsant_recoil_init(int take_damage){ baphysics_set_target_horizontal_velocity(200.0f); baphysics_set_target_yaw(sp38); baphysics_set_horizontal_velocity(sp38, baphysics_get_target_horizontal_velocity()); - func_8029C7F4(1, YAW_STATE_1_DEFAULT, 2, BA_PHYSICS_LOCKED_ROTATION); + code_14420_setUpdateTypes(1, YAW_STATE_1_DEFAULT, 2, BA_PHYSICS_LOCKED_ROTATION); baphysics_set_vertical_velocity(510.0f); baphysics_set_gravity(-1200.0f); baMarker_collisionOff(); @@ -341,7 +341,7 @@ static void __bsant_recoil_end(void){ baphysics_reset_gravity(); baMarker_collisionOn(); baeyes_open(); - func_8029E4EC(); + bsant_end(); } void bsant_ow_init(void){ @@ -383,7 +383,7 @@ void bsant_die_init(void){ anctrl_setPlaybackType(aCtrl, ANIMCTRL_ONCE); anctrl_start(aCtrl, "bsant.c", 0x2f6); func_8030E58C(SFX_36_BANJO_DOH, 1.8f); - _player_getPosition(sp2C); + playerPosition_get(sp2C); func_80294980(sp20); func_80257F18(sp20, sp2C, &sp38); D_8037D290 = 250.0f; @@ -392,12 +392,12 @@ void bsant_die_init(void){ baphysics_set_target_horizontal_velocity(D_8037D290); baphysics_set_target_yaw(sp38); baphysics_set_horizontal_velocity(sp38, baphysics_get_target_horizontal_velocity()); - func_8029C7F4(1, YAW_STATE_1_DEFAULT, 2, BA_PHYSICS_LOCKED_ROTATION); + code_14420_setUpdateTypes(1, YAW_STATE_1_DEFAULT, 2, BA_PHYSICS_LOCKED_ROTATION); baphysics_set_vertical_velocity(510.0f); baphysics_set_gravity(-1200.0f); pitch_setAngVel(1000.0f, 12.0f); func_802914CC(0xd); - ncDynamicCamD_func_802BF2C0(30.0f); + ncbadie_func_802BF2C0(30.0f); func_8029C984(); bsant_substate = 0; baMarker_collisionOff(); @@ -449,16 +449,16 @@ void bsant_die_end(void){ baeyes_open(); } -void func_8029F398(void){ +void bsant_locked_init(void){ func_8029E554(); baanim_playForDuration_loopSmooth(ASSET_5E_ANIM_BSANT_IDLE, 2.0f); - func_8029C7F4(1, YAW_STATE_1_DEFAULT, 3, BA_PHYSICS_NORMAL); + code_14420_setUpdateTypes(1, YAW_STATE_1_DEFAULT, 3, BA_PHYSICS_NORMAL); baphysics_set_target_horizontal_velocity(0.0f); func_8029C674(); func_802B3A50(); } -void func_8029F3F4(void){ +void bsant_locked_update(void){ enum bs_e sp1C = 0; func_802B3A50(); func_80299628(0); @@ -469,9 +469,9 @@ void func_8029F3F4(void){ bs_setState(sp1C); } -void func_8029F440(void){ +void bsant_locked_end(void){ func_8029C748(); - func_8029E4EC(); + bsant_end(); } void bsant_drone_init(void){ @@ -485,5 +485,5 @@ void bsant_drone_update(void){ void bsant_drone_end(void){ bsdrone_end(); - func_8029E4EC(); + bsant_end(); } diff --git a/src/core2/bs/beak_barge.c b/src/core2/bs/bBarge.c similarity index 94% rename from src/core2/bs/beak_barge.c rename to src/core2/bs/bBarge.c index 21107b516..c3fc7ca5a 100644 --- a/src/core2/bs/beak_barge.c +++ b/src/core2/bs/bBarge.c @@ -1,8 +1,10 @@ +// BanjoDecomp: core2/bs/bBarge.c #include #include "functions.h" #include "variables.h" #include "core2/ba/physics.h" #include "core2/ba/timer.h" +#include "core2/yaw.h" void func_80292864(f32, f32); @@ -47,7 +49,7 @@ void func_8029F4F0(void){ void func_8029F60C(void){ f32 player_position[3]; - _player_getPosition(player_position); + playerPosition_get(player_position); func_8032728C(player_position, 50.0f, 2, func_8029F4E0); } @@ -68,11 +70,11 @@ void bsbarge_init(void){ anctrl_setPlaybackType(plyrMvmnt, ANIMCTRL_ONCE); anctrl_start(plyrMvmnt, "bsbbarge.c", 0x98); D_8037D2A4 = 0; - func_8029C7F4(1,1,3, BA_PHYSICS_LOCKED_ROTATION); + code_14420_setUpdateTypes(1, YAW_STATE_1_DEFAULT, 3, BA_PHYSICS_LOCKED_ROTATION); baphysics_set_target_yaw(yaw_getIdeal()); baphysics_set_target_horizontal_velocity(baphysics_get_target_horizontal_velocity()*0.3); baphysics_set_horizontal_velocity(yaw_getIdeal(), baphysics_get_target_horizontal_velocity()); - func_8029E070(1); + modelAppendages_setKazooiesUpperHalfVisibility(true); D_8037D2A6 = 0; D_8037D2A5 = 0; baflag_clear(BA_FLAG_A); @@ -174,6 +176,6 @@ void bsbarge_update(void){ void bsbarge_end(void){ ability_use(5); - func_8029E070(0); + modelAppendages_setKazooiesUpperHalfVisibility(false); D_8037D2A6 = 0; } diff --git a/src/core2/bs/beak_egg_fire.c b/src/core2/bs/bEggAss.c similarity index 83% rename from src/core2/bs/beak_egg_fire.c rename to src/core2/bs/bEggAss.c index 6dac9bf1e..e55b3724e 100644 --- a/src/core2/bs/beak_egg_fire.c +++ b/src/core2/bs/bEggAss.c @@ -1,8 +1,10 @@ +// BanjoDecomp: core2/bs/bEggAss.c #include #include "functions.h" #include "variables.h" #include "core2/ba/physics.h" +#include "core2/yaw.h" /* .bss */ u8 D_8037D2E0; @@ -11,10 +13,10 @@ u8 D_8037D2E1; /* .code */ void bseggass_init(void){ baanim_playForDuration_onceSmooth(ASSET_2B_ANIM_BSEGGASS, 1.0f); - func_8029C7F4(1,3,1, BA_PHYSICS_LOCKED_ROTATION); + code_14420_setUpdateTypes(1, YAW_STATE_3_BOUNDED, 1, BA_PHYSICS_LOCKED_ROTATION); yaw_setVelocityBounded(350.0f, 14.0f); baphysics_set_target_horizontal_velocity(0.0f); - func_8029E058(1); + modelAppendages_setKazooiesAssVisibility(true); D_8037D2E0 = (D_8037D2E1 = 1); bainput_enable(5,0); } @@ -50,7 +52,7 @@ void bseggass_update(void) { } } if (anctrl_isStopped(plyr_mvmt)) { - next_state = (bakey_held(BUTTON_Z))? BS_CROUCH : BS_1_IDLE; + next_state = (bakey_held(BUTTON_Z))? BS_7_CROUCH : BS_1_IDLE; } else if (0.6 < (f64) anctrl_getAnimTimer(plyr_mvmt)) { next_state = func_802ADCD4(0); } @@ -63,5 +65,5 @@ void bseggass_update(void) { void bseggass_end(void){ bainput_enable(5, 1); baphysics_reset_gravity(); - func_8029E058(0); + modelAppendages_setKazooiesAssVisibility(false); } diff --git a/src/core2/bs/beak_egg_aim.c b/src/core2/bs/bEggHead.c similarity index 84% rename from src/core2/bs/beak_egg_aim.c rename to src/core2/bs/bEggHead.c index 5d6bd79f0..322d79864 100644 --- a/src/core2/bs/beak_egg_aim.c +++ b/src/core2/bs/bEggHead.c @@ -1,8 +1,10 @@ +// BanjoDecomp: core2/bs/bEggHead.c #include #include "functions.h" #include "variables.h" #include "core2/ba/physics.h" +#include "core2/yaw.h" void yaw_setVelocityBounded(f32, f32); //void anctrl_start(AnimCtrl *, char*, s32); @@ -14,10 +16,10 @@ u8 D_8037D2F1; /* .code */ void bsegghead_init(void){ baanim_playForDuration_onceSmooth(ASSET_2A_ANIM_BSEGGHEAD, 1.0f); - func_8029C7F4(1,3,1, BA_PHYSICS_LOCKED_ROTATION); + code_14420_setUpdateTypes(1, YAW_STATE_3_BOUNDED, 1, BA_PHYSICS_LOCKED_ROTATION); yaw_setVelocityBounded(350.0f, 14.0f); baphysics_set_target_horizontal_velocity(0.0f); - func_8029E070(1); + modelAppendages_setKazooiesUpperHalfVisibility(true); D_8037D2F0 = (D_8037D2F1 = 1); bainput_enable(2,0); } @@ -58,7 +60,7 @@ void bsegghead_update(void) { } } if (anctrl_isStopped(aCtrl)) { - next_state = (bakey_held(BUTTON_Z))? BS_CROUCH : BS_1_IDLE; + next_state = (bakey_held(BUTTON_Z))? BS_7_CROUCH : BS_1_IDLE; } else if (0.65 < (f64) anctrl_getAnimTimer(aCtrl)) { next_state = func_802ADCD4(0); @@ -71,5 +73,5 @@ void bsegghead_update(void) { void bsegghead_end(void){ bainput_enable(2, 1); baphysics_reset_gravity(); - func_8029E070(0); + modelAppendages_setKazooiesUpperHalfVisibility(false); } diff --git a/src/core2/bs/flap_flip.c b/src/core2/bs/bFlap.c similarity index 95% rename from src/core2/bs/flap_flip.c rename to src/core2/bs/bFlap.c index 898da2356..326279bb4 100644 --- a/src/core2/bs/flap_flip.c +++ b/src/core2/bs/bFlap.c @@ -1,9 +1,11 @@ +// BanjoDecomp: core2/bs/bFlap.c #include #include "functions.h" #include "variables.h" #include "core2/ba/physics.h" #include "core2/ba/timer.h" +#include "core2/yaw.h" f32 func_802A2858(void); @@ -21,7 +23,7 @@ u8 D_8037D30C; void bsbflap_init(void) { baanim_playForDuration_onceSmooth(ASSET_18_ANIM_BSBFLAP_ENTER, 0.3f); - func_8029C7F4(1, 1, 1, BA_PHYSICS_NORMAL); + code_14420_setUpdateTypes(1, YAW_STATE_1_DEFAULT, 1, BA_PHYSICS_NORMAL); if (bastick_distance() != 0.0f) { yaw_setIdeal(bastick_getAngleRelativeToBanjo()); } @@ -30,7 +32,7 @@ void bsbflap_init(void) { baphysics_set_horizontal_velocity(yaw_getIdeal(), baphysics_get_target_horizontal_velocity()); baphysics_set_vertical_velocity(0.0f); baphysics_set_gravity(D_80364A14); - func_8029E070(1); + modelAppendages_setKazooiesUpperHalfVisibility(true); baflag_set(BA_FLAG_12_HAS_FLAPPED); batimer_set(0, 2.5f); D_8037D30C = sfxsource_createSfxsourceAndReturnIndex(); @@ -197,6 +199,6 @@ void bsbflap_end(void) { ability_use(1); baphysics_reset_gravity(); baphysics_reset_terminal_velocity(); - func_8029E090(0, 0.2f); + modelAppendages_setKazooiesUpperHalfVisibilityAndTimer(0, 0.2f); sfxsource_freeSfxsourceByIndex(D_8037D30C); } diff --git a/src/core2/bs/backflip.c b/src/core2/bs/bFlip.c similarity index 94% rename from src/core2/bs/backflip.c rename to src/core2/bs/bFlip.c index 128363f25..5f16813ee 100644 --- a/src/core2/bs/backflip.c +++ b/src/core2/bs/bFlip.c @@ -1,7 +1,9 @@ +// BanjoDecomp: core2/bs/bFlip.c #include #include "functions.h" #include "variables.h" #include "core2/ba/physics.h" +#include "core2/yaw.h" /* .data */ const f32 D_80364A20 = 920.0f; @@ -51,10 +53,10 @@ void bsbflip_init(void){ anctrl_setStart(aCtrl, 0.0f); anctrl_setPlaybackType(aCtrl, ANIMCTRL_ONCE); anctrl_start(aCtrl, "bsbflip.c", 0x80); - func_8029C7F4(1,1,2, BA_PHYSICS_LOCKED_ROTATION); + code_14420_setUpdateTypes(1, YAW_STATE_1_DEFAULT, 2, BA_PHYSICS_LOCKED_ROTATION); bastick_setZoneMax(0, 0.03f); bastick_setZoneMax(1, 1.0f); - func_8029E070(1); + modelAppendages_setKazooiesUpperHalfVisibility(true); basfx_80299BD4(); D_8037D310 = 0; } @@ -137,7 +139,7 @@ void bsbflip_update(void){ if(player_isFallTumbling()) sp24 = BS_3D_FALL_TUMBLING; if(player_isStable()){ - func_8029E070(0); + modelAppendages_setKazooiesUpperHalfVisibility(false); _bsbflip_802A2DC0(); sp24 = func_8029C9C0(sp24); D_8037D310 = 4; @@ -163,6 +165,6 @@ void bsbflip_end(void){ ability_use(2); baphysics_reset_gravity(); baphysics_reset_terminal_velocity(); - func_8029E070(0); + modelAppendages_setKazooiesUpperHalfVisibility(false); bastick_resetZones(); } diff --git a/src/core2/bs/beak_bomb.c b/src/core2/bs/bFly.c similarity index 87% rename from src/core2/bs/beak_bomb.c rename to src/core2/bs/bFly.c index 265776934..5cc44ef2e 100644 --- a/src/core2/bs/beak_bomb.c +++ b/src/core2/bs/bFly.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/bs/bFly.c #include #include "core1/core1.h" #include "functions.h" @@ -5,10 +6,11 @@ #include "core2/ba/physics.h" #include "core2/ba/flap.h" #include "core2/ba/timer.h" +#include "core2/yaw.h" extern void baModel_setYDisplacement(f32); extern f32 bastick_getX(void); -extern void ncDynamicCam4_func_802BFE50(f32, f32, f32); +extern void ncbafly_func_802BFE50(f32, f32, f32); extern void func_80354030(f32[3], f32); @@ -36,7 +38,7 @@ int func_802A3350(void){ } void func_802A339C(f32 arg0[3], f32 arg1[3], f32 arg2){ - viewport_getLookbk_vector(arg0); + viewport_getLookVector(arg0); ml_vec3f_scale(arg0, arg2); viewport_getRotation_vec3f(arg1); } @@ -65,7 +67,7 @@ void func_802A34C8(void){ if(!bsbfly_inSet(bs_getNextState())){ baphysics_reset_gravity(); baphysics_reset_terminal_velocity(); - func_8029E070(0); + modelAppendages_setKazooiesUpperHalfVisibility(false); baModel_setYDisplacement(0.0f); func_8029CB84(); yaw_setUpdateState(1); @@ -110,7 +112,7 @@ void func_802A3648(void){ void func_802A36D0(void){ f32 plyr_pos[3]; - _player_getPosition(plyr_pos); + playerPosition_get(plyr_pos); plyr_pos[0] += randf2(-30.0f, 30.0f); plyr_pos[1] += 50.0f + randf2(0.0f, 30.0f); plyr_pos[2] += randf2(-30.0f, 30.0f); @@ -121,11 +123,11 @@ void func_802A36D0(void){ } int bsbfly_inSet(enum bs_e arg0){ - return arg0 == BS_BOMB + return arg0 == BS_2A_BOMB || arg0 == BS_57_BOMB_END || arg0 == BS_18_FLY_KNOCKBACK || arg0 == BS_59_BFLY_UNK59 - || arg0 == BS_FLY_OW + || arg0 == BS_91_FLY_OW || arg0 == BS_76_BFLY_LOCKED || arg0 == BS_24_FLY || arg0 == BS_99_BFLY_DRONE; @@ -137,7 +139,7 @@ int func_802A37F8(void){ void bsbfly_enter_init(void){ baanim_playForDuration_onceSmooth(ASSET_45_ANIM_BSBFLY_ENTER, 1.4f); - func_8029C7F4(1,1,3, BA_PHYSICS_AIRBORN); + code_14420_setUpdateTypes(1, YAW_STATE_1_DEFAULT, 3, BA_PHYSICS_AIRBORN); if(bastick_distance() != 0.0f) yaw_setIdeal(bastick_getAngleRelativeToBanjo()); @@ -145,7 +147,7 @@ void bsbfly_enter_init(void){ baphysics_set_velocity(0); baphysics_set_target_horizontal_velocity(0.0f); baphysics_set_gravity(-1200.0f); - func_8029E070(1); + modelAppendages_setKazooiesUpperHalfVisibility(true); basfx_80299BD4(); D_8037D344 = 0; D_8037D346 = 0; @@ -176,12 +178,12 @@ void bsbfly_enter_update(void){ void bsbfly_enter_end(void){ ability_use(8); - func_8029E070(0); + modelAppendages_setKazooiesUpperHalfVisibility(false); } void bsbfly_init(void){ baanim_playForDuration_loopSmooth(ASSET_38_ANIM_BSBFLY, 0.62f); - func_8029C7F4(1,1,3, BA_PHYSICS_LOCKED_ROTATION); + code_14420_setUpdateTypes(1, YAW_STATE_1_DEFAULT, 3, BA_PHYSICS_LOCKED_ROTATION); if(baflag_isTrue(BA_FLAG_9)){ baphysics_set_target_horizontal_velocity(0.0f); }else{ @@ -190,7 +192,7 @@ void bsbfly_init(void){ baphysics_set_horizontal_velocity(yaw_getIdeal(), baphysics_get_target_horizontal_velocity()); baphysics_set_target_yaw(yaw_getIdeal()); - func_8029E070(1); + modelAppendages_setKazooiesUpperHalfVisibility(true); baphysics_set_gravity(-300.0f); baphysics_set_terminal_velocity(-99.9f); func_802914CC(4); @@ -298,7 +300,7 @@ void bsbfly_update(void){ sp2C = 0; func_80346C10(&sp2C, 0, 1, ITEM_F_RED_FEATHER, 1); if(sp2C) - sp54 = BS_BOMB; + sp54 = BS_2A_BOMB; } if(player_inWater()) @@ -311,7 +313,7 @@ void bsbfly_update(void){ bs_setState(sp54); } -void func_802A3F70(void){ +void bsbfly_end(void){ func_802A34C8(); } @@ -321,23 +323,23 @@ int bsbfly_bombHitboxActive(void){ } //bsbfly_bomb_init -void func_802A3F9C(void){ +void bsbfly_bomb_init(void){ f32 sp1C[3]; baanim_playForDuration_once(ASSET_43_ANIM_BSBFLY_BEAKBOMB_START, 1.0f); - func_8029C7F4(1,1,3,BA_PHYSICS_FREEZE); + code_14420_setUpdateTypes(1, YAW_STATE_1_DEFAULT, 3, BA_PHYSICS_FREEZE); func_802A339C(D_8037D338, sp1C, 4200.0f); yaw_setIdeal(sp1C[1] + 180.0f); pitch_setIdeal(sp1C[0]); roll_setIdeal(0.0f); baphysics_set_velocity(D_8037D338); pitch_setIdeal(sp1C[0]); - func_8029E070(1); + modelAppendages_setKazooiesUpperHalfVisibility(true); func_802914CC(4); - ncDynamicCam4_func_802BFE74(1); + ncbafly_func_802BFE74(1); func_802A3430(); FUNC_8030E624(SFX_52_BANJO_YAH_OH, 1.0f, 28000); D_8037D345 = 0; - _player_getPosition(D_8037D328); + playerPosition_get(D_8037D328); D_8037D344 = 0; func_802D8BE4(0); } @@ -345,7 +347,7 @@ void func_802A3F9C(void){ void func_802A4078(void){ f32 plyr_pos[3]; - _player_getPosition(plyr_pos); + playerPosition_get(plyr_pos); plyr_pos[0] += D_8037D338[0]; plyr_pos[1] += D_8037D338[1]; plyr_pos[2] += D_8037D338[2]; @@ -362,7 +364,7 @@ s32 func_802A40E0(void){ return BS_41_DIE; } -void func_802A411C(void) { +void bsbfly_bomb_update(void) { s32 next_state; AnimCtrl *sp58; BKCollisionTriangle *phi_v0; @@ -424,7 +426,7 @@ void func_802A411C(void) { next_state = BS_58_BEAKBOMB_CRASH; } } - _player_getPosition(sp48); + playerPosition_get(sp48); ml_vec3f_diff(sp48, D_8037D328); if (sp48[0]*sp48[0] + sp48[1]*sp48[1] + sp48[2]*sp48[2] > 16000000.0f) { next_state = BS_57_BOMB_END; @@ -440,13 +442,13 @@ void func_802A411C(void) { bs_setState(next_state); } -void func_802A4404(void){ +void bsbfly_bomb_end(void){ basfx_80299E6C(); D_8037D345 = 0; func_802A34C8(); } -void func_802A4430(void){ +void bsbfly_beakbombend_init(void){ AnimCtrl *plyr_anctrl; plyr_anctrl = baanim_getAnimCtrlPtr(); @@ -456,8 +458,8 @@ void func_802A4430(void){ anctrl_setDuration(plyr_anctrl, 0.38f); anctrl_setPlaybackType(plyr_anctrl, ANIMCTRL_LOOP); anctrl_start(plyr_anctrl, "bsbfly.c", 0x38a); - func_8029C7F4(1, 1, 3, BA_PHYSICS_LOCKED_ROTATION); - func_8029E070(1); + code_14420_setUpdateTypes(1, YAW_STATE_1_DEFAULT, 3, BA_PHYSICS_LOCKED_ROTATION); + modelAppendages_setKazooiesUpperHalfVisibility(true); func_802A3430(); func_80293D74(); func_80294378(1); @@ -472,7 +474,7 @@ void func_802A4430(void){ D_8037D344 = 0; } -void func_802A4548(void){ +void bsbfly_beakbombend_update(void){ s32 next_state = 0; f32 sp20[3]; baphysics_get_velocity(sp20); @@ -508,7 +510,7 @@ void func_802A4548(void){ bs_setState(next_state); } -void func_802A4664(void){ +void bsbfly_beakbombend_end(void){ s32 next_state; basfx_80299E6C(); basfx_80299E90(); @@ -517,7 +519,7 @@ void func_802A4664(void){ sfxsource_playHighPriority(SFX_3EA_BANJO_GUH_HUH); } func_802A34C8(); - func_8029E070(0); + modelAppendages_setKazooiesUpperHalfVisibility(false); } void func_802A46C8(void) { @@ -531,8 +533,8 @@ void func_802A46C8(void) { void bsbfly_beakbomb_crash_init(void) { baanim_playForDuration_once(ASSET_3E_ANIM_BSBFLY_BEAKBOMB_CRASH, 1.4f); - func_8029C7F4(1, 1, 3, BA_PHYSICS_LOCKED_ROTATION); - func_8029E070(1); + code_14420_setUpdateTypes(1, YAW_STATE_1_DEFAULT, 3, BA_PHYSICS_LOCKED_ROTATION); + modelAppendages_setKazooiesUpperHalfVisibility(true); FUNC_8030E624(SFX_1F_HITTING_AN_ENEMY_3, 0.8f, 32750); basfx_80299CF4(SFX_36_BANJO_DOH, 1.0f, 28000); baMotor_80250D94(1.0f, 0.5f, 0.5f); @@ -576,7 +578,7 @@ void func_802A48B4(void) { if (item_getCount(ITEM_14_HEALTH) == 0) { func_8029C984(); func_8029151C(0xD); - ncDynamicCamD_func_802BF2C0(30.0f); + ncbadie_func_802BF2C0(30.0f); func_8029B930(); batimer_set(0, 2.5f); D_8037D344 = 2; @@ -614,7 +616,7 @@ void func_802A48B4(void) { void func_802A4A40(void) { func_80291548(); func_8029CB84(); - func_8029E070(0); + modelAppendages_setKazooiesUpperHalfVisibility(false); baMarker_collisionOn(); } @@ -637,7 +639,7 @@ void func_802A4A78(s32 arg0) { baanim_playForDuration_onceSmooth(ASSET_D3_ANIM_BSBFLY_BEAKBOMB_REBOUND, 1.2f); basfx_playOwSfx(1.0f); baMotor_80250D94(1.0f, 0.5f, 0.5f); - _player_getPosition(sp3C); + playerPosition_get(sp3C); func_80294980(sp30); func_80257F18(sp30, sp3C, &sp28); yaw_setIdeal(mlNormalizeAngle(sp28 + 180.0f)); @@ -649,13 +651,13 @@ void func_802A4A78(s32 arg0) { yaw_setIdeal(mlNormalizeAngle(sp28)); yaw_applyIdeal(); } - func_8029C7F4(1, 1, 2, BA_PHYSICS_LOCKED_ROTATION); + code_14420_setUpdateTypes(1, YAW_STATE_1_DEFAULT, 2, BA_PHYSICS_LOCKED_ROTATION); baphysics_set_vertical_velocity(800.0f); baphysics_set_gravity(sp2C); baphysics_set_terminal_velocity(-4000.0f); - func_8029E070(1); + modelAppendages_setKazooiesUpperHalfVisibility(true); func_802914CC(4); - ncDynamicCam4_func_802BFE50(12.0f, 10000.0f, 800.0f); + ncbafly_func_802BFE50(12.0f, 10000.0f, 800.0f); baMarker_collisionOff(); func_802A3430(); } @@ -677,7 +679,7 @@ void func_802A4C88(s32 arg0) { baphysics_reset(); baMarker_collisionOn(); baiFrame_start(); - func_8029E070(0); + modelAppendages_setKazooiesUpperHalfVisibility(false); func_80291548(); func_802A34C8(); } @@ -694,19 +696,19 @@ void func_802A4D10(void){ func_802A4C88(0); } -void func_802A4D30(void){ +void bsbfly_ow_init(void){ func_802A4A78(1); } -void func_802A4D50(void){ +void bsbfly_ow_update(void){ func_802A4C34(1); } -void func_802A4D70(void){ +void bsbfly_ow_end(void){ func_802A4C88(1); } -void func_802A4D90(void) { +void bsbfly_knockback_init(void) { f32 sp34; f32 player_position[3]; f32 sp1C[3]; @@ -714,7 +716,7 @@ void func_802A4D90(void) { func_802BB3DC(2, 100.0f, 0.85f); baanim_playForDuration_onceSmooth(0x10D, 1.0f); func_8030E58C(SFX_56_BANJO_HUI, 1.0f); - _player_getPosition(player_position); + playerPosition_get(player_position); func_80294980(sp1C); func_80257F18(sp1C, player_position, &sp34); yaw_setIdeal(mlNormalizeAngle(sp34 + 180.0f)); @@ -726,15 +728,15 @@ void func_802A4D90(void) { yaw_setIdeal(mlNormalizeAngle(sp34)); yaw_applyIdeal(); } - func_8029C7F4(1, 1, 2, BA_PHYSICS_LOCKED_ROTATION); + code_14420_setUpdateTypes(1, YAW_STATE_1_DEFAULT, 2, BA_PHYSICS_LOCKED_ROTATION); baphysics_set_vertical_velocity(400.0f); baphysics_set_gravity(-1800.0f); baMarker_collisionOff(); func_802914CC(4); - ncDynamicCam4_func_802BFE50(12.0f, 10000.0f, 800.0f); + ncbafly_func_802BFE50(12.0f, 10000.0f, 800.0f); } -void func_802A4EC8(void) { +void bsbfly_knockback_update(void) { s32 next_state; AnimCtrl *sp18; @@ -750,21 +752,21 @@ void func_802A4EC8(void) { bs_setState(next_state); } -void func_802A4F44(void){ +void bsbfly_knockback_end(void){ baphysics_reset_gravity(); baMarker_collisionOn(); func_802A34C8(); } -void func_802A4F74(void) { +void bsbfly_locked_init(void) { baanim_playForDuration_loopSmooth(ASSET_38_ANIM_BSBFLY, 0.62f); - func_8029C7F4(1, 1, 3, BA_PHYSICS_FREEZE); - func_8029E070(1); + code_14420_setUpdateTypes(1, YAW_STATE_1_DEFAULT, 3, BA_PHYSICS_FREEZE); + modelAppendages_setKazooiesUpperHalfVisibility(true); func_802914CC(4); func_802A3430(); } -void func_802A4FC8(void) { +void bsbfly_locked_update(void) { s32 next_state; next_state = 0; @@ -777,7 +779,7 @@ void func_802A4FC8(void) { bs_setState(next_state); } -void func_802A503C(void){ +void bsbfly_locked_end(void){ func_802A34C8(); } @@ -795,32 +797,32 @@ void func_802A505C(void){ extern void baanim_playForDuration_loop(s32, f32); /* .code */ -void func_802A50B0(void){ +void bsbfly_drone_init(void){ func_802A3430(); bsdrone_init(); } -void func_802A50D8(void){ +void bsbfly_drone_update(void){ bsdrone_update(); } -void func_802A50F8(void){ +void bsbfly_drone_end(void){ bsdrone_end(); func_802A34C8(); } -void func_802A5120(void){ +void bsfly_dingpotLaunch_init(void){ baanim_playForDuration_loop(ASSET_68_ANIM_BSJUMP_TUMBLE, 0.35f); - func_8029C7F4(1,1,3, BA_PHYSICS_AIRBORN); + code_14420_setUpdateTypes(1, YAW_STATE_1_DEFAULT, 3, BA_PHYSICS_AIRBORN); baphysics_set_target_horizontal_velocity(0.0f); baphysics_set_velocity(0); baphysics_set_vertical_velocity(2000.0f); basfx_80299CF4(SFX_63_BANJO_UWAAAAOOH, 1.0f, 32000); } -void func_802A5190(void){ +void bsfly_dingpotLaunch_update(void){ baphysics_set_vertical_velocity(2000.0f); bs_setState(0); } -void func_802A51C0(void){} +void bsfly_dingpotLaunch_end(void){} diff --git a/src/core2/bs/stilt_stride.c b/src/core2/bs/bLongLeg.c similarity index 88% rename from src/core2/bs/stilt_stride.c rename to src/core2/bs/bLongLeg.c index 7972e2774..343d1d763 100644 --- a/src/core2/bs/stilt_stride.c +++ b/src/core2/bs/bLongLeg.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/bs/bLongLeg.c #include #include "functions.h" #include "variables.h" @@ -6,6 +7,7 @@ #include "core2/ba/anim.h" #include "core2/ba/physics.h" #include "core2/ba/timer.h" +#include "core2/yaw.h" /* .data */ @@ -48,10 +50,10 @@ void func_802A524C(void){ int bslongleg_inSet(s32 move_indx){ return (move_indx == BS_26_LONGLEG_IDLE) - || (move_indx == BS_LONGLEG_WALK) - || (move_indx == BS_LONGLEG_JUMP) - || (move_indx == BS_LONGLEG_EXIT) - || (move_indx == BS_LONGLEG_SLIDE) + || (move_indx == BS_27_LONGLEG_WALK) + || (move_indx == BS_28_LONGLEG_JUMP) + || (move_indx == BS_29_LONGLEG_EXIT) + || (move_indx == BS_55_LONGLEG_SLIDE) || (move_indx == BS_9B_LONGLEG_DRONE) || (move_indx == BS_62_LONGLEG_LOCKED); } @@ -66,9 +68,9 @@ void func_802A5374(void){ baModel_80292078(1, -50.0f); bastick_setZoneMax(0, 0.03f); bastick_setZoneMax(1, 1.0f); - func_8029E070(1); - func_8029E064(1); - func_8029E0F4(1); + modelAppendages_setKazooiesUpperHalfVisibility(true); + modelAppendages_setKazooiesFeetAndShoesVisibility(true); + modelAppendages_setWadingBootsVisibility(true); pitch_setAngVel(1000.0f, 12.0f); roll_setAngularVelocity(1000.0f, 12.0f); baflag_set(BA_FLAG_3); @@ -80,9 +82,9 @@ void func_802A5404(void){ baModel_80292078(1,0); bastick_resetZones(); - func_8029E070(0); - func_8029E064(0); - func_8029E0F4(0); + modelAppendages_setKazooiesUpperHalfVisibility(false); + modelAppendages_setKazooiesFeetAndShoesVisibility(false); + modelAppendages_setWadingBootsVisibility(false); baModel_setDirection(PLAYER_MODEL_DIR_BANJO); pitch_setIdeal(0.0f); roll_setIdeal(0.0f); @@ -127,7 +129,7 @@ void bsblongleg_enter_init(void){ __bsblongleg_enterFromTrot(); else __bsblongleg_enter(); - func_8029C7F4(1,1,3, BA_PHYSICS_NORMAL); + code_14420_setUpdateTypes(1, YAW_STATE_1_DEFAULT, 3, BA_PHYSICS_NORMAL); baphysics_set_target_horizontal_velocity(0.0f); func_802A5374(); basfx_80299BD4(); @@ -158,7 +160,7 @@ void bsblongleg_enter_end(void){ void bsblongleg_stand_enter(void){ baanim_playForDuration_loopSmooth(ASSET_41_ANIM_BSLONGLEG_IDLE, 1.0f); - func_8029C7F4(1,1,1, BA_PHYSICS_NORMAL); + code_14420_setUpdateTypes(1, YAW_STATE_1_DEFAULT, 1, BA_PHYSICS_NORMAL); baphysics_set_target_horizontal_velocity(0.0f); baModel_setDirection(PLAYER_MODEL_DIR_KAZOOIE); func_802A5374(); @@ -175,16 +177,16 @@ void bsblongleg_stand_update(void){ stateTimer_clear(STATE_TIMER_2_LONGLEG); if(bastick_getZone() > 0) - next_state = BS_LONGLEG_WALK; + next_state = BS_27_LONGLEG_WALK; if(player_shouldSlideTrot()) - next_state = BS_LONGLEG_SLIDE; + next_state = BS_55_LONGLEG_SLIDE; if(bakey_pressed(BUTTON_A) && player_isStable()) - next_state = BS_LONGLEG_JUMP; + next_state = BS_28_LONGLEG_JUMP; if(stateTimer_isDone(STATE_TIMER_2_LONGLEG)) - next_state = BS_LONGLEG_EXIT; + next_state = BS_29_LONGLEG_EXIT; if(func_802A51D0()) next_state = BS_4C_LANDING_IN_WATER; @@ -204,7 +206,7 @@ void bsblongleg_walk_init(void){ anctrl_setIndex(aCtrl, ASSET_42_ANIM_BSLONGLEG_WALK); anctrl_setPlaybackType(aCtrl, ANIMCTRL_LOOP); anctrl_start(aCtrl, "bsblongleg.c", 0x1a1); - func_8029C7F4(2,1,1, BA_PHYSICS_NORMAL); + code_14420_setUpdateTypes(2, YAW_STATE_1_DEFAULT, 1, BA_PHYSICS_NORMAL); baanim_setVelocityMapRanges(D_80364A40, D_80364A44, D_80364A48, D_80364A4C); } @@ -229,13 +231,13 @@ void bsblongleg_walk_update(void){ next_state = BS_26_LONGLEG_IDLE; if(player_shouldSlideTrot()) - next_state = BS_LONGLEG_SLIDE; + next_state = BS_55_LONGLEG_SLIDE; if(bakey_pressed(BUTTON_A) && player_isStable()) - next_state = BS_LONGLEG_JUMP; + next_state = BS_28_LONGLEG_JUMP; if(stateTimer_isDone(STATE_TIMER_2_LONGLEG)) - next_state = BS_LONGLEG_EXIT; + next_state = BS_29_LONGLEG_EXIT; if(func_802A51D0()) next_state = BS_4C_LANDING_IN_WATER; @@ -324,7 +326,7 @@ void bsblongleg_jump_init(void){ anctrl_setSubRange(aCtrl, 0.0f, 0.42f); anctrl_setPlaybackType(aCtrl, ANIMCTRL_ONCE); anctrl_start(aCtrl, "bsblongleg.c", 0x27F); - func_8029C7F4(1,1,3, BA_PHYSICS_AIRBORN); + code_14420_setUpdateTypes(1, YAW_STATE_1_DEFAULT, 3, BA_PHYSICS_AIRBORN); if(bastick_distance() != 0.0f) yaw_setIdeal(bastick_getAngleRelativeToBanjo()); baphysics_set_target_yaw(yaw_getIdeal()); @@ -348,7 +350,7 @@ void bsblongleg_jump_update(void){ if(bakey_released(BUTTON_A) && 0.0f < sp34[1]) baphysics_reset_gravity(); - sp30 = player_getYPosition() - func_80294438(); + sp30 = playerPosition_getY() - func_80294438(); switch(D_8037D360){ case 0://L802A5F24 if((sp34[1] < 100.0f) || sp30 < 10.0f) @@ -386,10 +388,10 @@ void bsblongleg_jump_update(void){ sp44 = BS_26_LONGLEG_IDLE; if(bakey_pressed(BUTTON_A)) - sp44 = BS_LONGLEG_JUMP; + sp44 = BS_28_LONGLEG_JUMP; if(stateTimer_isDone(STATE_TIMER_2_LONGLEG)) - sp44 = BS_LONGLEG_EXIT; + sp44 = BS_29_LONGLEG_EXIT; break; }//L802A60F0 @@ -414,11 +416,11 @@ void bsblongleg_slide_init(void){ anctrl_setPlaybackType(aCtrl, ANIMCTRL_STOPPED); anctrl_setStart(aCtrl, 0.0865f); anctrl_start(aCtrl, "bsblongleg.c", 0x339); - func_8029C7F4(1,1,3, BA_PHYSICS_LOCKED_ROTATION); + code_14420_setUpdateTypes(1, YAW_STATE_1_DEFAULT, 3, BA_PHYSICS_LOCKED_ROTATION); baphysics_set_target_yaw(yaw_getIdeal()); baphysics_set_horizontal_velocity(yaw_getIdeal(), baphysics_get_target_horizontal_velocity()); - func_8029E070(1); - func_8029E064(1); + modelAppendages_setKazooiesUpperHalfVisibility(true); + modelAppendages_setKazooiesFeetAndShoesVisibility(true); pitch_setAngVel(1000.0f, 12.0f); roll_setAngularVelocity(1000.0f, 12.0f); baphysics_set_target_horizontal_velocity(0.0f); @@ -447,7 +449,7 @@ void bsblongleg_slide_update(void){ } if(D_8037D358 == 0.0f && bakey_pressed(BUTTON_A)) - sp3C = BS_LONGLEG_JUMP; + sp3C = BS_28_LONGLEG_JUMP; if(func_802A51D0()) sp3C = BS_4C_LANDING_IN_WATER; @@ -463,16 +465,16 @@ void func_802A6388(f32 arg0){ D_8037D35C = arg0; } -void func_802A6394(void){ +void bsblongleg_locked_init(void){ baanim_playForDuration_loopSmooth(ASSET_41_ANIM_BSLONGLEG_IDLE, 1.0f); - func_8029C7F4(1,1,3, BA_PHYSICS_NORMAL); + code_14420_setUpdateTypes(1, YAW_STATE_1_DEFAULT, 3, BA_PHYSICS_NORMAL); baphysics_set_target_horizontal_velocity(0.0f); func_802A5374(); baModel_setDirection(PLAYER_MODEL_DIR_KAZOOIE); func_8029C674(); } -void func_802A63F0(void){ +void bsblongleg_locked_update(void){ enum bs_e next_state = 0; func_802A531C(); func_8029C6D0(); @@ -487,7 +489,7 @@ void func_802A63F0(void){ bs_setState(next_state); } -void func_802A6450(void){ +void bsblongleg_locked_end(void){ func_8029C748(); func_802A5404(); } @@ -501,7 +503,7 @@ void bsblongleg_drone_update(void){ func_802A531C(); bsdrone_update(); if(stateTimer_isDone(STATE_TIMER_2_LONGLEG)) - bs_setState(BS_LONGLEG_EXIT); + bs_setState(BS_29_LONGLEG_EXIT); } void bsblongleg_drone_end(void){ diff --git a/src/core2/bs/beak_peck.c b/src/core2/bs/bPeck.c similarity index 93% rename from src/core2/bs/beak_peck.c rename to src/core2/bs/bPeck.c index ea581151b..a4f234268 100644 --- a/src/core2/bs/beak_peck.c +++ b/src/core2/bs/bPeck.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/bs/bPeck.c #include #include "functions.h" #include "variables.h" @@ -40,9 +41,9 @@ void bsbpeck_init(void){ bafalldamage_set_state(2); baanim_playForDuration_onceSmooth(ASSET_1A_ANIM_BSBPECK, 0.2f); - func_8029C7F4(1,YAW_STATE_3_BOUNDED, 1, BA_PHYSICS_AIRBORN); + code_14420_setUpdateTypes(1, YAW_STATE_3_BOUNDED, 1, BA_PHYSICS_AIRBORN); yaw_setVelocityBounded(1200.0f, 10.0f); - func_8029E070(1); + modelAppendages_setKazooiesUpperHalfVisibility(true); baphysics_set_gravity(D_80364A60); baphysics_set_vertical_velocity(D_80364A64); baModel_80292048(1, -38.0f, 0.0f, 105.0f); @@ -135,6 +136,6 @@ void bsbpeck_end(void){ baModel_80292048(1, 0.0f, 0.0f, 0.0f); baModel_80292048(0, 0.0f, 0.0f, 0.0f); baMarker_8028D638(0, 0); - func_8029E070(0); + modelAppendages_setKazooiesUpperHalfVisibility(false); baphysics_reset_gravity(); } diff --git a/src/core2/bs/shock_spring.c b/src/core2/bs/bShock.c similarity index 86% rename from src/core2/bs/shock_spring.c rename to src/core2/bs/bShock.c index 77046f033..ce8347a83 100644 --- a/src/core2/bs/shock_spring.c +++ b/src/core2/bs/bShock.c @@ -1,8 +1,10 @@ +// BanjoDecomp: core2/bs/bShock.c #include #include "functions.h" #include "variables.h" #include "core2/ba/physics.h" +#include "core2/yaw.h" /* .data */ const f32 D_80364A70 = 1250.0f; @@ -23,7 +25,7 @@ void bsbshock_charge_init(void){ anctrl_setSubRange(aCtrl, 0.0f, 0.1061f); anctrl_setPlaybackType(aCtrl,1); anctrl_start(aCtrl, "bsbshock.c", 0x61); - func_8029C7F4(1,1,3, BA_PHYSICS_AIRBORN); + code_14420_setUpdateTypes(1, YAW_STATE_1_DEFAULT, 3, BA_PHYSICS_AIRBORN); if(bastick_distance() != 0.0f) yaw_setIdeal(bastick_getAngleRelativeToBanjo()); @@ -31,8 +33,8 @@ void bsbshock_charge_init(void){ baphysics_set_target_yaw(yaw_getIdeal()); func_802B6FA8(); baphysics_set_horizontal_velocity(yaw_getIdeal(), baphysics_get_target_horizontal_velocity()); - func_8029E064(1); - func_8029E070(1); + modelAppendages_setKazooiesFeetAndShoesVisibility(true); + modelAppendages_setKazooiesUpperHalfVisibility(true); basfx_80299BD4(); D_8037D382 = sfxsource_createSfxsourceAndReturnIndex(); sfxsource_setSfxId(D_8037D382, SFX_2C_PULLING_NOISE); @@ -96,13 +98,13 @@ void bsbshock_charge_update(void){ } else{//L802A6D18 if(bainput_should_feathery_flap()) - sp2C = BS_BFLAP; + sp2C = BS_10_BFLAP; if(bainput_should_beak_bust()) sp2C = BS_F_BBUSTER; }//L802A6D44 if(anctrl_isAt( aCtrl, 0.3637f) && D_8037D380) - sp2C = BS_BSHOCK_JUMP; + sp2C = BS_22_BSHOCK_JUMP; if(anctrl_isAt(aCtrl, 0.5551f)){ baphysics_set_vertical_velocity(180.0f); @@ -117,8 +119,8 @@ void bsbshock_charge_update(void){ void bsbshock_charge_end(void){ sfxsource_freeSfxsourceByIndex(D_8037D382); - func_8029E064(0); - func_8029E070(0); + modelAppendages_setKazooiesFeetAndShoesVisibility(false); + modelAppendages_setKazooiesUpperHalfVisibility(false); if(baModel_80292230() != 0.0f){ baModel_80292158(0.0f); playerPosition_addY(50.0f); @@ -135,7 +137,7 @@ void bsbshock_init(void){ anctrl_setSubRange(aCtrl, 0.0f, 1.0f); anctrl_setPlaybackType(aCtrl,1); anctrl_start(aCtrl, "bsbshock.c", 0x13a); - func_8029C7F4(1,1,3, BA_PHYSICS_AIRBORN); + code_14420_setUpdateTypes(1, YAW_STATE_1_DEFAULT, 3, BA_PHYSICS_AIRBORN); if(bastick_distance() != 0.0f) yaw_setIdeal(bastick_getAngleRelativeToBanjo()); @@ -146,8 +148,8 @@ void bsbshock_init(void){ baphysics_set_vertical_velocity(D_80364A70); baphysics_set_gravity(D_80364A74); sfxsource_playHighPriority(SFX_E_SHOCKSPRING_BOING); - func_8029E064(1); - func_8029E070(1); + modelAppendages_setKazooiesFeetAndShoesVisibility(true); + modelAppendages_setKazooiesUpperHalfVisibility(true); ability_use(9); baModel_80292158(-50.0f); playerPosition_addY(-50.0f); @@ -178,7 +180,7 @@ void bsbshock_update(void){ sp2C = BS_3D_FALL_TUMBLING; if(bainput_should_feathery_flap()) - sp2C = BS_BFLAP; + sp2C = BS_10_BFLAP; if(bainput_should_beak_bust()) sp2C =BS_F_BBUSTER; @@ -191,8 +193,8 @@ void bsbshock_end(void){ if(bs_getNextState() != BS_11_BPECK) baphysics_reset_gravity(); - func_8029E064(0); - func_8029E070(0); + modelAppendages_setKazooiesFeetAndShoesVisibility(false); + modelAppendages_setKazooiesUpperHalfVisibility(false); baModel_80292158(0.0f); playerPosition_addY(50.0f); } diff --git a/src/core2/bs/beak_swim.c b/src/core2/bs/bSwim.c similarity index 90% rename from src/core2/bs/beak_swim.c rename to src/core2/bs/bSwim.c index f88395db2..93be28c9c 100644 --- a/src/core2/bs/beak_swim.c +++ b/src/core2/bs/bSwim.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/bs/bSwim.c #include #include "functions.h" #include "variables.h" @@ -5,6 +6,7 @@ #include "core2/ba/model.h" #include "core2/ba/physics.h" #include "core2/ba/timer.h" +#include "core2/yaw.h" extern f32 func_8029494C(void); @@ -18,7 +20,7 @@ u8 D_8037D396; f32 D_8037D398; void func_802A7140() { - func_8029C7F4(1, 3, 3, BA_PHYSICS_NO_GRAVITY); + code_14420_setUpdateTypes(1, YAW_STATE_3_BOUNDED, 3, BA_PHYSICS_NO_GRAVITY); } f32 func_802A716C() { @@ -64,7 +66,7 @@ bool func_802A73BC(void) { f32 sp1C; sp1C = (gsworld_getMap() == MAP_46_CCW_WINTER) ? 90.0f : 130.0f; - return floor_isCurrentFloorunk59() && player_getYPosition() > (floor_getCurrentFloorYPosition() - sp1C); + return floor_isCurrentFloorunk59() && playerPosition_getY() > (floor_getCurrentFloorYPosition() - sp1C); } void func_802A744C(void) { @@ -76,7 +78,7 @@ void func_802A744C(void) { baphysics_set_terminal_velocity(-399.99f); bastick_setZoneMax(0, 0.03f); bastick_setZoneMax(1, 1.0f); - func_8029E070(1); + modelAppendages_setKazooiesUpperHalfVisibility(true); func_80294378(3); baModel_setYDisplacement(60.0f); baphysics_set_acceleration(2.0f); @@ -106,13 +108,13 @@ void func_802A75B0(void) { baphysics_reset_terminal_velocity(); baphysics_reset_gravity(); bastick_resetZones(); - func_8029E070(0); + modelAppendages_setKazooiesUpperHalfVisibility(false); func_80294378(1); baModel_setYDisplacement(0.0f); } } -void func_802A762C() { +void bsbdive_idle_init() { baanim_playForDuration_loopSmooth(0x70, 2.0f); func_802A7140(); baphysics_set_target_velocity(0); @@ -120,7 +122,7 @@ void func_802A762C() { baphysics_set_acceleration(0.4f); } -void func_802A7674() { +void bsbdive_idle_update() { s32 state_id = 0; func_802A71D8(); @@ -145,11 +147,11 @@ void func_802A7674() { bs_setState(state_id); } -void func_802A7718() { +void bsbdive_idle_end() { func_802A75B0(); } -void func_802A7738(void) { +void bsbdiveb_init(void) { AnimCtrl* temp_s0; AnimCtrl* temp_v0; @@ -179,7 +181,7 @@ void func_802A77D8(void) { baphysics_set_velocity(sp24); } -void func_802A7838(void) { +void bsbdiveb_update(void) { s32 next_state; AnimCtrl *anim_ctrl; f64 temp_f2; @@ -229,12 +231,12 @@ void func_802A7838(void) { bs_setState(next_state); } -void func_802A7A2C() { +void bsbdiveb_end() { func_802906A4(1); func_802A75B0(); } -void func_802A7A54() { +void bsswim_divea_init() { baanim_playForDuration_loopSmooth(0x71, 0.75f); func_802A7140(); func_802A744C(); @@ -243,7 +245,7 @@ void func_802A7A54() { func_802906A4(2); } -void func_802A7AB0(void) { +void bsswim_divea_update(void) { s32 next_state; AnimCtrl *anim_ctl; @@ -275,12 +277,12 @@ void func_802A7AB0(void) { bs_setState(next_state); } -void func_802A7BA8(void) { +void bsswim_divea_end(void) { func_802906A4(1); func_802A75B0(); } -void func_802A7BD0(void) { +void bsbswim_ow_init(void) { f32 sp3C; f32 sp30[3]; f32 sp24[3]; @@ -288,7 +290,7 @@ void func_802A7BD0(void) { barebound_set_active(func_80296560()); baanim_playForDuration_onceSmooth(0x1A0, 1.4f); basfx_playOwSfx(1.0f); - _player_getPosition(sp30); + playerPosition_get(sp30); func_80294980(sp24); func_80257F18(sp24, sp30, &sp3C); yaw_setIdeal(mlNormalizeAngle(sp3C)); @@ -296,19 +298,19 @@ void func_802A7BD0(void) { baphysics_set_target_horizontal_velocity(barebound_get_horizontal_velocity()); baphysics_set_target_yaw(sp3C); baphysics_set_horizontal_velocity(sp3C, baphysics_get_target_horizontal_velocity()); - func_8029C7F4(1, 1, 2, BA_PHYSICS_LOCKED_ROTATION); + code_14420_setUpdateTypes(1, YAW_STATE_1_DEFAULT, 2, BA_PHYSICS_LOCKED_ROTATION); baMarker_collisionOff(); baeyes_close(); func_802A744C(); } -void func_802A7CA8(void) { +void bsbswim_ow_update(void) { s32 next_state; f32 plyr_pos[3]; ParticleEmitter *p_ctrl; next_state = 0; - _player_getPosition(plyr_pos); + playerPosition_get(plyr_pos); plyr_pos[1] += 60.0f; p_ctrl = func_8029B950(plyr_pos, 25.0f); particleEmitter_setParticleVelocityRange(p_ctrl, -60.0f, -50.0f, -60.0f, 60.0f, 100.0f, 60.0f); @@ -323,7 +325,7 @@ void func_802A7CA8(void) { } -void func_802A7D74(void) { +void bsbswim_ow_end(void) { baiFrame_start(); baMarker_collisionOn(); baeyes_open(); @@ -343,7 +345,7 @@ void bsSwim_dive_init(void) { } -void func_802A7E2C(void) { +void bsSwim_dive_update(void) { s32 next_state; AnimCtrl *sp38; f32 sp34; @@ -379,11 +381,11 @@ void func_802A7E2C(void) { bs_setState(next_state); } -void func_802A7F4C(void){ +void bsSwim_dive_end(void){ func_802A75B0(); } -void func_802A7F6C(void) { +void bsbswim_die_init(void) { D_8037D394 = BOOL(bs_getPrevState() == BS_41_DIE); if (D_8037D394 || level_get() == LEVEL_9_RUSTY_BUCKET_BAY || gsworld_getMap() == MAP_46_CCW_WINTER) { @@ -409,7 +411,7 @@ void func_802A7F6C(void) { basfx_80299CF4(SFX_CA_BANJO_DROWNING_1, 1.0f, 24000); } -void func_802A8098(void) { +void bsbswim_die_update(void) { s32 next_state; f32 sp40[3]; ParticleEmitter *p_ctrl; @@ -429,7 +431,7 @@ void func_802A8098(void) { switch (D_8037D396) { case 0: if (globalTimer_getTimeMasked(1) == 0) { - _player_getPosition(plyr_pos); + playerPosition_get(plyr_pos); plyr_pos[1] += 60.0f; p_ctrl = func_8029B950(plyr_pos, 25.0f); particleEmitter_setParticleVelocityRange(p_ctrl, -60.0f, -50.0f, -60.0f, 60.0f, 100.0f, 60.0f); @@ -443,7 +445,7 @@ void func_802A8098(void) { } if (batimer_isAt(1, 1.9f)) { func_802914CC(0xD); - ncDynamicCamD_func_802BF2C0(80.0f); + ncbadie_func_802BF2C0(80.0f); if (D_8037D394) { batimer_set(0, 0.5f); } else { @@ -461,7 +463,7 @@ void func_802A8098(void) { bs_setState(next_state); } -void func_802A82D4(void) { +void bsbswim_die_end(void) { func_802906A4(1); func_80291548(); core1_ce60_incOrDecCounter(false); @@ -478,8 +480,8 @@ void __bsbswim_update_rotation(void) { f32 sp2C[3]; if (balookat_getState() && balookat_try_get_position(sp2C)) { - _player_getPosition(sp44); - func_8025727C(sp44[0], sp44[1], sp44[2], sp2C[0], sp2C[1], sp2C[2], &sp38[0], &sp38[1]); + playerPosition_get(sp44); + ml_horizontal_and_vertical_angles(sp44[0], sp44[1], sp44[2], sp2C[0], sp2C[1], sp2C[2], &sp38[0], &sp38[1]); pitch_setIdeal(sp38[0]); yaw_setIdeal(sp38[1]); roll_setIdeal(0.0f); @@ -511,7 +513,7 @@ void bsbswim_lookat_end(void){ func_802A75B0(); } -void func_802A846C(void) { +void bsbswim_landingInWater_init(void) { AnimCtrl *temp_s0; f32 sp28; @@ -538,18 +540,18 @@ void func_802A846C(void) { } D_8037D398 = ml_map_f(sp28, 40.0f, 1000.0f, -300.0f, -1200.0f); baphysics_set_vertical_velocity(D_8037D398); - func_8029C7F4(1, 3, 3, BA_PHYSICS_NO_GRAVITY); + code_14420_setUpdateTypes(1, YAW_STATE_3_BOUNDED, 3, BA_PHYSICS_NO_GRAVITY); func_802A744C(); baphysics_set_type(BA_PHYSICS_AIRBORN); } -void func_802A85EC(void) { +void bsbswim_landingInWater_update(void) { s32 next_state; f32 sp38[3]; ParticleEmitter *sp34; next_state = 0; - _player_getPosition(sp38); + playerPosition_get(sp38); sp38[1] += 60.0f; sp34 = func_8029B950(sp38, 20.0f); particleEmitter_setParticleVelocityRange(sp34, -30.0f, -30.0f, -30.0f, 30.0f, 30.0f, 30.0f); @@ -570,7 +572,7 @@ void func_802A85EC(void) { bs_setState(next_state); } -void func_802A872C(void){ +void bsbswim_landingInWater_end(void){ func_802A75B0(); } diff --git a/src/core2/bs/talon_trot.c b/src/core2/bs/bTrot.c similarity index 93% rename from src/core2/bs/talon_trot.c rename to src/core2/bs/bTrot.c index abfc22b86..de118fec9 100644 --- a/src/core2/bs/talon_trot.c +++ b/src/core2/bs/bTrot.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/bs/bTrot.c #include #include "functions.h" #include "variables.h" @@ -6,6 +7,7 @@ #include "core2/ba/anim.h" #include "core2/ba/physics.h" #include "core2/statetimer.h" +#include "core2/yaw.h" /* .data */ f32 D_80364A90 = 30.0f; @@ -102,8 +104,8 @@ void bsbtrot_walkUpdateTargetVelocity(void){ void func_802A8A40(void){ bastick_setZoneMax(0, 0.03f); bastick_setZoneMax(1, 1.0f); - func_8029E070(1); - func_8029E064(1); + modelAppendages_setKazooiesUpperHalfVisibility(true); + modelAppendages_setKazooiesFeetAndShoesVisibility(true); pitch_setAngVel(1000.0f, 12.0f); roll_setAngularVelocity(1000.0f, 12.0f); baflag_set(BA_FLAG_3); @@ -120,14 +122,14 @@ void func_802A8AD8(void){ } if(stateTimer_isDone(STATE_TIMER_3_TURBO_TALON)){ - if(func_8029DFE0()){ - func_8029E0DC(0); + if(modelAppendages_hideTurboTrainers()){ + modelAppendages_setTurboTrainersVisibility(false); if(baflag_isFalse(BA_FLAG_14_LOSE_BOGGY_RACE)) - sfxsource_playHighPriority(0x3eb); + sfxsource_playHighPriority(SFX_3EB_UNKNOWN); func_803219F4(1); } }else{ - func_8029E0DC(1); + modelAppendages_setTurboTrainersVisibility(true); } } @@ -139,8 +141,8 @@ void func_802A8BB0(void){ baModel_setDirection(PLAYER_MODEL_DIR_BANJO); bastick_resetZones(); - func_8029E070(0); - func_8029E064(0); + modelAppendages_setKazooiesUpperHalfVisibility(false); + modelAppendages_setKazooiesFeetAndShoesVisibility(false); pitch_setIdeal(0.0f); roll_setIdeal(0.0f); baflag_clear(BA_FLAG_3); @@ -214,7 +216,7 @@ enum bs_e func_802A8D84(enum bs_e arg0){ void bsbtrot_enter_init(void){ func_802A8AD8(); baanim_playForDuration_onceSmooth(ASSET_16_ANIM_BSBTROT_ENTER, 1.0f); - func_8029C7F4(1,1,2, BA_PHYSICS_NORMAL); + code_14420_setUpdateTypes(1, YAW_STATE_1_DEFAULT, 2, BA_PHYSICS_NORMAL); baphysics_set_target_horizontal_velocity(0.0f); func_802A8A40(); basfx_80299BD4(); @@ -243,7 +245,7 @@ void bsbtrot_enter_end(void){ void bsbtrot_stand_init(void){ baanim_playForDuration_loopSmooth(ASSET_26_ANIM_BSBTROT_IDLE, 1.2f); - func_8029C7F4(1,1,1, BA_PHYSICS_NORMAL); + code_14420_setUpdateTypes(1, YAW_STATE_1_DEFAULT, 1, BA_PHYSICS_NORMAL); baphysics_set_target_horizontal_velocity(0.0f); func_802A8A40(); } @@ -283,7 +285,7 @@ void func_802A9054(void){ void bsbtrot_walk_init(void){ baanim_playForDuration_loopSmooth(func_802A9030(), 0.53f); - func_8029C7F4(2,1,1, BA_PHYSICS_NORMAL); + code_14420_setUpdateTypes(2, YAW_STATE_1_DEFAULT, 1, BA_PHYSICS_NORMAL); func_802A8A40(); func_802A9054(); } @@ -505,11 +507,11 @@ void bsbtrot_slide_init(void){ anctrl_setPlaybackType(aCtrl, ANIMCTRL_STOPPED); anctrl_start(aCtrl, "bsbtrot.c", 0x382); func_802A8A40(); - func_8029C7F4(1,1,3, BA_PHYSICS_LOCKED_ROTATION); + code_14420_setUpdateTypes(1, YAW_STATE_1_DEFAULT, 3, BA_PHYSICS_LOCKED_ROTATION); baphysics_set_target_yaw(yaw_getIdeal()); baphysics_set_horizontal_velocity(yaw_getIdeal(), baphysics_get_target_horizontal_velocity()); - func_8029E070(1); - func_8029E064(1); + modelAppendages_setKazooiesUpperHalfVisibility(true); + modelAppendages_setKazooiesFeetAndShoesVisibility(true); pitch_setAngVel(1000.0f, 12.0f); roll_setAngularVelocity(1000.0f, 12.0f); baphysics_set_target_horizontal_velocity(0.0f); @@ -559,7 +561,7 @@ int bsbtrot_inSet(s32 move_indx){ || (move_indx == BS_45_BTROT_SLIDE) || (move_indx == BS_14_BTROT_ENTER) || (move_indx == 0x79) - || (move_indx == BS_BTROT_OW) + || (move_indx == BS_7B_BTROT_OW) || (move_indx == BS_71_BTROT_FALL) || (move_indx == 0x9a); } @@ -573,7 +575,7 @@ void bsbtrot_fall_init(void){ anctrl_setPlaybackType(aCtrl, ANIMCTRL_STOPPED); anctrl_start(aCtrl, "bsbtrot.c", 0x400); func_802A8A40(); - func_8029C7F4(1,1,3, BA_PHYSICS_AIRBORN); + code_14420_setUpdateTypes(1, YAW_STATE_1_DEFAULT, 3, BA_PHYSICS_AIRBORN); baphysics_set_target_yaw(yaw_getIdeal()); bsbtrot_walkUpdateTargetVelocity(); baphysics_set_horizontal_velocity(yaw_getIdeal(), baphysics_get_target_horizontal_velocity()); @@ -678,16 +680,16 @@ void bsbtrot_fall_end(void){ func_802A8BB0(); } -void bsbtrot_unk79_init(void){ +void bsbtrot_locked_init(void){ baanim_playForDuration_loopSmooth(ASSET_26_ANIM_BSBTROT_IDLE, 1.2f); - func_8029C7F4(1,1,3, BA_PHYSICS_NORMAL); + code_14420_setUpdateTypes(1, YAW_STATE_1_DEFAULT, 3, BA_PHYSICS_NORMAL); baphysics_set_target_horizontal_velocity(0.0f); func_802A8A40(); baModel_setDirection(PLAYER_MODEL_DIR_KAZOOIE); func_8029C674(); } -void bsbtrot_unk79_update(void){ +void bsbtrot_locked_update(void){ enum bs_e sp1C = 0; func_8029C6D0(); func_802A8AD8(); @@ -697,7 +699,7 @@ void bsbtrot_unk79_update(void){ bs_setState(sp1C); } -void bsbtrot_unk79_end(void){ +void bsbtrot_locked_end(void){ func_8029C748(); func_802A8BB0(); } @@ -711,7 +713,7 @@ void bsbtrot_ow_init(void){ barebound_set_active(func_80296560()); baanim_playForDuration_onceSmooth(ASSET_66_ANIM_BSBTROT_OW, 1.1f); basfx_playOwSfx(1.0f); - _player_getPosition(sp30); + playerPosition_get(sp30); func_80294980(sp24); func_80257F18(sp24, sp30, &sp3C); yaw_setIdeal(mlNormalizeAngle(sp3C + 180.0f));\ @@ -719,7 +721,7 @@ void bsbtrot_ow_init(void){ baphysics_set_target_horizontal_velocity(barebound_get_horizontal_velocity()); baphysics_set_target_yaw(sp3C); baphysics_set_horizontal_velocity(sp3C, baphysics_get_target_horizontal_velocity()); - func_8029C7F4(1,1,2, BA_PHYSICS_LOCKED_ROTATION); + code_14420_setUpdateTypes(1, YAW_STATE_1_DEFAULT, 2, BA_PHYSICS_LOCKED_ROTATION); if(barebound_802987B4() == 2) baphysics_set_type(BA_PHYSICS_AIRBORN); baphysics_set_vertical_velocity(barebound_get_vertical_velocity()); diff --git a/src/core2/bs/wonderwing.c b/src/core2/bs/bWhirl.c similarity index 91% rename from src/core2/bs/wonderwing.c rename to src/core2/bs/bWhirl.c index 48be4a02c..95b7a6d3b 100644 --- a/src/core2/bs/wonderwing.c +++ b/src/core2/bs/bWhirl.c @@ -1,9 +1,11 @@ +// BanjoDecomp: core2/bs/bWhirl.c #include #include "functions.h" #include "variables.h" #include "core2/ba/anim.h" #include "core2/ba/physics.h" +#include "core2/yaw.h" const f32 D_80364AD0 = 80.0f; const f32 D_80364AD4 = 425.0f; @@ -37,7 +39,7 @@ static void __bsbwhirl_end(void){ ) ){ bastick_resetZones(); - func_8029E070(0); + modelAppendages_setKazooiesUpperHalfVisibility(false); func_8025A55C(-1, 0xfa0, 0xd); core1_ce60_incOrDecCounter(true); func_8025A7DC(COMUSIC_25_USING_GOLD_FEATHERS); @@ -80,11 +82,11 @@ void func_802AA58C(enum bs_e *arg0){ void bsbwhirl_enter_init(void){ baanim_playForDuration_onceSmooth(ASSET_22_ANIM_BSWHIRL_EXIT, 0.5f); - func_8029C7F4(1,1,1, BA_PHYSICS_NORMAL); + code_14420_setUpdateTypes(1, YAW_STATE_1_DEFAULT, 1, BA_PHYSICS_NORMAL); baphysics_set_target_horizontal_velocity(0.0f); bastick_setZoneMax(0, 0.03f); bastick_setZoneMax(1, 1.0f); - func_8029E070(1); + modelAppendages_setKazooiesUpperHalfVisibility(true); D_8037D3B0 = 0.0f; core1_ce60_incOrDecCounter(false); func_8025A55C(0, 0xfa0, 0xd); @@ -108,7 +110,7 @@ void bsbwhirl_enter_end(void){ void bsbwhirl_stand_init(void){ baanim_playForDuration_loopSmooth(ASSET_23_ANIM_BSWONDERWING_IDLE, 1.0f); - func_8029C7F4(1,1,1, BA_PHYSICS_NORMAL); + code_14420_setUpdateTypes(1, YAW_STATE_1_DEFAULT, 1, BA_PHYSICS_NORMAL); baphysics_set_target_horizontal_velocity(0.0f); } @@ -119,7 +121,7 @@ void bsbwhirl_stand_update(void){ func_802AA58C(&sp1C); if(player_isSliding()) - sp1C = BS_SLIDE; + sp1C = BS_32_SLIDE; if(player_inWater()) sp1C = BS_4C_LANDING_IN_WATER; @@ -135,7 +137,7 @@ void bsbwhirl_stand_end(void){ void bsbwhirl_walk_init(void){ baanim_playForDuration_loopSmooth(ASSET_11_ANIM_BSWHIRL_WALK, 0.53f); baanim_setVelocityMapRanges(D_80364AD0, D_80364AD4, D_80364AD8, D_80364ADC); - func_8029C7F4(2,1,1, BA_PHYSICS_NORMAL); + code_14420_setUpdateTypes(2, YAW_STATE_1_DEFAULT, 1, BA_PHYSICS_NORMAL); } void bsbwhirl_walk_update(void){ @@ -160,7 +162,7 @@ void bsbwhirl_walk_update(void){ func_802AA58C(&sp1C); if(player_isSliding()) - sp1C = BS_SLIDE; + sp1C = BS_32_SLIDE; bs_setState(sp1C); } @@ -180,7 +182,7 @@ void bsbwhirl_jump_init(void){ anctrl_setSubRange(aCtrl, 0.0f, 0.4495f); anctrl_setPlaybackType(aCtrl, ANIMCTRL_ONCE); anctrl_start(aCtrl, "bsbwhirl.c", 0x181); - func_8029C7F4(1,1,3,BA_PHYSICS_AIRBORN); + code_14420_setUpdateTypes(1, YAW_STATE_1_DEFAULT, 3, BA_PHYSICS_AIRBORN); if(bastick_distance() != 0.0f) yaw_setIdeal(bastick_getAngleRelativeToBanjo()); @@ -283,14 +285,14 @@ void bsbwhirl_drone_end(void){ __bsbwhirl_end(); } -void func_802AADBC(void){ +void bsbwhirl_bsA5unknown_init(void){ baanim_playForDuration_loopSmooth(ASSET_23_ANIM_BSWONDERWING_IDLE, 1.0f); - func_8029C7F4(1,1,3, BA_PHYSICS_NORMAL); + code_14420_setUpdateTypes(1, YAW_STATE_1_DEFAULT, 3, BA_PHYSICS_NORMAL); baphysics_set_target_horizontal_velocity(0.0f); func_8029C674(); } -void func_802AAE08(void){ +void bsbwhirl_bsA5unknown_update(void){ enum bs_e sp1C =0; __bsbwhirl_spawnSparkle(); func_8029C6D0(); @@ -300,7 +302,7 @@ void func_802AAE08(void){ bs_setState(sp1C); } -void func_802AAE4C(void){ +void bsbwhirl_bsA5unknown_end(void){ func_8029C748(); __bsbwhirl_end(); } diff --git a/src/core2/bs/beak_buster.c b/src/core2/bs/bbuster.c similarity index 94% rename from src/core2/bs/beak_buster.c rename to src/core2/bs/bbuster.c index 3190548f2..049ffedc0 100644 --- a/src/core2/bs/beak_buster.c +++ b/src/core2/bs/bbuster.c @@ -1,8 +1,10 @@ +// BanjoDecomp: core2/bs/bbuster.c #include #include "functions.h" #include "variables.h" #include "core2/ba/physics.h" +#include "core2/yaw.h" /*.data*/ const f32 D_80364990 = 400.0f; @@ -64,12 +66,12 @@ void bsbbuster_init(void){ anctrl_setSubRange(aCtrl, 0.0f, 0.35f); anctrl_setPlaybackType(aCtrl, ANIMCTRL_ONCE); anctrl_start(aCtrl, "bsbbuster.c", 0x81); - func_8029C7F4(1,1,3, BA_PHYSICS_AIRBORN); + code_14420_setUpdateTypes(1, YAW_STATE_1_DEFAULT, 3, BA_PHYSICS_AIRBORN); baphysics_set_gravity(0.0f); baphysics_set_target_horizontal_velocity(0.0f); ml_vec3f_clear(sp20); baphysics_set_velocity(sp20); - func_8029E070(1); + modelAppendages_setKazooiesUpperHalfVisibility(true); func_802A02B4(0); D_8037D2B9 = 0; D_8037D2B7 = 0; @@ -146,10 +148,10 @@ void bsbbuster_update(void){ D_8037D2B8 = 1; D_8037D2B0 = 0.09f; D_8037D2BA = 3; - _player_getPosition(player_position); + playerPosition_get(player_position); func_8032728C(player_position, 150.0f, 2, func_8029FB20); if(bafalldamage_get_damage(&sp3C)){ - sp44 = BS_SPLAT; + sp44 = BS_72_SPLAT; } } break; @@ -200,7 +202,7 @@ void bsbbuster_update(void){ void bsbbuster_end(void){ baphysics_reset_gravity(); baphysics_reset_terminal_velocity(); - func_8029E070(0); + modelAppendages_setKazooiesUpperHalfVisibility(false); D_8037D2B7 = 0; D_8037D2B8 = 0; } diff --git a/src/core2/bs/bee.c b/src/core2/bs/bee.c index bbc820bf8..ef32faa9c 100644 --- a/src/core2/bs/bee.c +++ b/src/core2/bs/bee.c @@ -17,8 +17,8 @@ void func_802A02C0(void){ pitch_setIdeal(0.0f); //pitch_setIdeal roll_setIdeal(0.0f); bastick_resetZones(); - func_8029E070(0); - func_8029E064(0); + modelAppendages_setKazooiesUpperHalfVisibility(false); + modelAppendages_setKazooiesFeetAndShoesVisibility(false); baflag_clear(BA_FLAG_3); baflag_clear(BA_FLAG_4); func_80293D74(); diff --git a/src/core2/bs/bee_fly.c b/src/core2/bs/beeFly.c similarity index 91% rename from src/core2/bs/bee_fly.c rename to src/core2/bs/beeFly.c index 1f03de7e5..1310f07d3 100644 --- a/src/core2/bs/bee_fly.c +++ b/src/core2/bs/beeFly.c @@ -1,9 +1,11 @@ +// BanjoDecomp: core2/bs/beeFly.c #include #include "functions.h" #include "variables.h" #include "core2/ba/physics.h" #include "core2/ba/flap.h" +#include "core2/yaw.h" void func_80354030(f32*, f32); @@ -11,7 +13,7 @@ f32 bastick_distance(void); f32 bastick_getAngleRelativeToBanjo(void); void baModel_setYDisplacement(f32); -void ncDynamicCam4_func_802BFE50(f32, f32, f32); +void ncbafly_func_802BFE50(f32, f32, f32); void yaw_setVelocityBounded(f32, f32); f32 bastick_getX(void); f32 bastick_getY(void); @@ -30,7 +32,7 @@ int bsBeeFly_inSet(s32); void func_802A04F0(void){ f32 player_position[3]; - _player_getPosition(player_position); + playerPosition_get(player_position); player_position[0] += randf2(-30.0f, 30.0f); player_position[1] += 30.0f + randf2(0.0f, 30.0f); player_position[2] += randf2(-30.0f, 30.0f); @@ -40,10 +42,10 @@ void func_802A04F0(void){ } -void func_802A0590(void){ +void bsbeefly_bs8Bunknown_init(void){ func_802A0340(); baanim_playForDuration_onceSmooth(0x1df, 1.5f); - func_8029C7F4(1,1,3, BA_PHYSICS_AIRBORN); + code_14420_setUpdateTypes(1, YAW_STATE_1_DEFAULT, 3, BA_PHYSICS_AIRBORN); if(bastick_distance() != 0.0f){ yaw_setIdeal(bastick_getAngleRelativeToBanjo()); } @@ -53,7 +55,7 @@ void func_802A0590(void){ D_8037D2C0 = 0; } -void func_802A0630(void){ +void bsbeefly_bs8Bunknown_update(void){ s32 next_state = 0; AnimCtrl * mvmnt; //sp1C @@ -71,13 +73,13 @@ void func_802A0630(void){ if(anctrl_isStopped(mvmnt)) baanim_playForDuration_loopSmooth(ASSET_1DC_ANIM_BEE_FLY, 0.38f); if(baphysics_get_vertical_velocity() < 0.0f) - next_state = BS_BEE_FLY; + next_state = BS_8C_BEE_FLY; break; } bs_setState(next_state); } -void func_802A0704(void){ +void bsbeefly_bs8Bunknown_end(void){ func_802A02C0(); } @@ -121,7 +123,7 @@ void _bsBeeFly_updateYaw(void){ f32 sp30; f32 stickX; stickX = bastick_getX(); - ncDynamicCam4_func_802BFE50(2.0f, 2000.0f, 350.0f); + ncbafly_func_802BFE50(2.0f, 2000.0f, 350.0f); if(bakey_held(BUTTON_R)){ yaw_setVelocityBounded(500.0f, 30.0f); sp34 = 6.0f; @@ -151,7 +153,7 @@ void bsbeefly_enter(void){ mvmnt = bs_getPrevState(); baanim_playForDuration_loopSmooth(ASSET_1DC_ANIM_BEE_FLY, 0.38); - func_8029C7F4(1, 1, 3, BA_PHYSICS_LOCKED_ROTATION); + code_14420_setUpdateTypes(1, YAW_STATE_1_DEFAULT, 3, BA_PHYSICS_LOCKED_ROTATION); if(baflag_isTrue(BA_FLAG_9)) baphysics_set_target_horizontal_velocity(0.0f); else @@ -185,7 +187,7 @@ void bsbeefly_update(void){ _bsBeeFly_updateYaw(); _bsBeeFly_updatePitch(); pitch_get(); //return value never used - if(bakey_pressed(BUTTON_A) && (player_getYPosition() < 7500.0)){ + if(bakey_pressed(BUTTON_A) && (playerPosition_getY() < 7500.0)){ baflap_add(1.0f); } if((baflap_getCount() == 0) && player_inWater()){ diff --git a/src/core2/bs/bee_main.c b/src/core2/bs/beeMain.c similarity index 85% rename from src/core2/bs/bee_main.c rename to src/core2/bs/beeMain.c index 754a135d3..ed51d441a 100644 --- a/src/core2/bs/bee_main.c +++ b/src/core2/bs/beeMain.c @@ -1,14 +1,16 @@ +// BanjoDecomp: core2/bs/beeMain.c #include #include "functions.h" #include "variables.h" #include "core2/ba/physics.h" #include "core2/ba/timer.h" +#include "core2/yaw.h" f32 func_8029B41C(void); void func_80299628(s32); void yaw_applyIdeal(void); -void ncDynamicCamD_func_802BF2C0(f32); +void ncbadie_func_802BF2C0(f32); f32 baanim_getTimer(void); void baanim_setEndAndDuration(f32, f32); @@ -56,15 +58,15 @@ void func_802A1020(void){ } } -void func_802A1080(void){ +void bsbeemain_idle_init(void){ func_802A0340(); baanim_playForDuration_loopSmooth(ASSET_1DE_ANIM_BEE_IDLE,3.0f); - func_8029C7F4(1,1,1, BA_PHYSICS_NORMAL); + code_14420_setUpdateTypes(1, YAW_STATE_1_DEFAULT, 1, BA_PHYSICS_NORMAL); baphysics_set_target_horizontal_velocity(0.0f); func_802900B4(); } -void func_802A10D4(void){ +void bsbeemain_idle_update(void){ s32 s0; s0 = 0; @@ -76,31 +78,31 @@ void func_802A10D4(void){ s0 = badrone_look(); if(bastick_getZone() > 0) - s0 = BS_BEE_WALK; + s0 = BS_86_BEE_WALK; if(bakey_pressed(BUTTON_A)) - s0 = BS_BEE_JUMP; + s0 = BS_87_BEE_JUMP; if(player_inWater()) - s0 = BS_BEE_FLY; + s0 = BS_8C_BEE_FLY; bs_setState(func_8029CA94(s0)); } -void func_802A117C(void){ +void bsbeemain_idle_end(void){ func_802900FC(); func_802A02C0(); } -void func_802A11A4(void){ +void bsbeemain_walk_init(void){ func_802A0340(); baanim_playForDuration_loopSmooth(ASSET_1DD_ANIM_BEE_WALK, 0.38f); - func_8029C7F4(2,1,1, BA_PHYSICS_NORMAL); + code_14420_setUpdateTypes(2, YAW_STATE_1_DEFAULT, 1, BA_PHYSICS_NORMAL); baanim_setVelocityMapRanges(D_803649E0, D_803649E4, D_803649E8, D_803649EC); func_802900B4(); } -void func_802A1214(void){ +void bsbeemain_walk_update(void){ s32 s0; s0 = 0; @@ -115,20 +117,20 @@ void func_802A1214(void){ s0 = BS_88_BEE_FALL; if(bakey_pressed(BUTTON_A)) - s0 = BS_BEE_JUMP; + s0 = BS_87_BEE_JUMP; if(player_inWater()) - s0 = BS_BEE_FLY; + s0 = BS_8C_BEE_FLY; bs_setState(s0); } -void func_802A12D4(void){ +void bsbeemain_walk_end(void){ func_802900FC(); func_802A02C0(); } -void func_802A12FC(void){ +void bsbeemain_jump_init(void){ AnimCtrl * s0; s0 = baanim_getAnimCtrlPtr(); @@ -141,7 +143,7 @@ void func_802A12FC(void){ anctrl_setDuration(s0, 1.2f); anctrl_setPlaybackType(s0, ANIMCTRL_ONCE); anctrl_start(s0, "bsbeemain.c", 0x15b); - func_8029C7F4(1,1,3, BA_PHYSICS_AIRBORN); + code_14420_setUpdateTypes(1, YAW_STATE_1_DEFAULT, 3, BA_PHYSICS_AIRBORN); if(bastick_distance() != 0.0f){ yaw_setIdeal(bastick_getAngleRelativeToBanjo()); } @@ -154,7 +156,7 @@ void func_802A12FC(void){ D_8037D2D4 = 0; } -void func_802A1438(void){ +void bsbeemain_jump_update(void){ s32 sp2c; AnimCtrl * sp28; f32 sp1c[3]; @@ -203,27 +205,27 @@ void func_802A1438(void){ } if(player_isStable()){ if(bastick_getZone() > 0) - sp2c = BS_BEE_WALK; + sp2c = BS_86_BEE_WALK; if(bakey_pressed(BUTTON_A)){ - sp2c = BS_BEE_JUMP; + sp2c = BS_87_BEE_JUMP; } } else{ if(bakey_pressed(BUTTON_A)){ - sp2c = BS_BEE_FLY; + sp2c = BS_8C_BEE_FLY; } } if(player_inWater()) - sp2c = BS_BEE_FLY; + sp2c = BS_8C_BEE_FLY; bs_setState(sp2c); } -void func_802A163C(void){ +void bsbeemain_jump_end(void){ func_802A02C0(); baphysics_reset_gravity(); } -void func_802A1664(void){ +void bsbeemain_fall_init(void){ AnimCtrl * s0; s0 = baanim_getAnimCtrlPtr(); @@ -235,11 +237,11 @@ void func_802A1664(void){ anctrl_setSubRange(s0, 0, 0.51f); anctrl_setPlaybackType(s0, ANIMCTRL_ONCE); anctrl_start(s0, "bsbeemain.c", 0x1e2); - func_8029C7F4(1,1,3, BA_PHYSICS_AIRBORN); + code_14420_setUpdateTypes(1, YAW_STATE_1_DEFAULT, 3, BA_PHYSICS_AIRBORN); D_8037D2D4 = 0; } -void func_802A170C(void){ +void bsbeemain_fall_update(void){ s32 sp2c; //next state AnimCtrl * sp28; f32 sp1c[3]; @@ -278,22 +280,22 @@ void func_802A170C(void){ sp2c = badrone_transform(); }else{ if(bastick_getZone() > 0) - sp2c = BS_BEE_WALK; + sp2c = BS_86_BEE_WALK; if(bakey_pressed(BUTTON_A)) - sp2c = BS_BEE_JUMP; + sp2c = BS_87_BEE_JUMP; sp2c = func_8029CA94(sp2c); } } else{ if(baflag_isFalse(BA_FLAG_F) && bakey_pressed(BUTTON_A)) - sp2c = BS_BEE_FLY; + sp2c = BS_8C_BEE_FLY; }//L802A189C if(player_inWater()) - sp2c = BS_BEE_FLY; + sp2c = BS_8C_BEE_FLY; bs_setState(sp2c); } -void func_802A18C8(void){ +void bsbeemain_fall_end(void){ func_802A02C0(); } @@ -318,7 +320,7 @@ void func_802A18E8(s32 arg0){ }else{ func_8030E58C(SFX_56_BANJO_HUI, 1.8f); } - _player_getPosition(sp2C); + playerPosition_get(sp2C); func_80294980(sp20); func_80257F18(sp20, sp2C, &sp38); yaw_setIdeal(mlNormalizeAngle(sp38 + 180.0f)); @@ -326,7 +328,7 @@ void func_802A18E8(s32 arg0){ baphysics_set_target_horizontal_velocity(200.0f); baphysics_set_target_yaw(sp38); baphysics_set_horizontal_velocity(sp38, baphysics_get_target_horizontal_velocity()); - func_8029C7F4(1, 1, 2, BA_PHYSICS_LOCKED_ROTATION); + code_14420_setUpdateTypes(1, YAW_STATE_1_DEFAULT, 2, BA_PHYSICS_LOCKED_ROTATION); baphysics_set_vertical_velocity(510.0f); baphysics_set_gravity(-1200.0f); baMarker_collisionOff(); @@ -367,27 +369,27 @@ void func_802A1B28(void){ func_802A02C0(); } -void func_802A1B68(void){ +void bsbeemain_ow_init(void){ func_802A18E8(1); } -void func_802A1B88(void){ +void bsbeemain_ow_update(void){ func_802A1A50(); } -void func_802A1BA8(void){ +void bsbeemain_ow_end(void){ func_802A1B28(); } -void func_802A1BC8(void){ +void bsbeemain_bounce_init(void){ func_802A18E8(2); } -void func_802A1BE8(void){ +void bsbeemain_bounce_update(void){ func_802A1A50(); } -void func_802A1C08(void){ +void bsbeemain_bounce_end(void){ func_802A1B28(); } @@ -407,8 +409,8 @@ void bsbeemain_die_init(void){ anctrl_setDuration(sp3C, 1.7f); anctrl_setPlaybackType(sp3C, ANIMCTRL_ONCE); anctrl_start(sp3C, "bsbeemain.c", 0x2ef); - func_8029C7F4(1,1,2, BA_PHYSICS_LOCKED_ROTATION); - _player_getPosition(sp2C); + code_14420_setUpdateTypes(1, YAW_STATE_1_DEFAULT, 2, BA_PHYSICS_LOCKED_ROTATION); + playerPosition_get(sp2C); func_80294980(sp20); func_80257F18(sp20, sp2C, &sp38); yaw_setIdeal(mlNormalizeAngle(sp38 + 180.0f)); @@ -423,14 +425,14 @@ void bsbeemain_die_init(void){ baMarker_collisionOff(); baeyes_close(); func_802914CC(0xd); - ncDynamicCamD_func_802BF2C0(30.0f); + ncbadie_func_802BF2C0(30.0f); func_8029C984(); func_8030E58C(SFX_36_BANJO_DOH, 1.8f); batimer_set(0, 2.9f); D_8037D2D4 = 0; } -void func_802A1DD8(void){ +void bsbeemain_die_update(void){ baphysics_set_target_horizontal_velocity(D_8037D2D0); func_80299628(0); switch(D_8037D2D4){ @@ -467,7 +469,7 @@ void func_802A1DD8(void){ } -void func_802A1F2C(void){ +void bsbeemain_die_end(void){ core1_ce60_incOrDecCounter(false); baphysics_reset_gravity(); func_80291548(); @@ -475,16 +477,16 @@ void func_802A1F2C(void){ func_802A02C0(); } -void func_802A1F6C(void){ +void bsbee_locked_init(void){ func_802A0340(); baanim_playForDuration_loopSmooth(ASSET_1DE_ANIM_BEE_IDLE, 3.0f); - func_8029C7F4(1,1,3, BA_PHYSICS_NORMAL); + code_14420_setUpdateTypes(1, YAW_STATE_1_DEFAULT, 3, BA_PHYSICS_NORMAL); baphysics_set_target_horizontal_velocity(0.0f); func_8029C674(); func_802B3A50(); } -void func_802A1FC8(void){ +void bsbee_locked_update(void){ s32 sp1C; sp1C = 0; @@ -497,7 +499,7 @@ void func_802A1FC8(void){ bs_setState(sp1C); } -void func_802A2014(void){ +void bsbee_locked_end(void){ pitch_setIdeal(0.0f); roll_setIdeal(0.0f); func_8029C748(); @@ -516,7 +518,7 @@ void func_802A2098(void){ baflag_clear(BA_FLAG_1A_OPEN_NOTEDOOR); baanim_playForDuration_loopSmooth(ASSET_1DE_ANIM_BEE_IDLE, 3.0f); yaw_setIdeal(func_8029B41C()); - func_8029C7F4(1,1,3, BA_PHYSICS_NORMAL); + code_14420_setUpdateTypes(1, YAW_STATE_1_DEFAULT, 3, BA_PHYSICS_NORMAL); baphysics_set_target_horizontal_velocity(0.0f); core1_ce60_incOrDecCounter(false); func_8025A2FC(0, 0xFA0); diff --git a/src/core2/bs/bs_list.c b/src/core2/bs/bsList.c similarity index 97% rename from src/core2/bs/bs_list.c rename to src/core2/bs/bsList.c index 94103f61e..4232c817e 100644 --- a/src/core2/bs/bs_list.c +++ b/src/core2/bs/bsList.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/bsList.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/bs/bs_storedstate.c b/src/core2/bs/bsStoredState.c similarity index 97% rename from src/core2/bs/bs_storedstate.c rename to src/core2/bs/bsStoredState.c index 4d7db9391..45badf5db 100644 --- a/src/core2/bs/bs_storedstate.c +++ b/src/core2/bs/bsStoredState.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/bsStoredState.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/bs/bs_statemachine.c b/src/core2/bs/bs_statemachine.c index dd1588f8d..5b18f4d99 100644 --- a/src/core2/bs/bs_statemachine.c +++ b/src/core2/bs/bs_statemachine.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_13780.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/bs/carry.c b/src/core2/bs/carry.c index 3ecb6e2e6..a8b79b32e 100644 --- a/src/core2/bs/carry.c +++ b/src/core2/bs/carry.c @@ -6,6 +6,7 @@ #include "core2/ba/anim.h" #include "core2/ba/carry.h" #include "core2/ba/physics.h" +#include "core2/yaw.h" /* .data */ const f32 D_80364AF0 = 30.0f; @@ -36,7 +37,7 @@ void bscarry_idle_init(void){ anctrl_setIndex(aCtrl, ASSET_72_ANIM_BSCARRY_IDLE); anctrl_setDuration(aCtrl, 1.2f); anctrl_start(aCtrl, "bscarry.c", 0x6f); - func_8029C7F4(1,1,1, BA_PHYSICS_NORMAL); + code_14420_setUpdateTypes(1, YAW_STATE_1_DEFAULT, 1, BA_PHYSICS_NORMAL); baphysics_set_target_horizontal_velocity(0.0f); pitch_setAngVel(1000.0f, 12.0f); roll_setAngularVelocity(1000.0f, 12.0f); @@ -48,7 +49,7 @@ void bscarry_idle_update(void){ if(bastick_getZone() > 0) sp1C = BS_3B_CARRY_WALK; - if(bacarry_get_marker() == NULL) + if(bacarry_getMarker() == NULL) sp1C = BS_1_IDLE; bs_setState(sp1C); @@ -65,7 +66,7 @@ void bscarry_walk_init(void){ anctrl_setDuration(aCtrl, 0.8f); anctrl_setPlaybackType(aCtrl, ANIMCTRL_LOOP); anctrl_start(aCtrl, "bscarry.c", 0xac); - func_8029C7F4(2,1,1, BA_PHYSICS_NORMAL); + code_14420_setUpdateTypes(2, YAW_STATE_1_DEFAULT, 1, BA_PHYSICS_NORMAL); baanim_setVelocityMapRanges(D_80364AF0, D_80364AF4, D_80364AF8, D_80364AFC); } @@ -77,7 +78,7 @@ void bscarry_walk_update(void){ if(bastick_getZone() == 0 && baphysics_is_slower_than(1.0f)) sp1C = BS_3A_CARRY_IDLE; - if(bacarry_get_marker() == NULL) + if(bacarry_getMarker() == NULL) sp1C = BS_1_IDLE; bs_setState(sp1C); @@ -106,7 +107,7 @@ void bscarry_interrupt(void){ break; case BS_INTR_16_THROW_CARRIED_OBJ: if(stateTimer_isDone(STATE_TIMER_1_THROW)){ - bs_setState(BS_CARRY_THROW); + bs_setState(BS_5B_CARRY_THROW); bs_setInterruptResponse(2); } else{ diff --git a/src/core2/bs/claw.c b/src/core2/bs/claw.c index 0ee1324be..121490781 100644 --- a/src/core2/bs/claw.c +++ b/src/core2/bs/claw.c @@ -3,6 +3,7 @@ #include "variables.h" #include "core2/abilityprogress.h" #include "core2/ba/physics.h" +#include "core2/yaw.h" void func_802915CC(f32); @@ -18,7 +19,7 @@ int bsclaw_hitboxActive(void){ void bsclaw_init(void){ baanim_playForDuration_once(ASSET_5_ANIM_BSPUNCH, 1.3f); - func_8029C7F4(1,1,3, BA_PHYSICS_LOCKED_ROTATION); + code_14420_setUpdateTypes(1, YAW_STATE_1_DEFAULT, 3, BA_PHYSICS_LOCKED_ROTATION); baphysics_set_target_yaw(yaw_getIdeal()); baphysics_set_target_horizontal_velocity(160.0f); func_802915CC(80.0f); diff --git a/src/core2/bs/climb.c b/src/core2/bs/climb.c index 8252ea420..618913ffb 100644 --- a/src/core2/bs/climb.c +++ b/src/core2/bs/climb.c @@ -72,7 +72,7 @@ void bsclimb_idle_init(void){ f32 pole_pos[3]; player_getPosition(plyr_pos); - climbGetBottom(pole_pos); + climb_getBottom(pole_pos); if(!bsclimb_inSet(bs_getPrevState())){ func_80257F18(plyr_pos, pole_pos, &angle_towards_pole); yaw_setIdeal(angle_towards_pole); @@ -164,13 +164,13 @@ void bsclimb_move_update(void){ if(!func_802AB788() && baphysics_get_vertical_velocity() < 30.0f) next_state = BS_4F_CLIMB_IDLE; - _player_getPosition(plyr_pos); - if(baphysics_get_target_vertical_velocity() < 0.0f && climbGetBottomY() == plyr_pos[1]) + playerPosition_get(plyr_pos); + if(baphysics_get_target_vertical_velocity() < 0.0f && climb_getBottomY() == plyr_pos[1]) next_state = BS_1_IDLE; if( func_8029825C() == 2 && 0.0f < baphysics_get_target_vertical_velocity() - && climbGetTopY() == plyr_pos[1] + && climb_getTopY() == plyr_pos[1] ){ next_state = BS_51_CLIMB_EXIT; } @@ -191,7 +191,7 @@ void bsclimb_move_end(void){ } //bsclimb_unknown_9E_init -void func_802ABCCC(void){ +void bsclimb_locked_init(void){ baanim_playForDuration_loopSmooth(ASSET_B2_ANIM_BSCLIMB_IDLE_2, 2.64f); baanim_setUpdateType(BAANIM_UPDATE_1_NORMAL); func_802AB654(); @@ -199,7 +199,7 @@ void func_802ABCCC(void){ } //bsclimb_unknown_9E_update -void func_802ABD0C(void){ +void bsclimb_locked_update(void){ s32 next_state = 0; if(!balookat_getState()) next_state = BS_4F_CLIMB_IDLE; @@ -208,7 +208,7 @@ void func_802ABD0C(void){ } //bsclimb_unknown_9E_end -void func_802ABD40(void){ +void bsclimb_locked_end(void){ func_802AB6F0(); } diff --git a/src/core2/bs/croc.c b/src/core2/bs/croc.c index 383d34b64..bf4606934 100644 --- a/src/core2/bs/croc.c +++ b/src/core2/bs/croc.c @@ -5,6 +5,7 @@ #include "core2/ba/anim.h" #include "core2/ba/physics.h" #include "core2/ba/timer.h" +#include "core2/yaw.h" int bscroc_inSet(enum bs_e state); @@ -54,7 +55,7 @@ void __bscroc_update_turbo_talon_trainers(void){ baflag_clear(BA_FLAG_10_TOUCHING_TURBO_TRAINERS); stateTimer_set(STATE_TIMER_3_TURBO_TALON, get_turbo_duration()); coMusicPlayer_playMusic(COMUSIC_8A_GETTING_TURBO_TRAINERS, -1); - func_8029E0DC(1); + modelAppendages_setTurboTrainersVisibility(true); } if(sp1C != 0.0f ){ @@ -62,7 +63,7 @@ void __bscroc_update_turbo_talon_trainers(void){ } if(stateTimer_isAt(STATE_TIMER_3_TURBO_TALON, 0.01f)){ - func_8029E0DC(0); + modelAppendages_setTurboTrainersVisibility(false); func_8030E58C(SFX_3EB_UNKNOWN, 1.35f); } } @@ -80,8 +81,8 @@ void __bscroc_update_velocity(void){ void __bscroc_end(void){ if(!bscroc_inSet(bs_getNextState())){ bastick_resetZones(); - func_8029E070(0); - func_8029E064(0); + modelAppendages_setKazooiesUpperHalfVisibility(false); + modelAppendages_setKazooiesFeetAndShoesVisibility(false); baflag_clear(BA_FLAG_3); baflag_clear(BA_FLAG_4); func_80293D74(); @@ -91,13 +92,13 @@ void __bscroc_end(void){ int bscroc_inSet(enum bs_e state){ return state == BS_5E_CROC_IDLE - || state == BS_CROC_WALK - || state == BS_CROC_JUMP + || state == BS_5F_CROC_WALK + || state == BS_60_CROC_JUMP || state == BS_61_CROC_FALL - || state == BS_CROC_OW - || state == BS_CROC_OW + || state == BS_63_CROC_OW + || state == BS_63_CROC_OW || state == BS_6E_CROC_BITE - || state == BS_CROC_EAT_BAD + || state == BS_6F_CROC_EAT_BAD || state == BS_70_CROC_EAT_GOOD || state == BS_8D_CROC_LOCKED || state == BS_94_CROC_DRONE; @@ -105,7 +106,7 @@ int bscroc_inSet(enum bs_e state){ void bscroc_idle_init(void){ baanim_playForDuration_loopSmooth(ASSET_E1_ANIM_BSCROC_IDLE, 1.0f); - func_8029C7F4(1,1,1, BA_PHYSICS_NORMAL); + code_14420_setUpdateTypes(1, YAW_STATE_1_DEFAULT, 1, BA_PHYSICS_NORMAL); baphysics_set_target_horizontal_velocity(0.0f); pitch_setAngVel(1000.0f, 12.0f); roll_setAngularVelocity(1000.0f, 12.0f); @@ -126,13 +127,13 @@ void bscroc_idle_update(void){ next_state = badrone_look(); if(bastick_getZone() > 0) - next_state = BS_CROC_WALK; + next_state = BS_5F_CROC_WALK; if(bakey_pressed(BUTTON_B)) next_state = BS_6E_CROC_BITE; if(bakey_pressed(BUTTON_A)) - next_state = BS_CROC_JUMP; + next_state = BS_60_CROC_JUMP; next_state = func_8029CA94(next_state); bs_setState(next_state); @@ -146,7 +147,7 @@ void bscroc_idle_end(void){ void bscroc_walk_init(void){ baanim_playForDuration_loopStartingAt(ASSET_E0_ANIM_BSCROC_WALK, 0.8f, 0.4f); - func_8029C7F4(BAANIM_UPDATE_2_SCALE_HORZ, 1, 1, BA_PHYSICS_NORMAL); + code_14420_setUpdateTypes(BAANIM_UPDATE_2_SCALE_HORZ, YAW_STATE_1_DEFAULT, 1, BA_PHYSICS_NORMAL); baanim_setVelocityMapRanges(bsCrocMinWalkVelocity, bsCrocMaxWalkVelocity, bsCrocSlowestWalkDuration, bsCrocFastestWalkDuration); func_802900B4(); } @@ -170,7 +171,7 @@ void bscroc_walk_update(void){ next_state = BS_6E_CROC_BITE; if(bakey_pressed(BUTTON_A)) - next_state = BS_CROC_JUMP; + next_state = BS_60_CROC_JUMP; bs_setState(next_state); } @@ -191,7 +192,7 @@ void bscroc_jump_init(void){ anctrl_setStart(aCtrl, 0.1f); anctrl_setPlaybackType(aCtrl, ANIMCTRL_ONCE); anctrl_start(aCtrl, "bscroc.c", 0x1ac); - func_8029C7F4(1,1,3, BA_PHYSICS_AIRBORN); + code_14420_setUpdateTypes(1, YAW_STATE_1_DEFAULT, 3, BA_PHYSICS_AIRBORN); if(bastick_distance() != 0.0f){ yaw_setIdeal(bastick_getAngleRelativeToBanjo()); } @@ -253,10 +254,10 @@ void bscroc_jump_update(void){ if(player_isStable()){ if(bastick_getZone() > 0) - sp2C = BS_CROC_WALK; + sp2C = BS_5F_CROC_WALK; if(bakey_pressed(BUTTON_A)) - sp2C = BS_CROC_JUMP; + sp2C = BS_60_CROC_JUMP; } if(bakey_pressed(BUTTON_B)) @@ -279,7 +280,7 @@ void bscroc_fall_init(void){ anctrl_setDuration(aCtrl, 0.7f); anctrl_setPlaybackType(aCtrl, ANIMCTRL_STOPPED); anctrl_start(aCtrl, "bscroc.c", 0x235); - func_8029C7F4(1,1,3, BA_PHYSICS_AIRBORN); + code_14420_setUpdateTypes(1, YAW_STATE_1_DEFAULT, 3, BA_PHYSICS_AIRBORN); D_8037D3EC = 0; } @@ -345,7 +346,7 @@ static void __bscroc_recoil_init(s32 damage){ else func_8030E58C(SFX_56_BANJO_HUI, 1.8f); - _player_getPosition(player_position); + playerPosition_get(player_position); func_80294980(sp20); func_80257F18(sp20, player_position, &sp38); yaw_setIdeal(mlNormalizeAngle(sp38 + 180.0f)); @@ -353,7 +354,7 @@ static void __bscroc_recoil_init(s32 damage){ baphysics_set_target_horizontal_velocity(200.0f); baphysics_set_target_yaw(sp38); baphysics_set_horizontal_velocity(sp38, baphysics_get_target_horizontal_velocity()); - func_8029C7F4(1,1,2, BA_PHYSICS_LOCKED_ROTATION); + code_14420_setUpdateTypes(1, YAW_STATE_1_DEFAULT, 2, BA_PHYSICS_LOCKED_ROTATION); baphysics_set_vertical_velocity(510.0f); baphysics_set_gravity(-1200.0f); baMarker_collisionOff(); @@ -429,8 +430,8 @@ void bscroc_die_init(void){ anctrl_setDuration(aCtrl, 1.7f); anctrl_setPlaybackType(aCtrl, ANIMCTRL_ONCE); anctrl_start(aCtrl, "bscroc.c", 0x32b); - func_8029C7F4(1,1,2, BA_PHYSICS_LOCKED_ROTATION); - _player_getPosition(player_position); + code_14420_setUpdateTypes(1, YAW_STATE_1_DEFAULT, 2, BA_PHYSICS_LOCKED_ROTATION); + playerPosition_get(player_position); func_80294980(sp20); func_80257F18(sp20, player_position, &sp38); yaw_setIdeal(mlNormalizeAngle(sp38 + 180.0f)); @@ -445,7 +446,7 @@ void bscroc_die_init(void){ baMarker_collisionOff(); baeyes_close(); func_802914CC(0xd); - ncDynamicCamD_func_802BF2C0(30.0f); + ncbadie_func_802BF2C0(30.0f); func_8029C984(); func_8030E58C(SFX_36_BANJO_DOH, 1.8f); batimer_set(0, 2.9f); @@ -514,7 +515,7 @@ static void func_802ACF58(void){ void bscroc_bite_init(void){ baanim_playForDuration_loopStartingAt(ASSET_122_ANIM_BSCROC_BITE, 0.25f, 0.2f); - func_8029C7F4(1,1,1, BA_PHYSICS_LOCKED_ROTATION); + code_14420_setUpdateTypes(1, YAW_STATE_1_DEFAULT, 1, BA_PHYSICS_LOCKED_ROTATION); func_802ACF58(); D_8037D3F4 = 0; _bscrocHitboxActive = true; @@ -547,11 +548,11 @@ void bscroc_bite_update(void){ if(player_shouldFall()) next_state = BS_61_CROC_FALL; else - next_state = BS_CROC_WALK; + next_state = BS_5F_CROC_WALK; } if(player_isStable() && bakey_pressed(BUTTON_A)) - next_state = BS_CROC_JUMP; + next_state = BS_60_CROC_JUMP; bs_setState(next_state); } @@ -563,7 +564,7 @@ void bscroc_bite_end(void){ void bscroc_eat_bad_init(void){ baanim_playForDuration_once(ASSET_123_ANIM_BSCROC_EAT_BAD, 2.41f); - func_8029C7F4(1,1,2, BA_PHYSICS_LOCKED_ROTATION); + code_14420_setUpdateTypes(1, YAW_STATE_1_DEFAULT, 2, BA_PHYSICS_LOCKED_ROTATION); baphysics_set_target_horizontal_velocity(0.0f); } @@ -614,7 +615,7 @@ void bscroc_set_ate_wrong_thing(void){ void bscroc_eat_good_init(void){ baanim_playForDuration_loopSmooth(ASSET_122_ANIM_BSCROC_BITE, 0.25f); - func_8029C7F4(1,1,1, BA_PHYSICS_NORMAL); + code_14420_setUpdateTypes(1, YAW_STATE_1_DEFAULT, 1, BA_PHYSICS_NORMAL); baModel_setPostDraw((void (*)(Gfx **, Mtx **, Vtx **))func_802AD2A8); D_8037D3E8 = assetcache_get(func_80294974()); D_8037D3F0 = 1.0f; @@ -645,7 +646,7 @@ void bscroc_eat_good_update(void){ break; case 3: if(s_ate_wrong) - next_state = BS_CROC_EAT_BAD; + next_state = BS_6F_CROC_EAT_BAD; else next_state = BS_5E_CROC_IDLE; break; @@ -670,7 +671,7 @@ void bscroc_eat_good_end(void){ void bscroc_locked_enter(void){ baanim_playForDuration_loopSmooth(ASSET_E1_ANIM_BSCROC_IDLE, 1.0f); - func_8029C7F4(1,1,3, BA_PHYSICS_NORMAL); + code_14420_setUpdateTypes(1, YAW_STATE_1_DEFAULT, 3, BA_PHYSICS_NORMAL); baphysics_set_target_horizontal_velocity(0.0f); func_8029C674(); func_802B3A50(); diff --git a/src/core2/bs/crouch.c b/src/core2/bs/crouch.c index c4e0d3a01..e9cd93c54 100644 --- a/src/core2/bs/crouch.c +++ b/src/core2/bs/crouch.c @@ -159,7 +159,7 @@ void bscrouch_update(void){ }//L802ADC50 if(player_isSliding()) - sp34 = BS_SLIDE; + sp34 = BS_32_SLIDE; if(player_shouldFall()) sp34 = BS_2F_FALL; @@ -181,7 +181,7 @@ enum bs_e func_802ADCD4(enum bs_e arg0){ arg0 = BS_1_IDLE; if(bakey_pressed(BUTTON_B) && can_claw()) - arg0 = BS_CLAW; + arg0 = BS_6_CLAW; if(bakey_pressed(BUTTON_A)) arg0 = bs_getTypeOfJump(); @@ -203,7 +203,7 @@ enum bs_e func_802ADCD4(enum bs_e arg0){ arg0 = BS_12_BFLIP; if(bainput_should_beak_barge()) - arg0 = BS_BBARGE; + arg0 = BS_13_BBARGE; } diff --git a/src/core2/bs/die.c b/src/core2/bs/die.c index 626983387..ae2b823f4 100644 --- a/src/core2/bs/die.c +++ b/src/core2/bs/die.c @@ -37,7 +37,7 @@ void bsdie_init(void){ anctrl_start(aCtrl, "bsdie.c", 0x7e); func_8029B930(); func_8030E58C(SFX_36_BANJO_DOH, 1.0f); - _player_getPosition(sp2C); + playerPosition_get(sp2C); func_80294980(sp20); func_80257F18(sp20, sp2C, &sp38); D_8037D410 = 250.0f; @@ -53,9 +53,9 @@ void bsdie_init(void){ baphysics_set_vertical_velocity(510.0f); baphysics_set_gravity(-1400.0f); pitch_setAngVel(1000.0f, 12.0f); - func_8029E070(1); + modelAppendages_setKazooiesUpperHalfVisibility(true); func_8029151C(0xd); - ncDynamicCamD_func_802BF2C0(30.0f); + ncbadie_func_802BF2C0(30.0f); func_8029C984(); batimer_set(0,2.9f); D_8037D414 = 0; @@ -112,7 +112,7 @@ void bsdie_update(void){ && floor_isCurrentFloorunk59() && ( D_8037D414 || ( anctrl_isStopped(aCtrl) - && ( player_getYPosition() < (floor_getCurrentFloorYPosition() - 150.0f)) + && ( playerPosition_getY() < (floor_getCurrentFloorYPosition() - 150.0f)) ) ) && player_inWater() @@ -127,7 +127,7 @@ void bsdie_update(void){ void bsdie_end(void){ core1_ce60_incOrDecCounter(false); baphysics_reset_gravity(); - func_8029E070(0); + modelAppendages_setKazooiesUpperHalfVisibility(false); pitch_setIdeal(0.0f); roll_setIdeal(0.0f); func_80291548(); diff --git a/src/core2/bs/scripted.c b/src/core2/bs/drone.c similarity index 97% rename from src/core2/bs/scripted.c rename to src/core2/bs/drone.c index 6a683962a..9e774c2cb 100644 --- a/src/core2/bs/scripted.c +++ b/src/core2/bs/drone.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/bs/drone.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/bs/scripted_enter.c b/src/core2/bs/droneenter.c similarity index 97% rename from src/core2/bs/scripted_enter.c rename to src/core2/bs/droneenter.c index e25767d92..f95220d91 100644 --- a/src/core2/bs/scripted_enter.c +++ b/src/core2/bs/droneenter.c @@ -1,8 +1,10 @@ +// BanjoDecomp: core2/bs/droneenter.c #include #include "functions.h" #include "variables.h" #include "core2/ba/physics.h" #include "core2/ba/timer.h" +#include "core2/yaw.h" enum bsdroneenter_state_e{ @@ -111,7 +113,7 @@ void bsDroneEnter_init(void) { func_8029BCF8(&anim_id, &anim_duration); baanim_playForDuration_loopSmooth(anim_id, anim_duration); - func_8029C7F4(1, 1, 3, BA_PHYSICS_FREEZE); + code_14420_setUpdateTypes(1, YAW_STATE_1_DEFAULT, 3, BA_PHYSICS_FREEZE); func_80294378(6); __bsDroneEnter_init(); bsDroneEnterSubstate = BSDRONEENTER_SUBSTATE_0_UNINITIALIZED; diff --git a/src/core2/bs/scripted_goto.c b/src/core2/bs/dronegoto.c similarity index 94% rename from src/core2/bs/scripted_goto.c rename to src/core2/bs/dronegoto.c index 7d69723e7..2b2befb88 100644 --- a/src/core2/bs/scripted_goto.c +++ b/src/core2/bs/dronegoto.c @@ -1,8 +1,10 @@ +// BanjoDecomp: core2/bs/dronegoto.c #include #include "functions.h" #include "variables.h" #include "core2/ba/physics.h" +#include "core2/yaw.h" /* .bss */ @@ -55,7 +57,7 @@ void func_802AEC78(void){ badrone_get_position_and_duration(target_position, &duration_s); baphysics_set_goto_position(target_position); baphysics_set_goto_duration(duration_s); - func_8029C7F4(1,1,3,BA_PHYSICS_GOTO); + code_14420_setUpdateTypes(1, YAW_STATE_1_DEFAULT, 3, BA_PHYSICS_GOTO); func_8029436C(1); D_8037D441 = 0; } diff --git a/src/core2/bs/scripted_look.c b/src/core2/bs/dronelook.c similarity index 84% rename from src/core2/bs/scripted_look.c rename to src/core2/bs/dronelook.c index 799fb2671..61ca4e3d5 100644 --- a/src/core2/bs/scripted_look.c +++ b/src/core2/bs/dronelook.c @@ -1,8 +1,10 @@ +// BanjoDecomp: core2/bs/dronelook.c #include #include "functions.h" #include "variables.h" #include "core2/ba/physics.h" #include "port/Controller/ModernCamera.h" +#include "core2/yaw.h" extern f32 bastick_getX(void); @@ -20,17 +22,17 @@ void bsDroneLook_init(void) { basfx_80299D2C(SFX_12D_CAMERA_ZOOM_CLOSEST, 1.2f, 12000); func_8029BCF8(&anim_id, &anim_duration); baanim_playForDuration_loopSmooth(anim_id, anim_duration); - func_8029C7F4(1, 1, 3, BA_PHYSICS_NORMAL); + code_14420_setUpdateTypes(1, YAW_STATE_1_DEFAULT, 3, BA_PHYSICS_NORMAL); baphysics_set_target_horizontal_velocity(0.0f); baphysics_set_velocity(0); ncDynamicCamera_enterFirstPerson(); __bsDroneLook_getEyePos(eye_position); - ncFirstPersonCamera_setZoomedOutPosition(eye_position); + ncba1p_setZoomedOutPosition(eye_position); player_getRotation(eye_rotation); eye_rotation[0] = 0.0f; eye_rotation[1] += 180.0f; eye_rotation[2] = 0.0f; - ncFirstPersonCamera_setZoomedOutRotation(eye_rotation); + ncba1p_setZoomedOutRotation(eye_rotation); baflag_set(BA_FLAG_17_FIRST_PERSON_VIEW); } @@ -43,14 +45,14 @@ void bsDroneLook_update(void) { next_state = 0; dt = time_getDelta(); - if (ncFirstPersonCamera_getState() == FIRSTPERSON_STATE_2_IDLE) { + if (ncba1p_getState() == FIRSTPERSON_STATE_2_IDLE) { //camera is in "idle" state - ncFirstPersonCamera_getZoomedInRotation(eye_rotation); + ncba1p_getZoomedInRotation(eye_rotation); eye_rotation[0] -= bastick_getY() * 90.0f * dt * port_cameraInvertYSign(); eye_rotation[1] -= bastick_getX() * 90.0f * dt * port_cameraInvertXSign(); eye_rotation[2] = 0.0f; eye_rotation[0] = (eye_rotation[0] > 180.0f) ? ml_max_f(305.0f, eye_rotation[0]) : ml_min_f(70.0f, eye_rotation[0]); - ncFirstPersonCamera_setZoomedOutRotation(eye_rotation); + ncba1p_setZoomedOutRotation(eye_rotation); yaw_setIdeal(eye_rotation[1] + 180.0f); exit_first_person = false; @@ -71,7 +73,7 @@ void bsDroneLook_update(void) { } } __bsDroneLook_getEyePos(eye_position); - ncFirstPersonCamera_setZoomedOutPosition(eye_position); + ncba1p_setZoomedOutPosition(eye_position); bs_setState(next_state); } diff --git a/src/core2/bs/scripted_vanish.c b/src/core2/bs/dronevanish.c similarity index 96% rename from src/core2/bs/scripted_vanish.c rename to src/core2/bs/dronevanish.c index db3ba567d..5647470e6 100644 --- a/src/core2/bs/scripted_vanish.c +++ b/src/core2/bs/dronevanish.c @@ -1,9 +1,11 @@ +// BanjoDecomp: core2/bs/dronevanish.c #include #include "functions.h" #include "variables.h" #include "core2/ba/physics.h" #include "core2/ba/timer.h" +#include "core2/yaw.h" /* .bss */ struct { @@ -97,7 +99,7 @@ void bsDroneVanish_init(void){ func_8029BCF8(&anim_id, &anim_duration); baanim_playForDuration_loopSmooth(anim_id, anim_duration); - func_8029C7F4(1,1,3, BA_PHYSICS_FREEZE); + code_14420_setUpdateTypes(1, YAW_STATE_1_DEFAULT, 3, BA_PHYSICS_FREEZE); func_80294378(6); __bsDroneVanish_init(); D_8037D468 = 0; diff --git a/src/core2/bs/scripted_transform.c b/src/core2/bs/dronexform.c similarity index 91% rename from src/core2/bs/scripted_transform.c rename to src/core2/bs/dronexform.c index adc06db19..915cc28da 100644 --- a/src/core2/bs/scripted_transform.c +++ b/src/core2/bs/dronexform.c @@ -1,12 +1,14 @@ +// BanjoDecomp: core2/bs/dronexform.c #include #include "core1/core1.h" #include "functions.h" #include "variables.h" #include "core2/ba/physics.h" #include "core2/ba/timer.h" +#include "core2/yaw.h" -extern void player_setYPosition(f32); +extern void playerPosition_setY(f32); extern void yaw_applyIdeal(void); extern f32 cosf(f32); @@ -56,28 +58,28 @@ void func_802AF900(void){ f32 sp44; f32 sp40; f32 sp3C; - f32 sp30[3]; + f32 player_position[3]; - player_getPosition(sp30); + player_getPosition(player_position); sp3C = D_8037D470.unk8; sp48 = func_80257A44(sp3C, 0.38f); sp4C = sp48 * 6.283185308; sp40 = sinf(sp4C); sp44 = cosf(sp4C); - sp30[0] += sp40 * D_8037D470.unk18; - sp30[1] += ml_interpolate_f(func_80257A44(sp3C, 1.14f), 0.0f, 130.0f); - sp30[2] += sp44 * D_8037D470.unk18; + player_position[0] += sp40 * D_8037D470.unk18; + player_position[1] += ml_interpolate_f(func_80257A44(sp3C, 1.14f), 0.0f, 130.0f); + player_position[2] += sp44 * D_8037D470.unk18; func_802AF88C(D_8037D470.unk4, sp40, sp44); - particleEmitter_setPosition(D_8037D470.unk4, sp30); + particleEmitter_setPosition(D_8037D470.unk4, player_position); particleEmitter_emitN(D_8037D470.unk4, 1); - player_getPosition(sp30); + player_getPosition(player_position); sp4C = (1.0 - ml_remainder_f(sp48 + 0.5, 1.0f))* 6.283185308; - sp30[0] -= sinf(sp4C) * D_8037D470.unk18; - sp30[1] += ml_interpolate_f(func_80257A44(sp3C, 1.14f), 130.0f, 0.0f); - sp30[2] -= cosf(sp4C) * D_8037D470.unk18; + player_position[0] -= sinf(sp4C) * D_8037D470.unk18; + player_position[1] += ml_interpolate_f(func_80257A44(sp3C, 1.14f), 130.0f, 0.0f); + player_position[2] -= cosf(sp4C) * D_8037D470.unk18; func_802AF88C(D_8037D470.unk0, sp40, sp44); - particleEmitter_setPosition(D_8037D470.unk0, sp30); + particleEmitter_setPosition(D_8037D470.unk0, player_position); particleEmitter_emitN(D_8037D470.unk0, 1); } @@ -249,13 +251,13 @@ void func_802B01C8(void){ static void __bsdronexform_setState(int next_state){ enum asset_e sp34; f32 sp30; - f32 sp24[3]; + f32 player_position[3]; D_8037D470.state = next_state; switch(next_state){ case 1:// 802B0230 D_8037D470.unk1C = 1; - D_8037D470.unk2C = player_getYPosition(); + D_8037D470.unk2C = playerPosition_getY(); func_802AFB94(0.28f); func_802AFBA0(180.0f); func_802AFBAC(0.04f); @@ -279,10 +281,10 @@ static void __bsdronexform_setState(int next_state){ break; case 5:// 802B02F4 - _player_getPosition(sp24); - sp24[1] += 30.0f; - viewport_adjustPointDistance(sp24, 80.0f); - func_802AFBB8(sp24); + playerPosition_get(player_position); + player_position[1] += 30.0f; + viewport_adjustPointDistance(player_position, 80.0f); + func_802AFBB8(player_position); batimer_set(0, 0.1f); break; @@ -324,7 +326,7 @@ void bsdronexform_init(void){ enum asset_e sp18; func_8029BCAC(&sp18, &sp1C); baanim_playForDuration_loopSmooth(sp18, sp1C); - func_8029C7F4(1,1,3, BA_PHYSICS_FREEZE); + code_14420_setUpdateTypes(1, YAW_STATE_1_DEFAULT, 3, BA_PHYSICS_FREEZE); baphysics_set_velocity(0); baphysics_set_target_velocity(0); pitch_setIdeal(0.0f); @@ -352,7 +354,7 @@ void bsdronexform_update(void){ switch(D_8037D470.state){ case 1: sp24 = batimer_decrement(0); - player_setYPosition(func_802B051C(0, 2.8f, 0.0f, 90.0f) + D_8037D470.unk2C); + playerPosition_setY(func_802B051C(0, 2.8f, 0.0f, 90.0f) + D_8037D470.unk2C); func_802AFB94(func_802B051C(0, 2.8f, 0.28f, 1.0f)); func_802AFBA0(func_802B051C(0, 2.8f, 180.0f, 55.0f)); func_802AFBAC(func_802B051C(0, 2.8f, 0.04f, 0.35f)); @@ -428,7 +430,7 @@ void bsdronexform_update(void){ case 9: sp24 = batimer_decrement(0); - player_setYPosition(func_802B051C(0, 0.7f, 90.0f, 0.0f) + D_8037D470.unk2C); + playerPosition_setY(func_802B051C(0, 0.7f, 90.0f, 0.0f) + D_8037D470.unk2C); if(sp24) bs_setState(bs_getIdleState()); break; diff --git a/src/core2/bs/jiggy_dance.c b/src/core2/bs/jig.c similarity index 92% rename from src/core2/bs/jiggy_dance.c rename to src/core2/bs/jig.c index 6ad7325a9..136e613cd 100644 --- a/src/core2/bs/jiggy_dance.c +++ b/src/core2/bs/jig.c @@ -1,8 +1,10 @@ +// BanjoDecomp: core2/bs/jig.c #include #include "functions.h" #include "variables.h" #include "core2/ba/physics.h" +#include "core2/yaw.h" /* .bss */ u8 D_8037D4B0; @@ -30,7 +32,7 @@ void bsjig_jiggy_init(void){ anctrl_setPlaybackType(aCtrl, ANIMCTRL_ONCE); anctrl_start(aCtrl, "bsjig.c", 0x7f); yaw_setIdeal(func_8029B41C()); //face camera - func_8029C7F4(1,1,3, BA_PHYSICS_NORMAL); + code_14420_setUpdateTypes(1, YAW_STATE_1_DEFAULT, 3, BA_PHYSICS_NORMAL); baphysics_set_target_horizontal_velocity(0.0f); core1_ce60_incOrDecCounter(false); func_8025A2FC(0,0xfa0); @@ -40,7 +42,7 @@ void bsjig_jiggy_init(void){ D_8037D4B1 = tmp; coMusicPlayer_playMusic(COMUSIC_D_JINGLE_JIGGY_COLLECTED, -1); func_8029151C(0xC); - func_8029E070(1); + modelAppendages_setKazooiesUpperHalfVisibility(true); func_8030E6D4(SFX_33_BANJO_AHOO); baflag_clear(BA_FLAG_7_TOUCHING_JIGGY); baflag_clear(BA_FLAG_F); @@ -101,7 +103,7 @@ void bsjig_jiggy_end(void){ item_inc(ITEM_E_JIGGY); func_802B0CD8(); - func_8029E070(0); + modelAppendages_setKazooiesUpperHalfVisibility(false); func_80291548(); if(bs_getNextState() != BS_34_JIG_NOTEDOOR){ @@ -149,7 +151,7 @@ void bsjig_notedoor_end(void){ baMarker_collisionOn(); func_8025A2FC(-1, 0xfa0); core1_ce60_incOrDecCounter(true); - func_8029E070(0); + modelAppendages_setKazooiesUpperHalfVisibility(false); func_80291548(); if( D_8037D4B2 && jiggyscore_total() == 100 @@ -171,7 +173,7 @@ void bsjig_notedoor_init(void){ anctrl_setPlaybackType(aCtrl, ANIMCTRL_ONCE); anctrl_start(aCtrl, "bsjig.c", 0x14d); yaw_setIdeal(func_8029B41C()); - func_8029C7F4(1,1,3, BA_PHYSICS_NORMAL); + code_14420_setUpdateTypes(1, YAW_STATE_1_DEFAULT, 3, BA_PHYSICS_NORMAL); baphysics_set_target_horizontal_velocity(0.0f); if(bs_getPrevState() != BS_44_JIG_JIGGY){ core1_ce60_incOrDecCounter(false); @@ -179,7 +181,7 @@ void bsjig_notedoor_init(void){ } coMusicPlayer_playMusic(COMUSIC_42_NOTEDOOR_OPENING_FANFARE,-1); func_8029151C(0xc); - func_8029E070(1); + modelAppendages_setKazooiesUpperHalfVisibility(true); func_8030E6D4(SFX_33_BANJO_AHOO); baMarker_collisionOff(); } diff --git a/src/core2/bs/jump.c b/src/core2/bs/jump.c index 2506d8990..ea331a73a 100644 --- a/src/core2/bs/jump.c +++ b/src/core2/bs/jump.c @@ -7,6 +7,7 @@ #include "core2/ba/physics.h" #include "core2/ba/timer.h" +#include "core2/yaw.h" f32 func_80294438(void); void basfx_playJumpSfx(f32, f32); @@ -39,7 +40,7 @@ void bsjump_init(void){ D_8037D4C2 = baflag_isTrue(BA_FLAG_2_ON_SPRING_PAD); sp30 = bs_getPrevState(); if(bsclimb_inSet(sp30)){ - climbRelease(); + climb_release(); } if(sp30 == BS_11_BPECK){ @@ -59,7 +60,7 @@ void bsjump_init(void){ anctrl_setSubRange(aCtrl, 0.0f, 0.5042f); anctrl_setPlaybackType(aCtrl, ANIMCTRL_ONCE); anctrl_start(aCtrl, "bsjump.c", 0x95); - func_8029C7F4(1,1,3, BA_PHYSICS_AIRBORN); + code_14420_setUpdateTypes(1, YAW_STATE_1_DEFAULT, 3, BA_PHYSICS_AIRBORN); if(bastick_distance() != 0.0f){ yaw_setIdeal(bastick_getAngleRelativeToBanjo()); } @@ -117,12 +118,12 @@ void bsjump_update(void){ } break; case 1://L802B14B4 - if( 500.0f < (player_getYPosition() - func_80294438())){ + if( 500.0f < (playerPosition_getY() - func_80294438())){ sp34 = BS_2F_FALL; } if(D_8037D4C2){ D_8037D4C2 = 0; - sp34 = BS_BSHOCK_CHARGE; + sp34 = BS_21_BSHOCK_CHARGE; } if(func_8028B254(0x5A)){ anctrl_setSubRange(aCtrl, 0.0, 1.0f); @@ -142,7 +143,7 @@ void bsjump_update(void){ D_8037D4C2 = 0; if(bainput_should_feathery_flap()) - sp34 = BS_BFLAP; + sp34 = BS_10_BFLAP; if(bainput_should_peck()) sp34 = BS_11_BPECK; @@ -183,7 +184,7 @@ void bsjump_fall_init(void){ anctrl_setTransitionDuration(aCtrl, 0.3f); anctrl_setDuration(aCtrl, 0.38f); anctrl_start(aCtrl, "bsjump.c", 0x188); - func_8029C7F4(1,1,3, BA_PHYSICS_AIRBORN); + code_14420_setUpdateTypes(1, YAW_STATE_1_DEFAULT, 3, BA_PHYSICS_AIRBORN); D_8037D4C0 = 0; } @@ -219,7 +220,7 @@ void bsjump_fall_update(void){ sp2C = BS_3D_FALL_TUMBLING; if(bainput_should_feathery_flap() && baflag_isFalse(BA_FLAG_5_HAS_PECKED)) - sp2C = BS_BFLAP; + sp2C = BS_10_BFLAP; if(bainput_should_peck()) sp2C = BS_11_BPECK; @@ -233,7 +234,7 @@ void bsjump_fall_update(void){ else if(player_inWater()){ func_8029CCC4(); if(baflag_isTrue(BA_FLAG_6) || baflag_isTrue(BA_FLAG_14_LOSE_BOGGY_RACE)){ - sp2C = BS_D_TIMEOUT; + sp2C = BS_D_TIMEOUT_TRANSFORMATION; } }//L802B18E8 @@ -248,11 +249,11 @@ void bsjump_fall_update(void){ void bsjump_fall_end(void){} -void func_802B1928(void) { +void bsjump_climbExit_init(void) { AnimCtrl *anim_ctrl; anim_ctrl = baanim_getAnimCtrlPtr(); - climbRelease(); + climb_release(); anctrl_reset(anim_ctrl); anctrl_setIndex(anim_ctrl, ASSET_8_ANIM_BSJUMP); anctrl_setDuration(anim_ctrl, 1.9f); @@ -275,7 +276,7 @@ void func_802B1928(void) { func_802B1100(); } -void func_802B1A54(void) { +void bsjump_climbExit_update(void) { s32 next_state; AnimCtrl *anim_ctrl; f32 velocity[3]; @@ -319,7 +320,7 @@ void func_802B1A54(void) { bs_setState(next_state); } -void func_802B1BCC(void){ +void bsjump_climbExit_end(void){ func_80294378(1); baphysics_reset_gravity(); } @@ -388,7 +389,7 @@ bool bsjump_jumpingFromWater(void){ void bsjump_tumble_init(void){ baanim_playForDuration_loop(ASSET_68_ANIM_BSJUMP_TUMBLE, 0.35f); - func_8029C7F4(1,1,3, BA_PHYSICS_AIRBORN); + code_14420_setUpdateTypes(1, YAW_STATE_1_DEFAULT, 3, BA_PHYSICS_AIRBORN); baModel_setYDisplacement(60.0f); if(bafalldamage_get_state() == 1){ batimer_set(0, 0.5f); @@ -413,7 +414,7 @@ void bsjump_tumble_update(void){ } if(batimer_isNonzero(0)){ if(bainput_should_feathery_flap()) - sp1C = BS_BFLAP; + sp1C = BS_10_BFLAP; if(bainput_should_peck()) sp1C = BS_11_BPECK; @@ -426,7 +427,7 @@ void bsjump_tumble_update(void){ sp1C = BS_4C_LANDING_IN_WATER; if(player_isStable()) - sp1C = BS_SPLAT; + sp1C = BS_72_SPLAT; bs_setState(sp1C); } @@ -434,7 +435,7 @@ void bsjump_tumble_update(void){ void bsjump_tumble_end(void){ enum bs_e next_state = bs_getNextState(); if( next_state == BS_F_BBUSTER - || next_state == BS_BFLAP + || next_state == BS_10_BFLAP || next_state == BS_11_BPECK ){ bafalldamage_set_state(3); diff --git a/src/core2/bs/hurt.c b/src/core2/bs/ow.c similarity index 98% rename from src/core2/bs/hurt.c rename to src/core2/bs/ow.c index 333f8c836..d627bd33a 100644 --- a/src/core2/bs/hurt.c +++ b/src/core2/bs/ow.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/bs/ow.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/bs/player_spawn.c b/src/core2/bs/player_spawn.c index d69f06c9c..3a6087257 100644 --- a/src/core2/bs/player_spawn.c +++ b/src/core2/bs/player_spawn.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_14420.c #include #include "core1/core1.h" #include "functions.h" @@ -59,123 +60,138 @@ s16 D_80364624[14] = { BS_1B_WONDERWING_IDLE }; -u8 D_80364640[14] = {1, 1, 1, 1, 0, 0, 1, 0 , 1, 1, 1, 1, 0, 1}; +u8 D_80364640[14] = { + true, + true, + true, + true, + false, + false, + true, + false, + true, + true, + true, + true, + false, + true +}; Struct_core2_13FC0 D_80364650[14] = { - {BS_92_ANT_DRONE, ASSET_5F_ANIM_BSANT_WALK, 0.4f}, - {BS_93_PUMPKIN_DRONE, ASSET_A0_ANIM_BSPUMPKIN_WALK, 0.4f}, - {BS_94_CROC_DRONE, ASSET_E0_ANIM_BSCROC_WALK, 0.6f}, - {BS_95_WALRUS_DRONE, ASSET_120_ANIM_BSWALRUS_WALK, 0.7f}, - {BS_96_SWIM_DRONE, ASSET_39_ANIM_BSSWIM_MOVE, 0.8f}, - {BS_97_DIVE_DRONE, ASSET_71_ANIM_BSSWIM_DIVE_SLOW, 0.75f}, - {BS_98_WALK_DRONE, ASSET_3_ANIM_BSWALK, 0.43f}, - {BS_99_BFLY_DRONE, ASSET_38_ANIM_BSBFLY, 0.62f}, - {BS_9A_BTROT_DRONE, ASSET_15_ANIM_BSBTROT_WALK, 0.53f}, - {BS_9B_LONGLEG_DRONE, ASSET_42_ANIM_BSLONGLEG_WALK, 0.8f}, - {BS_9C_WALRUS_SLED_DRONE, ASSET_19E_ANIM_BSWALRUS_SLED, 0.8f}, - {BS_9D_BEE_DRONE, ASSET_1DC_ANIM_BEE_FLY, 0.38f}, - {BS_98_WALK_DRONE, ASSET_3_ANIM_BSWALK, 0.43f}, - {BS_A4_WONDERWING_DRONE, ASSET_11_ANIM_BSWHIRL_WALK, 0.53f} + {BS_92_ANT_DRONE, ASSET_5F_ANIM_BSANT_WALK, 0.4f}, + {BS_93_PUMPKIN_DRONE, ASSET_A0_ANIM_BSPUMPKIN_WALK, 0.4f}, + {BS_94_CROC_DRONE, ASSET_E0_ANIM_BSCROC_WALK, 0.6f}, + {BS_95_WALRUS_DRONE, ASSET_120_ANIM_BSWALRUS_WALK, 0.7f}, + {BS_96_SWIM_DRONE, ASSET_39_ANIM_BSSWIM_MOVE, 0.8f}, + {BS_97_DIVE_DRONE, ASSET_71_ANIM_BSSWIM_DIVE_SLOW, 0.75f}, + {BS_98_WALK_DRONE, ASSET_3_ANIM_BSWALK, 0.43f}, + {BS_99_BFLY_DRONE, ASSET_38_ANIM_BSBFLY, 0.62f}, + {BS_9A_BTROT_DRONE, ASSET_15_ANIM_BSBTROT_WALK, 0.53f}, + {BS_9B_LONGLEG_DRONE, ASSET_42_ANIM_BSLONGLEG_WALK, 0.8f}, + {BS_9C_WALRUS_SLED_DRONE, ASSET_19E_ANIM_BSWALRUS_SLED, 0.8f}, + {BS_9D_BEE_DRONE, ASSET_1DC_ANIM_BEE_FLY, 0.38f}, + {BS_98_WALK_DRONE, ASSET_3_ANIM_BSWALK, 0.43f}, + {BS_A4_WONDERWING_DRONE, ASSET_11_ANIM_BSWHIRL_WALK, 0.53f} }; Struct_core2_13FC0 D_803646C0[14] = { - {BS_92_ANT_DRONE, ASSET_5E_ANIM_BSANT_IDLE, 1.2f}, - {BS_93_PUMPKIN_DRONE, ASSET_A0_ANIM_BSPUMPKIN_WALK, 0.8f}, - {BS_94_CROC_DRONE, ASSET_E1_ANIM_BSCROC_IDLE, 1.0f}, - {BS_95_WALRUS_DRONE, ASSET_11F_ANIM_BSWALRUS_IDLE, 4.0f}, - {BS_96_SWIM_DRONE, ASSET_57_ANIM_BSSWIM_IDLE, 1.2f}, - {BS_97_DIVE_DRONE, ASSET_70_ANIM_BSSWIM_DIVE_IDLE, 2.0f}, - {BS_98_WALK_DRONE, ASSET_19B_ANIM_UNKNOWN, 4.5f}, - {BS_99_BFLY_DRONE, ASSET_38_ANIM_BSBFLY, 0.62f}, - {BS_9A_BTROT_DRONE, ASSET_26_ANIM_BSBTROT_IDLE, 1.2f}, - {BS_9B_LONGLEG_DRONE, ASSET_41_ANIM_BSLONGLEG_IDLE, 1.0f}, - {BS_9C_WALRUS_SLED_DRONE, ASSET_19E_ANIM_BSWALRUS_SLED, 0.8f}, - {BS_9D_BEE_DRONE, ASSET_1DE_ANIM_BEE_IDLE, 3.0f}, - {BS_98_WALK_DRONE, ASSET_B2_ANIM_BSCLIMB_IDLE_2, 2.64f}, - {BS_A4_WONDERWING_DRONE, ASSET_23_ANIM_BSWONDERWING_IDLE, 1.0f}, + {BS_92_ANT_DRONE, ASSET_5E_ANIM_BSANT_IDLE, 1.2f}, + {BS_93_PUMPKIN_DRONE, ASSET_A0_ANIM_BSPUMPKIN_WALK, 0.8f}, + {BS_94_CROC_DRONE, ASSET_E1_ANIM_BSCROC_IDLE, 1.0f}, + {BS_95_WALRUS_DRONE, ASSET_11F_ANIM_BSWALRUS_IDLE, 4.0f}, + {BS_96_SWIM_DRONE, ASSET_57_ANIM_BSSWIM_IDLE, 1.2f}, + {BS_97_DIVE_DRONE, ASSET_70_ANIM_BSSWIM_DIVE_IDLE, 2.0f}, + {BS_98_WALK_DRONE, ASSET_19B_ANIM_UNKNOWN, 4.5f}, + {BS_99_BFLY_DRONE, ASSET_38_ANIM_BSBFLY, 0.62f}, + {BS_9A_BTROT_DRONE, ASSET_26_ANIM_BSBTROT_IDLE, 1.2f}, + {BS_9B_LONGLEG_DRONE, ASSET_41_ANIM_BSLONGLEG_IDLE, 1.0f}, + {BS_9C_WALRUS_SLED_DRONE, ASSET_19E_ANIM_BSWALRUS_SLED, 0.8f}, + {BS_9D_BEE_DRONE, ASSET_1DE_ANIM_BEE_IDLE, 3.0f}, + {BS_98_WALK_DRONE, ASSET_B2_ANIM_BSCLIMB_IDLE_2, 2.64f}, + {BS_A4_WONDERWING_DRONE, ASSET_23_ANIM_BSWONDERWING_IDLE, 1.0f} }; Struct_core2_13FC0 D_80364730[14] = { - {BS_92_ANT_DRONE, ASSET_5E_ANIM_BSANT_IDLE, 1.2f}, - {BS_93_PUMPKIN_DRONE, ASSET_A0_ANIM_BSPUMPKIN_WALK, 0.8f}, - {BS_94_CROC_DRONE, ASSET_E1_ANIM_BSCROC_IDLE, 1.0f}, - {BS_95_WALRUS_DRONE, ASSET_11F_ANIM_BSWALRUS_IDLE, 4.0f}, - {BS_96_SWIM_DRONE, ASSET_57_ANIM_BSSWIM_IDLE, 1.2f}, - {BS_97_DIVE_DRONE, ASSET_70_ANIM_BSSWIM_DIVE_IDLE, 2.0f}, - {BS_98_WALK_DRONE, ASSET_19B_ANIM_UNKNOWN, 4.5f}, - {BS_99_BFLY_DRONE, ASSET_38_ANIM_BSBFLY, 0.62f}, - {BS_9A_BTROT_DRONE, ASSET_26_ANIM_BSBTROT_IDLE, 1.2f}, - {BS_9B_LONGLEG_DRONE, ASSET_41_ANIM_BSLONGLEG_IDLE, 1.0f}, - {BS_9C_WALRUS_SLED_DRONE, ASSET_19E_ANIM_BSWALRUS_SLED, 0.8f}, - {BS_9D_BEE_DRONE, ASSET_1DE_ANIM_BEE_IDLE, 3.0f}, - {BS_98_WALK_DRONE, ASSET_B2_ANIM_BSCLIMB_IDLE_2, 2.64f}, - {BS_A4_WONDERWING_DRONE, ASSET_23_ANIM_BSWONDERWING_IDLE, 1.0f}, + {BS_92_ANT_DRONE, ASSET_5E_ANIM_BSANT_IDLE, 1.2f}, + {BS_93_PUMPKIN_DRONE, ASSET_A0_ANIM_BSPUMPKIN_WALK, 0.8f}, + {BS_94_CROC_DRONE, ASSET_E1_ANIM_BSCROC_IDLE, 1.0f}, + {BS_95_WALRUS_DRONE, ASSET_11F_ANIM_BSWALRUS_IDLE, 4.0f}, + {BS_96_SWIM_DRONE, ASSET_57_ANIM_BSSWIM_IDLE, 1.2f}, + {BS_97_DIVE_DRONE, ASSET_70_ANIM_BSSWIM_DIVE_IDLE, 2.0f}, + {BS_98_WALK_DRONE, ASSET_19B_ANIM_UNKNOWN, 4.5f}, + {BS_99_BFLY_DRONE, ASSET_38_ANIM_BSBFLY, 0.62f}, + {BS_9A_BTROT_DRONE, ASSET_26_ANIM_BSBTROT_IDLE, 1.2f}, + {BS_9B_LONGLEG_DRONE, ASSET_41_ANIM_BSLONGLEG_IDLE, 1.0f}, + {BS_9C_WALRUS_SLED_DRONE, ASSET_19E_ANIM_BSWALRUS_SLED, 0.8f}, + {BS_9D_BEE_DRONE, ASSET_1DE_ANIM_BEE_IDLE, 3.0f}, + {BS_98_WALK_DRONE, ASSET_B2_ANIM_BSCLIMB_IDLE_2, 2.64f}, + {BS_A4_WONDERWING_DRONE, ASSET_23_ANIM_BSWONDERWING_IDLE, 1.0f} }; Struct_core2_13FC0 D_803647A0[14] = { - {BS_92_ANT_DRONE, ASSET_5E_ANIM_BSANT_IDLE, 1.2f}, - {BS_93_PUMPKIN_DRONE, ASSET_A0_ANIM_BSPUMPKIN_WALK, 0.8f}, - {BS_94_CROC_DRONE, ASSET_E1_ANIM_BSCROC_IDLE, 1.0f}, - {BS_95_WALRUS_DRONE, ASSET_11F_ANIM_BSWALRUS_IDLE, 4.0f}, - {BS_96_SWIM_DRONE, ASSET_57_ANIM_BSSWIM_IDLE, 1.2f}, - {BS_97_DIVE_DRONE, ASSET_70_ANIM_BSSWIM_DIVE_IDLE, 2.0f}, - {BS_98_WALK_DRONE, ASSET_6F_ANIM_BSSTAND_IDLE, 5.5f}, - {BS_99_BFLY_DRONE, ASSET_38_ANIM_BSBFLY, 0.62f}, - {BS_9A_BTROT_DRONE, ASSET_26_ANIM_BSBTROT_IDLE, 1.2f}, - {BS_9B_LONGLEG_DRONE, ASSET_41_ANIM_BSLONGLEG_IDLE, 1.0f}, - {BS_9C_WALRUS_SLED_DRONE, ASSET_19E_ANIM_BSWALRUS_SLED, 0.8f}, - {BS_9D_BEE_DRONE, ASSET_1DE_ANIM_BEE_IDLE, 3.0f}, - {BS_98_WALK_DRONE, ASSET_B2_ANIM_BSCLIMB_IDLE_2, 2.64f}, - {BS_A4_WONDERWING_DRONE, ASSET_23_ANIM_BSWONDERWING_IDLE, 1.0f} + {BS_92_ANT_DRONE, ASSET_5E_ANIM_BSANT_IDLE, 1.2f}, + {BS_93_PUMPKIN_DRONE, ASSET_A0_ANIM_BSPUMPKIN_WALK, 0.8f}, + {BS_94_CROC_DRONE, ASSET_E1_ANIM_BSCROC_IDLE, 1.0f}, + {BS_95_WALRUS_DRONE, ASSET_11F_ANIM_BSWALRUS_IDLE, 4.0f}, + {BS_96_SWIM_DRONE, ASSET_57_ANIM_BSSWIM_IDLE, 1.2f}, + {BS_97_DIVE_DRONE, ASSET_70_ANIM_BSSWIM_DIVE_IDLE, 2.0f}, + {BS_98_WALK_DRONE, ASSET_6F_ANIM_BSSTAND_IDLE, 5.5f}, + {BS_99_BFLY_DRONE, ASSET_38_ANIM_BSBFLY, 0.62f}, + {BS_9A_BTROT_DRONE, ASSET_26_ANIM_BSBTROT_IDLE, 1.2f}, + {BS_9B_LONGLEG_DRONE, ASSET_41_ANIM_BSLONGLEG_IDLE, 1.0f}, + {BS_9C_WALRUS_SLED_DRONE, ASSET_19E_ANIM_BSWALRUS_SLED, 0.8f}, + {BS_9D_BEE_DRONE, ASSET_1DE_ANIM_BEE_IDLE, 3.0f}, + {BS_98_WALK_DRONE, ASSET_B2_ANIM_BSCLIMB_IDLE_2, 2.64f}, + {BS_A4_WONDERWING_DRONE, ASSET_23_ANIM_BSWONDERWING_IDLE, 1.0f} }; Struct_core2_13FC0 D_80364810[14] = { - {BS_8E_ANT_LOCKED, 0, 0.0f}, - {BS_8F_PUMPKIN_LOCKED, 0, 0.0f}, - {BS_8D_CROC_LOCKED, 0, 0.0f}, - {BS_73_UNKNOWN, ASSET_11F_ANIM_BSWALRUS_IDLE, 4.0f}, - {BS_77_SWIM_LOOKAT_DRONE, 0, 0.0f}, - {BS_78_DIVE_LOOKAT_DRONE, 0, 0.0f}, - {BS_73_UNKNOWN, ASSET_14A_ANIM_BSREST_LISTEN, 11.4f}, - {BS_76_BFLY_LOCKED, 0, 0.0f}, - {BS_79_BTROT_LOCKED, 0, 0.0f}, - {BS_62_LONGLEG_LOCKED, 0, 0.0f}, - {BS_81_WALRUS_SLED_LOCKED, 0, 0.0f}, - {BS_6B_BEE_LOCKED, 0, 0.0f}, - {BS_9E_CLIMB_LOCKED, 0, 0.0f}, - {BS_A5_WONDERWING_UNKA5, 0, 0.0f}, + {BS_8E_ANT_LOCKED, 0, 0.0f}, + {BS_8F_PUMPKIN_LOCKED, 0, 0.0f}, + {BS_8D_CROC_LOCKED, 0, 0.0f}, + {BS_73_UNKNOWN, ASSET_11F_ANIM_BSWALRUS_IDLE, 4.0f}, + {BS_77_SWIM_LOOKAT_DRONE, 0, 0.0f}, + {BS_78_DIVE_LOOKAT_DRONE, 0, 0.0f}, + {BS_73_UNKNOWN, ASSET_14A_ANIM_BSREST_LISTEN, 11.4f}, + {BS_76_BFLY_LOCKED, 0, 0.0f}, + {BS_79_BTROT_LOCKED, 0, 0.0f}, + {BS_62_LONGLEG_LOCKED, 0, 0.0f}, + {BS_81_WALRUS_SLED_LOCKED, 0, 0.0f}, + {BS_6B_BEE_LOCKED, 0, 0.0f}, + {BS_9E_CLIMB_LOCKED, 0, 0.0f}, + {BS_A5_WONDERWING_UNKA5, 0, 0.0f} }; Struct_core2_13FC0 D_80364880[14] = { - {BS_8E_ANT_LOCKED, 0, 0.0f}, - {BS_8F_PUMPKIN_LOCKED, 0, 0.0f}, - {BS_8D_CROC_LOCKED, 0, 0.0f}, - {BS_74_UNKNOWN, ASSET_11F_ANIM_BSWALRUS_IDLE, 4.0f}, - {BS_77_SWIM_LOOKAT_DRONE, 0, 0.0f}, - {BS_78_DIVE_LOOKAT_DRONE, 0, 0.0f}, - {BS_74_UNKNOWN, ASSET_6F_ANIM_BSSTAND_IDLE, 5.5f}, - {BS_76_BFLY_LOCKED, 0, 0.0f}, - {BS_79_BTROT_LOCKED, 0, 0.0f}, - {BS_62_LONGLEG_LOCKED, 0, 0.0f}, - {BS_81_WALRUS_SLED_LOCKED, 0, 0.0f}, - {BS_6B_BEE_LOCKED, 0, 0.0f}, - {BS_9E_CLIMB_LOCKED, 0, 0.0f}, - {BS_A5_WONDERWING_UNKA5, 0, 0.0f} + {BS_8E_ANT_LOCKED, 0, 0.0f}, + {BS_8F_PUMPKIN_LOCKED, 0, 0.0f}, + {BS_8D_CROC_LOCKED, 0, 0.0f}, + {BS_74_UNKNOWN, ASSET_11F_ANIM_BSWALRUS_IDLE, 4.0f}, + {BS_77_SWIM_LOOKAT_DRONE, 0, 0.0f}, + {BS_78_DIVE_LOOKAT_DRONE, 0, 0.0f}, + {BS_74_UNKNOWN, ASSET_6F_ANIM_BSSTAND_IDLE, 5.5f}, + {BS_76_BFLY_LOCKED, 0, 0.0f}, + {BS_79_BTROT_LOCKED, 0, 0.0f}, + {BS_62_LONGLEG_LOCKED, 0, 0.0f}, + {BS_81_WALRUS_SLED_LOCKED, 0, 0.0f}, + {BS_6B_BEE_LOCKED, 0, 0.0f}, + {BS_9E_CLIMB_LOCKED, 0, 0.0f}, + {BS_A5_WONDERWING_UNKA5, 0, 0.0f} }; Struct_core2_13FC0 D_803648F0[14] = { - {BS_8E_ANT_LOCKED, 0, 0.0f}, - {BS_8F_PUMPKIN_LOCKED, 0, 0.0f}, - {BS_8D_CROC_LOCKED, 0, 0.0f}, - {BS_75_UNKNOWN, ASSET_11F_ANIM_BSWALRUS_IDLE, 4.0f}, - {BS_77_SWIM_LOOKAT_DRONE, 0, 0.0f}, - {BS_78_DIVE_LOOKAT_DRONE, 0, 0.0f}, - {BS_75_UNKNOWN, ASSET_14A_ANIM_BSREST_LISTEN, 11.4f}, - {BS_76_BFLY_LOCKED, 0, 0.0f}, - {BS_79_BTROT_LOCKED, 0, 0.0f}, - {BS_62_LONGLEG_LOCKED, 0, 0.0f}, - {BS_81_WALRUS_SLED_LOCKED, 0, 0.0f}, - {BS_6B_BEE_LOCKED, 0, 0.0f}, - {BS_9E_CLIMB_LOCKED, 0, 0.0f}, - {BS_A5_WONDERWING_UNKA5, 0, 0.0f} + {BS_8E_ANT_LOCKED, 0, 0.0f}, + {BS_8F_PUMPKIN_LOCKED, 0, 0.0f}, + {BS_8D_CROC_LOCKED, 0, 0.0f}, + {BS_75_UNKNOWN, ASSET_11F_ANIM_BSWALRUS_IDLE, 4.0f}, + {BS_77_SWIM_LOOKAT_DRONE, 0, 0.0f}, + {BS_78_DIVE_LOOKAT_DRONE, 0, 0.0f}, + {BS_75_UNKNOWN, ASSET_14A_ANIM_BSREST_LISTEN, 11.4f}, + {BS_76_BFLY_LOCKED, 0, 0.0f}, + {BS_79_BTROT_LOCKED, 0, 0.0f}, + {BS_62_LONGLEG_LOCKED, 0, 0.0f}, + {BS_81_WALRUS_SLED_LOCKED, 0, 0.0f}, + {BS_6B_BEE_LOCKED, 0, 0.0f}, + {BS_9E_CLIMB_LOCKED, 0, 0.0f}, + {BS_A5_WONDERWING_UNKA5, 0, 0.0f} }; /* .bss */ @@ -376,7 +392,7 @@ void func_8029B984(f32 dst[3]){ f32 plyr_pos[3]; f32 sp18[3]; - _player_getPosition(plyr_pos); + playerPosition_get(plyr_pos); viewport_getPosition_vec3f(sp18); ml_vec3f_diff_copy(dst, sp18, plyr_pos); } @@ -596,7 +612,7 @@ enum bs_e bs_getIdleState(void){ return BS_26_LONGLEG_IDLE; } if (player_inWater()) { - if (player_getYPosition() > (floor_getCurrentFloorYPosition() - 80.0f)) { + if (playerPosition_getY() > (floor_getCurrentFloorYPosition() - 80.0f)) { return BS_2D_SWIM_IDLE; } return BS_2B_DIVE_IDLE; @@ -615,7 +631,7 @@ void func_8029C0D0(void) { f32 sp34; if (floor_isCurrentFloorunk59()) { - _player_getPosition(sp3C); + playerPosition_get(sp3C); sp3C[1] = sp34 = floor_getCurrentFloorYPosition(); p_ctrl = func_802F4094(sp3C, 35.0f); fxRipple_802F3554(3, sp3C); @@ -635,7 +651,7 @@ void func_8029C0D0(void) { void func_8029C22C(void) { - if(floor_isCurrentFloorunk59() && floor_getCurrentFloorYPosition() > player_getYPosition()) + if(floor_isCurrentFloorunk59() && floor_getCurrentFloorYPosition() > playerPosition_getY()) return; D_80364620 = D_80364620 ? false : true; @@ -652,7 +668,7 @@ void func_8029C22C(void) { void func_8029C304(s32 arg0) { f32 sp1C[3]; - _player_getPosition(sp1C); + playerPosition_get(sp1C); sp1C[1] = floor_getCurrentFloorYPosition(); fxRipple_802F3584(arg0, sp1C, (uintptr_t)func_802946CC()); } @@ -660,7 +676,7 @@ void func_8029C304(s32 arg0) { void func_8029C348(void) { f32 sp1C[3]; - _player_getPosition(sp1C); + playerPosition_get(sp1C); sp1C[0] += randf2(-30.0f, 30.0f); sp1C[1] += randf2(60.0f, 70.0f); sp1C[2] += randf2(-30.0f, 30.0f); @@ -675,7 +691,7 @@ void func_8029C3E8(f32 arg0, f32 arg1) { f32 sp2C; f32 sp28; - _player_getPosition(sp30); + playerPosition_get(sp30); sp28 = ml_map_f(baphysics_get_horizontal_velocity(), 0.0f, 1000.0f, arg0, arg1); sp2C = player_getYaw(); func_802589E4(sp3C, sp2C, sp28); @@ -740,7 +756,7 @@ void func_8029C674(void) { baflag_set(BA_FLAG_17_FIRST_PERSON_VIEW); ncDynamicCamera_enterFirstPerson(); func_8028E9C4(5, sp1C); - ncFirstPersonCamera_setZoomedOutPosition(sp1C); + ncba1p_setZoomedOutPosition(sp1C); } } @@ -752,11 +768,11 @@ void func_8029C6D0(void) { if (balookat_getState() == 4 && D_8037D1E8) { func_8028E9C4(5, sp18); - ncFirstPersonCamera_setZoomedOutPosition(sp18); + ncba1p_setZoomedOutPosition(sp18); func_8028E9C4(5, sp30); balookat_try_get_position(sp24); func_802BC434(sp3C, sp24, sp30); - ncFirstPersonCamera_setZoomedOutRotation(sp3C); + ncba1p_setZoomedOutRotation(sp3C); } } @@ -780,7 +796,7 @@ enum bs_e bs_getTypeOfJump(void){ return BS_5_JUMP; } -void func_8029C7F4(s32 arg0, s32 yaw_state, s32 arg2, s32 arg3){ +void code_14420_setUpdateTypes(enum baanim_update_type_e arg0, enum yaw_state_e yaw_state, s32 arg2, BaPhysicsType arg3){ baanim_setUpdateType(arg0); yaw_setUpdateState(yaw_state); func_8029957C(arg2); @@ -850,16 +866,16 @@ s32 func_8029C9C0(s32 arg0){ // [port] v1.1 fix: check sliding first so claw swipe can't trigger during a slide if(bakey_pressed(BUTTON_B) && can_claw() && (EventSystem_Should(VB_CLAW_SWIPE_SLIDE, true) || !player_isSliding())) - arg0 = BS_CLAW; + arg0 = BS_6_CLAW; if(bakey_held(BUTTON_Z) && bainput_should_beak_barge()) - arg0 = BS_BBARGE; + arg0 = BS_13_BBARGE; if(bainput_should_look_first_person_camera()) arg0 = badrone_look(); if(player_isSliding()) - arg0 = BS_SLIDE; + arg0 = BS_32_SLIDE; return arg0; } @@ -878,14 +894,14 @@ s32 func_8029CA94(s32 arg0){ arg0 = BS_14_BTROT_ENTER; if(baflag_isTrue(BA_FLAG_6)) - arg0 = BS_53_TIMEOUT; + arg0 = BS_53_TIMEOUT_BANJO; if(baflag_isTrue(BA_FLAG_7_TOUCHING_JIGGY)) { arg0 = BS_44_JIG_JIGGY; } if(baflag_isTrue(BA_FLAG_14_LOSE_BOGGY_RACE)) - arg0 = (player_getTransformation() == TRANSFORM_4_WALRUS) ? BS_80_WALRUS_SLED_LOSE : BS_53_TIMEOUT; + arg0 = (player_getTransformation() == TRANSFORM_4_WALRUS) ? BS_80_WALRUS_SLED_LOSE : BS_53_TIMEOUT_BANJO; baflag_clear(BA_FLAG_F); @@ -963,7 +979,7 @@ void func_8029CDC0(void) { f32 sp2C[3]; f32 sp20[3]; - _player_getPosition(sp20); + playerPosition_get(sp20); sp20[0] += (randf() * 90.0f) - 45.0f; sp20[2] += (randf() * 90.0f) - 45.0f; sp2C[0] = (randf() * 20.0f) - 10.0f; diff --git a/src/core2/bs/pumpkin.c b/src/core2/bs/pumpkin.c index 1f1b41ff9..c5f3d8b2e 100644 --- a/src/core2/bs/pumpkin.c +++ b/src/core2/bs/pumpkin.c @@ -5,6 +5,7 @@ #include "core2/ba/model.h" #include "core2/ba/anim.h" #include "core2/ba/physics.h" +#include "core2/yaw.h" extern void baanim_playForDuration_loop(s32, f32); extern void func_8029AD68(f32, s32); @@ -53,8 +54,8 @@ void func_802B223C(void) { void func_802B229C(void) { if (!bspumpkin_inSet(bs_getNextState())) { bastick_resetZones(); - func_8029E070(0); - func_8029E064(0); + modelAppendages_setKazooiesUpperHalfVisibility(false); + modelAppendages_setKazooiesFeetAndShoesVisibility(false); baflag_clear(BA_FLAG_3); baflag_clear(BA_FLAG_4); func_80293D74(); @@ -75,7 +76,7 @@ int bspumpkin_inSet(s32 move_indx){ void bspumpkin_idle_init(void) { baanim_playForDuration_loop(ASSET_A0_ANIM_BSPUMPKIN_WALK, 0.8f); - func_8029C7F4(1, 1, 1, BA_PHYSICS_NORMAL); + code_14420_setUpdateTypes(1, YAW_STATE_1_DEFAULT, 1, BA_PHYSICS_NORMAL); baphysics_set_target_horizontal_velocity(0.0f); pitch_setAngVel(1000.0f, 12.0f); roll_setAngularVelocity(1000.0f, 12.0f); @@ -119,7 +120,7 @@ void bspumpkin_walk_init(void) { anctrl_setDuration(anim_ctrl, 0.8f); anctrl_setPlaybackType(anim_ctrl, ANIMCTRL_LOOP); anctrl_start(anim_ctrl, "bspumpkin.c", 0x11D); - func_8029C7F4(2, 1, 1, BA_PHYSICS_NORMAL); + code_14420_setUpdateTypes(2, YAW_STATE_1_DEFAULT, 1, BA_PHYSICS_NORMAL); baanim_setVelocityMapRanges(D_80364CF0, D_80364CF4, D_80364CF8, D_80364CFC); func_802900B4(); } @@ -158,7 +159,7 @@ void bspumpkin_jump_init(void) { anctrl_setDuration(anim_ctrl, 1.2f); anctrl_setPlaybackType(anim_ctrl, ANIMCTRL_ONCE); anctrl_start(anim_ctrl, "bspumpkin.c", 0x16C); - func_8029C7F4(1, 1, 3, BA_PHYSICS_AIRBORN); + code_14420_setUpdateTypes(1, YAW_STATE_1_DEFAULT, 3, BA_PHYSICS_AIRBORN); if (bastick_distance() != 0.0f) { yaw_setIdeal(bastick_getAngleRelativeToBanjo()); } @@ -252,7 +253,7 @@ void bspumpkin_fall_init(void) { anctrl_setDuration(anim_ctrl, 0.7f); anctrl_setPlaybackType(anim_ctrl, ANIMCTRL_STOPPED); anctrl_start(anim_ctrl, "bspumpkin.c", 0x1F1); - func_8029C7F4(1, 1, 3, BA_PHYSICS_AIRBORN); + code_14420_setUpdateTypes(1, YAW_STATE_1_DEFAULT, 3, BA_PHYSICS_AIRBORN); D_8037D4E0 = 0; } @@ -303,16 +304,16 @@ void bspumpkin_fall_end(void){ func_802B229C(); } -void func_802B2BF0(void) { +void bspumpkin_flush_init(void) { func_8029656C(D_8037D4E8); func_8028FAB0(D_8037D4E8); baanim_playForDuration_loop(ASSET_A0_ANIM_BSPUMPKIN_WALK, 0.8f); - func_8029C7F4(1, 1, 2, BA_PHYSICS_FREEZE); + code_14420_setUpdateTypes(1, YAW_STATE_1_DEFAULT, 2, BA_PHYSICS_FREEZE); func_80294378(6); batimer_set(0, 0.0f); } -void func_802B2C58(void) { +void bspumpkin_flush_update(void) { f32 sp3C; f32 sp38; f32 sp34; @@ -330,7 +331,7 @@ void func_802B2C58(void) { func_8028FAB0(sp28); } -void func_802B2D50(void) { +void bspumpkin_flush_end(void) { func_80294378(1); baModel_setScale(1.0f); } @@ -353,7 +354,7 @@ void __bspumpkin_bounce_init(s32 arg0) { } else { func_8030E58C(SFX_56_BANJO_HUI, 1.8f); } - _player_getPosition(plyr_pos); + playerPosition_get(plyr_pos); func_80294980(sp20); func_80257F18(sp20, plyr_pos, &sp38); yaw_setIdeal(mlNormalizeAngle(sp38 + 180.0f)); @@ -361,7 +362,7 @@ void __bspumpkin_bounce_init(s32 arg0) { baphysics_set_target_horizontal_velocity(200.0f); baphysics_set_target_yaw(sp38); baphysics_set_horizontal_velocity(sp38, baphysics_get_target_horizontal_velocity()); - func_8029C7F4(1, 1, 2, BA_PHYSICS_LOCKED_ROTATION); + code_14420_setUpdateTypes(1, YAW_STATE_1_DEFAULT, 2, BA_PHYSICS_LOCKED_ROTATION); baphysics_set_vertical_velocity(510.0f); baphysics_set_gravity(-1200.0f); baMarker_collisionOff(); @@ -441,7 +442,7 @@ void bspumpkin_die_init(void) { anctrl_setPlaybackType(anim_ctrl, ANIMCTRL_ONCE); anctrl_start(anim_ctrl, "bspumpkin.c", 0x32E); func_8030E58C(SFX_36_BANJO_DOH, 1.8f); - _player_getPosition(plyr_pos); + playerPosition_get(plyr_pos); func_80294980(sp20); func_80257F18(sp20, plyr_pos, &sp38); D_8037D4F4 = 250.0f; @@ -450,12 +451,12 @@ void bspumpkin_die_init(void) { baphysics_set_target_horizontal_velocity(D_8037D4F4); baphysics_set_target_yaw(sp38); baphysics_set_horizontal_velocity(sp38, baphysics_get_target_horizontal_velocity()); - func_8029C7F4(1, 1, 2, BA_PHYSICS_LOCKED_ROTATION); + code_14420_setUpdateTypes(1, YAW_STATE_1_DEFAULT, 2, BA_PHYSICS_LOCKED_ROTATION); baphysics_set_vertical_velocity(510.0f); baphysics_set_gravity(-1200.0f); pitch_setAngVel(1000.0f, 12.0f); func_802914CC(0xD); - ncDynamicCamD_func_802BF2C0(30.0f); + ncbadie_func_802BF2C0(30.0f); func_8029C984(); baMarker_collisionOff(); baeyes_close(); @@ -532,15 +533,15 @@ void bspumpkin_die_end(void) { func_80291548(); } -void func_802B34A0(void) { +void bspumpkin_locked_init(void) { baanim_playForDuration_loopSmooth(0xA0, 0.8f); - func_8029C7F4(1, 1, 3, BA_PHYSICS_NORMAL); + code_14420_setUpdateTypes(1, YAW_STATE_1_DEFAULT, 3, BA_PHYSICS_NORMAL); baphysics_set_target_horizontal_velocity(0.0f); func_8029C674(); func_802B3A50(); } -void func_802B34F8(void) { +void bspumpkin_locked_update(void) { s32 next_state; next_state = 0; @@ -552,7 +553,7 @@ void func_802B34F8(void) { bs_setState(next_state); } -void func_802B353C(void) { +void bspumpkin_locked_end(void) { func_8029C748(); func_802B229C(); } diff --git a/src/core2/bs/rebound.c b/src/core2/bs/rebound.c index 8c28825fe..a8f4b9f7a 100644 --- a/src/core2/bs/rebound.c +++ b/src/core2/bs/rebound.c @@ -4,6 +4,7 @@ #include "core2/ba/physics.h" #include "core2/ba/timer.h" +#include "core2/yaw.h" extern f32 func_80296548(void); extern f32 func_8029653C(void); @@ -27,7 +28,7 @@ void func_802B35DC(void) { void func_802B360C(void) { f32 sp44[3]; f32 sp38[3]; - f32 sp2C[3]; + f32 player_position[3]; f32 sp28; f32 sp24; f32 sp20; @@ -35,16 +36,16 @@ void func_802B360C(void) { sp1C = func_80296560(); func_80294980(sp38); - _player_getPosition(sp2C); - func_80257F18(sp38, sp2C, &sp28); + playerPosition_get(player_position); + func_80257F18(sp38, player_position, &sp28); if ((sp1C == 0xE) || (sp1C == 0x10)) { func_802B35D0(1); - func_8029C7F4(1, 1, 2, BA_PHYSICS_UNK1); + code_14420_setUpdateTypes(1, YAW_STATE_1_DEFAULT, 2, BA_PHYSICS_UNK1); yaw_setIdeal(mlNormalizeAngle(sp28)); baphysics_set_gravity(func_80296548()); sp20 = func_8029653C(); - sp24 = func_8029B56C(sp2C[1], sp38[1], sp20, baphysics_get_gravity()); - ml_vec3f_diff_copy(sp44, sp38, sp2C); + sp24 = func_8029B56C(player_position[1], sp38[1], sp20, baphysics_get_gravity()); + ml_vec3f_diff_copy(sp44, sp38, player_position); D_8037D504 = sp24; sp44[0] /= sp24; sp44[1] /= sp24; @@ -61,7 +62,7 @@ void func_802B360C(void) { baphysics_set_horizontal_velocity(sp28, baphysics_get_target_horizontal_velocity()); baphysics_set_vertical_velocity(barebound_get_vertical_velocity()); baphysics_set_gravity(barebound_get_gravity()); - func_8029C7F4(1, 1, 2, BA_PHYSICS_LOCKED_ROTATION); + code_14420_setUpdateTypes(1, YAW_STATE_1_DEFAULT, 2, BA_PHYSICS_LOCKED_ROTATION); if (barebound_802987B4() == 2) { baphysics_set_type(BA_PHYSICS_AIRBORN); } @@ -85,7 +86,7 @@ void func_802B37DC(void) { } } -void func_802B3868(void) { +void rebound_init(void) { AnimCtrl *anim_ctrl; f32 sp20; @@ -109,7 +110,7 @@ void func_802B3868(void) { } -void func_802B3954(void) { +void rebound_update(void) { s32 next_state; AnimCtrl *anim_ctrl; @@ -132,7 +133,7 @@ void func_802B3954(void) { } -void func_802B3A20(void) { +void rebound_end(void) { func_802B35DC(); baphysics_reset_gravity(); baMarker_collisionOn(); diff --git a/src/core2/bs/rest.c b/src/core2/bs/rest.c index 7d625bf87..e652db7b4 100644 --- a/src/core2/bs/rest.c +++ b/src/core2/bs/rest.c @@ -3,6 +3,7 @@ #include "variables.h" #include "core2/ba/physics.h" +#include "core2/yaw.h" void func_802B3A50(void) { f32 sp34; @@ -10,7 +11,7 @@ void func_802B3A50(void) { f32 sp1C[3]; if (balookat_getState()) { - _player_getPosition(plyr_pos); + playerPosition_get(plyr_pos); if (balookat_try_get_position(sp1C) && func_80257F18(plyr_pos, sp1C, &sp34)) { yaw_setIdeal(sp34); } @@ -22,7 +23,7 @@ void func_802B3AAC(enum asset_e anim_id, f32 anim_duration) { anim_ctrl = baanim_getAnimCtrlPtr(); if (anim_id == ASSET_14A_ANIM_BSREST_LISTEN) { - func_8029E070(1); + modelAppendages_setKazooiesUpperHalfVisibility(true); switch (anctrl_getIndex(baanim_getAnimCtrlPtr())) { case ASSET_14A_ANIM_BSREST_LISTEN: baanim_playForDuration_loopSmooth(anim_id, anim_duration); @@ -41,7 +42,7 @@ void func_802B3AAC(enum asset_e anim_id, f32 anim_duration) { } else { baanim_playForDuration_loopSmooth(anim_id, anim_duration); } - func_8029C7F4(1, 1, 3, BA_PHYSICS_NORMAL); + code_14420_setUpdateTypes(1, YAW_STATE_1_DEFAULT, 3, BA_PHYSICS_NORMAL); baphysics_set_target_horizontal_velocity(0.0f); func_802B3A50(); } @@ -85,10 +86,10 @@ bool func_802B3BB0(void) { } void func_802B3CCC(void){ - func_8029E070(0); + modelAppendages_setKazooiesUpperHalfVisibility(false); } -void func_802B3CEC(void){ +void bsrest_bs73unknown_init(void){ enum asset_e anim_id; f32 anim_duration; @@ -96,7 +97,7 @@ void func_802B3CEC(void){ func_802B3AAC(anim_id, anim_duration); } -void func_802B3D1C(void) { +void bsrest_bs73unknown_update(void) { enum bs_e next_state; next_state = 0; @@ -109,11 +110,11 @@ void func_802B3D1C(void) { bs_setState(next_state); } -void func_802B3D6C(void){ +void bsrest_bs73unknown_end(void){ func_802B3CCC(); } -void func_802B3D8C(void){ +void bsrest_bs75unknown_init(void){ enum asset_e anim_id; f32 anim_duration; @@ -122,7 +123,7 @@ void func_802B3D8C(void){ } -void func_802B3DBC(void) { +void bsrest_bs75unknown_update(void) { enum bs_e next_state; next_state = 0; @@ -136,11 +137,11 @@ void func_802B3DBC(void) { } -void func_802B3E0C(void){ +void bsrest_bs75unknown_end(void){ func_802B3CCC(); } -void func_802B3E2C(void){ +void bsrest_bs74unknown_init(void){ enum asset_e anim_id; f32 anim_duration; @@ -149,7 +150,7 @@ void func_802B3E2C(void){ func_8029C674(); } -void func_802B3E64(void) { +void bsrest_bs74unknown_update(void) { s32 next_state; next_state = 0; @@ -167,7 +168,7 @@ void func_802B3E64(void) { } -void func_802B3EF4(void){ +void bsrest_bs74unknown_end(void){ func_802B3CCC(); func_8029C748(); } diff --git a/src/core2/bs/sled.c b/src/core2/bs/sled.c index 9d8a8ac92..eaa653542 100644 --- a/src/core2/bs/sled.c +++ b/src/core2/bs/sled.c @@ -2,6 +2,7 @@ #include "functions.h" #include "variables.h" #include "core2/ba/physics.h" +#include "core2/yaw.h" extern ActorMarker *func_80296554(void); @@ -29,7 +30,7 @@ void __bssled_unlinkSledMarker(void){ void bssled_init(void){ __bssled_linkSledMarker(); baanim_playForDuration_loopSmooth(ASSET_228_ANIM_BANJO_SLED, 1.8f); - func_8029C7F4(1, 1, 3, BA_PHYSICS_FREEZE); + code_14420_setUpdateTypes(1, YAW_STATE_1_DEFAULT, 3, BA_PHYSICS_FREEZE); baphysics_set_target_horizontal_velocity(0.0f); func_80294A8C(0); func_80294378(6); diff --git a/src/core2/bs/slide.c b/src/core2/bs/slide.c index 3c2a75be5..1cd561ef8 100644 --- a/src/core2/bs/slide.c +++ b/src/core2/bs/slide.c @@ -3,6 +3,7 @@ #include "variables.h" #include "core2/ba/physics.h" +#include "core2/yaw.h" /* .bss */ s32 D_8037D520; @@ -15,7 +16,7 @@ void func_802B40D0(void){ f32 sp2C[3]; f32 sp28; - _player_getPosition(sp38); + playerPosition_get(sp38); sp38[1] += 20.0f; D_8037D524++; if(!(D_8037D524 < 3)) @@ -68,7 +69,7 @@ void bsslide_init(void){ anctrl_setPlaybackType(aCtrl, ANIMCTRL_STOPPED); anctrl_setDuration(aCtrl, 1.0f); anctrl_start(aCtrl, "bsslide.c", 0x7f); - func_8029C7F4(1,1,3, BA_PHYSICS_LOCKED_ROTATION); + code_14420_setUpdateTypes(1, YAW_STATE_1_DEFAULT, 3, BA_PHYSICS_LOCKED_ROTATION); baphysics_set_target_yaw(yaw_getIdeal()); baphysics_set_horizontal_velocity(yaw_getIdeal() ,baphysics_get_target_horizontal_velocity()); pitch_setAngVel(800.0f, 8.0f); diff --git a/src/core2/bs/splat.c b/src/core2/bs/splat.c index eb3ec99ed..7d5c1fc52 100644 --- a/src/core2/bs/splat.c +++ b/src/core2/bs/splat.c @@ -4,6 +4,7 @@ #include "bsint.h" #include "core2/ba/physics.h" +#include "core2/yaw.h" void func_80292900(f32, f32); void baMotor_80250D94(f32, f32, f32); @@ -23,7 +24,7 @@ void func_802B4570(void) { void bssplat_init(void){ s32 sp1C; baanim_playForDuration_onceSmooth(ASSET_149_ANIM_BSSPLAT, 1.1f); - func_8029C7F4(1,1,3, BA_PHYSICS_LOCKED_ROTATION); + code_14420_setUpdateTypes(1, YAW_STATE_1_DEFAULT, 3, BA_PHYSICS_LOCKED_ROTATION); bafalldamage_get_damage(&sp1C); item_adjustByDiffWithHud(ITEM_14_HEALTH, -sp1C); if(func_8029CEB0() == 4){ diff --git a/src/core2/bs/stand.c b/src/core2/bs/stand.c index 1626eb750..da427da74 100644 --- a/src/core2/bs/stand.c +++ b/src/core2/bs/stand.c @@ -4,6 +4,7 @@ #include "bsint.h" #include "core2/statetimer.h" #include "core2/ba/physics.h" +#include "core2/yaw.h" extern f32 bastick_distance(void); void yaw_setVelocityBounded(f32, f32); @@ -52,23 +53,23 @@ s32 func_802B488C(s32 arg0){ s32 retVal = arg0; switch(bastick_getZone()){ case 1: //L802B48CC - retVal = BS_WALK_CREEP; + retVal = BS_1F_WALK_CREEP; break; case 2: //L802B48D4 retVal = BS_2_WALK_SLOW; break; case 3: //L802B48D4 - retVal = BS_WALK; + retVal = BS_3_WALK; break; case 4: //L802B48D4 retVal = BS_4_WALK_FAST; break; } if(bakey_held(BUTTON_Z)) - retVal = BS_CROUCH; + retVal = BS_7_CROUCH; if(bakey_pressed(BUTTON_B) && can_claw()) - retVal = BS_CLAW; + retVal = BS_6_CLAW; if(bakey_pressed(BUTTON_A)) retVal = bs_getTypeOfJump(); @@ -77,7 +78,7 @@ s32 func_802B488C(s32 arg0){ retVal = badrone_look(); if(player_isSliding()) - retVal = BS_SLIDE; + retVal = BS_32_SLIDE; retVal = func_8029CA94(retVal); @@ -89,10 +90,10 @@ s32 func_802B488C(s32 arg0){ void bsstand_init(void){ if(bsclimb_inSet(bs_getPrevState())) - climbRelease(); + climb_release(); baanim_playForDuration_once(ASSET_6F_ANIM_BSSTAND_IDLE, 5.5f); - func_8029C7F4(1,1,1, BA_PHYSICS_NORMAL); + code_14420_setUpdateTypes(1, YAW_STATE_1_DEFAULT, 1, BA_PHYSICS_NORMAL); baphysics_set_target_horizontal_velocity(0.0f); func_802900B4(); D_8037D540 = 0; @@ -205,12 +206,12 @@ void bsstand_update(void) { if (sp18 & 8) { if (sp18 & 4) { if (anctrl_isAt(anim_ctrl, 0.0909f)) basfx_80299BD4(); - if (anctrl_isAt(anim_ctrl, 0.0909f)) func_8029E070(1); - if (anctrl_isAt(anim_ctrl, 0.6818f)) func_8029E070(0); + if (anctrl_isAt(anim_ctrl, 0.0909f)) modelAppendages_setKazooiesUpperHalfVisibility(true); + if (anctrl_isAt(anim_ctrl, 0.6818f)) modelAppendages_setKazooiesUpperHalfVisibility(false); }//L802B4E70 if (sp18 & 2) { - if (anctrl_isAt(anim_ctrl, 0.7727f)) func_8029E070(1); - if (anctrl_isAt(anim_ctrl, 0.9999f)) func_8029E070(0); + if (anctrl_isAt(anim_ctrl, 0.7727f)) modelAppendages_setKazooiesUpperHalfVisibility(true); + if (anctrl_isAt(anim_ctrl, 0.9999f)) modelAppendages_setKazooiesUpperHalfVisibility(false); }//L802B50E4 } else if (sp18 & 0x20) { if (anctrl_getIndex(anim_ctrl) == ASSET_95_ANIM_BSSTAND_KAZOOIE_PECK) { @@ -244,11 +245,11 @@ void bsstand_update(void) { if (sp18 & 0x10) { baanim_playForDuration_once(ASSET_95_ANIM_BSSTAND_KAZOOIE_PECK, 5.5f); anctrl_start(anim_ctrl, "bsstand.c", 0x1AB); - func_8029E070(1); + modelAppendages_setKazooiesUpperHalfVisibility(true); func_802900FC(); } else if (sp18 & 0x20) { baanim_playForDuration_once(ASSET_95_ANIM_BSSTAND_KAZOOIE_PECK, 5.5f); - func_8029E070(1); + modelAppendages_setKazooiesUpperHalfVisibility(true); func_802900FC(); } else if (sp18 & 8) { if (anctrl_getIndex(anim_ctrl) == ASSET_6F_ANIM_BSSTAND_IDLE) { @@ -263,7 +264,7 @@ void bsstand_update(void) { anctrl_setPlaybackType(anim_ctrl, ANIMCTRL_LOOP); anctrl_setStart(anim_ctrl, sp1C); anctrl_start(anim_ctrl, "bsstand.c", 0x1C3); - func_8029E070(0); + modelAppendages_setKazooiesUpperHalfVisibility(false); } } if (player_shouldFall() != 0) { @@ -273,14 +274,14 @@ void bsstand_update(void) { } void bsstand_end(void){ - func_8029E070(0); + modelAppendages_setKazooiesUpperHalfVisibility(false); func_802900FC(); baeyes_open(); } //bsStand_Land_init void bsstand_landing_init(void){ - func_8029C7F4(1,1,1, BA_PHYSICS_NORMAL); + code_14420_setUpdateTypes(1, YAW_STATE_1_DEFAULT, 1, BA_PHYSICS_NORMAL); baphysics_set_target_horizontal_velocity(0.0f); } @@ -309,11 +310,11 @@ void bsstand_landing_update(void){ ///BREAK??? void func_802B5350(void){ - s32 sp1C = bs_getInterruptType(); - if(sp1C == BS_INTR_D_SURF){ + s32 interrupt_type = bs_getInterruptType(); + if(interrupt_type == BS_INTR_D_SURF){ bs_setState(0x52); } - if(sp1C == 0x7){ + if(interrupt_type == BS_INTR_7){ if(bsStoredState_getTransformation() != TRANSFORM_1_BANJO) bs_setInterruptResponse(1); else{ @@ -321,14 +322,14 @@ void func_802B5350(void){ bs_setState(BS_3A_CARRY_IDLE); } } - else if(sp1C == 0x12){//L802B53D0 + else if(interrupt_type == BS_INTR_12){//L802B53D0 bs_setInterruptResponse(1); if( bsStoredState_getTransformation() == TRANSFORM_1_BANJO && !baflag_isTrue(BA_FLAG_F) && stateTimer_isDone(STATE_TIMER_0_UNKNOWN)){ bacarriedobj_spawn(baMarker_getCarriedObjectActorId()); bs_setInterruptResponse(2); } } - else if(sp1C == 0x8){//L802B5438 + else if(interrupt_type == BS_INTR_8){//L802B5438 bs_setInterruptResponse(2); bs_setState(BS_3C_TALK); }else{ diff --git a/src/core2/bs/surf.c b/src/core2/bs/surf.c index 6ad84a30b..89d803f76 100644 --- a/src/core2/bs/surf.c +++ b/src/core2/bs/surf.c @@ -3,12 +3,13 @@ #include "variables.h" #include "core2/ba/physics.h" +#include "core2/yaw.h" /* .bss */ s32 D_8037D560; /* .code */ -void func_802B5FD0(void) { +void bssurf_init(void) { AnimCtrl *anim_ctrl; anim_ctrl = baanim_getAnimCtrlPtr(); @@ -17,12 +18,12 @@ void func_802B5FD0(void) { anctrl_setDuration(anim_ctrl, 1.8f); anctrl_setPlaybackType(anim_ctrl, ANIMCTRL_LOOP); anctrl_start(anim_ctrl, "bssurf.c", 0x33); - func_8029C7F4(1, 1, 3, BA_PHYSICS_NORMAL); + code_14420_setUpdateTypes(1, YAW_STATE_1_DEFAULT, 3, BA_PHYSICS_NORMAL); baphysics_set_target_horizontal_velocity(0.0f); D_8037D560 = 1; } -void func_802B6064(void) { +void bssurf_update(void) { enum bs_e next_state; next_state = 0; @@ -34,12 +35,12 @@ void func_802B6064(void) { } D_8037D560 = 0; if (baflag_isTrue(BA_FLAG_6)) { - next_state = BS_53_TIMEOUT; + next_state = BS_53_TIMEOUT_BANJO; } bs_setState(next_state); } -void func_802B60D0(void){} +void bssurf_end(void){} void func_802B60D8(void) { if (bs_getInterruptType() == BS_INTR_D_SURF) { diff --git a/src/core2/bs/swim.c b/src/core2/bs/swim.c index a96668f62..e6e4d77a7 100644 --- a/src/core2/bs/swim.c +++ b/src/core2/bs/swim.c @@ -4,6 +4,7 @@ #include "core2/ba/anim.h" #include "core2/ba/physics.h" +#include "core2/yaw.h" extern void bainput_setDiveCooldown(s32, f32); @@ -73,7 +74,7 @@ void __bsswim_updateVelocity(void) { baphysics_set_target_horizontal_velocity(ml_interpolate_f(sp1C, bsSwimHorzVelocityMin, bsSwimHorzVelocityMax)); } -void swim_enteredWater(void) { +void __bsswim_enteredWater(void) { if (level_get() == LEVEL_9_RUSTY_BUCKET_BAY) { progressDialog_showDialogMaskZero(FILEPROG_AB_SWIM_OILY_WATER); } else if (gsworld_getMap() == MAP_46_CCW_WINTER) { @@ -139,10 +140,10 @@ void bsswim_idle_init(void) { anctrl_setDuration(anim_ctrl, 1.2f); anctrl_start(anim_ctrl, "bsswim.c", 0xFD); } - func_8029C7F4(1, 3, 3, BA_PHYSICS_NORMAL); + code_14420_setUpdateTypes(1, YAW_STATE_3_BOUNDED, 3, BA_PHYSICS_NORMAL); yaw_setVelocityBounded(500.0f, 5.0f); baphysics_set_target_horizontal_velocity(0.0f); - swim_enteredWater(); + __bsswim_enteredWater(); bsSwimCurrentAnimation = 0; } @@ -180,7 +181,7 @@ void bsswim_idle_update(void) { next_state = BS_5_JUMP; } if (baflag_isTrue(BA_FLAG_6) || baflag_isTrue(BA_FLAG_14_LOSE_BOGGY_RACE)) { - next_state = BS_D_TIMEOUT; + next_state = BS_D_TIMEOUT_TRANSFORMATION; } bs_setState(next_state); } @@ -245,7 +246,7 @@ void bsswim_swim_update(void) { if ((func_80294530() != 0) && (can_dive() != 0)) { func_802944D0(sp1C); if (sp1C[1] < -0.7) { - if ((floor_getCurrentFloorYPosition() - player_getYPosition()) > 90.0f) { + if ((floor_getCurrentFloorYPosition() - playerPosition_getY()) > 90.0f) { next_state = BS_30_DIVE_ENTER; } } @@ -257,7 +258,7 @@ void bsswim_swim_update(void) { next_state = BS_5_JUMP; } if (baflag_isTrue(BA_FLAG_6) || baflag_isTrue(BA_FLAG_14_LOSE_BOGGY_RACE)) { - next_state = BS_D_TIMEOUT; + next_state = BS_D_TIMEOUT_TRANSFORMATION; } bs_setState(next_state); } @@ -266,13 +267,13 @@ void bsswim_swim_end(void){ __bsswim_end(); } -void __bsswim_enteredWater(void) { +void __bsswim_update_rotation(void) { f32 sp34; f32 plyr_pos[3]; f32 sp1C[3]; if (balookat_getState() != 0) { - _player_getPosition(plyr_pos); + playerPosition_get(plyr_pos); if (balookat_try_get_position(sp1C) && func_80257F18(plyr_pos, sp1C, &sp34)) { yaw_setIdeal(sp34); } @@ -281,11 +282,11 @@ void __bsswim_enteredWater(void) { void bsswim_lookat_init(void) { baanim_playForDuration_loopSmooth(0x57, 1.2f); - func_8029C7F4(1, 3, 3, BA_PHYSICS_NORMAL); + code_14420_setUpdateTypes(1, YAW_STATE_3_BOUNDED, 3, BA_PHYSICS_NORMAL); yaw_setVelocityBounded(500.0f, 5.0f); baphysics_set_target_horizontal_velocity(0.0f); - swim_enteredWater(); __bsswim_enteredWater(); + __bsswim_update_rotation(); } void bsswim_lookat_update(void) { @@ -295,7 +296,7 @@ void bsswim_lookat_update(void) { if (balookat_getState() == 0) { next_state = BS_2D_SWIM_IDLE; } - __bsswim_enteredWater(); + __bsswim_update_rotation(); bs_setState(next_state); } @@ -304,7 +305,7 @@ void bsswim_lookat_end(void){ } void bsswim_drone_init(void){ - swim_enteredWater(); + __bsswim_enteredWater(); bsdrone_init(); } diff --git a/src/core2/bs/talk.c b/src/core2/bs/talk.c index da8ad965a..e2c8fb195 100644 --- a/src/core2/bs/talk.c +++ b/src/core2/bs/talk.c @@ -20,7 +20,7 @@ void bstalk_init(void){ func_8029C848(player_anim_ctrl); anctrl_setPlaybackType(player_anim_ctrl, ANIMCTRL_LOOP); anctrl_start(player_anim_ctrl, "bstalk.c", 0x38); - _player_getPosition(plyr_pos); + playerPosition_get(plyr_pos); get_talk_target_position(target_pos); func_80257F18(plyr_pos, target_pos, &yaw); yaw_setIdeal(yaw); diff --git a/src/core2/bs/throw.c b/src/core2/bs/throw.c index 2e5e95de3..ee4a64da0 100644 --- a/src/core2/bs/throw.c +++ b/src/core2/bs/throw.c @@ -5,7 +5,7 @@ #include "core2/ba/anim.h" #include "core2/ba/physics.h" -extern ActorMarker *bacarry_get_marker(void); +extern ActorMarker *bacarry_getMarker(void); /* .bss */ u8 D_8037D580; @@ -35,12 +35,12 @@ void bsthrow_update(void){ f32 sp34[3]; f32 player_position[3]; f32 sp24; - ActorMarker *sp20 = bacarry_get_marker(); + ActorMarker *sp20 = bacarry_getMarker(); if(D_8037D580 == 0 && sp20 != NULL) bacarry_set_marker(sp20); - _player_getPosition(player_position); + playerPosition_get(player_position); get_throw_target_position(sp34); func_80257F18(player_position, sp34, &sp24); yaw_setIdeal(sp24); diff --git a/src/core2/bs/timeout.c b/src/core2/bs/timeout.c index 0d01ed5cc..f4c636b9a 100644 --- a/src/core2/bs/timeout.c +++ b/src/core2/bs/timeout.c @@ -3,27 +3,28 @@ #include "variables.h" #include "core2/ba/physics.h" #include "core2/ba/timer.h" +#include "core2/yaw.h" void baeyes_openSingleEye(s32, f32); f32 func_8029B41C(void); -void ncDynamicCamD_func_802BF2C0(f32); +void ncbadie_func_802BF2C0(f32); -void func_802B6270(void){ +void timeout_banjo_init(void){ baanim_playForDuration_once(ASSET_77_ANIM_BSTIMEOUT, 3.2f); - func_8029C7F4(1,1,3, BA_PHYSICS_NORMAL); + code_14420_setUpdateTypes(1, YAW_STATE_1_DEFAULT, 3, BA_PHYSICS_NORMAL); baphysics_set_target_horizontal_velocity(0.0f); - func_802914CC(0xd); + func_802914CC(0xD); yaw_setIdeal(func_8029B41C() + 35.0f); - ncDynamicCamD_func_802BF2C0(80.0f); - func_8025A58C(0,0xfa0); + ncbadie_func_802BF2C0(80.0f); + func_8025A58C(0, 4000); comusic_playTrack(COMUSIC_3C_MINIGAME_LOSS); core1_ce60_incOrDecCounter(false); - func_8029E070(1); + modelAppendages_setKazooiesUpperHalfVisibility(true); baMarker_collisionOff(); } -void func_802B6314(void){ +void timeout_banjo_update(void){ AnimCtrl *aCtrl = baanim_getAnimCtrlPtr(); if(anctrl_isAt(aCtrl, 0.0625f)) baeyes_close(); @@ -40,37 +41,37 @@ void func_802B6314(void){ func_8029B6F0(); } -void func_802B63C8(void){ +void timeout_banjo_end(void){ baeyes_open(); func_80291548(); core1_ce60_incOrDecCounter(true); } -void func_802B63F8(void){ +void timeout_transformation_init(void){ AnimCtrl *aCtrl = baanim_getAnimCtrlPtr(); anctrl_reset(aCtrl); func_8029C848(aCtrl); anctrl_setPlaybackType(aCtrl, ANIMCTRL_LOOP); - anctrl_start(aCtrl, "bstimeout.c", 0x7e); - func_8029C7F4(1,1,3,BA_PHYSICS_FREEZE); + anctrl_start(aCtrl, "bstimeout.c", 0x7E); + code_14420_setUpdateTypes(1, YAW_STATE_1_DEFAULT, 3, BA_PHYSICS_FREEZE); baphysics_set_target_horizontal_velocity(0.0f); - func_802914CC(0xd); + func_802914CC(0xD); yaw_setIdeal(func_8029B41C() + 35.0f); - ncDynamicCamD_func_802BF2C0(80.0f); - func_8025A58C(0,0xfa0); + ncbadie_func_802BF2C0(80.0f); + func_8025A58C(0, 4000); comusic_playTrack(COMUSIC_3C_MINIGAME_LOSS); core1_ce60_incOrDecCounter(false); baMarker_collisionOff(); batimer_set(0, 2.9f); } -void func_802B64D0(void){ +void timeout_transformation_update(void){ if(batimer_decrement(0)) func_8029B6F0(); } -void func_802B6500(void){ - func_8029E070(0); +void timeout_transformation_end(void){ + modelAppendages_setKazooiesUpperHalfVisibility(false); func_80291548(); core1_ce60_incOrDecCounter(true); func_8025A904(); diff --git a/src/core2/bs/turn.c b/src/core2/bs/turn.c index 2a0dfc397..58758d251 100644 --- a/src/core2/bs/turn.c +++ b/src/core2/bs/turn.c @@ -54,10 +54,10 @@ void bsturn_update(void){ sp2C = BS_4_WALK_FAST; if(bakey_held(BUTTON_Z)) - sp2C = BS_CROUCH; + sp2C = BS_7_CROUCH; if(bakey_pressed(BUTTON_B)) - sp2C = BS_CLAW; + sp2C = BS_6_CLAW; if(bakey_pressed(BUTTON_A)) sp2C = bs_getTypeOfJump(); diff --git a/src/core2/bs/walk.c b/src/core2/bs/walk.c index c55574ad3..e2540c5ee 100644 --- a/src/core2/bs/walk.c +++ b/src/core2/bs/walk.c @@ -4,6 +4,7 @@ #include "animation.h" #include "core2/ba/anim.h" #include "core2/ba/physics.h" +#include "core2/yaw.h" void baanim_setDurationRange(f32, f32); void func_802927E0(f32, f32); @@ -96,10 +97,10 @@ s32 func_802B6F20(s32 arg0){ if(bakey_pressed(BUTTON_B)){ if( bsWalkWalkFastWalkVelocityThreshold < baphysics_get_target_horizontal_velocity()){ if(can_roll()) - arg0 = BS_ROLL; + arg0 = BS_31_ROLL; }else{//L802B6F74 if(can_claw()) - arg0 = BS_CLAW; + arg0 = BS_6_CLAW; } } return arg0; @@ -128,7 +129,7 @@ void bswalk_creep_init(void){ anctrl_setStart(anim_ctrl, start_position); anctrl_setPlaybackType(anim_ctrl, ANIMCTRL_LOOP); anctrl_start(anim_ctrl, "bswalk.c", 0xe4); - func_8029C7F4(BAANIM_UPDATE_2_SCALE_HORZ,1,1, BA_PHYSICS_NORMAL); + code_14420_setUpdateTypes(BAANIM_UPDATE_2_SCALE_HORZ, YAW_STATE_1_DEFAULT, 1, BA_PHYSICS_NORMAL); baanim_setDurationRange(0.3f, 1.5f); baanim_setVelocityMapRanges(bsWalkMinCreepVelocity, bsWalkCreepSlowWalkVelocityThreshold, bsWalkSlowestCreepDuration, bsWalkFastestCreepDuration); } @@ -152,14 +153,14 @@ void bswalk_creep_update(void){ next_state = BS_2_WALK_SLOW; break; case 3://L802B7188 - next_state = BS_WALK; + next_state = BS_3_WALK; break; case 4: next_state = BS_4_WALK_FAST; break; }//L802B7194 if(player_isOnDangerousGround()) - next_state = BS_WALK_MUD; + next_state = BS_7A_WALK_MUD; if(bainput_should_look_first_person_camera()) next_state = badrone_look(); @@ -168,7 +169,7 @@ void bswalk_creep_update(void){ next_state = BS_2F_FALL; if(bakey_held(BUTTON_Z)) - next_state = BS_CROUCH; + next_state = BS_7_CROUCH; next_state = func_802B6F20(next_state); @@ -176,7 +177,7 @@ void bswalk_creep_update(void){ next_state = bs_getTypeOfJump(); if(player_isSliding()) - next_state = BS_SLIDE; + next_state = BS_32_SLIDE; next_state = func_8029CA94(next_state); @@ -201,7 +202,7 @@ void bswalk_slow_init(void){ anctrl_setStart(anim_ctrl, start_position); anctrl_setPlaybackType(anim_ctrl, ANIMCTRL_LOOP); anctrl_start(anim_ctrl, "bswalk.c", 0x168); - func_8029C7F4(BAANIM_UPDATE_2_SCALE_HORZ,1,1, BA_PHYSICS_NORMAL); + code_14420_setUpdateTypes(BAANIM_UPDATE_2_SCALE_HORZ, YAW_STATE_1_DEFAULT, 1, BA_PHYSICS_NORMAL); baanim_setDurationRange(0.3f, 1.5f); baanim_setVelocityMapRanges(bsWalkCreepSlowWalkVelocityThreshold, bsWalkSlowWalkWalkVelocityThreshold, bsWalkSlowestSlowWalkDuration, bsWalkFastestSlowWalkDuration); } @@ -222,17 +223,17 @@ void bswalk_slow_upate(void){ next_state = BS_1_IDLE; break; case 1://L802B7180 - next_state = BS_WALK_CREEP; + next_state = BS_1F_WALK_CREEP; break; case 3://L802B7188 - next_state = BS_WALK; + next_state = BS_3_WALK; break; case 4: next_state = BS_4_WALK_FAST; break; }//L802B7194 if(player_isOnDangerousGround()) - next_state = BS_WALK_MUD; + next_state = BS_7A_WALK_MUD; if(bainput_should_look_first_person_camera()) next_state = badrone_look(); @@ -241,7 +242,7 @@ void bswalk_slow_upate(void){ next_state = BS_2F_FALL; if(bakey_held(BUTTON_Z)) - next_state = BS_CROUCH; + next_state = BS_7_CROUCH; next_state = func_802B6F20(next_state); @@ -249,7 +250,7 @@ void bswalk_slow_upate(void){ next_state = bs_getTypeOfJump(); if(player_isSliding()) - next_state = BS_SLIDE; + next_state = BS_32_SLIDE; next_state = func_8029CA94(next_state); @@ -279,7 +280,7 @@ void bswalk_init(void){ anctrl_setStart(anim_ctrl, start_position); anctrl_setPlaybackType(anim_ctrl, ANIMCTRL_LOOP); anctrl_start(anim_ctrl, "bswalk.c", 0x1ed); - func_8029C7F4(BAANIM_UPDATE_2_SCALE_HORZ,1,1, BA_PHYSICS_NORMAL); + code_14420_setUpdateTypes(BAANIM_UPDATE_2_SCALE_HORZ, YAW_STATE_1_DEFAULT, 1, BA_PHYSICS_NORMAL); baanim_setDurationRange(0.3f, 1.5f); baanim_setVelocityMapRanges(bsWalkSlowWalkWalkVelocityThreshold, bsWalkWalkFastWalkVelocityThreshold, bsWalkSlowestWalkDuration, bsWalkFastestWalkDuration); func_802B6EB0(0.3f); @@ -304,10 +305,10 @@ void bswalk_update(void){ break; }//L802B76B8 if(player_isOnDangerousGround()) - next_state = BS_WALK_MUD; + next_state = BS_7A_WALK_MUD; if(func_8028B4C4() && bsWalkSkidVelocity < baphysics_get_horizontal_velocity()){ - next_state = BS_SKID; + next_state = BS_C_SKID; } if(bainput_should_look_first_person_camera()) @@ -317,7 +318,7 @@ void bswalk_update(void){ next_state = BS_2F_FALL; if(bakey_held(BUTTON_Z)) - next_state = BS_CROUCH; + next_state = BS_7_CROUCH; next_state = func_802B6F20(next_state); @@ -325,7 +326,7 @@ void bswalk_update(void){ next_state = bs_getTypeOfJump(); if(player_isSliding()) - next_state = BS_SLIDE; + next_state = BS_32_SLIDE; next_state = func_8029CA94(next_state); @@ -363,7 +364,7 @@ void bswalk_fast_init(void){ anctrl_setStart(anim_ctrl, sp28); anctrl_setPlaybackType(anim_ctrl, ANIMCTRL_LOOP); anctrl_start(anim_ctrl, "bswalk.c", 0x27d); - func_8029C7F4(BAANIM_UPDATE_2_SCALE_HORZ,1,1, BA_PHYSICS_NORMAL); + code_14420_setUpdateTypes(BAANIM_UPDATE_2_SCALE_HORZ, YAW_STATE_1_DEFAULT, 1, BA_PHYSICS_NORMAL); baanim_setDurationRange(0.3f, 1.5f); baanim_setVelocityMapRanges(bsWalkWalkFastWalkVelocityThreshold, bsWalkMaxFastWalkVelocity, bsWalkSlowestFastWalkDuration, bsWalkFastestFastWalkDuration); pitch_setAngVel(1000.0f, 12.0f); @@ -400,24 +401,24 @@ void bswalk_fast_update(void){ break; case 3://L802B7A60 if(baphysics_is_slower_than(bsWalkWalkFastWalkVelocityThreshold) && func_802B6EF4()) - next_state = BS_WALK; + next_state = BS_3_WALK; if(bainput_should_look_first_person_camera()) next_state = badrone_look(); break; }//L802B7AA4 if(player_isOnDangerousGround()) - next_state = BS_WALK_MUD; + next_state = BS_7A_WALK_MUD; if(func_8028B4C4() && bsWalkSkidVelocity < baphysics_get_horizontal_velocity()){ - next_state = BS_SKID; + next_state = BS_C_SKID; } if(player_shouldFall()) next_state = BS_2F_FALL; if(bakey_held(BUTTON_Z)) - next_state = BS_CROUCH; + next_state = BS_7_CROUCH; next_state = func_802B6F20(next_state); @@ -425,7 +426,7 @@ void bswalk_fast_update(void){ next_state = bs_getTypeOfJump(); if(player_isSliding()) - next_state = BS_SLIDE; + next_state = BS_32_SLIDE; next_state = func_8029CA94(next_state); @@ -442,7 +443,7 @@ void bswalk_fast_end(void){ void bswalk_mud_init(void){ baanim_playForDuration_loopSmooth(ASSET_B_ANIM_BSWALK_MUD, 0.43f); - func_8029C7F4(BAANIM_UPDATE_2_SCALE_HORZ,1,1, BA_PHYSICS_NORMAL); + code_14420_setUpdateTypes(BAANIM_UPDATE_2_SCALE_HORZ, YAW_STATE_1_DEFAULT, 1, BA_PHYSICS_NORMAL); baanim_setDurationRange(0.3f, 1.5f); baanim_setVelocityMapRanges(bsWalkMinMudVelocity, bsWalkMaxMudVelocity, bsWalkSlowestMudDuration, bsWalkFastestMudDuration); } @@ -466,7 +467,7 @@ void bswalk_mud_update(void){ next_state = BS_2F_FALL; if(bakey_held(BUTTON_Z)) - next_state = BS_CROUCH; + next_state = BS_7_CROUCH; next_state = func_802B6F20(next_state); @@ -474,7 +475,7 @@ void bswalk_mud_update(void){ next_state = bs_getTypeOfJump(); if(player_isSliding()) - next_state = BS_SLIDE; + next_state = BS_32_SLIDE; next_state = func_8029CA94(next_state); diff --git a/src/core2/bs/walrus.c b/src/core2/bs/walrus.c index 952203c40..cd53cfb7b 100644 --- a/src/core2/bs/walrus.c +++ b/src/core2/bs/walrus.c @@ -4,6 +4,7 @@ #include "core2/ba/anim.h" #include "core2/ba/physics.h" #include "core2/ba/timer.h" +#include "core2/yaw.h" extern void func_8029AD68(f32, s32); @@ -93,8 +94,8 @@ void func_802B8048(void){ pitch_setIdeal(0.0f); roll_setIdeal(0.0f); bastick_resetZones(); - func_8029E070(0); - func_8029E064(0); + modelAppendages_setKazooiesUpperHalfVisibility(false); + modelAppendages_setKazooiesFeetAndShoesVisibility(false); baflag_clear(BA_FLAG_3); baflag_clear(BA_FLAG_4); func_80293D74(); @@ -105,7 +106,7 @@ void func_802B8048(void){ void func_802B80D0(void) { if (bswalrus_inSledSet(bs_getNextState()) == 0) { func_802B8048(); - func_8029E0E8(0); + modelAppendages_setSledVisibility(false); } } @@ -116,7 +117,7 @@ void func_802B8110(void){ void func_802B813C(void) { if (!bswalrus_inSledSet(bs_getPrevState())) { D_8037D5C0 = 0.0f; - func_8029E0E8(1); + modelAppendages_setSledVisibility(true); func_8029CF48(4, 1, 0.15f); } } @@ -132,18 +133,18 @@ int bswalrus_inSledSet(enum bs_e state){ int bswalrus_inSet(enum bs_e state){ return state == BS_67_WALRUS_IDLE - || state == BS_WALRUS_WALK - || state == BS_WALRUS_JUMP + || state == BS_68_WALRUS_WALK + || state == BS_69_WALRUS_JUMP || state == BS_6A_WALRUS_FALL - || state == BS_WALRUS_OW - || state == BS_WALRUS_DIE + || state == BS_6C_WALRUS_OW + || state == BS_6D_WALRUS_DIE || state == BS_95_WALRUS_DRONE || bswalrus_inSledSet(state); } void bswalrus_idle_init(void){ baanim_playForDuration_loopSmooth(ASSET_11F_ANIM_BSWALRUS_IDLE, 4.0f); - func_8029C7F4(1,1,1, BA_PHYSICS_NORMAL); + code_14420_setUpdateTypes(1, YAW_STATE_1_DEFAULT, 1, BA_PHYSICS_NORMAL); baphysics_set_target_horizontal_velocity(0.0f); pitch_setAngVel(1000.0f, 12.0f); roll_setAngularVelocity(1000.0f, 12.0f); @@ -166,10 +167,10 @@ void bswalrus_idle_update(void){ next_state = badrone_look(); if(bastick_getZone() > 0) - next_state = BS_WALRUS_WALK; + next_state = BS_68_WALRUS_WALK; if(bakey_pressed(BUTTON_A)) - next_state = BS_WALRUS_JUMP; + next_state = BS_69_WALRUS_JUMP; bs_setState(next_state); } @@ -181,7 +182,7 @@ void bswalrus_idle_end(void){ void bswalrus_walk_init(void){ baanim_playForDuration_loopSmooth(ASSET_120_ANIM_BSWALRUS_WALK, 0.8f); - func_8029C7F4(BAANIM_UPDATE_2_SCALE_HORZ,1,1, BA_PHYSICS_NORMAL); + code_14420_setUpdateTypes(BAANIM_UPDATE_2_SCALE_HORZ, YAW_STATE_1_DEFAULT, 1, BA_PHYSICS_NORMAL); baanim_setVelocityMapRanges(D_80364DC0, D_80364DC4, D_80364DC8, D_80364DCC); func_802900B4(); func_802B8110(); @@ -201,7 +202,7 @@ void bswalrus_walk_update(void){ next_state = BS_6A_WALRUS_FALL; if(bakey_pressed(BUTTON_A)) - next_state = BS_WALRUS_JUMP; + next_state = BS_69_WALRUS_JUMP; bs_setState(next_state); } @@ -222,7 +223,7 @@ void bswalrus_jump_init(void){ anctrl_setStart(aCtrl, 0.1); anctrl_setPlaybackType(aCtrl, ANIMCTRL_ONCE); anctrl_start(aCtrl, "bswalrus.c", 0x1f8); - func_8029C7F4(1,1,3, BA_PHYSICS_AIRBORN); + code_14420_setUpdateTypes(1, YAW_STATE_1_DEFAULT, 3, BA_PHYSICS_AIRBORN); if(bastick_distance() != 0.0f) yaw_setIdeal(bastick_getAngleRelativeToBanjo()); baphysics_set_target_yaw(yaw_getIdeal()); @@ -289,10 +290,10 @@ void bswalrus_jump_update(void){ if(player_isStable()){ if(bastick_getZone() > 0) - next_state = BS_WALRUS_WALK; + next_state = BS_68_WALRUS_WALK; if(bakey_pressed(BUTTON_A)) - next_state = BS_WALRUS_JUMP; + next_state = BS_69_WALRUS_JUMP; } bs_setState(next_state); @@ -311,7 +312,7 @@ void bswalrus_fall_init(void){ anctrl_setDuration(aCtrl, 0.7f); anctrl_setPlaybackType(aCtrl, ANIMCTRL_STOPPED); anctrl_start(aCtrl, "bswalrus.c", 0x284); - func_8029C7F4(1,1,3, BA_PHYSICS_AIRBORN); + code_14420_setUpdateTypes(1, YAW_STATE_1_DEFAULT, 3, BA_PHYSICS_AIRBORN); func_802B8110(); D_8037D5C8 = 0; } @@ -372,13 +373,13 @@ static void __bswalrus_recoil_init(s32 damage){ f32 sp24[3]; barebound_set_active(func_80296560()); - baanim_playForDuration_onceSmooth(0x19c, 1.0f); + baanim_playForDuration_onceSmooth(ASSET_19C_ANIM_BSWALRUS_BOUNCE, 1.0f); if(damage == 1) func_8030E58C(SFX_38_BANJO_AYE_1, 1.8f); else func_8030E58C(SFX_56_BANJO_HUI, 1.8f); - _player_getPosition(sp30); + playerPosition_get(sp30); func_80294980(sp24); func_80257F18(sp24, sp30, &sp3C); yaw_setIdeal(mlNormalizeAngle(sp3C + 180.0f)); @@ -386,7 +387,7 @@ static void __bswalrus_recoil_init(s32 damage){ baphysics_set_target_horizontal_velocity(barebound_get_horizontal_velocity()); baphysics_set_target_yaw(sp3C); baphysics_set_horizontal_velocity(sp3C, baphysics_get_target_horizontal_velocity()); - func_8029C7F4(1,1,2, BA_PHYSICS_LOCKED_ROTATION); + code_14420_setUpdateTypes(1, YAW_STATE_1_DEFAULT, 2, BA_PHYSICS_LOCKED_ROTATION); baphysics_set_vertical_velocity(barebound_get_vertical_velocity()); baphysics_set_gravity(barebound_get_gravity()); baMarker_collisionOff(); @@ -451,7 +452,7 @@ void bswalrus_die_init(void){ anctrl_setPlaybackType(aCtrl, ANIMCTRL_ONCE); anctrl_start(aCtrl, "bswalrus.c", 0x366); func_8030E58C(SFX_36_BANJO_DOH, 1.8f); - _player_getPosition(sp2C); + playerPosition_get(sp2C); func_80294980(sp20); func_80257F18(sp20, sp2C, &sp38); D_8037D5C4 = 250.0f; @@ -460,12 +461,12 @@ void bswalrus_die_init(void){ baphysics_set_target_horizontal_velocity(D_8037D5C4); baphysics_set_target_yaw(sp38); baphysics_set_horizontal_velocity(sp38, baphysics_get_target_horizontal_velocity()); - func_8029C7F4(1,1,2, BA_PHYSICS_LOCKED_ROTATION); + code_14420_setUpdateTypes(1, YAW_STATE_1_DEFAULT, 2, BA_PHYSICS_LOCKED_ROTATION); baphysics_set_vertical_velocity(420.0f); //B) baphysics_set_gravity(-1200.0f); pitch_setAngVel(1000.0f, 12.0f); func_802914CC(0xd); - ncDynamicCamD_func_802BF2C0(30.0f); + ncbadie_func_802BF2C0(30.0f); func_8025AB00(); func_8025A2FC(0, 0xfa0); comusic_playTrack(0x1A); @@ -530,16 +531,16 @@ void bswalrus_drone_end(void){ func_802B8048(); } -void func_802B90D0(void){ +void bswalrus_sledlocked_init(void){ baanim_playForDuration_loopSmooth(ASSET_19E_ANIM_BSWALRUS_SLED, 0.8f); - func_8029C7F4(1,1,3, BA_PHYSICS_NORMAL); + code_14420_setUpdateTypes(1, YAW_STATE_1_DEFAULT, 3, BA_PHYSICS_NORMAL); baphysics_set_target_horizontal_velocity(0.0f); func_8029C674(); func_802B813C(); func_802B3A50(); } -void func_802B9130(void){ +void bswalrus_sledlocked_update(void){ enum bs_e next_state = 0; func_802B3A50(); func_80299628(0); @@ -550,14 +551,14 @@ void func_802B9130(void){ bs_setState(next_state); } -void func_802B917C(void){ +void bswalrus_sledlocked_end(void){ func_8029C748(); func_802B80D0(); } void bswalrus_sled_init(void){ baanim_playForDuration_loopSmooth(ASSET_19E_ANIM_BSWALRUS_SLED, 0.8f); - func_8029C7F4(BAANIM_UPDATE_2_SCALE_HORZ,1,1, BA_PHYSICS_NORMAL); + code_14420_setUpdateTypes(BAANIM_UPDATE_2_SCALE_HORZ, YAW_STATE_1_DEFAULT, 1, BA_PHYSICS_NORMAL); baanim_setVelocityMapRanges(D_80364DC0, D_80364DC4, D_80364DE0, D_80364DE4); func_802900B4(); func_802B813C(); @@ -603,7 +604,7 @@ void bswalrus_sled_jump_init(void){ anctrl_setStart(aCtrl, 0.14f); anctrl_setPlaybackType(aCtrl, ANIMCTRL_ONCE); anctrl_start(aCtrl, "bswalrus.c", 0x477); - func_8029C7F4(1,1,3, BA_PHYSICS_AIRBORN); + code_14420_setUpdateTypes(1, YAW_STATE_1_DEFAULT, 3, BA_PHYSICS_AIRBORN); if(bastick_distance() != 0.0f) yaw_setIdeal(bastick_getAngleRelativeToBanjo()); baphysics_set_target_yaw(yaw_getIdeal()); @@ -663,7 +664,7 @@ void bswalrus_sled_jump_end(void){ func_802B80D0(); } -void func_802B95A0(void){ +void bswalrus_sledloseinair_init(void){ AnimCtrl *aCtrl = baanim_getAnimCtrlPtr(); anctrl_reset(aCtrl); anctrl_setIndex(aCtrl, ASSET_19F_ANIM_BSWALRUS_SLED_JUMP); @@ -671,12 +672,12 @@ void func_802B95A0(void){ anctrl_setDuration(aCtrl, 1.0f); anctrl_setPlaybackType(aCtrl, ANIMCTRL_STOPPED); anctrl_start(aCtrl, "bswalrus.c", 0x4e2); - func_8029C7F4(1,1,3, BA_PHYSICS_AIRBORN); + code_14420_setUpdateTypes(1, YAW_STATE_1_DEFAULT, 3, BA_PHYSICS_AIRBORN); func_802B813C(); D_8037D5C8 = 0; } -void func_802B963C(void){ +void bswalrus_sledloseinair_update(void){ enum bs_e next_state = 0; AnimCtrl *aCtrl = baanim_getAnimCtrlPtr(); f32 sp1C[3]; @@ -720,16 +721,16 @@ void func_802B963C(void){ bs_setState(next_state); } -void func_802B976C(void){ +void bswalrus_sledloseinair_end(void){ func_802B8048(); } void bswalrus_timeout_init(void) { baanim_playForDuration_once(ASSET_1A9_ANIM_BSWALRUS_LOSS, 3.2f); - func_8029C7F4(1, 1, 3, BA_PHYSICS_FREEZE); + code_14420_setUpdateTypes(1, YAW_STATE_1_DEFAULT, 3, BA_PHYSICS_FREEZE); baphysics_set_target_horizontal_velocity(0.0f); func_802914CC(0xD); - ncDynamicCamD_func_802BF2C0(60.0f); + ncbadie_func_802BF2C0(60.0f); func_8025A58C(0, 4000); comusic_playTrack(COMUSIC_3C_MINIGAME_LOSS); core1_ce60_incOrDecCounter(false); @@ -739,7 +740,7 @@ void bswalrus_timeout_init(void) { baeyes_close(); } -void func_802B9830(void) { +void bswalrus_timeout_update(void) { yaw_setIdeal(func_8029B41C() + 35.0f); func_80299628(0); if (batimer_decrement(0) != 0) { @@ -747,7 +748,7 @@ void func_802B9830(void) { } } -void func_802B9880(void) { +void bswalrus_timeout_end(void) { func_80291548(); core1_ce60_incOrDecCounter(true); func_8025A904(); diff --git a/src/core2/bs/washing_machine.c b/src/core2/bs/washy.c similarity index 92% rename from src/core2/bs/washing_machine.c rename to src/core2/bs/washy.c index aa08904df..9efa5bf21 100644 --- a/src/core2/bs/washing_machine.c +++ b/src/core2/bs/washy.c @@ -1,9 +1,11 @@ +// BanjoDecomp: core2/bs/washy.c #include #include "functions.h" #include "variables.h" #include "core2/ba/physics.h" #include "core2/ba/timer.h" +#include "core2/yaw.h" /* .bss */ u8 D_8037D5D0; @@ -42,18 +44,18 @@ void func_802B9980(s32 arg0){ D_8037D5D0 = arg0; } -void func_802B9AAC(void){ +void bswashy_end(void){ func_802900FC(); } -void func_802B9ACC(void){ +void bswashy_init(void){ baanim_playForDuration_once(ASSET_281_ANIM_WISHYWASHY_DOOOH, 40.0f); - func_8029C7F4(1, 1, 3, BA_PHYSICS_NORMAL); + code_14420_setUpdateTypes(1, YAW_STATE_1_DEFAULT, 3, BA_PHYSICS_NORMAL); func_802900B4(); func_802B9980(0); } -void func_802B9B14(void){ +void bswashy_update(void){ s32 next_state = 0; s32 sp18; diff --git a/src/core2/bundle.c b/src/core2/bundle.c index c162b7d1a..ce710eb32 100644 --- a/src/core2/bundle.c +++ b/src/core2/bundle.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_41FB0.c #include "functions.h" #include "variables.h" #include diff --git a/src/core2/camera/dynamicCam1.c b/src/core2/camera/dynamicCam1.c deleted file mode 100644 index fd28a665b..000000000 --- a/src/core2/camera/dynamicCam1.c +++ /dev/null @@ -1,46 +0,0 @@ -#include -#include "functions.h" -#include "variables.h" - -extern f32 func_802BD51C(void); -extern f32 player_getYaw(void); -extern void func_802BD870(f32, f32, f32, f32); - -void ncDynamicCam1_init(void){ - func_802BD870(12.0f, 10.0f, 120.0f, 120.0f); -} - -void ncDynamicCam1_end(void){} - -void ncDynamicCam1_update(void) { - f32 sp8C[3]; - f32 sp80[3]; - f32 sp74[3]; - f32 sp68[3]; - f32 sp5C[3]; - f32 sp50[3]; - f32 sp4C; - f32 sp48; - f32 temp_f20; - f32 sp40; - f32 sp3C; - - ncDynamicCamera_getPosition(sp74); - func_802BD4C0(sp8C); - sp3C = func_802BD8D4(); - temp_f20 = time_getDelta(); - ml_vec3f_diff_copy(sp50, sp74, sp8C); - sp4C = gu_sqrtf((sp50[0] * sp50[0]) + (sp50[2] * sp50[2])); - sp4C += func_80259198((sp3C - sp4C) * temp_f20 * 2, temp_f20 * 120.0f); - func_8025801C(sp50, &sp48); - sp40 = func_80259198(mlDiffDegF(mlNormalizeAngle(180.0f + player_getYaw()), sp48) * (temp_f20 * 1), temp_f20 * 50.0f); - sp48 = mlNormalizeAngle(sp48 + sp40); - func_80256E24(sp68, 0.0f, sp48, 0.0f, 0.0f, sp4C); - ml_vec3f_add(sp80, sp8C, sp68); - sp80[1] = sp74[1] + ((func_802BD51C() - sp74[1]) * temp_f20 * 2); - ncDynamicCamera_setPosition(sp80); - func_8025727C(sp8C[0], sp8C[1], sp8C[2], sp80[0], sp80[1], sp80[2], &sp5C[0], &sp5C[1]); - sp5C[0] = -sp5C[0]; - sp5C[2] = 0.0f; - func_802BD720(sp5C); -} diff --git a/src/core2/ch/beehive.c b/src/core2/ch/beehive.c index c54111705..4f4037470 100644 --- a/src/core2/ch/beehive.c +++ b/src/core2/ch/beehive.c @@ -34,8 +34,8 @@ void chBeehive_die(ActorMarker *this, ActorMarker *other){ __spawnQueue_add_4((GenFunction_4)spawnQueue_actor_f32, ACTOR_4C_STEAM, reinterpret_cast(s32, actor->position[0]), reinterpret_cast(s32, actor->position[1]), reinterpret_cast(s32, actor->position[2])); __spawnQueue_add_4((GenFunction_4)spawnQueue_actor_f32, ACTOR_4A_WOOD_EXPLOSION, reinterpret_cast(s32, actor->position[0]), reinterpret_cast(s32, actor->position[1]), reinterpret_cast(s32, actor->position[2])); actor->marker->propPtr->unk8_3 = 0; - func_803115C4(ASSET_D96_DIALOG_BEEHIVE_MEET); - func_803115C4(ASSET_DA6_DIALOG_BEEHIVE_WITH_BEES); + func_803115C4(VER_SELECT(ASSET_D96_DIALOG_BEEHIVE_MEET, 0x0A14, 0, 0)); + func_803115C4(VER_SELECT(ASSET_DA6_DIALOG_BEEHIVE_WITH_BEES, 0x0A24, 0, 0)); } void chBeehive_update(Actor *this){ @@ -62,7 +62,7 @@ void chBeehive_update(Actor *this){ ){ if(player_movementGroup() == BSGROUP_0_NONE || player_movementGroup() == BSGROUP_8_TROT){ if( player_getTransformation() == TRANSFORM_1_BANJO - && gcdialog_showDialog(ASSET_D96_DIALOG_BEEHIVE_MEET, 0, NULL, NULL, NULL, 0) + && gcdialog_showDialog(VER_SELECT(ASSET_D96_DIALOG_BEEHIVE_MEET, 0xA14, 0, 0), 0, NULL, NULL, NULL, 0) ){ fileProgressFlag_set(FILEPROG_D_BEEHIVE_TEXT, 1); } diff --git a/src/core2/ch/beeswarm.c b/src/core2/ch/beeswarm.c index 40ccdb12b..a45d072ca 100644 --- a/src/core2/ch/beeswarm.c +++ b/src/core2/ch/beeswarm.c @@ -1,8 +1,6 @@ #include #include "functions.h" #include "variables.h" - -#include "core2/quiz_storage.h" #include "port/Interpolation/FrameInterpolation.h" extern void func_8030DBFC(u32, f32, f32, f32); @@ -39,7 +37,7 @@ Actor *chBeeSwarm_draw(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx); /* .data */ -ActorInfo D_80367310 = { +ActorInfo chBeeSwarm = { MARKER_217_BEE_SWARM, ACTOR_34D_BEE_SWARM, ASSET_49E_SPRITE_BEE_SWARM, 1, NULL, chBeeSwarm_update, NULL, chBeeSwarm_draw, @@ -225,7 +223,7 @@ void chBeeSwarm_802CF1C8(f32 arg0[3], f32 arg1[3], f32 arg2[3], f32 arg3, f32 ar } if (arg5 != 0) { sp3C[0] = sp3C[1] = sp3C[2] = 0.0f; - func_8025727C(arg2[0], arg2[1], arg2[2], sp3C[0], sp3C[1], sp3C[2], arg5, arg5 + 1); + ml_horizontal_and_vertical_angles(arg2[0], arg2[1], arg2[2], sp3C[0], sp3C[1], sp3C[2], arg5, arg5 + 1); } } @@ -451,7 +449,7 @@ void chBeeSwarm_update(Actor *this) { if (!fileProgressFlag_get(FILEPROG_8F_MET_BEE_INFESTED_BEEHIVE) && subaddie_playerIsWithinCylinder(this, 250, 300) && ((player_movementGroup() == BSGROUP_0_NONE) || (player_movementGroup() == BSGROUP_8_TROT)) && (player_getTransformation() == TRANSFORM_1_BANJO) - && (gcdialog_showDialog(0xDA6, 0, NULL, NULL, NULL, NULL) != 0) + && (gcdialog_showDialog(VER_SELECT(0xDA6, 0xA24, 0, 0), 0, NULL, NULL, NULL, NULL) != 0) ) { fileProgressFlag_set(FILEPROG_8F_MET_BEE_INFESTED_BEEHIVE, true); } diff --git a/src/core2/ch/bottlesbonus.c b/src/core2/ch/bottlesbonus.c index be20b6560..f24b279ee 100644 --- a/src/core2/ch/bottlesbonus.c +++ b/src/core2/ch/bottlesbonus.c @@ -51,20 +51,21 @@ typedef struct{ extern void actor_postdrawMethod(ActorMarker *); extern void viewport_setNearAndFar(f32, f32); -extern s16 *func_8030C704(void); +extern s16 *picturebox_getColorBuffer(void); + Actor *chBottlesBonus_draw(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx); void chBottlesBonus_update(Actor *this); /* .data */ Struct_core2_560F0_0 D_803681A0[] = { { 0, 0x000, 0, 0x211}, - {99, 0xE27, 0, 0x2C1}, - {99, 0xE29, 0, 0x2C2}, - {99, 0xE2B, 0, 0x2C9}, - {99, 0xE2D, 0, 0x2C3}, - {99, 0xE2F, 0, 0x2C4}, - {99, 0xE31, 0, 0x2C5}, - {75, 0xE34, 0, 0x007} + {99, VER_SELECT(0xE27, 0xA69, 0, 0), 0, 0x2C1}, + {99, VER_SELECT(0xE29, 0xA6B, 0, 0), 0, 0x2C2}, + {99, VER_SELECT(0xE2B, 0xA6D, 0, 0), 0, 0x2C9}, + {99, VER_SELECT(0xE2D, 0xA6F, 0, 0), 0, 0x2C3}, + {99, VER_SELECT(0xE2F, 0xA71, 0, 0), 0, 0x2C4}, + {99, VER_SELECT(0xE31, 0xA73, 0, 0), 0, 0x2C5}, + {75, VER_SELECT(0xE34, 0xA76, 0, 0), 0, 0x007} }; ActorAnimationInfo chBottlesBonusAnimations[] ={ @@ -157,7 +158,7 @@ Actor *chBottlesBonus_draw(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx) void *sp50; sp6C = marker_getActor(marker); - sp50 = func_8030C704(); //grabs frame as texture? + sp50 = picturebox_getColorBuffer(); //grabs frame as texture? if ((sp50 == NULL) || (getGameMode() != GAME_MODE_8_BOTTLES_BONUS)) return sp6C; @@ -171,9 +172,9 @@ Actor *chBottlesBonus_draw(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx) gDPSetTextureFilter((*gfx)++, G_TF_BILERP); gDPSetColorDither((*gfx)++, G_CD_DISABLE); func_802DF160(gfx, mtx, vtx); - func_80253190(gfx); - - gDPSetTextureFilter((*gfx)++, G_TF_BILERP); + depthbuffer_clear(gfx); + + gDPSetTextureFilter((*gfx)++, G_TF_POINT); gSPSegment((*gfx)++, 0x04, osVirtualToPhysical(sp50)); modelRender_setPreDrawCallback((model_render_pre_draw_callback_f)actor_predrawMethod, (void *)sp6C); modelRender_setPostDrawCallback((model_render_post_draw_callback_f)actor_postdrawMethod, (void *)marker); diff --git a/src/core2/ch/bottlesbonuscursor.c b/src/core2/ch/bottlesbonuscursor.c index 5e328b2c0..4b37d33a9 100644 --- a/src/core2/ch/bottlesbonuscursor.c +++ b/src/core2/ch/bottlesbonuscursor.c @@ -37,25 +37,25 @@ void chBottlesBonusCursor_func_802DF99C(void); void chBottlesBonusCursor_update(Actor *this); /* .data */ -ActorAnimationInfo D_803683B0[] = { +ActorAnimationInfo chBottlesBonusCursorAnimations[] = { {0x000, 0.0f}, - {0x2A2, 1.0f}, - {0x2A5, 1.0f}, - {0x2A4, 0.4f}, - {0x2A3, 0.4f}, - {0x2A1, 0.3f}, - {0x2A7, 0.4f}, - {0x2A1, 0.3f}, - {0x2A6, 2.6f}, - {0x2A8, 2.6f} + {ASSET_2A2_ANIM_BOTTLES_BONUS_CURSOR_UNKNOWN, 1.0f}, + {ASSET_2A5_ANIM_BOTTLES_BONUS_CURSOR_UNKNOWN, 1.0f}, + {ASSET_2A4_ANIM_BOTTLES_BONUS_CURSOR_UNKNOWN, 0.4f}, + {ASSET_2A3_ANIM_BOTTLES_BONUS_CURSOR_UNKNOWN, 0.4f}, + {ASSET_2A1_ANIM_BOTTLES_BONUS_CURSOR_UNKNOWN, 0.3f}, + {ASSET_2A7_ANIM_BOTTLES_BONUS_CURSOR_UNKNOWN, 0.4f}, + {ASSET_2A1_ANIM_BOTTLES_BONUS_CURSOR_UNKNOWN, 0.3f}, + {ASSET_2A6_ANIM_BOTTLES_BONUS_CURSOR_UNKNOWN, 2.6f}, + {ASSET_2A8_ANIM_BOTTLES_BONUS_CURSOR_UNKNOWN, 2.6f} }; f32 D_80368400[3] = {570.0f, 328.9f, -186.4f}; f32 D_8036840C[3] = {-11.28f, 3.92f, -52.96f}; -ActorInfo D_80368418 = { - 0x17A, 0x2B4, 0x565, - 0x1, D_803683B0, +ActorInfo chBottlesBonusCursor = { + MARKER_17A_BOTTLES_BONUS_BANJO_HAND, ACTOR_2B4_BOTTLES_BONUS_BANJO_HAND, ASSET_565_MODEL_BOTTLES_BONUS_BANJO_HAND, + 0x1, chBottlesBonusCursorAnimations, chBottlesBonusCursor_update, actor_update_func_80326224, func_80325340, 0, 0, 0.0f, 0 }; @@ -65,6 +65,7 @@ ActorMarker *chBottlesBonusCursorMarker; f32 D_8037E068[60][2]; Struct_core2_584D0_0 D_8037E248[20]; //puzzle pieces s32 D_8037E5B8; + struct { s32 unk0; u8 pad4[0xC]; @@ -76,6 +77,7 @@ struct { f32 unk28; f32 unk2C; } D_8037E5C0; + f32 D_8037E5F0; f32 D_8037E5F4; f32 D_8037E5F8[3]; @@ -152,7 +154,7 @@ void chBottlesBonusCursor_draw(Gfx **gfx, Mtx **mtx, Vtx **vtx) { actor_setOpacity(this, 0xB9); viewport_func_8024E030(this->position, D_8037E5C0.unk18); sp3C = (this->scale * 650.0f); - func_80253208(gfx, + depthbuffer_clearRegion(gfx, (s32)(D_8037E5C0.unk18[0] - sp3C/2), (s32)(D_8037E5C0.unk18[1] - sp3C/2), (s32)sp3C, (s32)sp3C, gFramebuffers[getActiveFramebuffer()] diff --git a/src/core2/ch/climb_base.c b/src/core2/ch/climbBase.c similarity index 95% rename from src/core2/ch/climb_base.c rename to src/core2/ch/climbBase.c index 5b3f87c66..a3e561bac 100644 --- a/src/core2/ch/climb_base.c +++ b/src/core2/ch/climbBase.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/ch/climbBase.c #include #include "functions.h" #include "variables.h" @@ -12,8 +13,8 @@ typedef struct { }ActorLocal_climbBase; /* .data */ -ActorInfo D_80367B20 = { - 0x35, 0x26, 0x0, +ActorInfo D_80367B20 = { + MARKER_35_CLIMB_BASE, ACTOR_26_CLIMB_BASE, 0x0, 0x1, NULL, func_802D77D4, actor_update_func_80326224, func_80325340, 0, 0, 0.0f, 0 diff --git a/src/core2/ch/clucker.c b/src/core2/ch/clucker.c index d3b77877a..3c3953bb7 100644 --- a/src/core2/ch/clucker.c +++ b/src/core2/ch/clucker.c @@ -2,7 +2,7 @@ #include "functions.h" #include "variables.h" -extern void func_8033A45C(s32, s32); +extern void modelRender_setAppendageVisibility(s32, s32); typedef struct{ u8 unk0; @@ -118,8 +118,8 @@ void chClucker_die(ActorMarker *this_marker, ActorMarker *other_marker){ Actor *chClucker_draw(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx){ Actor *this = marker_getActor(marker); - func_8033A45C(3, (this->state == 5)? 1 : 0); - func_8033A45C(4, (this->state == 0 || this->state == 1 || this->state == 6)? 0 : 1); + modelRender_setAppendageVisibility(3, (this->state == 5)? 1 : 0); + modelRender_setAppendageVisibility(4, (this->state == 0 || this->state == 1 || this->state == 6)? 0 : 1); return actor_draw(marker, gfx, mtx, vtx); } diff --git a/src/core2/ch/collectible.c b/src/core2/ch/collectible.c index 9d6aafa1f..f31cf7f09 100644 --- a/src/core2/ch/collectible.c +++ b/src/core2/ch/collectible.c @@ -10,21 +10,21 @@ Actor *chCollectible_draw(ActorMarker *this, Gfx **gdl, Mtx **mptr, Vtx **arg3); void chCollectible_update(Actor *this); /* .data */ -extern ActorInfo D_80367D00 = { +extern ActorInfo chBlueEgg = { MARKER_60_BLUE_EGG_COLLECTIBLE, ACTOR_52_BLUE_EGG, ASSET_36D_SPRITE_BLUE_EGG, 0, NULL, chCollectible_update, actor_update_func_80326224, chCollectible_draw, 0, 0, 0.7f, 0 }; -extern ActorInfo D_80367D24 = { +extern ActorInfo chRedFeather = { MARKER_B5_RED_FEATHER_COLLECTIBLE, ACTOR_129_RED_FEATHER, ASSET_580_SPRITE_RED_FEATHER, 0, NULL, chCollectible_update, actor_update_func_80326224, chCollectible_draw, 0, 0, 0.5f, 0 }; -extern ActorInfo D_80367D48 = { +extern ActorInfo chGoldFeather = { MARKER_1E5_GOLD_FEATHER_COLLECTIBLE, ACTOR_370_GOLD_FEATHER, ASSET_6D1_SPRITE_GOLDFEATHER, 0, NULL, chCollectible_update, actor_update_func_80326224, chCollectible_draw, @@ -99,7 +99,7 @@ s32 chCollectible_collectEgg(ActorProp *arg0){ if(arg0->isActorProp) actPtr = marker_getActor(arg0->marker); } - return chCollectible_collectItem(actPtr, FILEPROG_5_BLUE_EGG_TEXT, 0xD9E, COMUSIC_C_EGG_COLLECTED, 0xD, 2.0f); + chCollectible_collectItem(actPtr, FILEPROG_5_BLUE_EGG_TEXT, VER_SELECT(0xD9E, 0xA1C, 0, 0), COMUSIC_C_EGG_COLLECTED, 0xD, 2.0f); } bool chCollectible_collectRedFeather(ActorProp *arg0){ @@ -107,7 +107,7 @@ bool chCollectible_collectRedFeather(ActorProp *arg0){ fxSparkle_redFeather(&arg0->x); if(arg0->isActorProp) actPtr = marker_getActor(arg0->marker); - return chCollectible_collectItem(actPtr, FILEPROG_6_RED_FEATHER_TEXT, 0xD9F, COMUSIC_B_RED_FEATHER_COLLECTED, 0xF, 4.0f); + chCollectible_collectItem(actPtr, FILEPROG_6_RED_FEATHER_TEXT, VER_SELECT(0xD9F, 0xA1D, 0, 0), COMUSIC_B_RED_FEATHER_COLLECTED, 0xF, 4.0f); } bool chCollectible_collectGoldFeather(ActorProp *arg0){ @@ -115,7 +115,7 @@ bool chCollectible_collectGoldFeather(ActorProp *arg0){ fxSparkle_goldFeather(&arg0->x); if(arg0->isActorProp) actPtr = marker_getActor(arg0->marker); - return chCollectible_collectItem(actPtr, FILEPROG_7_GOLD_FEATHER_TEXT, 0xDA0, COMUSIC_14_GOLD_FEATHER_COLLECTED, ITEM_10_GOLD_FEATHER, 6.0f); + chCollectible_collectItem(actPtr, FILEPROG_7_GOLD_FEATHER_TEXT, VER_SELECT(0xDA0, 0xA1E, 0, 0), COMUSIC_14_GOLD_FEATHER_COLLECTED, ITEM_10_GOLD_FEATHER, 6.0f); } Actor *chCollectible_draw(ActorMarker *this, Gfx **gdl, Mtx **mptr, Vtx **arg3){ diff --git a/src/core2/ch/crab.c b/src/core2/ch/crab.c index a2193fdfe..6e253cb25 100644 --- a/src/core2/ch/crab.c +++ b/src/core2/ch/crab.c @@ -1,32 +1,47 @@ +// BanjoDecomp: core2/ch/crab.c #include #include "functions.h" #include "variables.h" /* .data */ + +enum crab_states +{ + CRAB_STATE_1_IDLE_UNK = 1, + CRAB_STATE_2_IDLE_UNK, + CRAB_STATE_3_TURN_TO_PLAYER, + CRAB_STATE_4_CHASE_PLAYER, + CRAB_STATE_5_UPSIDE_DOWN, + CRAB_STATE_6_FLIP_UPSIDE_DOWN, + CRAB_STATE_7_FLIP_UPRIGHT, + CRAB_STATE_8_MUTIES_FIRST_DIALOG, + CRAB_STATE_9_MUTIES_REVISIT +}; + ActorAnimationInfo chCrabAnimations[] ={ { 0, 0.0f}, - { ASSET_1DA_ANIM_CRAB_IDLE, 0.8f}, - { ASSET_2C_ANIM_CRAB_WALK, 2.0f}, - { ASSET_2C_ANIM_CRAB_WALK, 1.4f}, - { ASSET_2C_ANIM_CRAB_WALK, 0.7f}, - { ASSET_96_ANIM_CRAB_UPSIDEDOWN, 0.5f}, + { ASSET_1DA_ANIM_CRAB_IDLE, 0.8f}, + { ASSET_2C_ANIM_CRAB_WALK, 2.0f}, + { ASSET_2C_ANIM_CRAB_WALK, 1.4f}, + { ASSET_2C_ANIM_CRAB_WALK, 0.7f}, + { ASSET_96_ANIM_CRAB_UPSIDEDOWN, 0.5f}, { ASSET_97_ANIM_CRAB_FLIP_UPSIDEDOWN, 0.8f}, - { ASSET_155_ANIM_CRAB_FLIP_UPRIGHT, 0.55f}, - { ASSET_2C_ANIM_CRAB_WALK, 1.4f}, - { ASSET_2C_ANIM_CRAB_WALK, 4.0f} + { ASSET_155_ANIM_CRAB_FLIP_UPRIGHT, 0.55f}, + { ASSET_2C_ANIM_CRAB_WALK, 1.4f}, + { ASSET_2C_ANIM_CRAB_WALK, 4.0f} }; ActorAnimationInfo chCrabMutantAnimations[] = { {0x000, 0.0f}, - {ASSET_1DB_ANIM_MUTANT_CRAB_IDLE, 0.8f}, - {ASSET_156_ANIM_MUTANT_CRAB_WALK, 2.0f}, - {ASSET_156_ANIM_MUTANT_CRAB_WALK, 1.4f}, - {ASSET_156_ANIM_MUTANT_CRAB_WALK, 0.7f}, - {ASSET_158_ANIM_MUTANT_CRAB_UPSIDEDOWN, 0.5f}, + {ASSET_1DB_ANIM_MUTANT_CRAB_IDLE, 0.8f}, + {ASSET_156_ANIM_MUTANT_CRAB_WALK, 2.0f}, + {ASSET_156_ANIM_MUTANT_CRAB_WALK, 1.4f}, + {ASSET_156_ANIM_MUTANT_CRAB_WALK, 0.7f}, + {ASSET_158_ANIM_MUTANT_CRAB_UPSIDEDOWN, 0.5f}, {ASSET_157_ANIM_MUTANT_CRAB_FLIP_UPSIDEDOWN, 0.8f}, - {ASSET_159_ANIM_MUTANT_CRAB_UPRIGHT, 0.55f}, - {ASSET_156_ANIM_MUTANT_CRAB_WALK, 1.4f}, - {ASSET_156_ANIM_MUTANT_CRAB_WALK, 2.0f} + {ASSET_159_ANIM_MUTANT_CRAB_UPRIGHT, 0.55f}, + {ASSET_156_ANIM_MUTANT_CRAB_WALK, 1.4f}, + {ASSET_156_ANIM_MUTANT_CRAB_WALK, 2.0f} }; /* .code */ @@ -44,18 +59,18 @@ void __chCrab_802CB078(Actor *this) { return; } else{ - if( subaddie_playerIsWithinSphereAndActive(this, 1500) + if( subaddie_playerIsWithinSphereAndActive(this, 1500) && ( (this->modelCacheIndex == ACTOR_F2_BLACK_SNIPPET) || func_803292E0(this)) ) { this->actor_specific_1_f = 0.0f; - subaddie_set_state(this, 3U); + subaddie_set_state(this, CRAB_STATE_3_TURN_TO_PLAYER); } } } } void __chCrab_802CB140(Actor *this) { - subaddie_set_state(this, 2U); + subaddie_set_state(this, CRAB_STATE_2_IDLE_UNK); __chCrab_802CB040(this); func_80328CEC(this, (s32) this->yaw_ideal, 135, 175); this->unk38_31 = 150; @@ -65,10 +80,10 @@ void __chCrab_touch(ActorMarker *marker, ActorMarker *other){ Actor *this; this = marker_getActor(marker); - if ((this->state == 4) && func_803294F0(this, 80, subaddie_getYawToPlayer(this))) { + if ((this->state == CRAB_STATE_4_CHASE_PLAYER) && func_803294F0(this, 80, subaddie_getYawToPlayer(this))) { sfx_playFadeShorthandDefault(SFX_1E_HITTING_AN_ENEMY_2, 1.0f, 28000, this->position, 950, 1900); __chCrab_802CB140(this); - subaddie_set_state(this, 1); + subaddie_set_state(this, CRAB_STATE_1_IDLE_UNK); } } @@ -77,7 +92,7 @@ void __chCrab_ow(ActorMarker *marker, ActorMarker *other) { this = marker_getActor(marker); this->lifetime_value = 3.0f; - subaddie_set_state(this, 6); + subaddie_set_state(this, CRAB_STATE_6_FLIP_UPSIDE_DOWN); actor_playAnimationOnce(this); if (marker->id == MARKER_13_SNIPPET) { sfx_playFadeShorthandDefault(SFX_6E_VILE_EGH, 2.0f, 26000, this->position, 950, 1900); @@ -142,7 +157,7 @@ void __chCrab_spawn_mutant_crab_jiggy(void) { } void __chCrab_mutantTextCallback(ActorMarker *caller, enum asset_e text_id, s32 model_id){ - if (text_id == ASSET_D33_DIALOG_MUTANT_CRAB_DEFEAT) { + if (text_id == VER_SELECT(ASSET_D33_DIALOG_MUTANT_CRAB_DEFEAT, 0xA06, 0, 0)) { func_80324E38(0.0f, 3); timed_setStaticCameraToNode(0.0f, 4); timedFunc_set_0(0.1f, __chCrab_spawn_mutant_crab_jiggy); @@ -150,17 +165,17 @@ void __chCrab_mutantTextCallback(ActorMarker *caller, enum asset_e text_id, s32 func_80324E38(3.0f, 0); return; } - levelSpecificFlags_set(LEVEL_FLAG_E_CC_MUTIE_SNIPPETS, false); + levelSpecificFlags_set(LEVEL_FLAG_E_CC_MUTIE_SNIPPETS, FALSE); } -s32 __chCrab_802CB76C(ActorMarker *marker, ActorMarker *other) { +bool __chCrab_802CB76C(ActorMarker *marker, ActorMarker *other) { Actor *this; this = marker_getActor(marker); if ((this->modelCacheIndex == ACTOR_F2_BLACK_SNIPPET) && !maCastle_hasBanjoKazooieCodeBeenEntered()) { - return false; + return FALSE; } - return true; + return TRUE; } void __chCrab_die(ActorMarker *marker, ActorMarker *other){ @@ -179,7 +194,7 @@ void __chCrab_die(ActorMarker *marker, ActorMarker *other){ sfx_playFadeShorthandDefault(SFX_79_TICKER_DEATH, 1.0f, 28000, this->position, 950, 1900); __spawnQueue_add_4((GenFunction_4)spawnQueue_actor_f32, ACTOR_4C_STEAM, reinterpret_cast(s32, this->position[0]), reinterpret_cast(s32, this->position[1]), reinterpret_cast(s32, this->position[2])); this->lifetime_value = 5.0f; - marker->collidable = false; + marker->collidable = FALSE; this->unk138_27 = 1; marker_despawn(marker); if( gsworld_getMap() == MAP_B_CC_CLANKERS_CAVERN @@ -192,7 +207,7 @@ void __chCrab_die(ActorMarker *marker, ActorMarker *other){ jiggy_spawn_position[1] = 3812.0f; jiggy_spawn_position[2] = 0.0f; coMusicPlayer_playMusic(COMUSIC_2D_PUZZLE_SOLVED_FANFARE, 0x7FFF); - func_80324DBC(2.25f, ASSET_D33_DIALOG_MUTANT_CRAB_DEFEAT, 0xF, jiggy_spawn_position, NULL, __chCrab_mutantTextCallback, NULL); + func_80324DBC(2.25f, VER_SELECT(ASSET_D33_DIALOG_MUTANT_CRAB_DEFEAT, 0xA06, 0, 0), 0xF, jiggy_spawn_position, NULL, __chCrab_mutantTextCallback, NULL); } } p_ctrl = partEmitMgr_newEmitter(2); @@ -235,10 +250,10 @@ void chCrab_update(Actor *this) { is_mutant_snippet = this->modelCacheIndex == ACTOR_F5_MUTIE_SNIPPET; if (!this->volatile_initialized) { marker_setCollisionScripts(this->marker, __chCrab_touch, __chCrab_ow, __chCrab_die); - func_803300C0(this->marker, &__chCrab_802CB76C); - this->unk124_0 = this->unk138_31 = false; - this->has_met_before = false; - this->volatile_initialized = true; + func_803300C0(this->marker, (s32 (*)(ActorMarker *, ActorMarker *)) &__chCrab_802CB76C); // [port] bool/s32 fn-ptr cast + this->unk124_0 = this->unk138_31 = FALSE; + this->has_met_before = FALSE; + this->volatile_initialized = TRUE; anctrl_setTransitionDuration(this->anctrl, 0.25f); if (gsworld_getMap() == MAP_A_TTC_SANDCASTLE) { if (!jiggyscore_isCollected(JIGGY_10_TTC_SANDCASTLE)) { @@ -267,11 +282,11 @@ void chCrab_update(Actor *this) { && subaddie_playerIsWithinSphereAndActive(this, 500) && !subaddie_playerIsWithinSphereAndActive(this, 200) && !player_movementGroup() ) { - if ((this->state != 6) && (this->state != 5)) { - gcdialog_showDialog(ASSET_D32_DIALOG_MUTANT_CRAB_MEET, 0xF, this->position, NULL, __chCrab_mutantTextCallback, NULL); - mapSpecificFlags_set(0, true); - levelSpecificFlags_set(LEVEL_FLAG_E_CC_MUTIE_SNIPPETS, true); - this->has_met_before = true; + if ((this->state != CRAB_STATE_6_FLIP_UPSIDE_DOWN) && (this->state != CRAB_STATE_5_UPSIDE_DOWN)) { + gcdialog_showDialog(VER_SELECT(ASSET_D32_DIALOG_MUTANT_CRAB_MEET, 0xA05, 0, 0), 0xF, this->position, NULL, __chCrab_mutantTextCallback, NULL); + mapSpecificFlags_set(0, TRUE); + levelSpecificFlags_set(LEVEL_FLAG_E_CC_MUTIE_SNIPPETS, TRUE); + this->has_met_before = TRUE; } } if (gsworld_getMap() == MAP_A_TTC_SANDCASTLE) { @@ -281,66 +296,66 @@ void chCrab_update(Actor *this) { && !jiggyscore_isCollected(JIGGY_10_TTC_SANDCASTLE) && subaddie_playerIsWithinSphereAndActive(this, 1600) ) { - gcdialog_showDialog(ASSET_A12_DIALOG_BLACK_SNIPPET_SPAWNED, 4, this->position, NULL, NULL, NULL); - mapSpecificFlags_set(0, true); + gcdialog_showDialog(VER_SELECT(ASSET_A12_DIALOG_BLACK_SNIPPET_SPAWNED, 0x912, 0, 0), 4, this->position, NULL, NULL, NULL); + mapSpecificFlags_set(0, TRUE); } else if (mapSpecificFlags_get(1)) { - gcdialog_showDialog(ASSET_A13_DIALOG_BLACK_SNIPPET_DEFEATED, 4, this->position, NULL, NULL, NULL); - mapSpecificFlags_set(1, false); + gcdialog_showDialog(VER_SELECT(ASSET_A13_DIALOG_BLACK_SNIPPET_DEFEATED, 0x913, 0, 0), 4, this->position, NULL, NULL, NULL); + mapSpecificFlags_set(1, FALSE); } } if (levelSpecificFlags_get(LEVEL_FLAG_E_CC_MUTIE_SNIPPETS)) { - if ((this->state != 8) && (this->state != 9)) { - subaddie_set_state_with_direction(this, (this->has_met_before) ? 8 : 9, 0.0f, 1); - this->has_met_before = false; + if ((this->state != CRAB_STATE_8_MUTIES_FIRST_DIALOG) && (this->state != CRAB_STATE_9_MUTIES_REVISIT)) { + subaddie_set_state_with_direction(this, (this->has_met_before) ? CRAB_STATE_8_MUTIES_FIRST_DIALOG : CRAB_STATE_9_MUTIES_REVISIT, 0.0f, 1); + this->has_met_before = FALSE; } } switch(this->state){ - case 1: //L802CBE30 - if (subaddie_maybe_set_state(this, 2, 0.03f)) { + case CRAB_STATE_1_IDLE_UNK: //L802CBE30 + if (subaddie_maybe_set_state(this, CRAB_STATE_2_IDLE_UNK, 0.03f)) { __chCrab_802CB040(this); } __chCrab_802CB078(this); break; - case 9: //L802CBE6C + case CRAB_STATE_9_MUTIES_REVISIT: //L802CBE6C if (!levelSpecificFlags_get(LEVEL_FLAG_E_CC_MUTIE_SNIPPETS)) { - subaddie_set_state_with_direction(this, 3, 0.0f, 1); + subaddie_set_state_with_direction(this, CRAB_STATE_3_TURN_TO_PLAYER, 0.0f, 1); } break; - case 2: //L802CBE9C + case CRAB_STATE_2_IDLE_UNK: //L802CBE9C subaddie_turnToYaw(this, 1.0f); if( func_8032CA80(this, (this->modelCacheIndex == ACTOR_F2_BLACK_SNIPPET)? 0xD: 0) && func_80329480(this) ) { func_80328CEC(this, (s32) this->yaw, 90, 150); } - subaddie_maybe_set_state_position_direction(this, 1, 0.0f, 1, 0.0075f); + subaddie_maybe_set_state_position_direction(this, CRAB_STATE_1_IDLE_UNK, 0.0f, 1, 0.0075f); __chCrab_802CB078(this); break; - case 3: //L802CBF44 + case CRAB_STATE_3_TURN_TO_PLAYER: //L802CBF44 this->yaw_ideal = (f32) subaddie_getYawToPlayer(this); subaddie_turnToYaw(this, 4.0f); if (func_80329480(this)) { - subaddie_set_state(this, 4); + subaddie_set_state(this, CRAB_STATE_4_CHASE_PLAYER); this->actor_specific_1_f = 12.0f; } break; - case 8: //L802CBF9C + case CRAB_STATE_8_MUTIES_FIRST_DIALOG: //L802CBF9C this->yaw_ideal = subaddie_getYawToPlayer(this) + 90.0; subaddie_turnToYaw(this, 4.0f); if (func_80329480(this)) { - subaddie_set_state(this, 9); + subaddie_set_state(this, CRAB_STATE_9_MUTIES_REVISIT); this->actor_specific_1_f = 12.0f; } else if (!levelSpecificFlags_get(LEVEL_FLAG_E_CC_MUTIE_SNIPPETS)) { - subaddie_set_state_with_direction(this, 3, 0.0f, 1); + subaddie_set_state_with_direction(this, CRAB_STATE_3_TURN_TO_PLAYER, 0.0f, 1); } break; - case 4: //L802CC024 + case CRAB_STATE_4_CHASE_PLAYER: //L802CC024 if ((globalTimer_getTime() & 0xF) == 9) { this->yaw_ideal = (f32) subaddie_getYawToPlayer(this); } @@ -350,12 +365,12 @@ void chCrab_update(Actor *this) { } break; - case 5: //L802CC0AC + case CRAB_STATE_5_UPSIDE_DOWN: //L802CC0AC this->lifetime_value = MAX(0.0, this->lifetime_value - sp30); if (this->lifetime_value == 0.0f) { - subaddie_set_state(this, 7); + subaddie_set_state(this, CRAB_STATE_7_FLIP_UPRIGHT); actor_playAnimationOnce(this); - if (this->marker->id == 0x16B) { + if (this->marker->id == MARKER_16B_SNIPPET_UPSIDEDOWN) { this->marker->id = MARKER_13_SNIPPET; } if (this->marker->id == MARKER_DE_BLACK_SNIPPET_UPSIDEDOWN) { @@ -364,26 +379,26 @@ void chCrab_update(Actor *this) { } break; - case 6: //L802CC18C + case CRAB_STATE_6_FLIP_UPSIDE_DOWN: //L802CC18C if (anctrl_isStopped(this->anctrl)) { if (this->lifetime_value == 0.0f) { func_80326310(this); } else { - subaddie_set_state(this, 5); + subaddie_set_state(this, CRAB_STATE_5_UPSIDE_DOWN); actor_loopAnimation(this); } } break; - case 7: //L802CC1E8 + case CRAB_STATE_7_FLIP_UPRIGHT: //L802CC1E8 if (anctrl_isStopped(this->anctrl)) { - subaddie_set_state(this, 1); + subaddie_set_state(this, CRAB_STATE_1_IDLE_UNK); actor_loopAnimation(this); } break; } - if ((this->state == 2) || (this->state == 3) || (this->state == 4)) { + if ((this->state == CRAB_STATE_2_IDLE_UNK) || (this->state == CRAB_STATE_3_TURN_TO_PLAYER) || (this->state == CRAB_STATE_4_CHASE_PLAYER)) { if (sp34 != D_803670B0) { D_803670B0 = sp34; D_803670B4 = 1; @@ -397,6 +412,24 @@ void chCrab_update(Actor *this) { } /* .data */ -ActorInfo chSnippet = { MARKER_13_SNIPPET, ACTOR_67_SNIPPET, ASSET_358_SNIPPET, 0x1, chCrabAnimations, chCrab_update, actor_update_func_80326224, actor_draw, 1900, 0, 0.8f, 0}; -ActorInfo chBlackSnippet = { MARKER_DD_BLACK_SNIPPET, ACTOR_F2_BLACK_SNIPPET, ASSET_566_MODEL_BLACK_SNIPPET, 0x1, chCrabAnimations, chCrab_update, actor_update_func_80326224, actor_draw, 1900, 0, 0.8f, 0}; -ActorInfo chMutieSnippet = { MARKER_13_SNIPPET, ACTOR_F5_MUTIE_SNIPPET, ASSET_38F_MODEL_MUTIE_SNIPPET, 0x1, chCrabMutantAnimations, chCrab_update, actor_update_func_80326224, actor_draw, 1900, 0, 0.8f, 0}; + +ActorInfo chSnippet = { + MARKER_13_SNIPPET, ACTOR_67_SNIPPET, ASSET_358_SNIPPET, + 0x1, chCrabAnimations, + chCrab_update, actor_update_func_80326224, actor_draw, + 1900, 0, 0.8f, 0 +}; + +ActorInfo chBlackSnippet = { + MARKER_DD_BLACK_SNIPPET, ACTOR_F2_BLACK_SNIPPET, ASSET_566_MODEL_BLACK_SNIPPET, + 0x1, chCrabAnimations, + chCrab_update, actor_update_func_80326224, actor_draw, + 1900, 0, 0.8f, 0 +}; + +ActorInfo chMutieSnippet = { + MARKER_13_SNIPPET, ACTOR_F5_MUTIE_SNIPPET, ASSET_38F_MODEL_MUTIE_SNIPPET, + 0x1, chCrabMutantAnimations, + chCrab_update, actor_update_func_80326224, actor_draw, + 1900, 0, 0.8f, 0 +}; \ No newline at end of file diff --git a/src/core2/ch/extralife.c b/src/core2/ch/extralife.c index d0f8a2936..484842ec8 100644 --- a/src/core2/ch/extralife.c +++ b/src/core2/ch/extralife.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_41F30.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/ch/feather.c b/src/core2/ch/feather.c index 363b00296..f4cd8ff77 100644 --- a/src/core2/ch/feather.c +++ b/src/core2/ch/feather.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_43800.c #include #include "core1/core1.h" #include "functions.h" diff --git a/src/core2/ch/gameSelect.h b/src/core2/ch/gameSelect.h new file mode 100644 index 000000000..a7a3ec955 --- /dev/null +++ b/src/core2/ch/gameSelect.h @@ -0,0 +1,14 @@ +// BanjoDecomp: core2/ch/gameSelect.h +#ifndef BANJO_KAZOOIE_CH_GAMESELECT_H +#define BANJO_KAZOOIE_CH_GAMESELECT_H + +typedef enum { + GAME_SELECT_INITIALIZE = 1, + GAME_SELECT_IDLE = 2, + GAME_SELECT_STARTING = 3, + GAME_SELECT_STARTING_SILLY = 4, + GAME_SELECT_ERASE_CONFIRMATION = 5, + GAME_SELECT_DONE = 6 +} GameSelectState; + +#endif // BANJO_KAZOOIE_CH_GAMESELECT_H diff --git a/src/core2/ch/ghost.c b/src/core2/ch/ghost.c index 98c80714e..16dd4500f 100644 --- a/src/core2/ch/ghost.c +++ b/src/core2/ch/ghost.c @@ -9,11 +9,11 @@ typedef struct { f32 unk4; } ActorLocal_Core2_D4050; -void func_8035B900(Actor *this); -void func_8035BD48(Actor *this); +void chTeehee_update(Actor *this); +void chPurpleTeehee_update(Actor *this); /* .data */ -ActorAnimationInfo D_80372BE0[] ={ +ActorAnimationInfo chTeeheeAnimations[] ={ {0x00, 0.0f}, {ASSET_9E_ANIM_TEEHEE_IDLE, 2.0f}, {ASSET_9F_ANIM_TEEHEE_ALERTED, 1.5f}, @@ -23,17 +23,17 @@ ActorAnimationInfo D_80372BE0[] ={ {ASSET_2AB_ANIM_TEEHEE_DIE, 1.0f} }; -ActorInfo D_80372C18 = { //TEEHEE +ActorInfo chTeeHee = { //TEEHEE MARKER_99_TEEHEE, ACTOR_CA_TEEHEE, ASSET_3CB_MODEL_TEEHEE, - 0x1, D_80372BE0, - func_8035B900, actor_update_func_80326224, actor_draw, + 0x1, chTeeheeAnimations, + chTeehee_update, actor_update_func_80326224, actor_draw, 6500, 0, 0.9f, 0 }; -ActorInfo D_80372C3C = { //PURPLE_TEEHEE (inside tumblar) +ActorInfo chPurpleTeeHee = { //PURPLE_TEEHEE (inside tumblar) MARKER_296_TEEHEE_PURPLE, ACTOR_3C1_PURPLE_TEEHEE, ASSET_564_MODEL_PURPLE_TEEHEE, - 0x1, D_80372BE0, - func_8035B900, func_8035BD48, actor_draw, + 0x1, chTeeheeAnimations, + chTeehee_update, chPurpleTeehee_update, actor_draw, 6500, 0, 0.9f, 0 }; @@ -41,27 +41,48 @@ s32 D_80372C60[3] = {0x46, 0xFE, 0x46}; s32 D_80372C6C[3] = {0xFE, 0x46, 0xFE}; +enum chteehee_state_e { + CH_TEEHEE_STATE_0_NOT_INIT, + CH_TEEHEE_STATE_1_IDLE, + CH_TEEHEE_STATE_2_ALERT, + CH_TEEHEE_STATE_3_CHASE, + CH_TEEHEE_STATE_4_UNK, + CH_TEEHEE_STATE_5_UNK, + CH_TEEHEE_STATE_6_DIE +}; + +enum chpurpleteehee_state_e { + CH_PURPLE_TEEHEE_STATE_0_NOT_INIT, + CH_PURPLE_TEEHEE_STATE_1_UNK, + CH_PURPLE_TEEHEE_STATE_2_UNUSED, + CH_PURPLE_TEEHEE_STATE_3_ROAMING, + CH_PURPLE_TEEHEE_STATE_4_UNUSED, + CH_PURPLE_TEEHEE_STATE_5_UNUSED, + CH_PURPLE_TEEHEE_STATE_6_DIE +}; + /* .code */ -void func_8035AFE0(f32 scale, f32 pos[3], s32 cnt, enum asset_e sprite_id, s32 arg4[3]){ +void chTeehee_emitDust(f32 scale, f32 pos[3], s32 cnt, enum asset_e sprite_id, s32 arg4[3]) +{ ParticleEmitter *pCtrl = partEmitMgr_newEmitter(cnt); particleEmitter_setSprite(pCtrl, sprite_id); particleEmitter_setRGB(pCtrl, arg4); particleEmitter_setPosition(pCtrl, pos); particleEmitter_setSpawnPositionRange(pCtrl, - -100.0f*scale, 20.0f*scale, -100.0f*scale, - 100.0f*scale, 200.0f*scale, 100.0f*scale + -100.0f * scale, 20.0f * scale, -100.0f * scale, + 100.0f * scale, 200.0f * scale, 100.0f * scale ); particleEmitter_setAccelerationRange(pCtrl, - 0.0f, -10.0f*scale, 0.0f, - 0.0f, -10.0f*scale, 0.0f + 0.0f, -10.0f * scale, 0.0f, + 0.0f, -10.0f * scale, 0.0f ); particleEmitter_setParticleVelocityRange(pCtrl, - -100.0f*scale, -20.0f*scale, -100.0f*scale, - 100.0f*scale, 100.0f*scale, 100.0f*scale + -100.0f * scale, -20.0f * scale, -100.0f * scale, + 100.0f * scale, 100.0f * scale, 100.0f * scale ); - particleEmitter_setStartingScaleRange(pCtrl, scale*0.4, scale*0.6); - particleEmitter_setFinalScaleRange(pCtrl, scale*1.0, scale*1.4); + particleEmitter_setStartingScaleRange(pCtrl, scale * 0.4, scale * 0.6); + particleEmitter_setFinalScaleRange(pCtrl, scale * 1.0, scale * 1.4); particleEmitter_setSpawnIntervalRange(pCtrl, 0.0f, 0.01f); particleEmitter_setParticleLifeTimeRange(pCtrl, 1.0f, 1.4f); particleEmitter_setFade(pCtrl, 0.0f, 0.01f); @@ -69,49 +90,54 @@ void func_8035AFE0(f32 scale, f32 pos[3], s32 cnt, enum asset_e sprite_id, s32 a particleEmitter_emitN(pCtrl, cnt); } -void func_8035B1CC(ActorMarker *this_marker, ActorMarker *other_marker){ +void chTeehee_die(ActorMarker *this_marker, ActorMarker *other_marker) +{ Actor *this = marker_getActor(this_marker); - f32 sp30; + f32 scale; - sp30 = this->scale; - func_8030E878(SFX_121_AWAWAU, 1.3f, 32000, this->position, this->scale*400.0f, this->scale*1800.0f); - func_8030E878(SFX_30_MAGIC_POOF, 1.0f, 32000, this->position, this->scale*400.0f, this->scale*1800.0f); - subaddie_set_state_with_direction(this, 6, 0.01f, 1); + scale = this->scale; + func_8030E878(SFX_121_AWAWAU, 1.3f, 32000, this->position, this->scale * 400.0f, this->scale * 1800.0f); + func_8030E878(SFX_30_MAGIC_POOF, 1.0f, 32000, this->position, this->scale * 400.0f, this->scale * 1800.0f); + subaddie_set_state_with_direction(this, CH_TEEHEE_STATE_6_DIE, 0.01f, 1); actor_playAnimationOnce(this); actor_collisionOff(this); func_80326310(this); - func_8035AFE0(sp30, this->position, 8, ASSET_700_SPRITE_DUST, D_80372C60); + chTeehee_emitDust(scale, this->position, 8, ASSET_700_SPRITE_DUST, D_80372C60); } -void func_8035B2C4(ActorMarker *this_marker, ActorMarker *other_marker){ +void chTeeheePurple_die(ActorMarker *this_marker, ActorMarker *other_marker) +{ Actor *this = marker_getActor(this_marker); - f32 sp30 = this->scale; - func_8030E878(SFX_121_AWAWAU, 1.3f, 32000, this->position, this->scale*400.0f, this->scale*1800.0f); - func_8030E878(SFX_30_MAGIC_POOF, 1.0f, 32000, this->position, this->scale*400.0f, this->scale*1800.0f); - subaddie_set_state_with_direction(this, 6, 0.01f, 1); + f32 scale = this->scale; + func_8030E878(SFX_121_AWAWAU, 1.3f, 32000, this->position, this->scale * 400.0f, this->scale * 1800.0f); + func_8030E878(SFX_30_MAGIC_POOF, 1.0f, 32000, this->position, this->scale * 400.0f, this->scale * 1800.0f); + subaddie_set_state_with_direction(this, CH_PURPLE_TEEHEE_STATE_6_DIE, 0.01f, 1); actor_playAnimationOnce(this); actor_collisionOff(this); - func_8035AFE0(sp30, this->position, 8, ASSET_700_SPRITE_DUST, D_80372C6C); + chTeehee_emitDust(scale, this->position, 8, ASSET_700_SPRITE_DUST, D_80372C6C); } -void func_8035B3B4(ActorMarker *this_marker, ActorMarker *other_marker){ +void chTeehee_hitPlayer(ActorMarker *this_marker, ActorMarker *other_marker) +{ Actor *this = marker_getActor(this_marker); this->lifetime_value = 1.0f; } -int func_8035B3E4(Actor *this){ - if(subaddie_playerIsWithinSphereAndActive(this, (s32)(this->scale*600.0f)) && func_803292E0(this)) - return 1; - return 0; +bool func_8035B3E4(Actor *this) +{ + if(subaddie_playerIsWithinSphereAndActive(this, (s32)(this->scale * 600.0f)) && func_803292E0(this)) + return true; + return false; } -int func_8035B444(Actor *this, f32 arg1){ +bool func_8035B444(Actor *this, f32 arg1) +{ int out; - subaddie_turnToYaw(this, arg1); + subaddie_turnToYaw(this, arg1); if(!func_80329054(this, 2) && func_80329480(this)) - return 0; - return 1; + return false; + return true; } void func_8035B49C(Actor *this){ @@ -127,16 +153,16 @@ void func_8035B49C(Actor *this){ } void func_8035B56C(Actor *this){ - f32 sp2C; + f32 scale_doubled; f32 plyr_pos[3]; - sp2C = 2*(f64)this->scale; + scale_doubled = 2 * (f64)this->scale; player_getPosition(plyr_pos); if(this->position_y < plyr_pos[1]){ - if(this->position_y + sp2C < plyr_pos[1]){ - this->position_y = this->position_y + sp2C; - this->velocity_x += sp2C; + if(this->position_y + scale_doubled < plyr_pos[1]){ + this->position_y = this->position_y + scale_doubled; + this->velocity_x += scale_doubled; } else{ this->velocity_x += plyr_pos[1] - this->position_y; @@ -144,9 +170,9 @@ void func_8035B56C(Actor *this){ } } else if(plyr_pos[1] < this->position_y){ - if(plyr_pos[1] < this->position_y - sp2C){ - this->position_y = this->position_y - sp2C; - this->velocity_x -= sp2C; + if(plyr_pos[1] < this->position_y - scale_doubled){ + this->position_y = this->position_y - scale_doubled; + this->velocity_x -= scale_doubled; } else{ this->velocity_x -= (this->position_y - plyr_pos[1]); @@ -170,14 +196,14 @@ void func_8035B6CC(Actor *this){ subaddie_set_state_with_direction(this, 2, 0.01f, 1); actor_playAnimationOnce(this); this->actor_specific_1_f = 1.0f; - func_8030E878(0x3F4, randf2(1.0f, 1.2f), 32000, this->position, this->scale*400.0f, this->scale*1800.0f); + func_8030E878(0x3F4, randf2(1.0f, 1.2f), 32000, this->position, this->scale * 400.0f, this->scale * 1800.0f); } void func_8035B75C(Actor *this){ subaddie_set_state_with_direction(this, 3, 0.01f, 1); actor_loopAnimation(this); this->actor_specific_1_f = volatileFlag_get(VOLATILE_FLAG_C1_IN_FINAL_CHARACTER_PARADE) ? 0.0 : 12.0; - func_8030E878(0x3F4, randf2(1.0f, 1.2f), 32000, this->position, this->scale*400.0f, this->scale*1800.0f); + func_8030E878(0x3F4, randf2(1.0f, 1.2f), 32000, this->position, this->scale * 400.0f, this->scale * 1800.0f); } void func_8035B824(Actor *this){ @@ -196,78 +222,78 @@ void func_8035B8A8(Actor *this){ func_80328CEC(this, (s32)this->yaw_ideal, 0xE1, 0x87); } -void func_8035B900(Actor *this){ +void chTeehee_update(Actor *this){ ActorLocal_Core2_D4050 *local = (ActorLocal_Core2_D4050 *)&this->local; - s32 sp30 = globalTimer_getTime(); - f32 sp2C = time_getDelta(); + s32 global_time = globalTimer_getTime(); + f32 time_delta = time_getDelta(); if(!this->volatile_initialized){ this->volatile_initialized = true; - marker_setCollisionScripts(this->marker, NULL, func_8035B3B4, func_8035B1CC); + marker_setCollisionScripts(this->marker, NULL, chTeehee_hitPlayer, chTeehee_die); this->marker->propPtr->unk8_3 = false; actor_collisionOn(this); this->velocity_z = 0.0f; this->lifetime_value = 0.0f; - this->unk1C[0] = this->position_y + this->scale*100.0f; - this->velocity_y = this->scale*2.0; + this->unk1C[0] = this->position_y + this->scale * 100.0f; + this->velocity_y = this->scale * 2.0; this->velocity_x = this->unk1C[0]; local->unk0 = randf2(1.0f, 4.5f); anctrl_setTransitionDuration(this->anctrl, 0.8f); }//L8035B9D4 - if(0.0 < this->lifetime_value - sp2C){ - this->lifetime_value -= sp2C; + if(0.0 < this->lifetime_value - time_delta){ + this->lifetime_value -= time_delta; } else{//L8035BA08 switch(this->state){ - case 1: //L8035BA30 + case CH_TEEHEE_STATE_1_IDLE: //L8035BA30 func_8035B49C(this); if(func_8035B3E4(this)){ func_8035B6CC(this); } - else if(0.0 < local->unk0 - sp2C){ - local->unk0 = local->unk0 - sp2C; + else if(0.0 < local->unk0 - time_delta){ + local->unk0 = local->unk0 - time_delta; } else{ func_8035B824(this); } break; - case 2: //L8035BA98 + case CH_TEEHEE_STATE_2_ALERT: //L8035BA98 this->yaw_ideal = subaddie_getYawToPlayer(this); func_8035B444(this, 4.0f); if(actor_animationIsAt(this, 0.99f)){ func_8035B75C(this); } break; - case 3: //L8035BAE0 + case CH_TEEHEE_STATE_3_CHASE: //L8035BAE0 func_8035B56C(this); - if((sp30 & 0x3F) == 7 && randf() < 0.7){ - func_8030E878(0x3F4, randf2(1.0f, 1.2f), 32000, this->position, this->scale*400.0f, this->scale*1800.0f); + if((global_time & 0x3F) == 7 && randf() < 0.7){ + func_8030E878(0x3F4, randf2(1.0f, 1.2f), 32000, this->position, this->scale * 400.0f, this->scale * 1800.0f); }//L8035BB6C this->yaw_ideal = subaddie_getYawToPlayer(this); if(!func_8035B3E4(this) || !func_8035B444(this, 5.0f)){ func_8035B674(this); } break; - case 4: //L8035BBB0 + case CH_TEEHEE_STATE_4_UNK: //L8035BBB0 func_8035B49C(this); if(!func_8035B444(this, 2.0f)){ func_8035B8A8(this); } - else if(local->unk4 - sp2C <= 0.0){ + else if(local->unk4 - time_delta <= 0.0){ func_8035B674(this); } else{ - local->unk4 = local->unk4 - sp2C; + local->unk4 = local->unk4 - time_delta; } break; - case 5: //L8035BC1C + case CH_TEEHEE_STATE_5_UNK: //L8035BC1C func_8035B49C(this); subaddie_turnToYaw(this, 3.0f); if(func_80329480(this)){ func_8035B674(this); } break; - case 6: //L8035BC48 + case CH_TEEHEE_STATE_6_DIE: //L8035BC48 break; } }//L8035BC48 @@ -297,12 +323,12 @@ int func_8035BC5C(Actor *this, s32 target, s32 delta){ return done; } -void func_8035BD48(Actor *this){ +void chPurpleTeehee_update(Actor *this){ if(!this->volatile_initialized){ this->volatile_initialized = true; this->marker->propPtr->unk8_3 = false; actor_collisionOn(this); - marker_setCollisionScripts(this->marker, NULL, func_8035B3B4, func_8035B2C4); + marker_setCollisionScripts(this->marker, NULL, chTeehee_hitPlayer, chTeeheePurple_die); mapSpecificFlags_set(3, false); mapSpecificFlags_set(4, false); if(gsworld_getMap() == MAP_24_MMM_TUMBLARS_SHED){ @@ -312,32 +338,32 @@ void func_8035BD48(Actor *this){ marker_despawn(this->marker); } else{//L8035BE04 - subaddie_set_state_with_direction(this, 1, 0.01f, 1); + subaddie_set_state_with_direction(this, CH_PURPLE_TEEHEE_STATE_1_UNK, 0.01f, 1); actor_setOpacity(this, 0); } } else{//L8035BE2C - subaddie_set_state_with_direction(this, 3, 0.01f, 1); + subaddie_set_state_with_direction(this, CH_PURPLE_TEEHEE_STATE_3_ROAMING, 0.01f, 1); actor_setOpacity(this, 0xff); } }//L8035BE50 switch(this->state){ - case 1: //L8035BE78 + case CH_PURPLE_TEEHEE_STATE_1_UNK: //L8035BE78 actor_collisionOff(this); if(mapSpecificFlags_getClear(4)){ marker_despawn(this->marker); } else if(mapSpecificFlags_getClear(3)){ - subaddie_set_state_with_direction(this, 3, 0.01f, 1); + subaddie_set_state_with_direction(this, CH_PURPLE_TEEHEE_STATE_3_ROAMING, 0.01f, 1); } break; - case 3: //L8035BECC + case CH_PURPLE_TEEHEE_STATE_3_ROAMING: //L8035BECC this->unk58_0 = true; actor_collisionOn(this); if(mapSpecificFlags_getClear(4)){ this->unk38_0 = true; - func_8035B2C4(this->marker, NULL); + chTeeheePurple_die(this->marker, NULL); } else{//L8035BF14 if(this->alpha_124_19 == 0xFF || func_8035BC5C(this, 0xff, 0xA)){ @@ -345,11 +371,11 @@ void func_8035BD48(Actor *this){ } if((globalTimer_getTime() &0x3F) == 7 && randf() < 0.7){ - func_8030E878(0x3f4, randf2(1.0f, 1.2f), 32000, this->position, this->scale*400.0f, this->scale*1800.0f); + func_8030E878(0x3f4, randf2(1.0f, 1.2f), 32000, this->position, this->scale * 400.0f, this->scale * 1800.0f); } } break; - case 6: //L8035BFD4 + case CH_PURPLE_TEEHEE_STATE_6_DIE: //L8035BFD4 if(func_8035BC5C(this, 0, -7)){ this->unk58_0 = false; this->unk48 = 0.0f; @@ -358,7 +384,7 @@ void func_8035BD48(Actor *this){ marker_despawn(this->marker); } else{ - subaddie_set_state_with_direction(this, 1, 0.01f, 1); + subaddie_set_state_with_direction(this, CH_PURPLE_TEEHEE_STATE_1_UNK, 0.01f, 1); timedFunc_set_2(randf2(5.0f, 10.0f), (GenFunction_2)mapSpecificFlags_set, 3, true); } } diff --git a/src/core2/ch/gloop.c b/src/core2/ch/gloop.c index 6a71d5c7d..2fee4d88e 100644 --- a/src/core2/ch/gloop.c +++ b/src/core2/ch/gloop.c @@ -60,7 +60,7 @@ void chgloop_update(Actor *this){ if( !mapSpecificFlags_get(2) && subaddie_playerIsWithinSphereAndActive(this, 350) - && gcdialog_showDialog(ASSET_D34_DIALOG_GLOOP_MEET, 0, NULL, NULL, NULL, NULL) + && gcdialog_showDialog(VER_SELECT(ASSET_D34_DIALOG_GLOOP_MEET, 0xA07, 0, 0), 0, NULL, NULL, NULL, NULL) ){ mapSpecificFlags_set(2, true); } diff --git a/src/core2/ch/goldfeather.c b/src/core2/ch/goldfeather.c index ff39d1ff0..bc45e3e15 100644 --- a/src/core2/ch/goldfeather.c +++ b/src/core2/ch/goldfeather.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_51950.c #include #include "functions.h" #include "variables.h" @@ -7,14 +8,14 @@ extern f32 player_getYaw(void); void func_802D88E0(Actor *this); /* .data */ -ActorInfo D_80367C90 = { +ActorInfo fxSpentRedFeather = { 0x100, 0x1FF, 0x580, 0x0, NULL, func_802D88E0, actor_update_func_80326224, fxTouchSparkle_draw, 0, 0, 0.0f, 0 }; -ActorInfo D_80367CB4 = { +ActorInfo fxSpentGoldFeather = { 0x101, 0x200, 0x6D1, 0x0, NULL, func_802D88E0, actor_update_func_80326224, fxTouchSparkle_draw, diff --git a/src/core2/ch/gravestone.c b/src/core2/ch/gravestone.c index 97cf86660..4a17efff6 100644 --- a/src/core2/ch/gravestone.c +++ b/src/core2/ch/gravestone.c @@ -47,8 +47,8 @@ Actor *chgravestone_draw(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx) { this = marker_getActorAndRotation(marker, rotation); local = (ActorLocal_core2_D7D10 *)&this->local; - func_8033A45C(3, (s32) this->velocity[1]); - func_8033A45C(4, local->unk0); + modelRender_setAppendageVisibility(3, (s32) this->velocity[1]); + modelRender_setAppendageVisibility(4, local->unk0); modelRender_setPreDrawCallback( (model_render_pre_draw_callback_f)actor_predrawMethod, (void *)this); modelRender_setPostDrawCallback((model_render_post_draw_callback_f)actor_postdrawMethod, (void *)marker); modelRender_draw(gfx, mtx, this->position, rotation, this->scale, D_80373008, func_803257B4(marker)); diff --git a/src/core2/ch/grill_chompa.c b/src/core2/ch/grillechompa.c similarity index 97% rename from src/core2/ch/grill_chompa.c rename to src/core2/ch/grillechompa.c index cbb060d68..a6a74f62c 100644 --- a/src/core2/ch/grill_chompa.c +++ b/src/core2/ch/grillechompa.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/ch/grillechompa.c #include #include "functions.h" #include "variables.h" @@ -72,7 +73,7 @@ Actor *chGrilleChompa_draw(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx) return actor; } else{ - func_8033A45C(3, (actor->state == 1 || actor->state == 6)? 0:1); + modelRender_setAppendageVisibility(3, (actor->state == 1 || actor->state == 6)? 0:1); return actor_draw(marker, gfx, mtx, vtx); } diff --git a/src/core2/ch/honeycomb.c b/src/core2/ch/honeycomb.c index e4725a3ad..9ae9cf22a 100644 --- a/src/core2/ch/honeycomb.c +++ b/src/core2/ch/honeycomb.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_42CB0.c #include #include "functions.h" #include "variables.h" @@ -11,13 +12,15 @@ typedef struct{ void chHoneycomb_update(Actor *this); /* .data */ -ActorInfo D_80366C80 = { MARKER_53_EMPTY_HONEYCOMB, ACTOR_47_EMPTY_HONEYCOMB, ASSET_361_MODEL_EMPTY_HONEYCOMB, +ActorInfo chEmptyHoneycomb = { + MARKER_53_EMPTY_HONEYCOMB, ACTOR_47_EMPTY_HONEYCOMB, ASSET_361_MODEL_EMPTY_HONEYCOMB, 0, NULL, chHoneycomb_update, actor_update_func_80326224, actor_draw, 0, 0, 0.8f, 0 }; -ActorInfo D_80366CA4 = { MARKER_55_HONEYCOMB, ACTOR_50_HONEYCOMB, ASSET_363_MODEL_HONEYCOMB, +ActorInfo chHoneycomb = { + MARKER_55_HONEYCOMB, ACTOR_50_HONEYCOMB, ASSET_363_MODEL_HONEYCOMB, 0, NULL, chHoneycomb_update, actor_update_func_80326224, actor_draw, 0, 0, 0.8f, 0 diff --git a/src/core2/ch/icecube.c b/src/core2/ch/icecube.c index 2582264c4..231756902 100644 --- a/src/core2/ch/icecube.c +++ b/src/core2/ch/icecube.c @@ -39,7 +39,7 @@ s32 D_80372BD4[3] = {200, 200, 255}; /*.code */ Actor *chicecube_draw(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx){ Actor *actor = marker_getActor(marker); - func_8033A45C(3, actor->unk38_31); + modelRender_setAppendageVisibility(3, actor->unk38_31); actor = actor_draw(marker, gfx, mtx, vtx); return actor; } diff --git a/src/core2/ch/jiggy.c b/src/core2/ch/jiggy.c index 3e3165905..02cb2178a 100644 --- a/src/core2/ch/jiggy.c +++ b/src/core2/ch/jiggy.c @@ -1,32 +1,21 @@ +// BanjoDecomp: core2/ch/jiggy.c #include #include "functions.h" #include "variables.h" #include "enums.h" +#include "jiggy.h" +#include "core2/commonParticle.h" #include "port/Enhancements/Events/Hooks/Events.h" extern void func_802BE720(void); -extern f32 modelRender_func_8033A244(f32); -extern void modelRender_func_8033A280(f32); - -typedef struct chjiggy_s{ - u32 unk0; - u32 index; -} ActorLocal_Jiggy; - -Actor *spawnQueue_actor_s32(f32, f32, f32); -void spawnJiggyDestroyedEffects(u32 x, u32 y, u32 z, u32 arg3); -Actor *chjiggy_draw(ActorMarker *this, Gfx **gdl, Mtx **mptr, Vtx **arg3); -void chjiggy_update_2(Actor * arg0); -void chjiggy_update(Actor *this); -enum jiggy_e chjiggy_getJiggyId(Actor *this); - +extern void modelRender_func_8033A280(f32); /* .data */ ActorAnimationInfo JIGGY_ANIMATIONS[] = { - {0, 0.0f}, - {0, 0.0f}, - {0, 0.0f} + { 0, 0.0f }, + { 0, 0.0f }, + { 0, 0.0f } }; ActorInfo chJiggy = { @@ -37,120 +26,137 @@ ActorInfo chJiggy = { }; /* .code */ -enum jiggy_e getJiggyId(Actor *this){ +enum jiggy_e getJiggyId(Actor *this) { s32 id; - s32 sp18[3]; + s32 position[3]; id = gsworld_getMap(); - sp18[0] = (s32)this->position[0]; - sp18[1] = (s32)this->position[1]; - sp18[2] = (s32)this->position[2]; - id = func_80307164(sp18); - if( id < 0){ + position[0] = (s32)this->position[0]; + position[1] = (s32)this->position[1]; + position[2] = (s32)this->position[2]; + + id = func_80307164(position); + + if (id < 0) { return 0; } - else{ - return func_80306DBC(id) + 1; - } + + return func_80306DBC(id) + 1; } -void playJiggyDestroyedSoundsAndReset(ActorMarker * arg0, u32 arg1){ +void playJiggyDestroyedSoundsAndReset(ActorMarker *marker, u32 resetSwitchFlag) { func_8030E6D4(SFX_30_MAGIC_POOF); coMusicPlayer_playMusic(COMUSIC_3C_MINIGAME_LOSS, 0x7FF8); - mapSpecificFlags_set(arg1, 1); - marker_despawn(arg0); + mapSpecificFlags_set(resetSwitchFlag, TRUE); + marker_despawn(marker); } -void spawnJiggyDestroyedEffects(u32 x, u32 y, u32 z, u32 arg3){ +void spawnJiggyDestroyedEffects(u32 x, u32 y, u32 z, u32 resetSwitchFlag) { __spawnQueue_add_4((GenFunction_4)spawnQueue_actor_s32, ACTOR_4C_STEAM, x, y, z); __spawnQueue_add_4((GenFunction_4)spawnQueue_actor_s32, ACTOR_14F_DESTROYED_JIGGY, x, y, z); - mapSpecificFlags_set(arg3, 1); + mapSpecificFlags_set(resetSwitchFlag, TRUE); } -void resetFlag(u32 arg0){ - mapSpecificFlags_set(arg0, 0); +void resetFlag(enum bgs_specific_flags flag) { + mapSpecificFlags_set(flag, FALSE); } -void destroyJiggy(Actor *this, s32 arg1, s32 arg2, s32 arg3, s32 arg4, s32 arg5, enum volatile_flags_e arg6){ - if( !mapSpecificFlags_get(arg1) - && mapSpecificFlags_get(arg2) - && item_getCount(ITEM_0_HOURGLASS_TIMER) == 0 - ){ - CALL_EVENT(OnTimedJiggyExpired, (s32)chjiggy_getJiggyId(this)); - player_setModelVisible(1); - actor_collisionOff(this); - gcStaticCamera_activate(arg3); - volatileFlag_setAndTriggerDialog_0(arg6); - timedFunc_set_4(0.6f, (GenFunction_4)spawnJiggyDestroyedEffects, (s32)this->position[0], (s32)this->position[1], (s32)this->position[2], arg4); - timedFunc_set_2(0.6f, (GenFunction_2)playJiggyDestroyedSoundsAndReset, (uintptr_t)this->marker, arg5); - timedFunc_set_0(1.0f, (GenFunction_0)func_802BE720); - timedFunc_set_1(3.9f, (GenFunction_1)resetFlag, arg4); - mapSpecificFlags_set(arg1, 1); +void destroyJiggy(Actor *this, s32 jiggyFlag, s32 timerRunningFlag, s32 cameraId, s32 switchPressedFlag, s32 resetSwitchFlag, enum volatile_flags_e dialogFlag) { + + // Jiggy is still active + if (mapSpecificFlags_get(jiggyFlag) + || !mapSpecificFlags_get(timerRunningFlag) + || item_getCount(ITEM_0_HOURGLASS_TIMER) != 0) { + + return; } + + CALL_EVENT(OnTimedJiggyExpired, (s32)chjiggy_getJiggyId(this)); + player_setModelVisible(1); + actor_collisionOff(this); + + // Switch camera to a static one showing the newly destroyed jiggy + gcStaticCamera_activate(cameraId); + + progressDialog_setAndTriggerDialog_0(dialogFlag); + timedFunc_set_4(0.6f, (GenFunction_4)spawnJiggyDestroyedEffects, (s32)this->position[0], (s32)this->position[1], (s32)this->position[2], switchPressedFlag); + timedFunc_set_2(0.6f, (GenFunction_2)playJiggyDestroyedSoundsAndReset, reinterpret_cast(uintptr_t, this->marker), resetSwitchFlag); + timedFunc_set_0(1.0f, (GenFunction_0)func_802BE720); + timedFunc_set_1(3.9f, (GenFunction_1)resetFlag, switchPressedFlag); + mapSpecificFlags_set(jiggyFlag, TRUE); } -void chjiggy_updateRotation(Actor *this){ +void chjiggy_updateRotation(Actor *this) { f32 delta = time_getDelta(); + + // Controls the rotation speed this->yaw += delta * 230.0f; - if(360.0f <= this->yaw){ + + if (360.0f <= this->yaw) { this->yaw -= 360.0f; } + this->yaw_ideal = this->yaw; } -//chjiggy_draw -Actor *chjiggy_draw(ActorMarker *this, Gfx **gdl, Mtx **mptr, Vtx **arg3){ - Actor * thisActor = marker_getActor(this); - ActorLocal_Jiggy *local = (ActorLocal_Jiggy *)&thisActor->local; +Actor *chjiggy_draw(ActorMarker *this, Gfx **gdl, Mtx **mptr, Vtx **vtx) { + Actor *jiggy_actor = marker_getActor(this); + ActorLocal_Jiggy *local = (ActorLocal_Jiggy *)&jiggy_actor->local; u32 jiggyId; - if(!local->unk0){ - jiggyId = chjiggy_getJiggyId(thisActor); - if((jiggyId == JIGGY_1C_CC_RINGS) || (jiggyId == JIGGY_1D_CC_SLOW_SAWBLADES)){ + if (!local->isHidden) { + jiggyId = chjiggy_getJiggyId(jiggy_actor); + + if ((jiggyId == JIGGY_1C_CC_RINGS) || (jiggyId == JIGGY_1D_CC_SLOW_SAWBLADES)) { modelRender_func_8033A280(10.0f); modelRender_func_8033A244(30000.0f); } - thisActor = actor_draw(this, gdl, mptr, arg3); + + jiggy_actor = actor_draw(this, gdl, mptr, vtx); } - return thisActor; + + return jiggy_actor; } -void chjiggy_update_2(Actor * arg0){ - func_80343DEC(arg0); - chjiggy_updateRotation(arg0); +void chjiggy_update_2(Actor *this) { + func_80343DEC(this); + chjiggy_updateRotation(this); } -//chjiggy_update -void chjiggy_update(Actor *this){ +void chjiggy_update(Actor *this) { ActorLocal_Jiggy *local = (ActorLocal_Jiggy *)&this->local; int i; - if(this->marker->unk14_21){ - for(i = 0; i < 4; i++){ - if(randf() < 0.015){ + // A small chance to show a jiggy shine effect. Up to four can be shown at once. + if (this->marker->unk14_21) { + for (i = 0; i < 4; i++) { + if (randf() < 0.015) { commonParticle_add(this->marker, i + 5, func_80329904); - commonParticle_new(8, 1); + commonParticle_new(COMMON_PARTICLE_8_JIGGY_SHINE, 1); } } - }//L802C7E44 - switch(this->state){ - case 1: //L802C7E68 - local->unk0 = 0; - if(local->index == 0) - local->index = getJiggyId(this); + } + + switch (this->state) { + case JIGGY_STATE_1_INIT: + local->isHidden = FALSE; + + if (local->id == 0) { + local->id = getJiggyId(this); + } - if(jiggyscore_isCollected(local->index)){ + if (jiggyscore_isCollected(local->id)) { marker_despawn(this->marker); - } - else{ - subaddie_set_state(this, 2); - switch(chjiggy_getJiggyId(this)){ - case JIGGY_17_CC_CLANKER_RAISED: //L802C7EF8 - case JIGGY_49_CCW_EYRIE:// L802C7EF8 + } else { + subaddie_set_state(this, JIGGY_STATE_2_IDLE); + switch (chjiggy_getJiggyId(this)) { + case JIGGY_17_CC_CLANKER_RAISED: + case JIGGY_49_CCW_EYRIE: this->marker->unk40_21 = 1; break; - case JIGGY_36_LAIR_TTC_WITCH_SWITCH:// L802C7F0C + + case JIGGY_36_LAIR_TTC_WITCH_SWITCH: this->unk44_14 = func_80341F2C(0x20A); this->unk48 = 0.0f; this->unk4C = 300.0f; @@ -159,53 +165,63 @@ void chjiggy_update(Actor *this){ func_80343DEC(this); chjiggy_updateRotation(this); break; - case JIGGY_3E_GV_GRABBA:// L802C7F6C - case JIGGY_4D_CCW_FLOWER:// L802C7F6C + + case JIGGY_3E_GV_GRABBA: + case JIGGY_4D_CCW_FLOWER: this->unk124_6 = 0; break; - case JIGGY_41_GV_MAZE:// L802C7F7C + + case JIGGY_41_GV_MAZE: this->marker->unk14_10 = 30; break; - case JIGGY_13_TTC_LOCKUP: //L802C7F94 + + case JIGGY_13_TTC_LOCKUP: this->marker->unk14_10 = 40; break; } } + break; - case 2: //L802C7FAC + + case JIGGY_STATE_2_IDLE: chjiggy_updateRotation(this); - switch(chjiggy_getJiggyId(this)){ - case JIGGY_20_BGS_ELEVATED_WALKWAY: //L802C7FE8 - destroyJiggy(this, 4, 3, 0xD, 5, 2, VOLATILE_FLAG_AE_BGS_WALKWAY_JIGGY_MISSED); + + switch (chjiggy_getJiggyId(this)) { + case JIGGY_20_BGS_ELEVATED_WALKWAY: + destroyJiggy(this, BGS_SPECIFIC_FLAG_4_WALKWAY_JIGGY, BGS_SPECIFIC_FLAG_3_WALKWAY_JIGGY_TIMER_RUNNING, STATIC_CAMERA_D_WALKWAY_JIGGY_DESTROY, + BGS_SPECIFIC_FLAG_5_WALKWAY_JIGGY_SWITCH_PRESSED, BGS_SPECIFIC_FLAG_2_WALKWAY_JIGGY_RESET, VOLATILE_FLAG_AE_BGS_WALKWAY_JIGGY_MISSED); break; - case JIGGY_25_BGS_MAZE://L802C8018 - destroyJiggy(this, 0xd, 0xc, 0x1e, 9, 0xb, VOLATILE_FLAG_AF_BGS_MAZE_JIGGY_MISSED); + + case JIGGY_25_BGS_MAZE: + destroyJiggy(this, BGS_SPECIFIC_FLAG_D_MAZE_JIGGY, BGS_SPECIFIC_FLAG_C_MAZE_JIGGY_TIMER_RUNNING, STATIC_CAMERA_1E_MAZE_JIGGY_DESTROY, + BGS_SPECIFIC_FLAG_9_MAZE_JIGGY_SWITCH_PRESSED, BGS_SPECIFIC_FLAG_B_MAZE_JIGGY_RESET, VOLATILE_FLAG_AF_BGS_MAZE_JIGGY_MISSED); break; - case JIGGY_2F_FP_XMAS_TREE://L802C8048 + + case JIGGY_2F_FP_XMAS_TREE: if (levelSpecificFlags_get(LEVEL_FLAG_29_FP_XMAS_TREE_COMPLETE)) { actor_collisionOn(this); - } - else { + } else { actor_collisionOff(this); } break; } + break; - }//L802C8074 + } } -enum jiggy_e chjiggy_getJiggyId(Actor *this){ +enum jiggy_e chjiggy_getJiggyId(Actor *this) { ActorLocal_Jiggy *local = (ActorLocal_Jiggy *)&this->local; - return local->index; + return local->id; } -void chjiggy_hide(Actor * this){ +void chjiggy_hide(Actor *this) { ActorLocal_Jiggy *local = (ActorLocal_Jiggy *)&this->local; - local->unk0 = 1; + local->isHidden = TRUE; actor_collisionOff(this); } -void chjiggy_setJiggyId(Actor *this, u32 id){ +void chjiggy_setJiggyId(Actor *this, u32 id) { ActorLocal_Jiggy *local = (ActorLocal_Jiggy *)&this->local; - local->index = id; + local->id = id; } diff --git a/src/core2/ch/jiggy.h b/src/core2/ch/jiggy.h new file mode 100644 index 000000000..96c5c1c1d --- /dev/null +++ b/src/core2/ch/jiggy.h @@ -0,0 +1,21 @@ +// BanjoDecomp: core2/ch/jiggy.h +#ifndef BANJO_KAZOOIE_CH_JIGGY_H +#define BANJO_KAZOOIE_CH_JIGGY_H + +typedef struct chjiggy_s { + bool isHidden; + u32 id; +} ActorLocal_Jiggy; + +Actor *spawnQueue_actor_s32(f32, f32, f32); +Actor *chjiggy_draw(ActorMarker *this, Gfx **gdl, Mtx **mptr, Vtx **arg3); +void chjiggy_update_2(Actor * arg0); +void chjiggy_update(Actor *this); +enum jiggy_e chjiggy_getJiggyId(Actor *this); + +enum jiggy_state_e { + JIGGY_STATE_1_INIT = 1, + JIGGY_STATE_2_IDLE = 2 +}; + +#endif // BANJO_KAZOOIE_CH_JIGGY_H diff --git a/src/core2/ch/jinjo.c b/src/core2/ch/jinjo.c index f7190f36a..09d57b993 100644 --- a/src/core2/ch/jinjo.c +++ b/src/core2/ch/jinjo.c @@ -29,27 +29,45 @@ ActorInfo chJinjoYellow = { MARKER_5E_JINJO_YELLOW, ACTOR_5E_JINJO_YELLOW, ASSET ActorInfo chJinjoPink = { MARKER_5D_JINJO_PINK, ACTOR_61_JINJO_PINK, ASSET_3C1_MODEL_JINJO_PINK, 0x1, chJinjoAnimations, chJinjo_update, actor_update_func_80326224, actor_draw, 0, 0, 0.0f, 0}; ActorInfo chJinjoOrange = { MARKER_5C_JINJO_ORANGE, ACTOR_5F_JINJO_ORANGE, ASSET_3BC_MODEL_JINJO_ORANGE, 0x1, chJinjoAnimations, chJinjo_update, actor_update_func_80326224, actor_draw, 0, 0, 0.0f, 0}; +enum chjinjo_state_e { + CH_JINJO_STATE_0_NOT_INIT, + CH_JINJO_STATE_1_IDLE, + CH_JINJO_STATE_2_ONE_HAND_WAVE, + CH_JINJO_STATE_3_TWO_HAND_WAVE, + CH_JINJO_STATE_4_JUMPING_WAVE, + CH_JINJO_STATE_5_UNK, + CH_JINJO_STATE_6_COLLECTED, + CH_JINJO_STATE_7_FLY_START, + CH_JINJO_STATE_8_FLY_END, + CH_JINJO_STATE_9_UNK +}; + +/*.code */ enum asset_e __chJinjo_getMeetDialogId(enum marker_e marker_id){ switch(marker_id){ - case MARKER_5A_JINJO_BLUE: return ASSET_D98_DIALOG_JINJO_MEET_BLUE; - case MARKER_5B_JINJO_GREEN: return ASSET_D99_DIALOG_JINJO_MEET_GREEN; - case MARKER_5C_JINJO_ORANGE: return ASSET_D9B_DIALOG_JINJO_MEET_ORANGE; - case MARKER_5D_JINJO_PINK: return ASSET_D9A_DIALOG_JINJO_MEET_PINK; - case MARKER_5E_JINJO_YELLOW: return ASSET_D97_DIALOG_JINJO_MEET_YELLOW; + case MARKER_5A_JINJO_BLUE: return VER_SELECT(ASSET_D98_DIALOG_JINJO_MEET_BLUE, 0x0A16, 0, 0); + case MARKER_5B_JINJO_GREEN: return VER_SELECT(ASSET_D99_DIALOG_JINJO_MEET_GREEN, 0x0A17, 0, 0); + case MARKER_5C_JINJO_ORANGE: return VER_SELECT(ASSET_D9B_DIALOG_JINJO_MEET_ORANGE, 0x0A19, 0, 0); + case MARKER_5D_JINJO_PINK: return VER_SELECT(ASSET_D9A_DIALOG_JINJO_MEET_PINK, 0x0A18, 0, 0); + case MARKER_5E_JINJO_YELLOW: return VER_SELECT(ASSET_D97_DIALOG_JINJO_MEET_YELLOW, 0x0A15, 0, 0); } return 0; } -void __chJinjo_802CDBA8(ActorMarker *this, ActorMarker *other){ +void __chJinjo_collected(ActorMarker *this, ActorMarker *other){ Actor *actorPtr = marker_getActor(this); ActorLocal_Jinjo *localPtr = &actorPtr->jinjo; - if(actorPtr->state < 5){ + if(actorPtr->state < CH_JINJO_STATE_5_UNK){ if(!fileProgressFlag_get(FILEPROG_E_JINJO_TEXT)){ gcdialog_showDialog(__chJinjo_getMeetDialogId(actorPtr->marker->id), 4, 0, 0, 0, 0); fileProgressFlag_set(FILEPROG_E_JINJO_TEXT, 1); } - subaddie_set_state_with_direction(actorPtr, 6, 0.0f , -1); + subaddie_set_state_with_direction(actorPtr, CH_JINJO_STATE_6_COLLECTED, 0.0f , -1); + /* + If multiple Jinjos of a color are collected, it overflows into the next Jinjo. + Example, two Green Jinjos -> Orange Jinjo collected & no Green Jinjo collected + */ if (!EventSystem_Should(VB_UPDATE_JINJO_HUD, false, actorPtr->position)) { if (item_adjustByDiffWithHud(ITEM_12_JINJOS, 1 << ((this->id + 6) & 0x1F)) == 0x1f) // [port] MIPS SLL uses low 5 bits; mask to avoid UB localPtr->unk4 = 1; @@ -64,7 +82,7 @@ void __chJinjo_802CDC9C(Actor *this, s16 arg1){ f32 tmpf; tmpf = this->yaw; - tmpf -= time_getDelta()*arg1/45.0; + tmpf -= time_getDelta() * arg1 / 45.0; if(tmpf >= 360.0f) tmpf -= 360.0f; @@ -74,7 +92,7 @@ void __chJinjo_802CDC9C(Actor *this, s16 arg1){ this->yaw = tmpf; } -void __chJinjo_802CDD3C(Actor * this){ +void __chJinjo_free(Actor * this){ ActorLocal_Jinjo *localPtr = &this->jinjo; if(localPtr->unkC != 0){ func_802F9D38(localPtr->unkC); @@ -84,21 +102,21 @@ void __chJinjo_802CDD3C(Actor * this){ void chJinjo_update(Actor * this){ f32 sp7C[3]; - f32 sp70[3]; + f32 player_velocity[3]; f32 sp6C; f32 sp68; //unused?? s16 sp66; s16 sp64; - s32 sp60; + s32 is_within_jinjos_vision; // f32 sp5C; ActorLocal_Jinjo *local; //= &this->jinjo; //sp34 - f32 sp58 = time_getDelta(); + f32 time_delta = time_getDelta(); s32 i; - int sp50; - f32 *sp30; + int is_flying_start; + f32 *this_position; //f32 sp4C; //unused - f32 sp40[3]; + f32 jiggy_position[3]; //s32 sp3C; //s32 sp38; @@ -111,50 +129,50 @@ void chJinjo_update(Actor * this){ local->unk0 = 1; local->unk4 = 0; local->unk8 = (this->position_y < func_80309B24(this->position)); - this->marker->collisionFunc = __chJinjo_802CDBA8; - marker_setFreeMethod(this->marker, __chJinjo_802CDD3C); + this->marker->collisionFunc = __chJinjo_collected; + marker_setFreeMethod(this->marker, __chJinjo_free); if(volatileFlag_get(VOLATILE_FLAG_C1_IN_FINAL_CHARACTER_PARADE)){ marker_despawn(this->marker); } }//L802CDE24 - sp30 = this->position; + this_position = this->position; func_8028E964(sp7C); - func_80257F18(sp30, sp7C, &sp6C); + func_80257F18(this_position, sp7C, &sp6C); sp64 = (this->yaw * 182.04444); // sp66 = sp64 - (s32)(sp6C*182.04444); sp66 = (s32) (sp6C * 182.04444); sp66 = sp64 - sp66; - sp60 = func_8028AED4(sp30, 55.0f); + is_within_jinjos_vision = func_8028AED4(this_position, 55.0f); switch(this->state){ - case 1: + case CH_JINJO_STATE_1_IDLE: if(randf() < 0.015){ - if(sp60){ - subaddie_set_state_with_direction(this, 3, 0.0f, -1); + if(is_within_jinjos_vision){ + subaddie_set_state_with_direction(this, CH_JINJO_STATE_3_TWO_HAND_WAVE, 0.0f, -1); }else{ - subaddie_set_state_with_direction(this, 2, 0.0f, -1); + subaddie_set_state_with_direction(this, CH_JINJO_STATE_2_ONE_HAND_WAVE, 0.0f, -1); } actor_playAnimationOnce(this); }//L802CDF24 break; - case 2: /* 46FA0 802CDF30 3C053F7D */ - case 3: + case CH_JINJO_STATE_2_ONE_HAND_WAVE: /* 46FA0 802CDF30 3C053F7D */ + case CH_JINJO_STATE_3_TWO_HAND_WAVE: if(actor_animationIsAt(this, 0.99f)){ - subaddie_set_state_with_direction(this, 1, 0.0f, -1); + subaddie_set_state_with_direction(this, CH_JINJO_STATE_1_IDLE, 0.0f, -1); } break; - case 4: /* 46FD8 802CDF68 3C053F7D */ + case CH_JINJO_STATE_4_JUMPING_WAVE: /* 46FD8 802CDF68 3C053F7D */ if(actor_animationIsAt(this, 0.99f)){ - subaddie_set_state_with_direction(this, 1, 0.0f, -1); + subaddie_set_state_with_direction(this, CH_JINJO_STATE_1_IDLE, 0.0f, -1); }else{//L802CDF9C tmp_f0 = this->yaw; if(sp66 >= 0){ - tmp_f0 -= 80.0f * sp58; + tmp_f0 -= 80.0f * time_delta; } else{//L802CDFBC - tmp_f0 += 80.0f * sp58; + tmp_f0 += 80.0f * time_delta; }//L802CDFD0 if(tmp_f0 >= 360.0f) tmp_f0 -= 360.0f; @@ -164,17 +182,17 @@ void chJinjo_update(Actor * this){ this->yaw = tmp_f0; }//L802CE018 break; - case 6:/* 47094 802CE024 02002025 */ + case CH_JINJO_STATE_6_COLLECTED:/* 47094 802CE024 02002025 */ __chJinjo_802CDC9C(this, sp66); if(actor_animationIsAt(this, 0.0f) && --(local->unk0) == 0){ - subaddie_set_state_with_direction(this, 7, 0.0f, -1); + subaddie_set_state_with_direction(this, CH_JINJO_STATE_7_FLY_START, 0.0f, -1); actor_playAnimationOnce(this); if(local->unk4){ - sp40[0] = this->position_x; - sp40[1] = this->position_y; - sp40[2] = this->position_z; - sp40[1] += 50.0f; - jiggy_spawn(10*level_get()-9, sp40); + jiggy_position[0] = this->position_x; + jiggy_position[1] = this->position_y; + jiggy_position[2] = this->position_z; + jiggy_position[1] += 50.0f; + jiggy_spawn(10 * level_get() - 9, jiggy_position); }//L802CE0CC core1_ce60_incOrDecCounter(false); func_8032BB88(this, 0, 4000); @@ -186,27 +204,27 @@ void chJinjo_update(Actor * this){ }//L802CE114 break; - case 7: - case 8: - sp50 = this->state == 7; - if(!sp50 || 0.1 < anctrl_getAnimTimer(this->anctrl)){//L802CE158 - player_getVelocity(sp70); - sp70[0] *= sp58*6.0f;\ - sp70[1] *= sp58*6.0f;\ - sp70[2] *= sp58*6.0f; - sp70[0] = sp70[0] + sp7C[0];\ - sp70[1] = sp70[1] + sp7C[1];\ - sp70[2] = sp70[2] + sp7C[2]; - sp70[0] -= this->position_x;\ - sp70[1] -= this->position_y;\ - sp70[2] -= this->position_z; - sp70[0] *= sp58*3.0f; - sp70[1] *= sp58*3.0f; - sp70[2] *= sp58*3.0f; - this->position_x = this->position_x + sp70[0]; - this->position_y = this->position_y + sp70[1]; - this->position_z = this->position_z + sp70[2]; - if(sp50 || anctrl_getAnimTimer(this->anctrl) < 0.8){ + case CH_JINJO_STATE_7_FLY_START: + case CH_JINJO_STATE_8_FLY_END: + is_flying_start = this->state == CH_JINJO_STATE_7_FLY_START; + if(!is_flying_start || 0.1 < anctrl_getAnimTimer(this->anctrl)){//L802CE158 + player_getVelocity(player_velocity); + player_velocity[0] *= time_delta * 6.0f;\ + player_velocity[1] *= time_delta * 6.0f;\ + player_velocity[2] *= time_delta * 6.0f; + player_velocity[0] = player_velocity[0] + sp7C[0];\ + player_velocity[1] = player_velocity[1] + sp7C[1];\ + player_velocity[2] = player_velocity[2] + sp7C[2]; + player_velocity[0] -= this->position_x;\ + player_velocity[1] -= this->position_y;\ + player_velocity[2] -= this->position_z; + player_velocity[0] *= time_delta * 3.0f; + player_velocity[1] *= time_delta * 3.0f; + player_velocity[2] *= time_delta * 3.0f; + this->position_x = this->position_x + player_velocity[0]; + this->position_y = this->position_y + player_velocity[1]; + this->position_z = this->position_z + player_velocity[2]; + if(is_flying_start || anctrl_getAnimTimer(this->anctrl) < 0.8){ for(i = 0; i < 4; i++){ if(randf() < 0.3){ commonParticle_add(this->marker, i + 5, func_80329904); @@ -216,38 +234,38 @@ void chJinjo_update(Actor * this){ }//L802CE2D0 } - if(sp50){ + if(is_flying_start){ if(anctrl_getAnimTimer(this->anctrl) < 0.2) __chJinjo_802CDC9C(this, sp66); if(actor_animationIsAt(this, 0.1f)){ local->unkC = func_802F9AA8(SFX_18_BIGBUTT_SLIDE); - func_802F9EC4(local->unkC, sp30, 500, 2000); + func_802F9EC4(local->unkC, this_position, 500, 2000); func_802F9F80(local->unkC, 0.0f, 9e+09, 0.0f); func_802FA0B0(local->unkC, 0); coMusicPlayer_playMusic(COMUSIC_43_ENTER_LEVEL_GLITTER, 0x7FFF); func_8025AABC(COMUSIC_43_ENTER_LEVEL_GLITTER); - func_8030E9C4(SFX_C7_SHWOOP, 0.8f, 0x7FFF, sp30, 300.0f, 2000.0f); + func_8030E9C4(SFX_C7_SHWOOP, 0.8f, 0x7FFF, this_position, 300.0f, 2000.0f); }//L802CE3C4 if(actor_animationIsAt(this, 0.434f)){ - func_8030E9C4(SFX_C7_SHWOOP, 0.9f, 0x7fff, sp30, 300.0f, 2000.0f); + func_8030E9C4(SFX_C7_SHWOOP, 0.9f, 0x7fff, this_position, 300.0f, 2000.0f); }//L802CE408 if(actor_animationIsAt(this, 0.811f)){ - func_8030E9C4(SFX_C7_SHWOOP, 1.0f, 0x7fff, sp30, 300.0f, 2000.0f); + func_8030E9C4(SFX_C7_SHWOOP, 1.0f, 0x7fff, this_position, 300.0f, 2000.0f); } }else{//L802CE450 - if(actor_animationIsAt(this,0.214f)){ - func_8030E9C4(SFX_C7_SHWOOP, 1.1f, 0x7fff, sp30, 300.0f, 2000.0f); + if(actor_animationIsAt(this, 0.214f)){ + func_8030E9C4(SFX_C7_SHWOOP, 1.1f, 0x7fff, this_position, 300.0f, 2000.0f); }//L802CE490 - if(actor_animationIsAt(this,0.55f)){ - func_8030E9C4(SFX_53_BANJO_HUIII, 1.5f, 0x7fff, sp30, 300.0f, 2000.0f); + if(actor_animationIsAt(this, 0.55f)){ + func_8030E9C4(SFX_53_BANJO_HUIII, 1.5f, 0x7fff, this_position, 300.0f, 2000.0f); }//L802CE4D0 - if(actor_animationIsAt(this,0.75f)){ + if(actor_animationIsAt(this, 0.75f)){ func_80326310(this); if(local->unk4 == 0){ func_8032BB88(this, -1, 4000); @@ -257,7 +275,7 @@ void chJinjo_update(Actor * this){ } }//L802CE518 - if(actor_animationIsAt(this,0.85f)){ + if(actor_animationIsAt(this, 0.85f)){ if(local->unkC){ func_802F9D38(local->unkC); local->unkC = 0; @@ -266,7 +284,7 @@ void chJinjo_update(Actor * this){ func_8025A7DC(COMUSIC_43_ENTER_LEVEL_GLITTER); }//L802CE558 - if(local->unk4 && actor_animationIsAt(this,0.95f)){ + if(local->unk4 && actor_animationIsAt(this, 0.95f)){ func_8032BB88(this, -1, 4000); if (EventSystem_Should(VB_SET_JINJO_COUNT, true)) { core1_ce60_incOrDecCounter(true); @@ -274,44 +292,47 @@ void chJinjo_update(Actor * this){ } }//L802CE598 - if(sp50){ + if(is_flying_start){ if(actor_animationIsAt(this, 0.96f) || actor_animationIsAt(this, 0.99f)){ - subaddie_set_state_with_direction(this, 8, 0.0f, -1); + subaddie_set_state_with_direction(this, CH_JINJO_STATE_8_FLY_END, 0.0f, -1); actor_playAnimationOnce(this); } } break; }//L802CE5F0 - if(this->state < 4 && !(((sp66 >= 0)? sp66: -sp66) <= 0x1000)){ - subaddie_set_state_with_direction(this, 4, 0.0f, -1); + if(this->state < CH_JINJO_STATE_4_JUMPING_WAVE + && !(((sp66 >= 0)? sp66: -sp66) <= 0x1000)) + { + subaddie_set_state_with_direction(this, CH_JINJO_STATE_4_JUMPING_WAVE, 0.0f, -1); actor_playAnimationOnce(this); }//L802CE630 + if(!gcdialog_hasCurrentTextId()){ switch(chJinjoAnimations[this->state].index){ case ASSET_31_ANIM_JINJO_JUMP: if(actor_animationIsAt(this, 0.6f)){ if(local->unk8){ - func_8030E988(SFX_8_BANJO_LANDING_04, 1.8f, 18000, sp30, 120.0f, 1200.0f); + func_8030E988(SFX_8_BANJO_LANDING_04, 1.8f, 18000, this_position, 120.0f, 1200.0f); }else{ - sfx_playFadeShorthandDefault(SFX_8_BANJO_LANDING_04, 1.8f, 18000, sp30, 120, 1200); + sfx_playFadeShorthandDefault(SFX_8_BANJO_LANDING_04, 1.8f, 18000, this_position, 120, 1200); } } break; case ASSET_2D_ANIM_JINJO_IDLE: //L802CE6F4 if(actor_animationIsAt(this, 0.2f)){ if(local->unk8){ - func_8030E988(SFX_17_JINJO_WHISTLE, 1.0f, 22000, sp30, 120.0f, 1200.0f); + func_8030E988(SFX_17_JINJO_WHISTLE, 1.0f, 22000, this_position, 120.0f, 1200.0f); }else{ - sfx_playFadeShorthandDefault(SFX_17_JINJO_WHISTLE, 1.0f, 22000, sp30, 120, 1200); + sfx_playFadeShorthandDefault(SFX_17_JINJO_WHISTLE, 1.0f, 22000, this_position, 120, 1200); } } break; case ASSET_2F_ANIM_JINJO_HELP: //L802CE760 if(actor_animationIsAt(this, 0.2f)){ if(local->unk8){ - func_8030E988(SFX_27_JINJO_HI, 1.0f, 22000, sp30, 120.0f, 1200.0f); + func_8030E988(SFX_27_JINJO_HI, 1.0f, 22000, this_position, 120.0f, 1200.0f); }else{ - sfx_playFadeShorthandDefault(SFX_27_JINJO_HI, 1.0f, 22000, sp30, 120, 1200); + sfx_playFadeShorthandDefault(SFX_27_JINJO_HI, 1.0f, 22000, this_position, 120, 1200); } } break; diff --git a/src/core2/ch/level_collectible.c b/src/core2/ch/levelcollectible.c similarity index 96% rename from src/core2/ch/level_collectible.c rename to src/core2/ch/levelcollectible.c index 7cdb04f6f..f93c8b323 100644 --- a/src/core2/ch/level_collectible.c +++ b/src/core2/ch/levelcollectible.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/levelcollectible.c #include #include "functions.h" #include "variables.h" @@ -5,7 +6,7 @@ extern void func_8028F7D4(f32, f32); void chLevelCollectible_update(Actor *this); -extern ActorMarker *func_8028E86C(void); +extern ActorMarker *bacarry_getMarkerWithExtraSteps(void); static s32 levelCollectible_syncKind(s32 markerId) { switch (markerId) { @@ -284,7 +285,7 @@ s32 port_remoteCarry_displayUpdate(Actor *this) { extern void timed_mapSpecificFlags_setTrue(f32, s32); extern void progressDialog_showDialogMaskFour(s32); -ActorAnimationInfo D_80367B50[] = { +ActorAnimationInfo chPresentCollectibleAnimations[] = { {0, 0.0f}, {ASSET_18A_ANIM_XMAS_GIFT, 1.5f}, {ASSET_18A_ANIM_XMAS_GIFT, 1.5f}, @@ -293,37 +294,37 @@ ActorAnimationInfo D_80367B50[] = { {ASSET_18A_ANIM_XMAS_GIFT, 1.5f} }; -ActorInfo D_80367B80 = { +ActorInfo chOrangeCollectible = { MARKER_36_ORANGE_COLLECTIBLE, ACTOR_29_ORANGE_COLLECTIBLE, ASSET_2D2_MODEL_ORANGE, 0x5, NULL, chLevelCollectible_update, actor_update_func_80326224, actor_draw, 0, 0, 0.6f,0 }; -ActorInfo D_80367BA4 = { +ActorInfo chGoldBullion = { MARKER_37_GOLD_BULLION, ACTOR_2A_GOLD_BULLION, ASSET_3C7_MODEL_GOLD_BULLION, 0x5, NULL, chLevelCollectible_update, actor_update_func_80326224, actor_draw, 0, 0, 0.6f, 0 }; -ActorInfo D_80367BC8 = { +ActorInfo chBluePresentCollectible = { MARKER_1FD_BLUE_PRESENT_COLLECTIBLE, ACTOR_1ED_BLUE_PRESENT_COLLECTIBLE, ASSET_47F_MODEL_XMAS_GIFT_BLUE, - 0x5, D_80367B50, + 0x5, chPresentCollectibleAnimations, chLevelCollectible_update, actor_update_func_80326224, actor_draw, 0, 0, 1.8f, 0 }; -ActorInfo D_80367BEC = { +ActorInfo chGreenPresentCollectible = { MARKER_1FE_GREEN_PRESENT_COLLECTIBLE, ACTOR_1EF_GREEN_PRESENT_COLLECTIBLE, ASSET_480_MODEL_XMAS_GIFT_GREEN, - 0x5, D_80367B50, + 0x5, chPresentCollectibleAnimations, chLevelCollectible_update, actor_update_func_80326224, actor_draw, 0, 0, 1.4f, 0 }; -ActorInfo D_80367C10 = { +ActorInfo chRedPresentCollectible = { MARKER_1FF_RED_PRESENT_COLLECTIBLE, ACTOR_1F1_RED_PRESENT_COLLECTIBLE, ASSET_481_MODEL_XMAS_GIFT_RED, - 0x5, D_80367B50, + 0x5, chPresentCollectibleAnimations, chLevelCollectible_update, actor_update_func_80326224, actor_draw, 0, 0, 1.4f, 0 }; @@ -401,21 +402,21 @@ void __chLevelCollectible_collide(ActorMarker *marker, ActorMarker *other_marker levelSpecificFlags_set(LEVEL_FLAG_2A_FP_UNKNOWN, true); coMusicPlayer_playMusic(COMUSIC_2B_DING_B, 0x7FFF); __chLevelCollectible_presentCollectEmitSparkles(this->position, ASSET_711_SPRITE_SPARKLE_DARK_BLUE); - dialog_id = ASSET_C20_DIALOG_PRESENT_COLLECTIBLE_MEET_BLUE; + dialog_id = VER_SELECT(ASSET_C20_DIALOG_PRESENT_COLLECTIBLE_MEET_BLUE, 0x99A, 0, 0); break; case MARKER_1FE_GREEN_PRESENT_COLLECTIBLE: levelSpecificFlags_set(LEVEL_FLAG_2B_FP_UNKNOWN, true); coMusicPlayer_playMusic(COMUSIC_2B_DING_B, 0x7FFF); __chLevelCollectible_presentCollectEmitSparkles(this->position, ASSET_712_SPRITE_SPARKLE_GREEN); - dialog_id = ASSET_C21_DIALOG_PRESENT_COLLECTIBLE_MEET_GREEN; + dialog_id = VER_SELECT(ASSET_C21_DIALOG_PRESENT_COLLECTIBLE_MEET_GREEN, 0x99B, 0, 0); break; case MARKER_1FF_RED_PRESENT_COLLECTIBLE: levelSpecificFlags_set(LEVEL_FLAG_2C_FP_UNKNOWN, true); coMusicPlayer_playMusic(COMUSIC_2B_DING_B, 0x7FFF); __chLevelCollectible_presentCollectEmitSparkles(this->position, ASSET_715_SPRITE_SPARKLE_RED); - dialog_id = ASSET_C22_DIALOG_PRESENT_COLLECTIBLE_MEET_RED; + dialog_id = VER_SELECT(ASSET_C22_DIALOG_PRESENT_COLLECTIBLE_MEET_RED, 0x99C, 0, 0); break; default: @@ -424,7 +425,7 @@ void __chLevelCollectible_collide(ActorMarker *marker, ActorMarker *other_marker if (dialog_id != 0) { timedFunc_set_1(0.5f, (GenFunction_1)__chLevelCollectible_callDialog, dialog_id); } - func_8028F030(this->modelCacheIndex); + bacarriedobj_incWithExtraSteps(this->modelCacheIndex); { s32 kind = levelCollectible_syncKind(marker->id); if (kind >= 0) { @@ -453,7 +454,7 @@ void func_802D7DE8(ActorMarker *marker, f32 arg1[3]) { mapSpecificFlags_set(0, true); } } - func_8028F010(this->modelCacheIndex); + bacarriedobj_decWithExtraSteps(this->modelCacheIndex); { s32 kind = levelCollectible_syncKind(marker->id); if (kind >= 0) { @@ -564,8 +565,8 @@ void func_802D8374(Actor *this){ s32 pad2C; f32 sp20[3]; - if(func_8028E86C() != this->marker){ - func_8028F050(this->modelCacheIndex); + if(bacarry_getMarkerWithExtraSteps() != this->marker){ + bacarriedobj_displayOnHudWithExtraSteps(this->modelCacheIndex); marker_despawn(this->marker); } else{ diff --git a/src/core2/ch/mole.c b/src/core2/ch/mole.c index fc2813357..67f90ae1b 100644 --- a/src/core2/ch/mole.c +++ b/src/core2/ch/mole.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/ch/mole.c #include #include "functions.h" #include "variables.h" @@ -14,6 +15,29 @@ typedef struct{ } ChMoleDescription; /* .data */ + +enum mole_states +{ + MOLE_STATE_1_AWAITING_PLAYER = 1, + MOLE_STATE_2_POP_OUT_OF_MOLEHILL, + MOLE_STATE_3_EXPLAINING_ABILITY, + MOLE_STATE_4_REENTER_MOLEHILL, + MOLE_STATE_5_REFRESHER +}; + +enum mole_ability_learn_actions +{ + MOLE_ABILITY_LEARN_ACTION_1_STILT_STRIDE = 1, + MOLE_ABILITY_LEARN_ACTION_2_UNK, + MOLE_ABILITY_LEARN_ACTION_3_TURBO_TALON_TRAINER, + MOLE_ABILITY_LEARN_ACTION_4_UNK, + MOLE_ABILITY_LEARN_ACTION_5_EGG_FIRING, + MOLE_ABILITY_LEARN_ACTION_6_FLIGHT, + MOLE_ABILITY_LEARN_ACTION_7_WONDERWING, + MOLE_ABILITY_LEARN_ACTION_8_REFILL_HEALTH, + MOLE_ABILITY_LEARN_ACTION_FF_UNK = 0xFF +}; + ActorAnimationInfo moleAnimations[]= { {0, 0.0f}, {ASSET_13A_ANIM_BOTTLES_ENTER, 2000000000.0f}, @@ -30,22 +54,22 @@ ActorInfo gChMole = { 0, 0, 0.0f, 0 }; -// D_80367DC4 ChMoleDescription moleTable[] = { - {ASSET_C23_DIALOG_BEAKBOMB_LEARN, ASSET_C24_DIALOG_BEAKBOMB_REFRESHER, 0x0F, ABILITY_1_BEAK_BOMB}, - {ASSET_B47_DIALOG_EGGS_LEARN, ASSET_B4B_DIALOG_EGGS_REFRESHER, 0x16, ABILITY_6_EGGS}, - {ASSET_B48_DIALOG_BEAKBUSTER_LEARN, ASSET_B4C_DIALOG_BEAKBUSTER_REFRESHER, 0x17, ABILITY_2_BEAK_BUSTER}, - {ASSET_B49_DIALOG_TALON_TROT_LEARN, ASSET_B4A_DIALOG_TALON_TROT_REFRESHER, 0x18, ABILITY_10_TALON_TROT}, - {ASSET_A1F_DIALOG_SHOCKJUMP_LEARN, ASSET_A23_DIALOG_SHOCKJUMP_REFRESHER, 0x0C, ABILITY_D_SHOCK_JUMP}, - {ASSET_A20_DIALOG_FLY_LEARN, ASSET_A22_DIALOG_FLY_REFRESHER, 0x0D, ABILITY_9_FLIGHT}, - {ASSET_D35_DIALOG_WONDERWING_LEARN, ASSET_D36_DIALOG_WONDERWING_REFRESHER, 0x01, ABILITY_12_WONDERWING}, - {ASSET_C88_DIALOG_WADING_BOOTS_LEARN, ASSET_C89_DIALOG_WADING_BOOTS_REFRESHER, 0x10, ABILITY_E_WADING_BOOTS}, - {ASSET_A84_DIALOG_TURBOTRAINERS_LEARN, ASSET_A85_DIALOG_TURBOTRAINERS_REFRESHER, 0x19, ABILITY_11_TURBO_TALON}, - {ASSET_F64_DIALOG_NOTEDOORS_LEARN, ASSET_F65_DIALOG_NOTEDOORS_REFRESHER, 0x0E, ABILITY_13_1ST_NOTEDOOR} + {VER_SELECT(ASSET_C23_DIALOG_BEAKBOMB_LEARN, 0x99D, 0, 0), VER_SELECT(ASSET_C24_DIALOG_BEAKBOMB_REFRESHER, 0x99E, 0, 0), 0x0F, ABILITY_1_BEAK_BOMB}, + {VER_SELECT(ASSET_B47_DIALOG_EGGS_LEARN, 0x965, 0, 0), VER_SELECT(ASSET_B4B_DIALOG_EGGS_REFRESHER, 0x969, 0, 0), 0x16, ABILITY_6_EGGS}, + {VER_SELECT(ASSET_B48_DIALOG_BEAKBUSTER_LEARN, 0x966, 0, 0), VER_SELECT(ASSET_B4C_DIALOG_BEAKBUSTER_REFRESHER, 0x96A, 0, 0), 0x17, ABILITY_2_BEAK_BUSTER}, + {VER_SELECT(ASSET_B49_DIALOG_TALON_TROT_LEARN, 0x967, 0, 0), VER_SELECT(ASSET_B4A_DIALOG_TALON_TROT_REFRESHER, 0x968, 0, 0), 0x18, ABILITY_10_TALON_TROT}, + {VER_SELECT(ASSET_A1F_DIALOG_SHOCKJUMP_LEARN, 0x91F, 0, 0), VER_SELECT(ASSET_A23_DIALOG_SHOCKJUMP_REFRESHER, 0x923, 0, 0), 0x0C, ABILITY_D_SHOCK_JUMP}, + {VER_SELECT(ASSET_A20_DIALOG_FLY_LEARN, 0x920, 0, 0), VER_SELECT(ASSET_A22_DIALOG_FLY_REFRESHER, 0x922, 0, 0), 0x0D, ABILITY_9_FLIGHT}, + {VER_SELECT(ASSET_D35_DIALOG_WONDERWING_LEARN, 0xA08, 0, 0), VER_SELECT(ASSET_D36_DIALOG_WONDERWING_REFRESHER, 0xA09, 0, 0), 0x01, ABILITY_12_WONDERWING}, + {VER_SELECT(ASSET_C88_DIALOG_WADING_BOOTS_LEARN, 0x9CB, 0, 0), VER_SELECT(ASSET_C89_DIALOG_WADING_BOOTS_REFRESHER, 0x9CC, 0, 0), 0x10, ABILITY_E_WADING_BOOTS}, + {VER_SELECT(ASSET_A84_DIALOG_TURBOTRAINERS_LEARN, 0x940, 0, 0), VER_SELECT(ASSET_A85_DIALOG_TURBOTRAINERS_REFRESHER, 0x941, 0, 0), 0x19, ABILITY_11_TURBO_TALON}, + {VER_SELECT(ASSET_F64_DIALOG_NOTEDOORS_LEARN, 0xACA, 0, 0), VER_SELECT(ASSET_F65_DIALOG_NOTEDOORS_REFRESHER, 0xACB, 0, 0), 0x0E, ABILITY_13_1ST_NOTEDOOR} }; +#define MOLE_ID_TO_TABLE_SHIFT 9 + /* .code */ -// chmole_learnedAllLevelAbilities int chmole_learnedAllLevelAbilities(enum level_e level){ // Checks if all of the level's abilities are learned. switch (level){ @@ -65,7 +89,7 @@ int chmole_learnedAllLevelAbilities(enum level_e level){ case LEVEL_7_GOBIS_VALLEY: return ability_isUnlocked(ABILITY_11_TURBO_TALON); default: - return false; + return FALSE; } } @@ -76,19 +100,19 @@ enum asset_e chmole_learnedAllLevelAbilitiesDialog(void){ int learned_all_moves = chmole_learnedAllLevelAbilities(level_id); switch(level_id){ case LEVEL_1_MUMBOS_MOUNTAIN: - return learned_all_moves ? ASSET_B4E_DIALOG_BOTTLES_ALL_MM_MOVES_LEARNED : ASSET_D38_DIALOG_BOTTLES_ALL_MOVES_LEARNED; + return learned_all_moves ? ASSET_B4E_DIALOG_BOTTLES_ALL_MM_MOVES_LEARNED : VER_SELECT(ASSET_D38_DIALOG_BOTTLES_ALL_MOVES_LEARNED, 0xA0B, 0, 0); case LEVEL_2_TREASURE_TROVE_COVE: - return learned_all_moves ? ASSET_A27_DIALOG_BOTTLES_ALL_TTC_MOVES_LEARNED : ASSET_D38_DIALOG_BOTTLES_ALL_MOVES_LEARNED; + return learned_all_moves ? ASSET_A27_DIALOG_BOTTLES_ALL_TTC_MOVES_LEARNED : VER_SELECT(ASSET_D38_DIALOG_BOTTLES_ALL_MOVES_LEARNED, 0xA0B, 0, 0); case LEVEL_3_CLANKERS_CAVERN: - return learned_all_moves ? ASSET_D37_DIALOG_BOTTLES_ALL_CC_MOVES_LEARNED : ASSET_D38_DIALOG_BOTTLES_ALL_MOVES_LEARNED; + return learned_all_moves ? VER_SELECT(ASSET_D37_DIALOG_BOTTLES_ALL_CC_MOVES_LEARNED, 0xA0A, 0, 0) : VER_SELECT(ASSET_D38_DIALOG_BOTTLES_ALL_MOVES_LEARNED, 0xA0B, 0, 0); case LEVEL_4_BUBBLEGLOOP_SWAMP: - return learned_all_moves ? ASSET_C8A_DIALOG_BOTTLES_ALL_BGS_MOVES_LEARNED : ASSET_D38_DIALOG_BOTTLES_ALL_MOVES_LEARNED; + return learned_all_moves ? VER_SELECT(ASSET_C8A_DIALOG_BOTTLES_ALL_BGS_MOVES_LEARNED, 0x9CD, 0, 0) : VER_SELECT(ASSET_D38_DIALOG_BOTTLES_ALL_MOVES_LEARNED, 0xA0B, 0, 0); case LEVEL_5_FREEZEEZY_PEAK: - return learned_all_moves ? ASSET_C2A_DIALOG_BOTTLES_ALL_FP_GV_MOVES_LEARNED : ASSET_D38_DIALOG_BOTTLES_ALL_MOVES_LEARNED; + return learned_all_moves ? VER_SELECT(ASSET_C2A_DIALOG_BOTTLES_ALL_FP_GV_MOVES_LEARNED, 0x9A4, 0, 0) : VER_SELECT(ASSET_D38_DIALOG_BOTTLES_ALL_MOVES_LEARNED, 0xA0B, 0, 0); case LEVEL_7_GOBIS_VALLEY: - return learned_all_moves ? ASSET_C2A_DIALOG_BOTTLES_ALL_FP_GV_MOVES_LEARNED : ASSET_D38_DIALOG_BOTTLES_ALL_MOVES_LEARNED; + return learned_all_moves ? VER_SELECT(ASSET_C2A_DIALOG_BOTTLES_ALL_FP_GV_MOVES_LEARNED, 0x9A4, 0, 0) : VER_SELECT(ASSET_D38_DIALOG_BOTTLES_ALL_MOVES_LEARNED, 0xA0B, 0, 0); default: - return ASSET_D38_DIALOG_BOTTLES_ALL_MOVES_LEARNED; + return VER_SELECT(ASSET_D38_DIALOG_BOTTLES_ALL_MOVES_LEARNED, 0xA0B, 0, 0); } } @@ -109,9 +133,9 @@ int chmole_learnedAllGameAbilities(void){ Actor *func_802D94B4(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx){ Actor *actor = marker_getActor(marker); - if(actor->state != 1 && actor->state != 5){ - func_8033A45C(3, 0); - func_8033A45C(4, 0); + if(actor->state != MOLE_STATE_1_AWAITING_PLAYER && actor->state != MOLE_STATE_5_REFRESHER){ + modelRender_setAppendageVisibility(3, 0); + modelRender_setAppendageVisibility(4, 0); actor = actor_draw(marker, gfx, mtx, vtx); } @@ -122,9 +146,9 @@ void func_802D9530(Actor *this){ Actor *other = subaddie_getLinkedActor(this); if(this->partnerActor && other){ if(this->partnerActor->id == 0xB8) - subaddie_set_state_with_direction(other, 3, 0.0001f, 1); + subaddie_set_state_with_direction(other, MOLE_STATE_3_EXPLAINING_ABILITY, 0.0001f, 1); } - subaddie_set_state_with_direction(this, 4, 0.0001f, 1); + subaddie_set_state_with_direction(this, MOLE_STATE_4_REENTER_MOLEHILL, 0.0001f, 1); actor_playAnimationOnce(this); this->unk44_31 = sfxsource_createSfxsourceAndReturnIndex(); sfxsource_setSfxId(this->unk44_31, SFX_3F9_UNKNOWN); @@ -136,37 +160,35 @@ void func_802D9530(Actor *this){ void func_802D9600(Actor * this){ anctrl_setSmoothTransition(this->anctrl, 0); - subaddie_set_state_with_direction(this, 1, 0.0001f, 1); + subaddie_set_state_with_direction(this, MOLE_STATE_1_AWAITING_PLAYER, 0.0001f, 1); this->marker->propPtr->unk8_3 = 0; } -// chmole_setStaticCamera void chmole_setStaticCamera(Actor *this){ // Sets the camera to a static camera - timed_setStaticCameraToNode(0.0f, moleTable[this->actorTypeSpecificField-9].camera_node); + timed_setStaticCameraToNode(0.0f, moleTable[this->actorTypeSpecificField - MOLE_ID_TO_TABLE_SHIFT].camera_node); } -// chmole_healthRefill void chmole_healthRefill(ActorMarker *marker, enum asset_e arg1, s32 arg2){ // Refills the player's health upon learning a new ability, if needed // Also releases the camera Actor *actor = marker_getActor(marker); - if( arg1 == moleTable[actor->actorTypeSpecificField-9].teach_text_id + if( arg1 == moleTable[actor->actorTypeSpecificField - MOLE_ID_TO_TABLE_SHIFT].teach_text_id && item_getCount(ITEM_14_HEALTH) < item_getCount(ITEM_15_HEALTH_TOTAL) ){ - gcdialog_showDialog(ASSET_D39_DIALOG_BOTTLES_REFILL_HEALTH, 7, 0, actor->marker, chmole_healthRefill, chmole_additionalAbilityLearnActions); + gcdialog_showDialog(VER_SELECT(ASSET_D39_DIALOG_BOTTLES_REFILL_HEALTH, 0xA0C, 0, 0), 7, 0, actor->marker, chmole_healthRefill, chmole_additionalAbilityLearnActions); }//L802D9738 - else if(arg1 == moleTable[actor->actorTypeSpecificField-9].teach_text_id || arg1 == ASSET_D39_DIALOG_BOTTLES_REFILL_HEALTH){ - gcdialog_showDialog(chmole_learnedAllGameAbilities()? 0xa87 : chmole_learnedAllLevelAbilitiesDialog(), 7, 0, actor->marker, chmole_healthRefill, NULL); + else if(arg1 == moleTable[actor->actorTypeSpecificField - MOLE_ID_TO_TABLE_SHIFT].teach_text_id || arg1 == VER_SELECT(ASSET_D39_DIALOG_BOTTLES_REFILL_HEALTH, 0xA0C, 0, 0)){ + gcdialog_showDialog(chmole_learnedAllGameAbilities()? VER_SELECT(ASSET_A87_DIALOG_BOTTLES_ALL_MOVES_LEARNED, 0x943, 0, 0) : chmole_learnedAllLevelAbilitiesDialog(), 7, 0, actor->marker, chmole_healthRefill, NULL); } else{//L802D97BC if(actor->has_met_before){ func_80347A14(1); - actor->has_met_before = false; + actor->has_met_before = FALSE; } timed_exitStaticCamera(0.0f); - if(actor->state == 5){ + if(actor->state == MOLE_STATE_5_REFRESHER){ func_8028F918(0); func_802D9600(actor); }//L802D9814 @@ -176,62 +198,59 @@ void chmole_healthRefill(ActorMarker *marker, enum asset_e arg1, s32 arg2){ }//L802D9820 } -// chmole_additionalAbilityLearnActions void chmole_additionalAbilityLearnActions(ActorMarker *marker, enum asset_e arg1, s32 arg2){ // Performs actions depending on what move is being learned Actor *actor = marker_getActor(marker); switch(arg2){ - case 1: // Stilt Stride + case MOLE_ABILITY_LEARN_ACTION_1_STILT_STRIDE: timed_setStaticCameraToNode(0.0f, 0x11); - levelSpecificFlags_set(LEVEL_FLAG_1A_UNKNOWN, true); + levelSpecificFlags_set(LEVEL_FLAG_1A_UNKNOWN, TRUE); break; - case 2: - levelSpecificFlags_set(LEVEL_FLAG_1A_UNKNOWN, false); + case MOLE_ABILITY_LEARN_ACTION_2_UNK: + levelSpecificFlags_set(LEVEL_FLAG_1A_UNKNOWN, FALSE); chmole_setStaticCamera(actor); break; - case 3: // Turbo Talon Trainer + case MOLE_ABILITY_LEARN_ACTION_3_TURBO_TALON_TRAINER: timed_setStaticCameraToNode(0.0f, 0x29); - levelSpecificFlags_set(LEVEL_FLAG_1A_UNKNOWN, true); + levelSpecificFlags_set(LEVEL_FLAG_1A_UNKNOWN, TRUE); break; - case 4: - levelSpecificFlags_set(LEVEL_FLAG_1A_UNKNOWN, false); + case MOLE_ABILITY_LEARN_ACTION_4_UNK: + levelSpecificFlags_set(LEVEL_FLAG_1A_UNKNOWN, FALSE); chmole_setStaticCamera(actor); break; - case 5: // Egg Firing + case MOLE_ABILITY_LEARN_ACTION_5_EGG_FIRING: item_adjustByDiffWithHud(ITEM_D_EGGS, 50); break; - case 6: // Flight + case MOLE_ABILITY_LEARN_ACTION_6_FLIGHT: item_adjustByDiffWithHud(ITEM_F_RED_FEATHER, 25); break; - case 7: // Wonderwing + case MOLE_ABILITY_LEARN_ACTION_7_WONDERWING: item_adjustByDiffWithHud(ITEM_10_GOLD_FEATHER, 5); break; - case 8: // Refill Health + case MOLE_ABILITY_LEARN_ACTION_8_REFILL_HEALTH: item_set(ITEM_14_HEALTH, item_getCount(ITEM_15_HEALTH_TOTAL)); break; - case 0xff: + case MOLE_ABILITY_LEARN_ACTION_FF_UNK: chmole_setStaticCamera(actor); break; } } -// chmole_learnAbility int chmole_learnAbility(Actor *this){ - s32 sp2C; + s32 teach_text_id; s32 sp28 = 0xe; - if (!EventSystem_Should(VB_OVERRIDE_MOLEHILL_ABILITY, false, this, &sp2C, &sp28)) { - // Known Ability: Refresher Dialog - if (ability_isUnlocked(moleTable[this->actorTypeSpecificField - 9].ability)) { - sp28 = 0xf; - sp2C = moleTable[this->actorTypeSpecificField - 9].refresher_text_id; - }//L802D99EC - // New Ability: Learn Dialog & Misc Actions - else { - func_80347A14(0); - this->has_met_before = true; - sp2C = moleTable[this->actorTypeSpecificField - 9].teach_text_id; - ability_unlock(moleTable[this->actorTypeSpecificField - 9].ability); - switch (moleTable[this->actorTypeSpecificField - 9].ability) { + // Known Ability: Refresher Dialog + if(ability_isUnlocked(moleTable[this->actorTypeSpecificField - MOLE_ID_TO_TABLE_SHIFT].ability)){ + sp28 = 0xf; + teach_text_id = moleTable[this->actorTypeSpecificField - MOLE_ID_TO_TABLE_SHIFT].refresher_text_id; + }//L802D99EC + // New Ability: Learn Dialog & Misc Actions + else{ + func_80347A14(0); + this->has_met_before = TRUE; + teach_text_id = moleTable[this->actorTypeSpecificField - MOLE_ID_TO_TABLE_SHIFT].teach_text_id; + ability_unlock(moleTable[this->actorTypeSpecificField - MOLE_ID_TO_TABLE_SHIFT].ability); + switch(moleTable[this->actorTypeSpecificField - MOLE_ID_TO_TABLE_SHIFT].ability){ case ABILITY_9_FLIGHT: case ABILITY_D_SHOCK_JUMP: gcsfx_playWithPitch(SFX_113_PAD_APPEARS, 0.9f, 32000); @@ -239,21 +258,20 @@ int chmole_learnAbility(Actor *this){ case ABILITY_13_1ST_NOTEDOOR: func_802FAD64(ITEM_C_NOTE); break; - } - }//L802D9A9C - } - gcdialog_showDialog(sp2C, sp28, this->position, this->marker, chmole_healthRefill, chmole_additionalAbilityLearnActions); - return true; + } + }//L802D9A9C + gcdialog_showDialog(teach_text_id, sp28, this->position, this->marker, chmole_healthRefill, chmole_additionalAbilityLearnActions); + return TRUE; } void func_802D9ADC(Actor *this){ Actor *other = subaddie_getLinkedActor(this); if(this->partnerActor && other && this->partnerActor->id == 0xB8){ - subaddie_set_state_with_direction(other, 2, 0.0001f, 1); + subaddie_set_state_with_direction(other, MOLE_STATE_2_POP_OUT_OF_MOLEHILL, 0.0001f, 1); } this->marker->propPtr->unk8_3 = 1; - anctrl_setSmoothTransition(this->anctrl, true); - subaddie_set_state_with_direction(this, 2, 0.0001f, 1); + anctrl_setSmoothTransition(this->anctrl, TRUE); + subaddie_set_state_with_direction(this, MOLE_STATE_2_POP_OUT_OF_MOLEHILL, 0.0001f, 1); actor_playAnimationOnce(this); this->unk44_31 = sfxsource_createSfxsourceAndReturnIndex(); sfxsource_setSfxId(this->unk44_31, SFX_3F9_UNKNOWN); @@ -266,16 +284,15 @@ void func_802D9ADC(Actor *this){ void chmole_Refresher(Actor *this){ // Plays the scene where Bottles gives the player a refresher on the ability. - subaddie_set_state(this, 5); + subaddie_set_state(this, MOLE_STATE_5_REFRESHER); chmole_setStaticCamera(this); func_8028F94C(2, this->position); chmole_learnAbility(this); } -// chmole_setFacingDirection void chmole_setFacingDirection(Actor *this){ // Sets the actor to always be facing the player - subaddie_set_state_with_direction(this, 3, 0.0001f, 1); + subaddie_set_state_with_direction(this, MOLE_STATE_3_EXPLAINING_ABILITY, 0.0001f, 1); actor_loopAnimation(this); } @@ -296,11 +313,10 @@ void func_802D9C90(Actor *this){ } } -// chmole_startingDialog void chmole_startingDialog(Actor *this){ // If the player knows the ability, use refresher function // Otherwise, set player's position and spawn mole - if(ability_isUnlocked(moleTable[this->actorTypeSpecificField - 9].ability)){ + if(ability_isUnlocked(moleTable[this->actorTypeSpecificField - MOLE_ID_TO_TABLE_SHIFT].ability)){ chmole_Refresher(this); } else{ @@ -314,7 +330,6 @@ void chmole_startingDialog(Actor *this){ } } -// chmole_update void chmole_update(Actor *this){ // Sets up the initial functions and state for the actor s32 sp50[6]; @@ -326,11 +341,11 @@ void chmole_update(Actor *this){ // Checks the actor's selector value is between 0x8 and 0x13 // Anything lower is a Spiral Mountain ability, and should use a different actor id - if(this->actorTypeSpecificField < 8 || this->actorTypeSpecificField >= 0x13) + if(this->actorTypeSpecificField < CH_SM_MOLE_ID_8_BRIDGE || this->actorTypeSpecificField >= CH_MOLE_ID_13_EMPTY) return; if(!this->volatile_initialized){ - this->volatile_initialized = true; + this->volatile_initialized = TRUE; marker_setFreeMethod(this->marker, func_802D9C90); if(this->initialized){ other = actorArray_findClosestActorFromActorId(this->position, ACTOR_12C_MOLEHILL, -1, &sp4C); @@ -338,7 +353,7 @@ void chmole_update(Actor *this){ if(this->partnerActor){ other = subaddie_getLinkedActor(this); if(other && this->partnerActor->id == MARKER_B8_MOLEHILL){ - subaddie_set_state(other, 1); + subaddie_set_state(other, MOLE_STATE_1_AWAITING_PLAYER); } } } @@ -349,17 +364,17 @@ void chmole_update(Actor *this){ // If actor exists and player is within radius, force trigger conversation node_prop = nodeprop_findByActorIdAndActorPosition(0x372, this); if(node_prop == NULL){ - this->unk38_0 = false; + this->unk38_0 = FALSE; } else{ - this->unk38_0 = true; + this->unk38_0 = TRUE; nodeprop_getPosition(node_prop, this->unk1C); } // Spawns molehill - __spawnQueue_add_1((GenFunction_1)chmole_spawnMolehill, (uintptr_t)this->marker); - this->marker->propPtr->unk8_3 = false; - this->marker->collidable = false; - this->initialized = true; + __spawnQueue_add_1((GenFunction_1)chmole_spawnMolehill, reinterpret_cast(uintptr_t, this->marker)); + this->marker->propPtr->unk8_3 = FALSE; + this->marker->collidable = FALSE; + this->initialized = TRUE; if(this->actorTypeSpecificField == CH_MOLE_ID_12_OPEN_NOTEDOORS){ node_prop = nodeprop_findByActorIdAndActorPosition(0x349, this); if(node_prop == NULL){ @@ -376,12 +391,12 @@ void chmole_update(Actor *this){ }//L802D9F34 controller_copyFaceButtons(0, sp50); // get face buttons press counters switch(this->state){ - case 1://L802D9F70 + case MOLE_STATE_1_AWAITING_PLAYER://L802D9F70 this->yaw_ideal = subaddie_getYawToPlayer(this); subaddie_turnToYaw(this, 4.0f); - if(func_8028F20C() && func_8028F0D4() && !func_8028EC04()){ + if(player_isStableWithExtraSteps() && player_isBanjoOrWishywashy() && !func_8028EC04()){ if( this->actorTypeSpecificField == CH_MOLE_ID_12_OPEN_NOTEDOORS - && !ability_isUnlocked(moleTable[this->actorTypeSpecificField-9].ability) + && !ability_isUnlocked(moleTable[this->actorTypeSpecificField - MOLE_ID_TO_TABLE_SHIFT].ability) && (player_movementGroup() == BSGROUP_0_NONE || player_movementGroup() == BSGROUP_8_TROT) ){ player_getPosition(sp34); @@ -400,8 +415,8 @@ void chmole_update(Actor *this){ } } break; - case 2://L802DA0A0 - this->marker->propPtr->unk8_3 = true; + case MOLE_STATE_2_POP_OUT_OF_MOLEHILL://L802DA0A0 + this->marker->propPtr->unk8_3 = TRUE; this->yaw_ideal = subaddie_getYawToPlayer(this); subaddie_turnToYaw(this, 4.0f); if( 0.0 < anctrl_getAnimTimer(this->anctrl) @@ -427,7 +442,7 @@ void chmole_update(Actor *this){ chmole_learnAbility(this); } break; - case 3://L802DA210 + case MOLE_STATE_3_EXPLAINING_ABILITY://L802DA210 this->yaw_ideal = subaddie_getYawToPlayer(this); subaddie_turnToYaw(this, 4.0f); if( ( actor_animationIsAt(this, 0.37f) @@ -456,7 +471,7 @@ void chmole_update(Actor *this){ func_8030E878(SFX_6F_BANJO_HEADSCRATCH, randf2(1.35f, 1.5f), 6000, this->position, 1250.0f, 2500.0f); } break; - case 4://L802DA400 + case MOLE_STATE_4_REENTER_MOLEHILL://L802DA400 if( 0.35 < anctrl_getAnimTimer(this->anctrl) && anctrl_getAnimTimer(this->anctrl) < 0.9 ){ @@ -473,16 +488,14 @@ void chmole_update(Actor *this){ int chmole_learnedAllSpiralMountainAbilities(void){ // Checks if the player has learned all of the Spiral Mountain abilities. - CALL_CANCELLABLE_RETURN_EVENT(OnCheckSpiralMountainAbilities) { - return ability_isUnlocked(ABILITY_F_DIVE) - && ability_isUnlocked(ABILITY_4_CLAW_SWIPE) - && ability_isUnlocked(ABILITY_C_ROLL) - && ability_isUnlocked(ABILITY_B_RATATAT_RAP) - && ability_isUnlocked(ABILITY_0_BARGE) - && ability_isUnlocked(ABILITY_A_HOLD_A_JUMP_HIGHER) - && ability_isUnlocked(ABILITY_7_FEATHERY_FLAP) - && ability_isUnlocked(ABILITY_8_FLAP_FLIP) - && ability_isUnlocked(ABILITY_5_CLIMB) - ; - } + return ability_isUnlocked(ABILITY_F_DIVE) + && ability_isUnlocked(ABILITY_4_CLAW_SWIPE) + && ability_isUnlocked(ABILITY_C_ROLL) + && ability_isUnlocked(ABILITY_B_RATATAT_RAP) + && ability_isUnlocked(ABILITY_0_BARGE) + && ability_isUnlocked(ABILITY_A_HOLD_A_JUMP_HIGHER) + && ability_isUnlocked(ABILITY_7_FEATHERY_FLAP) + && ability_isUnlocked(ABILITY_8_FLAP_FLIP) + && ability_isUnlocked(ABILITY_5_CLIMB) + ; } diff --git a/src/core2/ch/molehill.c b/src/core2/ch/molehill.c index 8a484c54c..83f010c1e 100644 --- a/src/core2/ch/molehill.c +++ b/src/core2/ch/molehill.c @@ -14,16 +14,16 @@ Actor *func_802DA560(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx); void func_802DA740(Actor *this); /*.data */ -ActorAnimationInfo D_80367E00[] = { +ActorAnimationInfo chMolehillAnimations[] = { {0x000, 0.0f}, - {0x13D, 2000000000.0f}, - {0x13D, 4.5f}, - {0x13C, 1.7f} + {ASSET_13D_ANIM_MOLEHILL_UNKNOWN, 2000000000.0f}, + {ASSET_13D_ANIM_MOLEHILL_UNKNOWN, 4.5f}, + {ASSET_13C_ANIM_MOLEHILL_UNKNOWN, 1.7f} }; -ActorInfo D_80367E20= { +ActorInfo chMolehill = { MARKER_B8_MOLEHILL, ACTOR_12C_MOLEHILL, ASSET_388_MODEL_MOLEHILL, - 0, D_80367E00, + 0, chMolehillAnimations, func_802DA740, actor_update_func_80326224, func_802DA560, 0, 0, 0.0f, 0 }; diff --git a/src/core2/ch/mumbo_sign.c b/src/core2/ch/mumbo_sign.c deleted file mode 100644 index 1944b538d..000000000 --- a/src/core2/ch/mumbo_sign.c +++ /dev/null @@ -1,26 +0,0 @@ -#include -#include "functions.h" -#include "variables.h" - -void chMumboSign_update(Actor *this); - -/* .data */ -ActorInfo D_80367530 = { MARKER_1E9_MUMBO_COST_SIGN, ACTOR_368_5_MUMBO_TOKEN_SIGN, ASSET_301_MODEL_5_MUMBO_TOKEN_SIGN, 0x0, 0x0, chMumboSign_update, actor_update_func_80326224, actor_draw, 0, 0, 0.0f, 0}; -ActorInfo D_80367554 = { MARKER_1E9_MUMBO_COST_SIGN, ACTOR_36B_10_MUMBO_TOKEN_SIGN, ASSET_302_MODEL_10_MUMBO_TOKEN_SIGN, 0x0, 0x0, chMumboSign_update, actor_update_func_80326224, actor_draw, 0, 0, 0.0f, 0}; -ActorInfo D_80367578 = { MARKER_1E9_MUMBO_COST_SIGN, ACTOR_36A_15_MUMBO_TOKEN_SIGN, ASSET_303_MODEL_15_MUMBO_TOKEN_SIGN, 0x0, 0x0, chMumboSign_update, actor_update_func_80326224, actor_draw, 0, 0, 0.0f, 0}; -ActorInfo D_8036759C = { MARKER_1E9_MUMBO_COST_SIGN, ACTOR_369_20_MUMBO_TOKEN_SIGN, ASSET_304_MODEL_20_MUMBO_TOKEN_SIGN, 0x0, 0x0, chMumboSign_update, actor_update_func_80326224, actor_draw, 0, 0, 0.0f, 0}; -ActorInfo D_803675C0 = { MARKER_1E9_MUMBO_COST_SIGN, ACTOR_36C_25_MUMBO_TOKEN_SIGN, ASSET_305_MODEL_25_MUMBO_TOKEN_SIGN, 0x0, 0x0, chMumboSign_update, actor_update_func_80326224, actor_draw, 0, 0, 0.0f, 0}; - -void chMumboSign_update(Actor *this) { - if (!this->volatile_initialized) { - if( fileProgressFlag_get(this->modelCacheIndex - ACTOR_368_5_MUMBO_TOKEN_SIGN + FILEPROG_90_PAID_TERMITE_COST) - || volatileFlag_get(VOLATILE_FLAG_1F_IN_CHARACTER_PARADE) - ) { - marker_despawn(this->marker); - } - this->volatile_initialized = true; - } - if (fileProgressFlag_get(this->modelCacheIndex - ACTOR_368_5_MUMBO_TOKEN_SIGN + FILEPROG_90_PAID_TERMITE_COST)) { - func_80326310(this); - } -} diff --git a/src/core2/ch/mumbosign.c b/src/core2/ch/mumbosign.c new file mode 100644 index 000000000..46ff261ba --- /dev/null +++ b/src/core2/ch/mumbosign.c @@ -0,0 +1,27 @@ +// BanjoDecomp: core2/mumbosign.c +#include +#include "functions.h" +#include "variables.h" + +void chMumboSign_update(Actor *this); + +/* .data */ +ActorInfo chMumboSign5 = { MARKER_1E9_MUMBO_COST_SIGN, ACTOR_368_5_MUMBO_TOKEN_SIGN, ASSET_301_MODEL_5_MUMBO_TOKEN_SIGN, 0x0, 0x0, chMumboSign_update, actor_update_func_80326224, actor_draw, 0, 0, 0.0f, 0}; +ActorInfo chMumboSign10 = { MARKER_1E9_MUMBO_COST_SIGN, ACTOR_36B_10_MUMBO_TOKEN_SIGN, ASSET_302_MODEL_10_MUMBO_TOKEN_SIGN, 0x0, 0x0, chMumboSign_update, actor_update_func_80326224, actor_draw, 0, 0, 0.0f, 0}; +ActorInfo chMumboSign15 = { MARKER_1E9_MUMBO_COST_SIGN, ACTOR_36A_15_MUMBO_TOKEN_SIGN, ASSET_303_MODEL_15_MUMBO_TOKEN_SIGN, 0x0, 0x0, chMumboSign_update, actor_update_func_80326224, actor_draw, 0, 0, 0.0f, 0}; +ActorInfo chMumboSign20 = { MARKER_1E9_MUMBO_COST_SIGN, ACTOR_369_20_MUMBO_TOKEN_SIGN, ASSET_304_MODEL_20_MUMBO_TOKEN_SIGN, 0x0, 0x0, chMumboSign_update, actor_update_func_80326224, actor_draw, 0, 0, 0.0f, 0}; +ActorInfo chMumboSign25 = { MARKER_1E9_MUMBO_COST_SIGN, ACTOR_36C_25_MUMBO_TOKEN_SIGN, ASSET_305_MODEL_25_MUMBO_TOKEN_SIGN, 0x0, 0x0, chMumboSign_update, actor_update_func_80326224, actor_draw, 0, 0, 0.0f, 0}; + +void chMumboSign_update(Actor *this) { + if (!this->volatile_initialized) { + if( fileProgressFlag_get(this->modelCacheIndex - ACTOR_368_5_MUMBO_TOKEN_SIGN + FILEPROG_90_PAID_TERMITE_COST) + || volatileFlag_get(VOLATILE_FLAG_1F_IN_CHARACTER_PARADE) + ) { + marker_despawn(this->marker); + } + this->volatile_initialized = true; + } + if (fileProgressFlag_get(this->modelCacheIndex - ACTOR_368_5_MUMBO_TOKEN_SIGN + FILEPROG_90_PAID_TERMITE_COST)) { + func_80326310(this); + } +} diff --git a/src/core2/ch/mumbotoken.c b/src/core2/ch/mumbotoken.c index 51242af9c..ddcb1ba29 100644 --- a/src/core2/ch/mumbotoken.c +++ b/src/core2/ch/mumbotoken.c @@ -7,14 +7,14 @@ typedef struct { enum mumbotoken_e uid; }ActorLocal_MumboToken; -void func_802E0B10(Actor *this); +void chMumboToken_update(Actor *this); enum mumbotoken_e func_802E0CB0(Actor *this); /* .data */ - ActorInfo D_803685A0 = { + ActorInfo chMumboToken = { MARKER_39_MUMBO_TOKEN, ACTOR_2D_MUMBO_TOKEN, ASSET_41A_SPRITE_MUMBO_TOKEN, - 0, NULL, - func_802E0B10, actor_update_func_80326224, fxTouchSparkle_draw, + 0, NULL, + chMumboToken_update, actor_update_func_80326224, fxTouchSparkle_draw, 2000, 0, 0.0f, 0 }; @@ -57,7 +57,7 @@ enum mumbotoken_e func_802E0A90(Actor *this){ } } -void func_802E0B10(Actor *this){ +void chMumboToken_update(Actor *this){ ActorLocal_MumboToken *local; f32 sp28[3]; diff --git a/src/core2/ch/shock_jumppad.c b/src/core2/ch/shock_jumppad.c index 2b53f347a..cd127c9ae 100644 --- a/src/core2/ch/shock_jumppad.c +++ b/src/core2/ch/shock_jumppad.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_43A40.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/ch/snacker.c b/src/core2/ch/snacker.c index 1191d59f6..63d518b95 100644 --- a/src/core2/ch/snacker.c +++ b/src/core2/ch/snacker.c @@ -80,7 +80,7 @@ static void __chsnacker_start_dialog(Actor *this) { text_index = mapSpecificFlags_getN(8, 3); if( !this->has_met_before ) { if(text_index < 4) { - if(gcdialog_showDialog(ASSET_A1B_DIALOG_SNACKER_SPAWNED_1 + text_index, 0, NULL, NULL, NULL, NULL)){ + if(gcdialog_showDialog(VER_SELECT(ASSET_A1B_DIALOG_SNACKER_SPAWNED_1, 0x91B, 0, 0) + text_index, 0, NULL, NULL, NULL, NULL)){ text_index++; mapSpecificFlags_setN(8, text_index, 3); this->has_met_before = true; @@ -195,7 +195,7 @@ void chsnacker_update(Actor *this) { this->unk154 = 0x085E0000; marker_setCollisionScripts(this->marker, __chsnacker_ow, func_802E1010, __chsnacker_die); } - _player_getPosition(player_position); + playerPosition_get(player_position); controller_state = snackerctl_get_state(); if(func_802E0DC0(this->position) || ((controller_state != SNACKER_CTL_STATE_1_RBB) && (controller_state != SNACKER_CTL_STATE_2_TTC))) { @@ -330,7 +330,7 @@ void chSnacker_spawn(void) { f32 sp20[3]; - _player_getPosition(spawn_position); + playerPosition_get(spawn_position); if (volatileFlag_get(VOLATILE_FLAG_C1_IN_FINAL_CHARACTER_PARADE) != 0) { nodeprop_getPosition(nodeprop_findByActorIdAndPosition_f32(ACTOR_3CB_UNKNOWN, spawn_position), spawn_position); } diff --git a/src/core2/ch/snowball.c b/src/core2/ch/snowball.c index fefe9928d..3d82557ef 100644 --- a/src/core2/ch/snowball.c +++ b/src/core2/ch/snowball.c @@ -160,7 +160,7 @@ void chSnowball_update(Actor *this) { } break; case 2: - this->marker->unk40_22 = NOT(func_8028F170()); + this->marker->unk40_22 = NOT(player_isInFirstPersonView()); this->velocity[0] *= 0.7; this->velocity[1] *= 0.7; this->velocity[2] *= 0.7; diff --git a/src/core2/ch/snowman.c b/src/core2/ch/snowman.c index 7bb4ce888..9b152afc8 100644 --- a/src/core2/ch/snowman.c +++ b/src/core2/ch/snowman.c @@ -49,8 +49,8 @@ Actor *chSnowman_draw(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx){ actor = marker_getActor(marker); local = (ActorLocal_chSirSlush *)&actor->local; - func_8033A45C(1, local->unk9); - func_8033A45C(2, local->unkA); + modelRender_setAppendageVisibility(1, local->unk9); + modelRender_setAppendageVisibility(2, local->unkA); return actor_draw(marker, gfx, mtx, vtx); } diff --git a/src/core2/ch/trainers.c b/src/core2/ch/trainers.c index 29635e1bc..da9df47f8 100644 --- a/src/core2/ch/trainers.c +++ b/src/core2/ch/trainers.c @@ -82,8 +82,8 @@ void chtrainers_update(Actor *this){ && !volatileFlag_get(VOLATILE_FLAG_F_HAS_MEET_TURBO_SHOES) && player_getTransformation() == TRANSFORM_1_BANJO ){ - if(gcdialog_showDialog(0xda4, 0, NULL, NULL, NULL, NULL)){ - volatileFlag_set(VOLATILE_FLAG_F_HAS_MEET_TURBO_SHOES, true); + if(gcdialog_showDialog(VER_SELECT(0xda4, 0xA22, 0, 0), 0, NULL, NULL, NULL, NULL)){ + volatileFlag_set(VOLATILE_FLAG_F_HAS_MEET_TURBO_SHOES, TRUE); } }//L802CA620 _chtrainers_802CA378(this, sp2C); diff --git a/src/core2/ch/wadingboots.c b/src/core2/ch/wadingboots.c index 0499263ce..319620ba9 100644 --- a/src/core2/ch/wadingboots.c +++ b/src/core2/ch/wadingboots.c @@ -9,16 +9,16 @@ Actor *chwadingboots_draw(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx); void chwadingboots_update(Actor *this); /* .data */ -ActorAnimationInfo D_80367A00[] = { +ActorAnimationInfo chWadingBootsAnimations[] = { {ASSET_67_ANIM_WADINGBOOTS_WALK, 0.7f}, {ASSET_67_ANIM_WADINGBOOTS_WALK, 0.7f}, {ASSET_67_ANIM_WADINGBOOTS_WALK, 0.7f}, {ASSET_67_ANIM_WADINGBOOTS_WALK, 0.7f}, }; -ActorInfo D_80367A20 = { +ActorInfo chWadingBoots = { MARKER_11_WADING_BOOTS, ACTOR_65_WADING_BOOTS, ASSET_366_MODEL_WADING_BOOTS, - 0x0, D_80367A00, + 0x0, chWadingBootsAnimations, chwadingboots_update, actor_update_func_80326224, chwadingboots_draw, 0, 0, 0.0f, 0 }; @@ -70,8 +70,8 @@ void chwadingboots_update(Actor *this){ if(!subaddie_playerIsWithinSphereAndActive(this, 250)) break; if(player_getTransformation() != TRANSFORM_1_BANJO) break; - if(gcdialog_showDialog(ASSET_DA5_DIALOG_WADINGBOOTS_MEET, 0, NULL, NULL, NULL, NULL)){ - volatileFlag_set(VOLATILE_FLAG_10_HAS_MEET_WADING_BOOTS, true); + if(gcdialog_showDialog(VER_SELECT(ASSET_DA5_DIALOG_WADINGBOOTS_MEET, 0xA23, 0, 0), 0, NULL, NULL, NULL, NULL)){ + volatileFlag_set(VOLATILE_FLAG_10_HAS_MEET_WADING_BOOTS, TRUE); } break; diff --git a/src/core2/checksums.c b/src/core2/checksums.c new file mode 100644 index 000000000..15652a8f4 --- /dev/null +++ b/src/core2/checksums.c @@ -0,0 +1,7 @@ +// BanjoDecomp: core2/checksums.c +#include +#include "checksums.h" + +// !! THIS FILE MUST BE LINKED FIRST FOR THIS OVERLAY !! + +/* bss */ struct overlay_checksums_s gChecksumsCore2; diff --git a/src/core2/climb.c b/src/core2/climb.c index deda2e7c5..d1a6e3015 100644 --- a/src/core2/climb.c +++ b/src/core2/climb.c @@ -7,30 +7,29 @@ /* .bss */ f32 climbPoleBottom[3]; f32 climbPoleTop[3]; -f32 climbRadius;//climbRadius +f32 climbRadius; f32 D_8037C580[3]; -f32 D_8037C58C; -u8 D_8037C590; //bool climbing +f32 climbRegrabWaitTime; +u8 isClimbingBool; u8 D_8037C591; /* .code */ -void climbClear(void){ //climbClear +void climb_clear(void){ ml_vec3f_clear(climbPoleBottom); ml_vec3f_clear(climbPoleTop); - D_8037C590 = 0; - D_8037C58C = 0.0f; - + isClimbingBool = 0; + climbRegrabWaitTime = 0.0f; } -void climbGetBottom(f32 dst[3]){ //climbGetBottom +void climb_getBottom(f32 dst[3]){ ml_vec3f_copy(dst, climbPoleBottom); } -f32 climbGetBottomY(void){ //climbGetBottomY +f32 climb_getBottomY(void){ return climbPoleBottom[1]; } -f32 climbGetRadius(void){ //climbGetRadius +f32 climb_getRadius(void){ return climbRadius; } @@ -38,32 +37,32 @@ u8 func_8029825C(void){ //climb_2098250 return D_8037C591; } -f32 climbGetTopY(void){ //climbGetTopY +f32 climb_getTopY(void){ return climbPoleTop[1]; } -void climbSet(f32 bottom[3], f32 top[3], f32 radius, u32 arg3){ - if( !(D_8037C58C > 0.0f) || D_8037C580[0] != bottom[0] +void climb_set(f32 bottom[3], f32 top[3], f32 radius, u32 arg3){ + if( !(climbRegrabWaitTime > 0.0f) || D_8037C580[0] != bottom[0] || D_8037C580[1] != bottom[1] || D_8037C580[2] != bottom[2]) { ml_vec3f_copy(climbPoleBottom, bottom); ml_vec3f_copy(climbPoleTop, top); climbRadius = radius; D_8037C591 = arg3; - D_8037C590 = 1; + isClimbingBool = 1; } } -void func_80298344(void){ //climbUpdateRegrab - D_8037C58C = ml_max_f(D_8037C58C - time_getDelta(), 0.0f); - if(D_8037C590 && ability_hasLearned(ABILITY_5_CLIMB)){ +void climb_regrab_update(void){ + climbRegrabWaitTime = ml_max_f(climbRegrabWaitTime - time_getDelta(), 0.0f); + if(isClimbingBool && ability_hasLearned(ABILITY_5_CLIMB)){ bs_checkInterrupt(BS_INTR_C_CLIMB); } - D_8037C590 = 0; + isClimbingBool = 0; } -void climbRelease(void){ //climbRelease - D_8037C590 = 0; +void climb_release(void){ + isClimbingBool = 0; ml_vec3f_copy(D_8037C580, climbPoleBottom); - D_8037C58C = 0.6f; + climbRegrabWaitTime = 0.6f; } diff --git a/src/core2/collision/climbsurface.c b/src/core2/collision/climbsurface.c index 1175fa005..f820a626f 100644 --- a/src/core2/collision/climbsurface.c +++ b/src/core2/collision/climbsurface.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_C4B0.c #include #include "core1/core1.h" #include "functions.h" @@ -61,8 +62,8 @@ s32 D_8037C284; /* .code */ void func_80293440(void){ f32 sp34[3]; - f32 bottomY = climbGetBottomY(); - f32 topY = climbGetTopY(); + f32 bottomY = climb_getBottomY(); + f32 topY = climb_getTopY(); f32 sp28; f32 diff; @@ -72,7 +73,7 @@ void func_80293440(void){ if(D_8037C218[1] < bottomY) D_8037C218[1] = bottomY; - climbGetBottom(sp34); + climb_getBottom(sp34); func_80257F18(D_8037C218, sp34, &sp28); diff = mlDiffDegF(sp28, yaw_get()); diff = mlAbsF(diff); @@ -297,7 +298,7 @@ void func_80293F0C(void){ f32 sp38[3]; f32 sp2C[3]; - _player_getPosition(sp44); + playerPosition_get(sp44); if(gsworld_getMap() == MAP_34_RBB_ENGINE_ROOM && ml_vec3f_inside_box_f(sp44, -900.0f, -940.0f, 200.0f, 900.0f, 940.0f, 800.0f)){ func_8031C5FC(D_8037C200, 150.0f); } else{ @@ -316,7 +317,7 @@ void func_80293F0C(void){ case 1: case 3: case 4: - _player_getPosition(D_8037C218); + playerPosition_get(D_8037C218); playerPosition_func_80298504(D_8037C228); ml_vec3f_diff_copy(D_8037C238, D_8037C218, D_8037C228); if ((D_8037C274 == 3) && func_8031C594(D_8037C200) && (D_8037C218[1] > (floor_getYPosition(D_8037C200) - 70.0f))) { @@ -325,15 +326,15 @@ void func_80293F0C(void){ baphysics_set_vertical_velocity(1.0f); } func_80293668(); - player_setPosition(D_8037C218); + playerPosition_set(D_8037C218); break; case 5: - _player_getPosition(D_8037C218); + playerPosition_get(D_8037C218); playerPosition_func_80298504(D_8037C228); func_80293668(); func_80293440(); - player_setPosition(D_8037C218); + playerPosition_set(D_8037C218); break; case 2: @@ -364,7 +365,7 @@ void func_80293F0C(void){ } if (D_8037C27F) { - player_setPosition(sp44); + playerPosition_set(sp44); } D_8037C27A = 0; @@ -375,7 +376,7 @@ void func_80293F0C(void){ D_8037C280 = 0; } playerPosition_func_80298504(sp2C); - _player_getPosition(sp38); + playerPosition_get(sp38); ml_vec3f_diff_copy(D_8037C268, sp38, sp2C); if (D_8037C204) { collisionTri_copy(&D_8037C208, D_8037C204); @@ -412,7 +413,7 @@ void func_80294390(void) { } f32 func_80294404(void){ - return player_getYPosition() - floor_getXPosition(D_8037C200); + return playerPosition_getY() - floor_getXPosition(D_8037C200); } f32 func_80294438(void){ diff --git a/src/core2/collision/dispatch.c b/src/core2/collision/dispatch.c index bf7c6ddc4..a2a5470ca 100644 --- a/src/core2/collision/dispatch.c +++ b/src/core2/collision/dispatch.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_999A0.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/collision/enemy.c b/src/core2/collision/enemy.c index 1d275daca..7c022dcc1 100644 --- a/src/core2/collision/enemy.c +++ b/src/core2/collision/enemy.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_45310.c #include #include "core1/core1.h" #include "functions.h" @@ -28,7 +29,7 @@ Actor *func_802CCA7C(ActorMarker *, Gfx **, Mtx **, Vtx **); void func_802CCC5C(Actor *this); /* .data */ -ActorInfo D_80367130 = { +ActorInfo chBuzzbomb = { MARKER_C2_BUZZBOMB, ACTOR_134_BUZZBOMB, ASSET_3ED_MODEL_BUZZBOMB, 0, NULL, func_802CCC5C, NULL, func_802CCA7C, @@ -434,7 +435,7 @@ void func_802CCC5C(Actor *this) { if (this->state == 1) { player_getPosition(sp8C); viewport_getPosition_vec3f(sp80); - viewport_getLookbk_vector(sp74); + viewport_getLookVector(sp74); sp5C[0] = this->position[0] - sp80[0]; sp5C[1] = this->position[1] - sp80[1]; sp5C[2] = this->position[2] - sp80[2]; diff --git a/src/core2/collision/filter.c b/src/core2/collision/filter.c index ffa350843..0c98679d4 100644 --- a/src/core2/collision/filter.c +++ b/src/core2/collision/filter.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_C9F00.c #include "functions.h" #include "variables.h" #include @@ -56,7 +57,7 @@ extern void func_80351FE0(void *, Struct68s *); void func_80351E60(Struct6Bs *, Struct68s *, f32); extern void chTumblar_update(void *, Struct68s *, f32); extern void func_8038B790(void *, Struct68s *, f32); -extern void CC_func_80387A40(void *, Struct68s *, f32); +extern void chZubbaDocile_update(void *, Struct68s *, f32); extern void func_80352114(void *, Struct68s *, f32); Struct_Core2_C9F00_0 D_803725F4[] = { @@ -65,14 +66,14 @@ Struct_Core2_C9F00_0 D_803725F4[] = { {chTumblar_init, chTumblar_update}, { NULL, NULL}, { NULL, func_8038B790}, - {func_80387940, CC_func_80387A40}, - {CC_func_80387960, CC_func_80387A40}, - {func_80387980, CC_func_80387A40}, - {func_803879A0, CC_func_80387A40}, - {func_803879C0, CC_func_80387A40}, - {CC_func_803879E0, CC_func_80387A40}, - {CC_func_80387A00, CC_func_80387A40}, - {CC_func_80387A20, CC_func_80387A40}, + {func_80387940, chZubbaDocile_update}, + {CC_func_80387960, chZubbaDocile_update}, + {func_80387980, chZubbaDocile_update}, + {func_803879A0, chZubbaDocile_update}, + {func_803879C0, chZubbaDocile_update}, + {CC_func_803879E0, chZubbaDocile_update}, + {CC_func_80387A00, chZubbaDocile_update}, + {CC_func_80387A20, chZubbaDocile_update}, {func_80351FE0, func_80352114} }; diff --git a/src/core2/collision/geometrybounds.c b/src/core2/collision/geometrybounds.c index 979a927bb..31e68f968 100644 --- a/src/core2/collision/geometrybounds.c +++ b/src/core2/collision/geometrybounds.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_B6640.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/collision/hitboxdata.c b/src/core2/collision/hitboxdata.c index c28adc8b6..8f2993899 100644 --- a/src/core2/collision/hitboxdata.c +++ b/src/core2/collision/hitboxdata.c @@ -1,14 +1,31 @@ +// BanjoDecomp: core2/code_B62B0.c #include #include "functions.h" #include "variables.h" +#include "version.h" -//Struct5Cs = u16 packed bitwise as (aaaa bbcc cdde eeff) +//CollisionParams = u16 packed bitwise as (aaaa bbcc cdde eeff) typedef struct{ - u16 unk0; - u16 unk2; //Struct5Cs - u16 unk4[11]; //Struct5Cs -} Struct_core2_B62B0_0; + u16 markerId; + u16 collisionUnion; + union{ + u16 collisionTypes[11]; + struct{ + u16 activeClawSwipe; + u16 activeRoll; + u16 jumpOnTop; + u16 activeRatATat; + u16 activeBeakBarge; + u16 activeBeakBuster; + u16 activeBeakBomb; + u16 activeEggFiring; + u16 activeWonderwing; + u16 activeCrocBite; + u16 otherContact; + }; + }; +} CollisionTable; typedef struct{ s32 (*unk0)(ActorMarker *, ActorMarker *); @@ -16,194 +33,202 @@ typedef struct{ } Struct_core2_B62B0_1; /* .data */ -Struct_core2_B62B0_0 D_80370AC0[0xBB] = { - {MARKER_12A_TOPPER_THE_CARROT_A, 0x0000, {0x0904, 0x8504, 0x8504, 0x0000, 0x8504, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x7484}}, - {MARKER_129_BAWL_THE_ONION_A, 0x0000, {0x0504, 0x0984, 0x8504, 0x0000, 0x8504, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x7484}}, - {MARKER_128_COLLYWOBBLE_THE_CAULIFLOWER_A, 0x0000, {0x0000, 0x0000, 0x8404, 0x0984, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x7404}}, - {MARKER_135_QUARRIE, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0804, 0x0804, 0x0000, 0x0804, 0x0804, 0x0000, 0x0000}}, - {MARKER_1E6_TOPPER_THE_CARROT_B, 0x0001, {0x0904, 0x0984, 0x8100, 0x0984, 0x0A04, 0x0A04, 0x0000, 0x0984, 0x0A04, 0x0000, 0x1020}}, - {MARKER_1E7_BAWL_THE_ONION_B, 0x0001, {0x0904, 0x0984, 0x8100, 0x0984, 0x0A04, 0x0A04, 0x0000, 0x0984, 0x0A04, 0x0000, 0x1020}}, - {MARKER_1E8_COLLYWOBBLE_THE_CAULIFLOWER_B, 0x0001, {0x0904, 0x0984, 0x8100, 0x0984, 0x0A04, 0x0A04, 0x0000, 0x0984, 0x0A04, 0x0000, 0x1020}}, - {MARKER_1EA_GRUNTLING_RED, 0x0001, {0x0A08, 0x0984, 0x8100, 0x0984, 0x0A04, 0x0A04, 0x0A84, 0x0984, 0x0A04, 0x0984, 0x2020}}, - {MARKER_295_GRUNTLING_BLUE, 0x0001, {0x0A0C, 0x8988, 0x8100, 0x0984, 0x0A04, 0x0A04, 0x0A84, 0x0988, 0x0A04, 0x0000, 0x2020}}, - {MARKER_1F1_GRUNTLING_BLACK, 0x0001, {0x0A10, 0x898C, 0x8100, 0x8988, 0x8A08, 0x8A08, 0x0A84, 0x098C, 0x0A04, 0x0000, 0x2020}}, - {0x1E0, 0x0000, {0x7000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x0004, 0x8000, 0x0000, 0x7000}}, - {0x005, 0x0001, {0x0904, 0x0984, 0x8100, 0x0984, 0x0A04, 0x0A04, 0x0A84, 0x0984, 0x0A04, 0x0000, 0x1020}}, - {0x004, 0x0001, {0x0A88, 0x0984, 0x8100, 0x0984, 0x0A04, 0x0A04, 0x0A84, 0x0988, 0x0A04, 0x0000, 0x1020}}, - {0x003, 0x0000, {0x0914, 0x990C, 0x2020, 0x8908, 0x8908, 0x8908, 0x0A04, 0x0914, 0x0904, 0x0000, 0x4020}}, - {0x29E, 0x0000, {0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0xA000, 0x0004, 0x8000, 0x0000, 0x8000}}, - {MARKER_7_CONGA, 0x0000, {0x0000, 0x0000, 0x3020, 0x9000, 0x0000, 0x0000, 0x0000, 0x0804, 0x9000, 0x0000, 0x3020}}, - {MARKER_13_SNIPPET, 0x0002, {0x0504, 0x7584, 0x8100, 0x7584, 0x7604, 0x0A04, 0x0A84, 0x0504, 0x0A04, 0x0000, 0x1020}}, - {0x16B, 0x0001, {0x0904, 0x0984, 0x8100, 0x0984, 0x0A04, 0x0A04, 0x0A84, 0x0904, 0x0A04, 0x0000, 0x1020}}, - {MARKER_DD_BLACK_SNIPPET, 0x0002, {0x060C, 0x7588, 0x8100, 0x7588, 0x7608, 0x8604, 0x0A84, 0x050C, 0x0A04, 0x0000, 0x1020}}, - {0x0DE, 0x0001, {0x0908, 0x0988, 0x8100, 0x0984, 0x0A04, 0x0A04, 0x0A84, 0x090C, 0x0A04, 0x0000, 0x1020}}, - {0x015, 0x0001, {0x0A88, 0x7988, 0x8100, 0x0984, 0x0A04, 0x0A04, 0x0A84, 0x0988, 0x0A04, 0x0000, 0x1424}}, - {0x065, 0x0804, {0x5040, 0x5040, 0x5040, 0x5040, 0x5040, 0x5040, 0x5040, 0x090E, 0x0804, 0x0000, 0x5844}}, - {0x014, 0x0003, {0x3020, 0x3020, 0x3020, 0x9080, 0x9080, 0x9080, 0x0A84, 0x0914, 0x0904, 0x0000, 0x3020}}, - {MARKER_A5_NIPPER, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0404, 0x0000, 0x0000, 0x5020}}, - {0x16C, 0x0000, {0x0000, 0x0000, 0x0000, 0xB804, 0x0000, 0x0000, 0x0000, 0x0404, 0xB804, 0x0000, 0x5020}}, - {MARKER_A4_LOCKUP_SLOW, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x2020}}, - {MARKER_F6_LOCKUP_MEDIUM, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x2020}}, - {MARKER_F7_LOCKUP_FAST, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x2020}}, - {0x0029, 0x0001, {0x0804, 0x0804, 0x2020, 0x0804, 0x0804, 0x0804, 0x0804, 0x0808, 0x0804, 0x0000, 0x3444}}, - {0x01CF, 0x0001, {0x0804, 0x0804, 0x1020, 0x0804, 0x0804, 0x0804, 0x0804, 0x0808, 0x0804, 0x0000, 0x1424}}, - {0x01A6, 0x0000, {0x3020, 0x3020, 0x3020, 0x3020, 0x3020, 0x3020, 0x3020, 0x0000, 0x0000, 0x3020, 0x3020}}, - {MARKER_1A7_CLANKER_WHIPCRACK, 0x0804, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x3020}}, - {MARKER_69_CHUMP_FISH, 0x0001, {0x2020, 0x2020, 0x2020, 0x0984, 0x0A04, 0x0A04, 0x0A84, 0x0988, 0x0A04, 0x0000, 0x2020}}, - {MARKER_173_CHUMP_FISH_2, 0x0001, {0x2020, 0x2020, 0x2020, 0x0984, 0x0A04, 0x0A04, 0x0A84, 0x0988, 0x0A04, 0x0000, 0x4020}}, - {MARKER_C1_FLIBBIT_RED, 0x0000, {0x0A09, 0x0985, 0x8100, 0x0985, 0x0A05, 0x0A05, 0x0000, 0x0989, 0x0A05, 0x0986, 0x2020}}, - {MARKER_C5_FLIBBIT_YELLOW, 0x0000, {0x0A0D, 0x8989, 0x8100, 0x8989, 0x7A09, 0x7A09, 0x0000, 0x098D, 0x0A05, 0x0986, 0x2020}}, - {MARKER_C2_BUZZBOMB, 0x0000, {0x0805, 0x0805, 0x8000, 0x0805, 0x0805, 0x0805, 0x0000, 0x0805, 0x0805, 0x0806, 0x3020}}, - {MARKER_B1_SIR_SLUSH, 0x0000, {0x7000, 0x8000, 0x8000, 0x8000, 0x9000, 0x9000, 0x9000, 0x0004, 0x8000, 0x0000, 0x7000}}, - {0x0287, 0x0001, {0x7000, 0x8000, 0x8000, 0x8000, 0x9000, 0x9000, 0x8804, 0x0004, 0x8000, 0x0000, 0x7000}}, - {MARKER_205_TWINKLY_MUNCHER, 0x0000, {0x0000, 0x0000, 0x0000, 0x0404, 0x0404, 0x0404, 0x0000, 0x0408, 0x0404, 0x0000, 0x0000}}, - {MARKER_245_XMAS_TREE_EGG_TOLL, 0x0000, {0x3004, 0x3004, 0x3004, 0x3004, 0x3004, 0x2004, 0x3004, 0x0000, 0x0000, 0x3004, 0x3004}}, - {MARKER_250_ICECUBE_A, 0x0000, {0x0A90, 0x8988, 0x8100, 0x0984, 0x0A04, 0x0A04, 0x0A84, 0x0910, 0x0A04, 0x0984, 0x3104}}, - {MARKER_25F_ICECUBE_B, 0x0001, {0x0A88, 0x0984, 0x8100, 0x0984, 0x0A04, 0x0A04, 0x0A84, 0x0908, 0x0A04, 0x0984, 0x3104}}, - {0x00AD, 0x0001, {0x0A10, 0x998C, 0x0020, 0x9988, 0x8A08, 0x0A04, 0x0A84, 0x0914, 0x0A04, 0x0000, 0x5124}}, - {MARKER_253_SCARAB_BEETLE, 0x0001, {0x0904, 0x0984, 0x8100, 0x0984, 0x0A04, 0x0A04, 0x0A84, 0x0984, 0x0A04, 0x0000, 0x3020}}, - {MARKER_219_MUMMUM, 0x0001, {0x0588, 0x7584, 0x8100, 0x7584, 0x7604, 0x7604, 0x0684, 0x0588, 0x0A04, 0x0000, 0x2020}}, - {MARKER_298_MUMMUM_BALL, 0x0000, {0x7000, 0x8000, 0x7000, 0x8000, 0x9000, 0x9000, 0xB000, 0x0004, 0x0A04, 0x0000, 0x2020}}, - {MARKER_218_LIMBO, 0x0001, {0x0588, 0x7584, 0x8100, 0x7584, 0x7604, 0x7604, 0x0684, 0x050C, 0x0A04, 0x0000, 0x2020}}, - {MARKER_99_TEEHEE, 0x0001, {0x2020, 0x2020, 0x2020, 0x2020, 0x2020, 0x2020, 0x0000, 0x0000, 0x0804, 0x0000, 0x2424}}, - {MARKER_296_TEEHEE_PURPLE, 0x0000, {0x2020, 0x2020, 0x2020, 0x2020, 0x2020, 0x2020, 0x0000, 0x0000, 0x0804, 0x0000, 0x2424}}, - {MARKER_96_GRAVESTONE, 0x0001, {0x0A10, 0x890C, 0x8100, 0x8908, 0x8988, 0x8988, 0x0A84, 0x0914, 0x0984, 0x0000, 0x3024}}, - {MARKER_297_GIANT_GRAVESTONE, 0x0001, {0x0A10, 0x890C, 0x8100, 0x8908, 0x8988, 0x8988, 0x0A84, 0x0914, 0x0984, 0x0000, 0x3024}}, - {MARKER_127_BAT, 0x0001, {0x0804, 0x0804, 0x8100, 0x0804, 0x0804, 0x0804, 0x0804, 0x0804, 0x0804, 0x0000, 0x1424}}, - {MARKER_254_PORTRAIT_CHOMPA_A, 0x0001, {0x0804, 0x0804, 0x2020, 0x0804, 0x0804, 0x0804, 0x0804, 0x080C, 0x0804, 0x0000, 0x3444}}, - {MARKER_1D1_PORTRAIT_CHOMPA_B, 0x0001, {0x0804, 0x0804, 0x1020, 0x0804, 0x0804, 0x0804, 0x0804, 0x080C, 0x0804, 0x0000, 0x1424}}, - {MARKER_21A_SEAMAN_GRUBLIN, 0x0001, {0x0A08, 0x8988, 0x8100, 0x0984, 0x0A04, 0x0A04, 0x0000, 0x0988, 0x0A04, 0x0000, 0x2020}}, - {MARKER_C9_FLOTSAM, 0x0001, {0x0808, 0x8808, 0x8000, 0x0804, 0x0804, 0x0804, 0x0000, 0x0808, 0x0804, 0x0000, 0x3424}}, - {MARKER_1B7_BOOM_BOX, 0x0000, {0x0804, 0x0804, 0x0804, 0x0804, 0x0804, 0x0804, 0x0000, 0x098C, 0x0404, 0x0804, 0x5000}}, - {MARKER_2E_GRIMLET, 0x0004, {0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x0000, 0x0000, 0x8000, 0x3000, 0x3004}}, - {MARKER_1A1_BOSS_BOOM_BOX_LARGEST, 0x0000, {0x8020, 0x8884, 0x8020, 0x8884, 0x9884, 0x9884, 0x0804, 0x0904, 0x0884, 0x0000, 0x4020}}, - {MARKER_1A2_BOSS_BOOM_BOX_LARGE, 0x0000, {0x8020, 0x8904, 0x8020, 0x8904, 0x9904, 0x9904, 0x0804, 0x0984, 0x0904, 0x0000, 0x4020}}, - {MARKER_1A3_BOSS_BOOM_BOX_MEDIUM, 0x0000, {0x9020, 0x9984, 0x9020, 0x9984, 0x9984, 0x9984, 0x0804, 0x0A04, 0x0984, 0x0000, 0x3020}}, - {MARKER_1A4_BOSS_BOOM_BOX_SMALL, 0x0000, {0x9020, 0x9A04, 0x9020, 0x9A04, 0x9A04, 0x9A04, 0x0804, 0x0A84, 0x0A04, 0x0000, 0x3020}}, - {MARKER_185_RBB_REAR_PROPELLER, 0x5060, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x5060}}, - {MARKER_191_ENGINE_ROOM_PROPELLOR_1, 0x0000, {0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x0000, 0x8000, 0x0000, 0x2000}}, - {MARKER_192_ENGINE_ROOM_PROPELLOR_2, 0x0000, {0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x0000, 0x8000, 0x0000, 0x2000}}, - {MARKER_193_ENGINE_ROOM_PROPELLOR_3, 0x0000, {0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x0000, 0x8000, 0x0000, 0x2000}}, - {MARKER_1E2_GRUBLIN_HOOD, 0x0001, {0x0A08, 0x8988, 0x8100, 0x0984, 0x0A04, 0x0A04, 0x0A84, 0x0988, 0x0A04, 0x0000, 0x2020}}, - {MARKER_1C5_WHIPCRACK, 0x0001, {0x3020, 0x3020, 0x3020, 0x3020, 0x3020, 0x3020, 0x3020, 0x080C, 0x0804, 0x0000, 0x3020}}, - {MARKER_1F9_SNARE_BEAR, 0x0000, {0x2040, 0x2040, 0x2040, 0x2040, 0x2040, 0x2040, 0x2040, 0x0000, 0x0000, 0x0000, 0x2040}}, - {MARKER_1B2_CLUCKER_A, 0x0001, {0x0804, 0x0804, 0x2020, 0x0804, 0x0804, 0x0804, 0x0804, 0x0810, 0x0804, 0x0000, 0x3444}}, - {MARKER_1D0_CLUCKER_B, 0x0001, {0x0804, 0x0804, 0x1020, 0x0804, 0x0804, 0x0804, 0x0804, 0x0810, 0x0804, 0x0000, 0x1424}}, - {MARKER_1B4_EEYRIE_BABY, 0x8000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8000}}, - {0x000E, 0x0001, {0x3000, 0x7504, 0x7080, 0x7504, 0x7584, 0x0804, 0x0804, 0x0488, 0x0804, 0x0000, 0x1020}}, - {0x01AC, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0804, 0x0804, 0x0000, 0x0000, 0x0000, 0x0000}}, - {MARKER_256_FIRE_FX, 0x0000, {0x2020, 0x2020, 0x2020, 0x2020, 0x2020, 0x2020, 0x2020, 0x0000, 0x0000, 0x2020, 0x2020}}, - {MARKER_C_ORANGE_PROJECTILE, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x2424}}, - {MARKER_DB_BURIED_TREASURE, 0x0000, {0x7000, 0x7000, 0x7000, 0x0804, 0x0804, 0x0804, 0x0804, 0x0804, 0x0804, 0x0000, 0x7000}}, - {MARKER_28_CLANKER_SAWBLADE, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0804, 0x0000, 0x2020}}, - {MARKER_4A_CC_KEY, 0x0404, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0404}}, - {MARKER_6E_PINK_EGG_LARGEST, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0804, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}}, - {MARKER_D7_PINK_EGG_MEDIUM, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0804, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}}, - {MARKER_D9_PINK_EGG_SMALLEST, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0804, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}}, - {MARKER_D6_PINK_EGG_LARGE, 0x0000, {0x0000, 0x0000, 0x0000, 0x0804, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}}, - {MARKER_D8_PINK_EGG_SMALL, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0804, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}}, - {0x006D, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0804, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}}, - {0x019B, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0404, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}}, - {0x019C, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0404, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}}, - {0x019D, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0404, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}}, - {0x019E, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0404, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}}, - {0x019F, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0404, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}}, - {0x01A0, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0404, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}}, - {MARKER_B9_FP_SNOWMAN_BUTTON,0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0804, 0x0000, 0x0000, 0x0000, 0x0000}}, - {MARKER_124_BOGGY_1, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0404, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}}, - {0x0097, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0004, 0x0000, 0x0000, 0x0000}}, - {0x0125, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0404}}, - {0x0126, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0404}}, - {MARKER_1FD_BLUE_PRESENT_COLLECTIBLE, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0004}}, - {MARKER_1FE_GREEN_PRESENT_COLLECTIBLE, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0004}}, - {MARKER_1FF_RED_PRESENT_COLLECTIBLE, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0004}}, - {MARKER_20B_WOZZA, 0x7000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0004, 0x0000, 0x0000, 0x7000}}, - {MARKER_20F_WOZZA_IN_CAVE, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0004, 0x0000, 0x0000, 0x0000}}, - {0x0204, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x7404, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}}, - {0x0207, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0404, 0x0000, 0x0000, 0x0000, 0x0404}}, - {0x0206, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0404, 0x0000, 0x0000, 0x0000}}, - {MARKER_BC_GOBI_1, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0004}}, - {0x00BE, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0804, 0x0804, 0x0804, 0x080C, 0x0804, 0x0000, 0x0000}}, - {MARKER_BF_GOBI_2, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0004}}, - {MARKER_C3_GOBI_3, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0004}}, - {MARKER_252_LOGGO, 0x0000, {0x0004, 0x0004, 0x0004, 0x0004, 0x0004, 0x0004, 0x0004, 0x0000, 0x0004, 0x0004, 0x0004}}, - {MARKER_48_NAPPER, 0x0004, {0x7000, 0x8000, 0x8000, 0x8000, 0x9000, 0x9000, 0xB000, 0x0000, 0x8000, 0x0000, 0x8004}}, - {0x0132, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0404, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}}, - {0x0130, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0404, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}}, - {0x012E, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0404, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}}, - {0x012C, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0404, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}}, - {0x01BF, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x7404, 0x7404, 0x0000, 0x0414, 0x7404, 0x0000, 0x0000}}, - {0x01B3, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x9804, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}}, - {0x01B0, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0814, 0x0000, 0x0000, 0x0000}}, - {MARKER_1AE_ZUBBA, 0x0000, {0x3004, 0x3004, 0x3004, 0x0804, 0x0804, 0x0804, 0x0804, 0x080C, 0x0804, 0x0000, 0x3004}}, - {0x0050, 0x0003, {0x0804, 0x0804, 0x0000, 0x0804, 0x0804, 0x0804, 0x0804, 0x0804, 0x0804, 0x0804, 0x0000}}, - {0x009A, 0x0000, {0x0000, 0x0000, 0x0000, 0x7804, 0x8804, 0x0000, 0x0000, 0x0804, 0x0804, 0x0000, 0x0000}}, - {0x009E, 0x0000, {0x0000, 0x0000, 0x0000, 0x7804, 0x8804, 0x0804, 0x0000, 0x0804, 0x0804, 0x0000, 0x0000}}, - {0x009D, 0x0000, {0x0000, 0x0000, 0x0000, 0x7804, 0x8804, 0x0000, 0x0000, 0x0804, 0x0804, 0x0000, 0x0000}}, - {0x00E7, 0x0000, {0x0000, 0x0000, 0x0000, 0x7804, 0x8804, 0x0000, 0x0000, 0x0804, 0x0804, 0x0000, 0x0000}}, - {0x009C, 0x0000, {0x0000, 0x0000, 0x0000, 0x7804, 0x8804, 0x0000, 0x0000, 0x0804, 0x0804, 0x0000, 0x0000}}, - {MARKER_EA_LIGHTHOUSE_DOOR, 0x0000, {0x0000, 0x0000, 0x0000, 0x7804, 0x8804, 0x0000, 0x0000, 0x0804, 0x0804, 0x0000, 0x0000}}, - {0x022D, 0x0000, {0x0000, 0x0000, 0x0000, 0x7804, 0x0000, 0x0000, 0x0000, 0x0804, 0x0804, 0x0000, 0x0000}}, - {0x022E, 0x0000, {0x0000, 0x0000, 0x0000, 0x7804, 0x0000, 0x0000, 0x0000, 0x0804, 0x0804, 0x0000, 0x0000}}, - {0x0235, 0x0000, {0x0000, 0x0000, 0x0000, 0x7804, 0x0000, 0x0804, 0x0000, 0x0804, 0x0804, 0x0000, 0x0000}}, - {0x0163, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0804, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}}, - {0x0239, 0x0000, {0x0000, 0x0000, 0x0000, 0x7804, 0x8804, 0x0000, 0x0804, 0x0804, 0x0804, 0x0000, 0x0000}}, - {0x0236, 0x0000, {0x0000, 0x0000, 0x0000, 0x7804, 0x8804, 0x0000, 0x0804, 0x0804, 0x0804, 0x0000, 0x0000}}, - {0x0237, 0x0000, {0x0000, 0x0000, 0x0000, 0x7804, 0x8804, 0x0000, 0x0804, 0x0804, 0x0804, 0x0000, 0x0000}}, - {0x0238, 0x0000, {0x0000, 0x0000, 0x0000, 0x7804, 0x8804, 0x0000, 0x0804, 0x0804, 0x0804, 0x0000, 0x0000}}, - {0x0263, 0x0000, {0x0000, 0x0000, 0x0000, 0x7804, 0x8804, 0x0000, 0x0000, 0x0804, 0x0804, 0x0000, 0x0000}}, - {0x017D, 0x0000, {0x0000, 0x0000, 0x0000, 0x7804, 0x8804, 0x0000, 0x0000, 0x0808, 0x0804, 0x0000, 0x0000}}, - {0x009F, 0x0000, {0x0000, 0x0000, 0x0000, 0x7804, 0x8804, 0x0000, 0x0000, 0x0808, 0x0804, 0x0000, 0x0000}}, - {0x00A0, 0x0000, {0x0000, 0x0000, 0x0000, 0x7804, 0x8804, 0x0000, 0x0000, 0x0808, 0x0804, 0x0000, 0x0000}}, - {0x00FF, 0x0000, {0x0000, 0x0000, 0x0000, 0x7804, 0x8804, 0x0000, 0x0000, 0x0808, 0x0804, 0x0000, 0x0000}}, - {0x0107, 0x0000, {0x0000, 0x0000, 0x0000, 0x7804, 0x8804, 0x0000, 0x0000, 0x0808, 0x0804, 0x0000, 0x0000}}, - {0x0108, 0x0000, {0x0000, 0x0000, 0x0000, 0x7804, 0x8804, 0x0000, 0x0000, 0x0804, 0x0804, 0x0000, 0x0000}}, - {0x0109, 0x0000, {0x0000, 0x0000, 0x0000, 0x7804, 0x8804, 0x0000, 0x0000, 0x080C, 0x0804, 0x0000, 0x0000}}, - {0x0118, 0x0000, {0x0000, 0x0000, 0x0000, 0x7804, 0x0000, 0x0000, 0x0000, 0x0808, 0x0804, 0x0000, 0x0000}}, - {0x0119, 0x0000, {0x0000, 0x0000, 0x0000, 0x7804, 0x0000, 0x0000, 0x0000, 0x0808, 0x0804, 0x0000, 0x0000}}, - {0x011A, 0x0000, {0x0000, 0x0000, 0x0000, 0x7804, 0x8804, 0x0000, 0x0000, 0x0808, 0x0804, 0x0000, 0x0000}}, - {0x011E, 0x0000, {0x0000, 0x0000, 0x0000, 0x7804, 0x8804, 0x8804, 0x0000, 0x0808, 0x0804, 0x0000, 0x0000}}, - {0x011F, 0x0000, {0x0000, 0x0000, 0x0000, 0x7804, 0x7804, 0x7804, 0x0000, 0x0808, 0x0804, 0x0000, 0x0000}}, - {0x0121, 0x0000, {0x0000, 0x0000, 0x0000, 0x7804, 0x0000, 0x0000, 0x8804, 0x0804, 0x0804, 0x0000, 0x0000}}, - {0x0123, 0x0000, {0x0000, 0x0000, 0x0000, 0x7804, 0x0000, 0x0000, 0x0000, 0x0804, 0x0804, 0x0000, 0x0000}}, - {0x01F2, 0x0000, {0x0000, 0x0000, 0x0000, 0x7804, 0x0000, 0x0000, 0x0000, 0x0804, 0x0804, 0x0000, 0x0000}}, - {0x01F3, 0x0000, {0x0000, 0x0000, 0x0000, 0x0804, 0x0000, 0x0000, 0x0000, 0x0804, 0x0804, 0x0000, 0x0000}}, - {0x0224, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8000, 0xA000, 0x080C, 0x0000, 0x0000, 0x0000}}, - {0x0225, 0x0000, {0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x0000, 0xA000, 0x080C, 0x8000, 0x0000, 0x0000}}, - {0x00A2, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x8804, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}}, - {0x01A9, 0x0000, {0x0000, 0x0000, 0x0000, 0x7804, 0x0000, 0x0804, 0x0000, 0x080C, 0x0000, 0x0000, 0x0000}}, - {0x0195, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0404, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}}, - {0x0196, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0404, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}}, - {0x0197, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0404, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}}, - {0x002F, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0404, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}}, - {0x0194, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0404, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}}, - {0x0186, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0404, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}}, - {0x0183, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0404, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}}, - {0x0184, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0404, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}}, - {0x0164, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0804, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}}, - {0x0165, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0804, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}}, - {0x00E4, 0x0000, {0x8004, 0x8004, 0x8004, 0x8404, 0x8404, 0x8004, 0x8004, 0x0000, 0x8004, 0x8004, 0x8004}}, - {0x00E5, 0x0000, {0x8004, 0x8004, 0x8004, 0x8404, 0x8404, 0x8004, 0x8004, 0x0000, 0x8004, 0x8004, 0x8004}}, - {0x00E6, 0x0000, {0x8004, 0x8004, 0x8004, 0x8404, 0x8404, 0x8004, 0x8004, 0x0000, 0x8004, 0x8004, 0x8004}}, - {0x00B2, 0x0001, {0x0804, 0x0000, 0x0000, 0x0000, 0x0000, 0x0804, 0x0000, 0x0000, 0x0000, 0x0000, 0x2020}}, - {0x01A5, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0001}}, - {0x01A6, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x3020}}, - {0x016D, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8004}}, - {0x016E, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8004}}, - {0x016F, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8004}}, - {0x0170, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x7004}}, - {0x0171, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x7004}}, - {0x0172, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x7004}}, - {0x025C, 0x0000, {0x3804, 0x3804, 0x3804, 0x3804, 0x3804, 0x3804, 0x3804, 0x0000, 0x0804, 0x3804, 0x3804}}, - {0x025D, 0x0000, {0x3804, 0x3804, 0x3804, 0x3804, 0x3804, 0x3804, 0x3804, 0x0000, 0x0804, 0x3804, 0x3804}}, - {0x027A, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0404, 0x0000, 0x0000, 0x0000}}, - {0x027F, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0404, 0x0000, 0x0000, 0x0000}}, - {0x025E, 0x0000, {0x4000, 0x4000, 0x4000, 0xA604, 0x4000, 0x4000, 0x4000, 0x0584, 0xA000, 0x0000, 0x4000}}, - {0x0260, 0x0000, {0x5000, 0x5000, 0x5000, 0x5000, 0x5000, 0x5000, 0x5000, 0x0000, 0xA000, 0x0000, 0x5000}}, - {0x0281, 0x0000, {0x4080, 0x4080, 0x4080, 0xA604, 0x4080, 0x4080, 0x4080, 0x0584, 0xA200, 0x0000, 0x4080}}, - {0x0282, 0x0000, {0x4080, 0x4080, 0x4080, 0x4080, 0x4080, 0xA604, 0xA604, 0x0000, 0xA200, 0x0000, 0x4080}}, - {0x0283, 0x0000, {0x4080, 0x4080, 0x4080, 0x4080, 0x4080, 0x4080, 0x4080, 0x0000, 0xA200, 0x0000, 0x4080}}, - {0x0284, 0x0000, {0x5404, 0x5404, 0x5404, 0x5404, 0x5404, 0x5404, 0x5404, 0x0000, 0xB404, 0x5404, 0x5404}}, + +#define COLLISION_TABLE_SIZE 187 + +CollisionTable collision_table[COLLISION_TABLE_SIZE] = { + {MARKER_12A_TOPPER_THE_CARROT_A, 0x0000, {0x0904, 0x8504, 0x8504, 0x0000, 0x8504, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x7484}}, + {MARKER_129_BAWL_THE_ONION_A, 0x0000, {0x0504, 0x0984, 0x8504, 0x0000, 0x8504, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x7484}}, + {MARKER_128_COLLYWOBBLE_THE_CAULIFLOWER_A, 0x0000, {0x0000, 0x0000, 0x8404, 0x0984, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x7404}}, + {MARKER_135_QUARRIE, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0804, 0x0804, 0x0000, 0x0804, 0x0804, 0x0000, 0x0000}}, + {MARKER_1E6_TOPPER_THE_CARROT_B, 0x0001, {0x0904, 0x0984, 0x8100, 0x0984, 0x0A04, 0x0A04, 0x0000, 0x0984, 0x0A04, 0x0000, 0x1020}}, + {MARKER_1E7_BAWL_THE_ONION_B, 0x0001, {0x0904, 0x0984, 0x8100, 0x0984, 0x0A04, 0x0A04, 0x0000, 0x0984, 0x0A04, 0x0000, 0x1020}}, + {MARKER_1E8_COLLYWOBBLE_THE_CAULIFLOWER_B, 0x0001, {0x0904, 0x0984, 0x8100, 0x0984, 0x0A04, 0x0A04, 0x0000, 0x0984, 0x0A04, 0x0000, 0x1020}}, + {MARKER_1EA_GRUNTLING_RED, 0x0001, {0x0A08, 0x0984, 0x8100, 0x0984, 0x0A04, 0x0A04, 0x0A84, 0x0984, 0x0A04, 0x0984, 0x2020}}, + {MARKER_295_GRUNTLING_BLUE, 0x0001, {0x0A0C, 0x8988, 0x8100, 0x0984, 0x0A04, 0x0A04, 0x0A84, 0x0988, 0x0A04, 0x0000, 0x2020}}, + {MARKER_1F1_GRUNTLING_BLACK, 0x0001, {0x0A10, 0x898C, 0x8100, 0x8988, 0x8A08, 0x8A08, 0x0A84, 0x098C, 0x0A04, 0x0000, 0x2020}}, + {MARKER_1E0_BRENTILDA, 0x0000, {0x7000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x0004, 0x8000, 0x0000, 0x7000}}, + {MARKER_5_GRUBLIN, 0x0001, {0x0904, 0x0984, 0x8100, 0x0984, 0x0A04, 0x0A04, 0x0A84, 0x0984, 0x0A04, 0x0000, 0x1020}}, + {MARKER_4_TERMITE, 0x0001, {0x0A88, 0x0984, 0x8100, 0x0984, 0x0A04, 0x0A04, 0x0A84, 0x0988, 0x0A04, 0x0000, 0x1020}}, + {MARKER_3_BIGBUTT, 0x0000, {0x0914, 0x990C, 0x2020, 0x8908, 0x8908, 0x8908, 0x0A04, 0x0914, 0x0904, 0x0000, 0x4020}}, + {MARKER_29E_BIGBUTT_KNOCKED_DOWN, 0x0000, {0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0xA000, 0x0004, 0x8000, 0x0000, 0x8000}}, + {MARKER_7_CONGA, 0x0000, {0x0000, 0x0000, 0x3020, 0x9000, 0x0000, 0x0000, 0x0000, 0x0804, 0x9000, 0x0000, 0x3020}}, + {MARKER_13_SNIPPET, 0x0002, {0x0504, 0x7584, 0x8100, 0x7584, 0x7604, 0x0A04, 0x0A84, 0x0504, 0x0A04, 0x0000, 0x1020}}, + {MARKER_16B_SNIPPET_UPSIDEDOWN, 0x0001, {0x0904, 0x0984, 0x8100, 0x0984, 0x0A04, 0x0A04, 0x0A84, 0x0904, 0x0A04, 0x0000, 0x1020}}, + {MARKER_DD_BLACK_SNIPPET, 0x0002, {0x060C, 0x7588, 0x8100, 0x7588, 0x7608, 0x8604, 0x0A84, 0x050C, 0x0A04, 0x0000, 0x1020}}, + {MARKER_DE_BLACK_SNIPPET_UPSIDEDOWN, 0x0001, {0x0908, 0x0988, 0x8100, 0x0984, 0x0A04, 0x0A04, 0x0A84, 0x090C, 0x0A04, 0x0000, 0x1020}}, + {MARKER_15_CLAM, 0x0001, {0x0A88, 0x7988, 0x8100, 0x0984, 0x0A04, 0x0A04, 0x0A84, 0x0988, 0x0A04, 0x0000, 0x1424}}, + {MARKER_65_SHRAPNEL, 0x0804, {0x5040, 0x5040, 0x5040, 0x5040, 0x5040, 0x5040, 0x5040, 0x090E, 0x0804, 0x0000, 0x5844}}, + {MARKER_14_SNACKER, 0x0003, {0x3020, 0x3020, 0x3020, 0x9080, 0x9080, 0x9080, 0x0A84, 0x0914, 0x0904, 0x0000, 0x3020}}, + {MARKER_A5_NIPPER, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0404, 0x0000, 0x0000, 0x5020}}, + {MARKER_16C_NIPPER, 0x0000, {0x0000, 0x0000, 0x0000, 0xB804, 0x0000, 0x0000, 0x0000, 0x0404, 0xB804, 0x0000, 0x5020}}, + {MARKER_A4_LOCKUP_SLOW, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x2020}}, + {MARKER_F6_LOCKUP_MEDIUM, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x2020}}, + {MARKER_F7_LOCKUP_FAST, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x2020}}, + {MARKER_29_GRILLE_CHOMPA, 0x0001, {0x0804, 0x0804, 0x2020, 0x0804, 0x0804, 0x0804, 0x0804, 0x0808, 0x0804, 0x0000, 0x3444}}, + {MARKER_1CF_GRILLE_CHOMPA_ATTACKING, 0x0001, {0x0804, 0x0804, 0x1020, 0x0804, 0x0804, 0x0804, 0x0804, 0x0808, 0x0804, 0x0000, 0x1424}}, + {MARKER_1A6_BETA_VENT, 0x0000, {0x3020, 0x3020, 0x3020, 0x3020, 0x3020, 0x3020, 0x3020, 0x0000, 0x0000, 0x3020, 0x3020}}, + {MARKER_1A7_CLANKER_WHIPCRACK, 0x0804, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x3020}}, + {MARKER_69_CHUMP_FISH, 0x0001, {0x2020, 0x2020, 0x2020, 0x0984, 0x0A04, 0x0A04, 0x0A84, 0x0988, 0x0A04, 0x0000, 0x2020}}, + {MARKER_173_CHUMP_FISH_2, 0x0001, {0x2020, 0x2020, 0x2020, 0x0984, 0x0A04, 0x0A04, 0x0A84, 0x0988, 0x0A04, 0x0000, 0x4020}}, + {MARKER_C1_FLIBBIT_RED, 0x0000, {0x0A09, 0x0985, 0x8100, 0x0985, 0x0A05, 0x0A05, 0x0000, 0x0989, 0x0A05, 0x0986, 0x2020}}, + {MARKER_C5_FLIBBIT_YELLOW, 0x0000, {0x0A0D, 0x8989, 0x8100, 0x8989, 0x7A09, 0x7A09, 0x0000, 0x098D, 0x0A05, 0x0986, 0x2020}}, + {MARKER_C2_BUZZBOMB, 0x0000, {0x0805, 0x0805, 0x8000, 0x0805, 0x0805, 0x0805, 0x0000, 0x0805, 0x0805, 0x0806, 0x3020}}, + {MARKER_B1_SIR_SLUSH, 0x0000, {0x7000, 0x8000, 0x8000, 0x8000, 0x9000, 0x9000, 0x9000, 0x0004, 0x8000, 0x0000, 0x7000}}, + {0x0287, 0x0001, {0x7000, 0x8000, 0x8000, 0x8000, 0x9000, 0x9000, 0x8804, 0x0004, 0x8000, 0x0000, 0x7000}}, // snowman.c + {MARKER_205_TWINKLY_MUNCHER, 0x0000, {0x0000, 0x0000, 0x0000, 0x0404, 0x0404, 0x0404, 0x0000, 0x0408, 0x0404, 0x0000, 0x0000}}, + {MARKER_245_XMAS_TREE_EGG_TOLL, 0x0000, {0x3004, 0x3004, 0x3004, 0x3004, 0x3004, 0x2004, 0x3004, 0x0000, 0x0000, 0x3004, 0x3004}}, + {MARKER_250_ICECUBE_A, 0x0000, {0x0A90, 0x8988, 0x8100, 0x0984, 0x0A04, 0x0A04, 0x0A84, 0x0910, 0x0A04, 0x0984, 0x3104}}, + {MARKER_25F_ICECUBE_B, 0x0001, {0x0A88, 0x0984, 0x8100, 0x0984, 0x0A04, 0x0A04, 0x0A84, 0x0908, 0x0A04, 0x0984, 0x3104}}, + {0x00AD, 0x0001, {0x0A10, 0x998C, 0x0020, 0x9988, 0x8A08, 0x0A04, 0x0A84, 0x0914, 0x0A04, 0x0000, 0x5124}}, + {MARKER_253_SCARAB_BEETLE, 0x0001, {0x0904, 0x0984, 0x8100, 0x0984, 0x0A04, 0x0A04, 0x0A84, 0x0984, 0x0A04, 0x0000, 0x3020}}, + {MARKER_219_MUMMUM, 0x0001, {0x0588, 0x7584, 0x8100, 0x7584, 0x7604, 0x7604, 0x0684, 0x0588, 0x0A04, 0x0000, 0x2020}}, + {MARKER_298_MUMMUM_BALL, 0x0000, {0x7000, 0x8000, 0x7000, 0x8000, 0x9000, 0x9000, 0xB000, 0x0004, 0x0A04, 0x0000, 0x2020}}, + {MARKER_218_LIMBO, 0x0001, {0x0588, 0x7584, 0x8100, 0x7584, 0x7604, 0x7604, 0x0684, 0x050C, 0x0A04, 0x0000, 0x2020}}, + {MARKER_99_TEEHEE, 0x0001, {0x2020, 0x2020, 0x2020, 0x2020, 0x2020, 0x2020, 0x0000, 0x0000, 0x0804, 0x0000, 0x2424}}, + {MARKER_296_TEEHEE_PURPLE, 0x0000, {0x2020, 0x2020, 0x2020, 0x2020, 0x2020, 0x2020, 0x0000, 0x0000, 0x0804, 0x0000, 0x2424}}, + {MARKER_96_GRAVESTONE, 0x0001, {0x0A10, 0x890C, 0x8100, 0x8908, 0x8988, 0x8988, 0x0A84, 0x0914, 0x0984, 0x0000, 0x3024}}, + {MARKER_297_GIANT_GRAVESTONE, 0x0001, {0x0A10, 0x890C, 0x8100, 0x8908, 0x8988, 0x8988, 0x0A84, 0x0914, 0x0984, 0x0000, 0x3024}}, + {MARKER_127_BAT, 0x0001, {0x0804, 0x0804, 0x8100, 0x0804, 0x0804, 0x0804, 0x0804, 0x0804, 0x0804, 0x0000, 0x1424}}, + {MARKER_254_PORTRAIT_CHOMPA_A, 0x0001, {0x0804, 0x0804, 0x2020, 0x0804, 0x0804, 0x0804, 0x0804, 0x080C, 0x0804, 0x0000, 0x3444}}, + {MARKER_1D1_PORTRAIT_CHOMPA_B, 0x0001, {0x0804, 0x0804, 0x1020, 0x0804, 0x0804, 0x0804, 0x0804, 0x080C, 0x0804, 0x0000, 0x1424}}, + {MARKER_21A_SEAMAN_GRUBLIN, 0x0001, {0x0A08, 0x8988, 0x8100, 0x0984, 0x0A04, 0x0A04, 0x0000, 0x0988, 0x0A04, 0x0000, 0x2020}}, + {MARKER_C9_FLOTSAM, 0x0001, {0x0808, 0x8808, 0x8000, 0x0804, 0x0804, 0x0804, 0x0000, 0x0808, 0x0804, 0x0000, 0x3424}}, + {MARKER_1B7_BOOM_BOX, 0x0000, {0x0804, 0x0804, 0x0804, 0x0804, 0x0804, 0x0804, 0x0000, 0x098C, 0x0404, 0x0804, 0x5000}}, + {MARKER_2E_GRIMLET, 0x0004, {0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x0000, 0x0000, 0x8000, 0x3000, 0x3004}}, + {MARKER_1A1_BOSS_BOOM_BOX_LARGEST, 0x0000, {0x8020, 0x8884, 0x8020, 0x8884, 0x9884, 0x9884, 0x0804, 0x0904, 0x0884, 0x0000, 0x4020}}, + {MARKER_1A2_BOSS_BOOM_BOX_LARGE, 0x0000, {0x8020, 0x8904, 0x8020, 0x8904, 0x9904, 0x9904, 0x0804, 0x0984, 0x0904, 0x0000, 0x4020}}, + {MARKER_1A3_BOSS_BOOM_BOX_MEDIUM, 0x0000, {0x9020, 0x9984, 0x9020, 0x9984, 0x9984, 0x9984, 0x0804, 0x0A04, 0x0984, 0x0000, 0x3020}}, + {MARKER_1A4_BOSS_BOOM_BOX_SMALL, 0x0000, {0x9020, 0x9A04, 0x9020, 0x9A04, 0x9A04, 0x9A04, 0x0804, 0x0A84, 0x0A04, 0x0000, 0x3020}}, + {MARKER_185_RBB_REAR_PROPELLER, 0x5060, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x5060}}, + {MARKER_191_ENGINE_ROOM_PROPELLOR_1, 0x0000, {0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x0000, 0x8000, 0x0000, 0x2000}}, + {MARKER_192_ENGINE_ROOM_PROPELLOR_2, 0x0000, {0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x0000, 0x8000, 0x0000, 0x2000}}, + {MARKER_193_ENGINE_ROOM_PROPELLOR_3, 0x0000, {0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x0000, 0x8000, 0x0000, 0x2000}}, + {MARKER_1E2_GRUBLIN_HOOD, 0x0001, {0x0A08, 0x8988, 0x8100, 0x0984, 0x0A04, 0x0A04, 0x0A84, 0x0988, 0x0A04, 0x0000, 0x2020}}, + {MARKER_1C5_WHIPCRACK, 0x0001, {0x3020, 0x3020, 0x3020, 0x3020, 0x3020, 0x3020, 0x3020, 0x080C, 0x0804, 0x0000, 0x3020}}, + {MARKER_1F9_SNARE_BEAR, 0x0000, {0x2040, 0x2040, 0x2040, 0x2040, 0x2040, 0x2040, 0x2040, 0x0000, 0x0000, 0x0000, 0x2040}}, + {MARKER_1B2_CLUCKER_A, 0x0001, {0x0804, 0x0804, 0x2020, 0x0804, 0x0804, 0x0804, 0x0804, 0x0810, 0x0804, 0x0000, 0x3444}}, + {MARKER_1D0_CLUCKER_B, 0x0001, {0x0804, 0x0804, 0x1020, 0x0804, 0x0804, 0x0804, 0x0804, 0x0810, 0x0804, 0x0000, 0x1424}}, + {MARKER_1B4_EEYRIE_BABY, 0x8000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8000}}, + {0x000E, 0x0001, {0x3000, 0x7504, 0x7080, 0x7504, 0x7584, 0x0804, 0x0804, 0x0488, 0x0804, 0x0000, 0x1020}}, + {MARKER_1AC_ZUBBA_DOOR, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0804, 0x0804, 0x0000, 0x0000, 0x0000, 0x0000}}, + {MARKER_256_FIRE_FX, 0x0000, {0x2020, 0x2020, 0x2020, 0x2020, 0x2020, 0x2020, 0x2020, 0x0000, 0x0000, 0x2020, 0x2020}}, + {MARKER_C_ORANGE_PROJECTILE, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x2424}}, + {MARKER_DB_BURIED_TREASURE, 0x0000, {0x7000, 0x7000, 0x7000, 0x0804, 0x0804, 0x0804, 0x0804, 0x0804, 0x0804, 0x0000, 0x7000}}, + {MARKER_28_CLANKER_SAWBLADE, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0804, 0x0000, 0x2020}}, + {MARKER_4A_CC_KEY, 0x0404, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0404}}, + {MARKER_6E_PINK_EGG_LARGEST, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0804, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}}, + {MARKER_D7_PINK_EGG_MEDIUM, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0804, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}}, + {MARKER_D9_PINK_EGG_SMALLEST, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0804, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}}, + {MARKER_D6_PINK_EGG_LARGE, 0x0000, {0x0000, 0x0000, 0x0000, 0x0804, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}}, + {MARKER_D8_PINK_EGG_SMALL, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0804, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}}, + {MARKER_6D_TANKTUP_LEG, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0804, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}}, + {MARKER_19B_CHOIR_TURTLE_YELLOW, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0404, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}}, + {MARKER_19C_CHOIR_TURTLE_CYAN, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0404, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}}, + {MARKER_19D_CHOIR_TURTLE_BLUE, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0404, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}}, + {MARKER_19E_CHOIR_TURTLE_RED, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0404, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}}, + {MARKER_19F_CHOIR_TURTLE_PINK, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0404, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}}, + {MARKER_1A0_CHOIR_TURTLE_PURPLE, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0404, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}}, + {MARKER_B9_FP_SNOWMAN_BUTTON, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0804, 0x0000, 0x0000, 0x0000, 0x0000}}, + {MARKER_124_BOGGY_1, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0404, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}}, + {MARKER_97_BOGGY_2, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0004, 0x0000, 0x0000, 0x0000}}, + {MARKER_125_BOGGY_RACE_FLAG, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0404}}, + {MARKER_126_BOGGY_RACE_FLAG, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0404}}, + {MARKER_1FD_BLUE_PRESENT_COLLECTIBLE, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0004}}, + {MARKER_1FE_GREEN_PRESENT_COLLECTIBLE, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0004}}, + {MARKER_1FF_RED_PRESENT_COLLECTIBLE, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0004}}, + {MARKER_20B_WOZZA, 0x7000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0004, 0x0000, 0x0000, 0x7000}}, + {MARKER_20F_WOZZA_IN_CAVE, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0004, 0x0000, 0x0000, 0x0000}}, + {MARKER_204_TWINKLY_BOX, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x7404, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}}, + {MARKER_207_XMAS_TREE_STAR, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0404, 0x0000, 0x0000, 0x0000, 0x0404}}, + {MARKER_206_XMAS_TREE_SWITCH, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0404, 0x0000, 0x0000, 0x0000}}, + {MARKER_BC_GOBI_1, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0004}}, + {MARKER_BE_GOBI_ROCK, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0804, 0x0804, 0x0804, 0x080C, 0x0804, 0x0000, 0x0000}}, + {MARKER_BF_GOBI_2, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0004}}, + {MARKER_C3_GOBI_3, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0004}}, + {MARKER_252_LOGGO, 0x0000, {0x0004, 0x0004, 0x0004, 0x0004, 0x0004, 0x0004, 0x0004, 0x0000, 0x0004, 0x0004, 0x0004}}, + {MARKER_48_NAPPER, 0x0004, {0x7000, 0x8000, 0x8000, 0x8000, 0x9000, 0x9000, 0xB000, 0x0000, 0x8000, 0x0000, 0x8004}}, + {MARKER_132_CCW_SPRING_SWITCH, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0404, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}}, + {MARKER_130_CCW_SUMMER_SWITCH, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0404, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}}, + {MARKER_12E_CCW_AUTUMN_SWITCH, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0404, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}}, + {MARKER_12C_CCW_WINTER_SWITCH, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0404, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}}, + {MARKER_1BF_GNAWTY_BOULDER, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x7404, 0x7404, 0x0000, 0x0414, 0x7404, 0x0000, 0x0000}}, + {MARKER_1B3_EAGLE_EGG, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x9804, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}}, + {MARKER_1B0_CCW_BEANSTALK, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0814, 0x0000, 0x0000, 0x0000}}, + {MARKER_1AE_ZUBBA, 0x0000, {0x3004, 0x3004, 0x3004, 0x0804, 0x0804, 0x0804, 0x0804, 0x080C, 0x0804, 0x0000, 0x3004}}, + {MARKER_50_BEEHIVE, 0x0003, {0x0804, 0x0804, 0x0000, 0x0804, 0x0804, 0x0804, 0x0804, 0x0804, 0x0804, 0x0804, 0x0000}}, + {MARKER_9A_1881_BARREL_TOP, 0x0000, {0x0000, 0x0000, 0x0000, 0x7804, 0x8804, 0x0000, 0x0000, 0x0804, 0x0804, 0x0000, 0x0000}}, + {MARKER_9E_CELLAR_HATCH, 0x0000, {0x0000, 0x0000, 0x0000, 0x7804, 0x8804, 0x0804, 0x0000, 0x0804, 0x0804, 0x0000, 0x0000}}, + {MARKER_9D_MANSION_DOOR, 0x0000, {0x0000, 0x0000, 0x0000, 0x7804, 0x8804, 0x0000, 0x0000, 0x0804, 0x0804, 0x0000, 0x0000}}, + {MARKER_E7_DINING_DOOR, 0x0000, {0x0000, 0x0000, 0x0000, 0x7804, 0x8804, 0x0000, 0x0000, 0x0804, 0x0804, 0x0000, 0x0000}}, + {MARKER_9C_SHACK_DOOR, 0x0000, {0x0000, 0x0000, 0x0000, 0x7804, 0x8804, 0x0000, 0x0000, 0x0804, 0x0804, 0x0000, 0x0000}}, + {MARKER_EA_LIGHTHOUSE_DOOR, 0x0000, {0x0000, 0x0000, 0x0000, 0x7804, 0x8804, 0x0000, 0x0000, 0x0804, 0x0804, 0x0000, 0x0000}}, + {MARKER_22D_SHIP_SHADOW_WINDOW, 0x0000, {0x0000, 0x0000, 0x0000, 0x7804, 0x0000, 0x0000, 0x0000, 0x0804, 0x0804, 0x0000, 0x0000}}, + {MARKER_22E_SHIP_SUNNY_WINDOW, 0x0000, {0x0000, 0x0000, 0x0000, 0x7804, 0x0000, 0x0000, 0x0000, 0x0804, 0x0804, 0x0000, 0x0000}}, + {MARKER_235_CRACKED_SKYLIGHT, 0x0000, {0x0000, 0x0000, 0x0000, 0x7804, 0x0000, 0x0804, 0x0000, 0x0804, 0x0804, 0x0000, 0x0000}}, + {MARKER_163_CRYPT_COFFIN_LID, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0804, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}}, + {MARKER_239_CCW_UNKNOWN_NABNUT_WINDOW, 0x0000, {0x0000, 0x0000, 0x0000, 0x7804, 0x8804, 0x0000, 0x0804, 0x0804, 0x0804, 0x0000, 0x0000}}, + {MARKER_236_CCW_UNKNOWN_NABNUT_WINDOW, 0x0000, {0x0000, 0x0000, 0x0000, 0x7804, 0x8804, 0x0000, 0x0804, 0x0804, 0x0804, 0x0000, 0x0000}}, + {MARKER_237_CCW_AUTUMN_NABNUT_WINDOW, 0x0000, {0x0000, 0x0000, 0x0000, 0x7804, 0x8804, 0x0000, 0x0804, 0x0804, 0x0804, 0x0000, 0x0000}}, + {MARKER_238_CCW_WINTER_NABNUT_WINDOW, 0x0000, {0x0000, 0x0000, 0x0000, 0x7804, 0x8804, 0x0000, 0x0804, 0x0804, 0x0804, 0x0000, 0x0000}}, + {MARKER_263_CCW_WHIPCRACK_ROOM_DOOR, 0x0000, {0x0000, 0x0000, 0x0000, 0x7804, 0x8804, 0x0000, 0x0000, 0x0804, 0x0804, 0x0000, 0x0000}}, + {MARKER_17D_IRON_GATE_NO_LOCK, 0x0000, {0x0000, 0x0000, 0x0000, 0x7804, 0x8804, 0x0000, 0x0000, 0x0808, 0x0804, 0x0000, 0x0000}}, + {MARKER_9F_CHURCH_GATE_LEFT_LOCK, 0x0000, {0x0000, 0x0000, 0x0000, 0x7804, 0x8804, 0x0000, 0x0000, 0x0808, 0x0804, 0x0000, 0x0000}}, + {MARKER_A0_HEDGE_GATE_RIGHT_LOCK_1, 0x0000, {0x0000, 0x0000, 0x0000, 0x7804, 0x8804, 0x0000, 0x0000, 0x0808, 0x0804, 0x0000, 0x0000}}, + {MARKER_FF_HEDGE_GATE_RIGHT_LOCK_2, 0x0000, {0x0000, 0x0000, 0x0000, 0x7804, 0x8804, 0x0000, 0x0000, 0x0808, 0x0804, 0x0000, 0x0000}}, + {MARKER_107_ENGINE_ROOM_DOOR, 0x0000, {0x0000, 0x0000, 0x0000, 0x7804, 0x8804, 0x0000, 0x0000, 0x0808, 0x0804, 0x0000, 0x0000}}, + {MARKER_108_CABIN_CLOSET_DOOR, 0x0000, {0x0000, 0x0000, 0x0000, 0x7804, 0x8804, 0x0000, 0x0000, 0x0804, 0x0804, 0x0000, 0x0000}}, + {MARKER_109_BREAKABLE_BRICK_WALL, 0x0000, {0x0000, 0x0000, 0x0000, 0x7804, 0x8804, 0x0000, 0x0000, 0x080C, 0x0804, 0x0000, 0x0000}}, + {MARKER_118_GRATE_TO_LEVEL_3_WATER_SWITCH, 0x0000, {0x0000, 0x0000, 0x0000, 0x7804, 0x0000, 0x0000, 0x0000, 0x0808, 0x0804, 0x0000, 0x0000}}, + {MARKER_119_GRATE_BETWEEN_MMM_AND_RBB_PUZZLES, 0x0000, {0x0000, 0x0000, 0x0000, 0x7804, 0x0000, 0x0000, 0x0000, 0x0808, 0x0804, 0x0000, 0x0000}}, + {MARKER_11A_GRATE_TO_RBB_PUZZLE, 0x0000, {0x0000, 0x0000, 0x0000, 0x7804, 0x8804, 0x0000, 0x0000, 0x0808, 0x0804, 0x0000, 0x0000}}, + {MARKER_11E_ICE_BALL_TO_CHEATO, 0x0000, {0x0000, 0x0000, 0x0000, 0x7804, 0x8804, 0x8804, 0x0000, 0x0808, 0x0804, 0x0000, 0x0000}}, + {MARKER_11F_RAREWARE_BOX, 0x0000, {0x0000, 0x0000, 0x0000, 0x7804, 0x7804, 0x7804, 0x0000, 0x0808, 0x0804, 0x0000, 0x0000}}, + {MARKER_121_GLASS_EYE, 0x0000, {0x0000, 0x0000, 0x0000, 0x7804, 0x0000, 0x0000, 0x8804, 0x0804, 0x0804, 0x0000, 0x0000}}, + {MARKER_123_WINDOW, 0x0000, {0x0000, 0x0000, 0x0000, 0x7804, 0x0000, 0x0000, 0x0000, 0x0804, 0x0804, 0x0000, 0x0000}}, + {MARKER_1F2_WIDE_WINDOW, 0x0000, {0x0000, 0x0000, 0x0000, 0x7804, 0x0000, 0x0000, 0x0000, 0x0804, 0x0804, 0x0000, 0x0000}}, + {MARKER_1F3_TALL_WINDOW, 0x0000, {0x0000, 0x0000, 0x0000, 0x0804, 0x0000, 0x0000, 0x0000, 0x0804, 0x0804, 0x0000, 0x0000}}, + {MARKER_224_BREAKABLE_FLOOR_COBWEB, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8000, 0xA000, 0x080C, 0x0000, 0x0000, 0x0000}}, + {MARKER_225_BREAKABLE_WALL_COBWEB, 0x0000, {0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x0000, 0xA000, 0x080C, 0x8000, 0x0000, 0x0000}}, + {MARKER_A2_CHURCH_DOOR, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x8804, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}}, + {MARKER_1A9_CC_BREAKABLE_GRATES, 0x0000, {0x0000, 0x0000, 0x0000, 0x7804, 0x0000, 0x0804, 0x0000, 0x080C, 0x0000, 0x0000, 0x0000}}, + {MARKER_195_WHISTLE_SWITCH_1, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0404, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}}, + {MARKER_196_WHISTLE_SWITCH_2, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0404, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}}, + {MARKER_197_WHISTLE_SWITCH_3, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0404, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}}, + {MARKER_2F_ANCHOR_SWITCH, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0404, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}}, + {MARKER_194_RBB_GREY_PROPELLER_SWITCH, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0404, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}}, + {MARKER_186_RBB_GREEN_PROPELLER_SWITCH, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0404, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}}, + {MARKER_183_RBB_CAGE_UP_SWITCH, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0404, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}}, + {MARKER_184_RBB_TNT_DOWN_SWITCH, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0404, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}}, + {MARKER_164_GL_GRUNTY_FLOOR_PICTURE_EYE_1, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0804, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}}, + {MARKER_165_GL_GRUNTY_FLOOR_PICTURE_EYE_2, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0804, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}}, + {MARKER_E4_CS_BK_SLEEPING, 0x0000, {0x8004, 0x8004, 0x8004, 0x8404, 0x8404, 0x8004, 0x8004, 0x0000, 0x8004, 0x8004, 0x8004}}, + {MARKER_E5_CS_BK_GAMEBOY, 0x0000, {0x8004, 0x8004, 0x8004, 0x8404, 0x8404, 0x8004, 0x8004, 0x0000, 0x8004, 0x8004, 0x8004}}, + {MARKER_E6_CS_BK_COOKING, 0x0000, {0x8004, 0x8004, 0x8004, 0x8404, 0x8404, 0x8004, 0x8004, 0x0000, 0x8004, 0x8004, 0x8004}}, + {MARKER_B2_SNOWBALL, 0x0001, {0x0804, 0x0000, 0x0000, 0x0000, 0x0000, 0x0804, 0x0000, 0x0000, 0x0000, 0x0000, 0x2020}}, + {MARKER_1A5_SANDYBUTT_EGG_TOLL, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0001}}, + {MARKER_1A6_BETA_VENT, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x3020}}, + {MARKER_16D_CHEATO_1, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8004}}, + {MARKER_16E_CHEATO_2, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8004}}, + {MARKER_16F_CHEATO_3, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8004}}, + {MARKER_170_BLUE_EGG_REFILL_PILLOW, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x7004}}, + {MARKER_171_RED_FEATHER_REFILL_PILLOW, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x7004}}, + {MARKER_172_GOLD_FEATHER_REFILL_PILLOW, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x7004}}, + {MARKER_25C_GRUNTY_SPELL_FIREBALL, 0x0000, {0x3804, 0x3804, 0x3804, 0x3804, 0x3804, 0x3804, 0x3804, 0x0000, 0x0804, 0x3804, 0x3804}}, + {MARKER_25D_GREEN_BLAST, 0x0000, {0x3804, 0x3804, 0x3804, 0x3804, 0x3804, 0x3804, 0x3804, 0x0000, 0x0804, 0x3804, 0x3804}}, + {MARKER_27A_JINJO_STATUE_BASE, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0404, 0x0000, 0x0000, 0x0000}}, + {MARKER_27F_JINJONATOR_STATUE_BASE, 0x0000, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0404, 0x0000, 0x0000, 0x0000}}, + {MARKER_25E_GRUNTILDA_FINAL_BOSS_VULNERABLE, 0x0000, {0x4000, 0x4000, 0x4000, 0xA604, 0x4000, 0x4000, 0x4000, 0x0584, 0xA000, 0x0000, 0x4000}}, + {MARKER_260_GRUNTY_PHASE_1_2_MOVING, 0x0000, {0x5000, 0x5000, 0x5000, 0x5000, 0x5000, 0x5000, 0x5000, 0x0000, 0xA000, 0x0000, 0x5000}}, + {MARKER_281_GRUNTY_PHASE_2_VULNERABLE, 0x0000, {0x4080, 0x4080, 0x4080, 0xA604, 0x4080, 0x4080, 0x4080, 0x0584, 0xA200, 0x0000, 0x4080}}, + {MARKER_282_GRUNTY_PHASE_3_FLIGHT, 0x0000, {0x4080, 0x4080, 0x4080, 0x4080, 0x4080, 0xA604, 0xA604, 0x0000, 0xA200, 0x0000, 0x4080}}, +#if VERSION == VERSION_USA_1_0 + {MARKER_283_GRUNTY_PHASE_4_5_INVULNERABLE, 0x0000, {0x4080, 0x4080, 0x4080, 0x4080, 0x4080, 0x4080, 0x4080, 0x0000, 0xA200, 0x0000, 0x4080}}, + {MARKER_284_GRUNTY_SPELL_BARRIER, 0x0000, {0x5404, 0x5404, 0x5404, 0x5404, 0x5404, 0x5404, 0x5404, 0x0000, 0xB404, 0x5404, 0x5404}}, +#elif VERSION == VERSION_PAL + {MARKER_283_GRUNTY_PHASE_4_5_INVULNERABLE, 0x0000, {0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x0004, 0xA000, 0x0000, 0x4000}}, + {MARKER_284_GRUNTY_SPELL_BARRIER, 0x0000, {0x5404, 0x5404, 0x5404, 0x5404, 0x5404, 0x5404, 0x5404, 0x0004, 0xB404, 0x5404, 0x5404}}, +#endif }; s32 func_8033D240(ActorMarker *arg0, ActorMarker *arg1); @@ -217,10 +242,10 @@ Struct_core2_B62B0_1 D_80371DC0[11] = { {func_8033D2A8, HITBOX_2_BEAK_BARGE}, {func_8033D2A8, HITBOX_1_BEAK_BUSTER}, {func_8033D2A8, HITBOX_3_BEAK_BOMB}, - {func_8033D240, 1}, + {func_8033D240, 1}, // Egg Firing {func_8033D2A8, HITBOX_6_WONDERWING}, {func_8033D2A8, HITBOX_9_CROC_BITE}, - {func_8033D240, 0} + {func_8033D240, 0} // Other Contact }; /* .bss */ @@ -249,49 +274,53 @@ void func_8033D2F4(void) { s32 var_a0; bool var_a1; s32 var_v1; - s32 var_v0 = 0xBB; + s32 var_v0 = COLLISION_TABLE_SIZE; for(var_v1 = 0; var_v1 < 0x2A9; var_v1++) { - for(((var_a0 = 0), (var_a1 = false), (D_80383F10[var_v1] = -1)); (var_a0 < var_v0) && !var_a1; var_a0++){ - if (var_v1 == D_80370AC0[var_a0].unk0) { + for(((var_a0 = 0), (var_a1 = FALSE), (D_80383F10[var_v1] = -1)); (var_a0 < var_v0) && !var_a1; var_a0++){ + if (var_v1 == collision_table[var_a0].markerId) { D_80383F10[var_v1] = var_a0; - var_a1 = true; + var_a1 = TRUE; } } } for(var_a0 = 0; var_a0 < var_v0; var_a0++) { for(var_v1 = 0; var_v1 < 10; var_v1++){ - D_80370AC0[var_a0].unk4[var_v1] |= D_80370AC0[var_a0].unk2; + collision_table[var_a0].collisionTypes[var_v1] |= collision_table[var_a0].collisionUnion; } } } bool func_8033D410(ActorMarker *arg0, ActorMarker *arg1) { s32 var_s2; - s32 sp38; + s32 collision_index; s16 temp_t0; s32 temp_s0; - sp38 = D_80383F10[arg1->id]; - if (sp38 == -1) { - return false; + collision_index = D_80383F10[arg1->id]; + if (collision_index == -1) { + return FALSE; } for(var_s2 = 0; var_s2 < 11; var_s2++){ - if ((D_80370AC0[sp38].unk4[var_s2] != 0) && (D_80371DC0[var_s2].unk0(arg0, arg1) == D_80371DC0[var_s2].unk4)) { - func_80330078(arg1, arg0, D_80370AC0[sp38].unk4 + var_s2); - func_80330078(arg0, arg1, D_80370AC0[sp38].unk4 + var_s2); + if ((collision_table[collision_index].collisionTypes[var_s2] != 0) && (D_80371DC0[var_s2].unk0(arg0, arg1) == D_80371DC0[var_s2].unk4)) { + func_80330078(arg1, arg0, collision_table[collision_index].collisionTypes + var_s2); + func_80330078(arg0, arg1, collision_table[collision_index].collisionTypes + var_s2); break; } } - return true; + return TRUE; } s32 collision_getPlayerInteraction(CollisionParams *arg0){ + // Player Bounce vs Player Knockback + // Includes the distance the player is sent return arg0->playerInteraction; } enum marker_collision_func_type_e collision_getNextState(CollisionParams *arg0){ + // 01 -> Alternate State + // 10 -> Death return arg0->nextState; } @@ -304,9 +333,16 @@ s32 collision_getDamageToPlayer(CollisionParams *arg0){ } s32 collision_getHitsToTrigger(CollisionParams *arg0){ + // Enemies have health + // 1 divided by hits to trigger = % of health the enemy loses return arg0->hitsToTrigger; } s32 collision_getDropBundleNum(CollisionParams *arg0){ + // By default, + // 0 is nothing + // 1 is one honeycomb + // 2 is two honeycombs + // 3 is three honeycombs return arg0->dropBundleNum; } diff --git a/src/core2/collision/polydetect.c b/src/core2/collision/polydetect.c index 9d3869777..1903fd150 100644 --- a/src/core2/collision/polydetect.c +++ b/src/core2/collision/polydetect.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_B9090.c #include "functions.h" #include "variables.h" #include diff --git a/src/core2/collision/raycast.c b/src/core2/collision/raycast.c index 3192cbe9a..c4422b518 100644 --- a/src/core2/collision/raycast.c +++ b/src/core2/collision/raycast.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_94A20.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/collision/raycastmap.c b/src/core2/collision/scarabbeetle.c similarity index 97% rename from src/core2/collision/raycastmap.c rename to src/core2/collision/scarabbeetle.c index d98f84bef..d0bfcebd6 100644 --- a/src/core2/collision/raycastmap.c +++ b/src/core2/collision/scarabbeetle.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/ch/scarabbeetle.c #include #include "functions.h" #include "variables.h" @@ -5,8 +6,8 @@ extern BKCollisionTriangle *func_80320DB0(f32[3], f32, f32[3], u32); /* .h */ -Actor *func_80358344(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx); -void func_80358684(Actor *this); +Actor *chScarabBeetle_draw(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx); +void chScarabBeetle_update(Actor *this); typedef struct { u8 sfxsourceIdx; @@ -24,14 +25,14 @@ typedef struct { }ActorLocal_core2_D0CA0; /* .data */ -ActorInfo D_803728A0 = { +// Scabby +ActorInfo chScarabBeetle = { MARKER_253_SCARAB_BEETLE, ACTOR_380_SCARAB_BEETLE, ASSET_51B_MODEL_SCARAB_BEETLE, 0, NULL, - func_80358684, NULL, func_80358344, + chScarabBeetle_update, NULL, chScarabBeetle_draw, 0, 0, 1.0f, 0 }; - /* .code */ bool func_80357C30(Actor *this) { ActorLocal_core2_D0CA0 *local; @@ -195,7 +196,7 @@ void func_80358304(ActorMarker *marker, ActorMarker *other_marker){ } } -Actor *func_80358344(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx) { +Actor *chScarabBeetle_draw(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx) { Actor *this; ActorLocal_core2_D0CA0 *local; @@ -266,7 +267,7 @@ void func_80358610(Actor *this) { func_80358524(this->position, 4, 0x520); } -void func_80358684(Actor *this) { +void chScarabBeetle_update(Actor *this) { f32 sp94[3]; ActorLocal_core2_D0CA0 *local; //sp90 s32 next_state; //sp8C diff --git a/src/core2/collision/spherecast.c b/src/core2/collision/spherecast.c index 0522afcc4..6c9ce5982 100644 --- a/src/core2/collision/spherecast.c +++ b/src/core2/collision/spherecast.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_A4D00.c #include "functions.h" #include "structs.h" #include "variables.h" diff --git a/src/core2/collision/tricheck.c b/src/core2/collision/tricheck.c index 37f171478..51a539d4a 100644 --- a/src/core2/collision/tricheck.c +++ b/src/core2/collision/tricheck.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_BDCC0.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/crc_bootvalidation.c b/src/core2/crc_bootvalidation.c index 73c64a4ee..079c30546 100644 --- a/src/core2/crc_bootvalidation.c +++ b/src/core2/crc_bootvalidation.c @@ -1,92 +1,90 @@ +// BanjoDecomp: core2/code_CF5F0.c #include -#include "functions.h" -#include "variables.h" +#include "bool.h" +#include "checksums.h" +#include "enums.h" -//THIS VALUE -#ifndef CORE2_CODE_CRC2 - #define CORE2_CODE_CRC2 0x9E44C2DC -#endif - -// bk_boot segment start (skipping entry function) -extern u8 boot_bk_boot_ROM_START[]; -// bk_boot segment end -extern u8 boot_bk_boot_ROM_END[]; -extern u8 crc_ROM_START[]; +extern u8 boot_bk_boot_ROM_START[]; // bk_boot segment start (skipping entry function) +extern u8 boot_bk_boot_ROM_END[]; // bk_boot segment end -// bk_boot segment crc next word s32 D_803727F0 = 0; -s32 D_803727F4 = CORE2_CODE_CRC2; +s32 D_803727F4 = VER_SELECT(0x9E44C2DC, 0xC1A6FD58, 0, 0); // CORE2_TEXT_CRC2 s32 D_803727F8 = 0; -s32 D_803727FC = 0; -// bk_boot segment crc values -s32 D_80372800 = 0; -s32 D_80372804 = 0; +s32 sBootROMOffset = 0; +u32 sCalculatedChecksum1 = 0; +u32 sCalculatedChecksum2 = 0; +s32 sBootROMRemainingBytes = 0; -// bk_boot segment crc remaining words -s32 D_80372808 = 0; - -// init bk_boot crc -void codeCF5F0_initChecksumsVars(void) { +void codeCF5F0_reset(void) { #if ANTI_TAMPER - D_803727FC = (s32) boot_bk_boot_ROM_START; - D_80372800 = 0; - D_80372804 = -1; - D_80372808 = (s32) (boot_bk_boot_ROM_END - boot_bk_boot_ROM_START); + sBootROMOffset = (s32) boot_bk_boot_ROM_START; + sCalculatedChecksum1 = 0; + sCalculatedChecksum2 = -1; + sBootROMRemainingBytes = (s32) (boot_bk_boot_ROM_END - boot_bk_boot_ROM_START); #endif } -// advance bk_boot crc by one word -s32 codeCF5F0_areChecksumsValid(void) { - // Lighthouse TODO what should this actually return? +bool codeCF5F0_validate(void) { #if ANTI_TAMPER - u32 crc1; - u32 crc2; - u8 romBytes[4]; - u8 curByte; - - if (D_803727FC != 0) { - if (D_80372808 != 0) { - crc1 = D_80372800; - crc2 = D_80372804; - osPiReadIo(D_803727FC, (u32*)romBytes); - curByte = romBytes[0]; - crc1 += curByte; - crc2 ^= curByte << (crc1 & 0x17); - curByte = romBytes[1]; - crc1 += curByte; - crc2 ^= curByte << (crc1 & 0x17); - curByte = romBytes[2]; - crc1 += curByte; - crc2 ^= curByte << (crc1 & 0x17); - curByte = romBytes[3]; - crc1 += curByte; - crc2 ^= curByte << (crc1 & 0x17); - D_80372800 = crc1; - D_80372804 = crc2; - D_803727FC = D_803727FC + 4; - D_80372808 = D_80372808 - 4; + u32 checksum1, checksum2; + u8 rom_bytes[4]; + u8 cur_byte; + + if (sBootROMOffset != 0) { + if (sBootROMRemainingBytes != 0) { + checksum1 = sCalculatedChecksum1; + checksum2 = sCalculatedChecksum2; + + osPiReadIo(sBootROMOffset, (u32 *) rom_bytes); + + cur_byte = rom_bytes[0]; + checksum1 += cur_byte; + checksum2 ^= cur_byte << (checksum1 & 0x17); + + cur_byte = rom_bytes[1]; + checksum1 += cur_byte; + checksum2 ^= cur_byte << (checksum1 & 0x17); + + cur_byte = rom_bytes[2]; + checksum1 += cur_byte; + checksum2 ^= cur_byte << (checksum1 & 0x17); + + cur_byte = rom_bytes[3]; + checksum1 += cur_byte; + checksum2 ^= cur_byte << (checksum1 & 0x17); + + sCalculatedChecksum1 = checksum1; + sCalculatedChecksum2 = checksum2; + + sBootROMOffset += 4; + sBootROMRemainingBytes -= 4; } else { - D_803727FC = 0; - osPiReadIo((u32)crc_ROM_START + 0, &crc1); - if (crc1 != D_80372800) - return 0; - osPiReadIo((u32)crc_ROM_START + 4, &crc2); - if (crc2 != D_80372804) - return 0; + sBootROMOffset = 0; + + osPiReadIo((u32) crc_ROM_START + CRC_BOOT_TEXT_CHECKSUM1, &checksum1); + if (checksum1 != sCalculatedChecksum1) + return FALSE; + + osPiReadIo((u32) crc_ROM_START + CRC_BOOT_TEXT_CHECKSUM2, &checksum2); + if (checksum2 != sCalculatedChecksum2) + return FALSE; } } #endif - return 1; + + return TRUE; } -void func_80356714(void) { - codeCF5F0_initChecksumsVars(); +void codeCF5F0_init(void) { + codeCF5F0_reset(); } -void codeCF5F0_forgetAllAbilitiesExceptClawSwipeIfChecksumsFail(void) { - codeCF5F0_areChecksumsValid(); - if (codeCF5F0_areChecksumsValid() == 0) { - ability_setAllLearned(0x10); +void codeCF5F0_triggerAntiTamperMeasurement(void) { +#if ANTI_TAMPER + codeCF5F0_validate(); + if (!codeCF5F0_validate()) { + ability_setAllLearned(1 << ABILITY_4_CLAW_SWIPE); } +#endif } diff --git a/src/core2/demo_input.c b/src/core2/demo.c similarity index 98% rename from src/core2/demo_input.c rename to src/core2/demo.c index 9b089624d..3f687c49c 100644 --- a/src/core2/demo_input.c +++ b/src/core2/demo.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/demo.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/dialog/binload.c b/src/core2/dialog/binload.c index 9b25f9d38..24b0ad99b 100644 --- a/src/core2/dialog/binload.c +++ b/src/core2/dialog/binload.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_94620.c #include #include "functions.h" #include "variables.h" @@ -18,7 +19,7 @@ s32 code94620_func_8031B5B0(void) { return s_dialogBin.unk0; } -s32 func_8031B5BC(void){ return ResourceMgr_GetDialogLanguageCount(); } +s32 func_8031B5BC(void){ return VER_SELECT(1, 3, 0, 0); } void func_8031B5C4(s32 arg0) { if ((arg0 >= 0) && (arg0 < func_8031B5BC())) { diff --git a/src/core2/dialog/progressDialog.c b/src/core2/dialog/progressDialog.c new file mode 100644 index 000000000..e81c5cd4c --- /dev/null +++ b/src/core2/dialog/progressDialog.c @@ -0,0 +1,135 @@ +// BanjoDecomp: core2/progressDialog.c +#include +#include "functions.h" +#include "variables.h" + +typedef KEY_VALUE_PAIR(s16, s16) MapProgressFlagToDialogID; + +/* Mapping for file progess flags to Dialog IDs */ +MapProgressFlagToDialogID fileProgressDialogMap[] = { + { FILEPROG_AB_SWIM_OILY_WATER, VER_SELECT(ASSET_BA1_DIALOG_GRUNTY_TOUCH_OILY_WATER, 0x976, 0, 0)}, + { FILEPROG_AC_DIVE_OILY_WATER, VER_SELECT(ASSET_BA2_DIALOG_GRUNTY_DIVE_OILY_WATER, 0x977, 0, 0)}, + { FILEPROG_AA_HAS_TOUCHED_CCW_BRAMBLE_FIELD, VER_SELECT(ASSET_CE6_DIALOG_GRUNTY_TOUCH_BRAMBLE, 0x9FB, 0, 0)}, + { FILEPROG_F_HAS_TOUCHED_PIRANHA_WATER, VER_SELECT(ASSET_C85_DIALOG_PIRANHA_TOUCH_SWAMP_WATER, 0x9C8, 0, 0)}, + { FILEPROG_A9_HAS_TOUCHED_RBB_OVEN, VER_SELECT(ASSET_BA0_DIALOG_GRUNTY_TOUCH_OVEN, 0x975, 0, 0)}, + { FILEPROG_10_HAS_TOUCHED_SAND_EEL_SAND, VER_SELECT(ASSET_A7E_DIALOG_SAND_EELS_MEET, 0x93A, 0, 0)}, + { FILEPROG_14_HAS_TOUCHED_FP_ICY_WATER, VER_SELECT(ASSET_C11_DIALOG_TOUCH_ICY_WATER, 0x98B, 0, 0)}, + { FILEPROG_F_HAS_TOUCHED_PIRANHA_WATER, VER_SELECT(ASSET_C85_DIALOG_PIRANHA_TOUCH_SWAMP_WATER, 0x9C8, 0, 0)}, + { FILEPROG_86_HAS_TOUCHED_MMM_THORN_HEDGE, VER_SELECT(ASSET_AE1_DIALOG_GRUNTY_HEDGE_THORNS, 0x953, 0, 0)}, + { FILEPROG_DD_HAS_TOUCHED_CCW_ICY_WATER, VER_SELECT(ASSET_CE7_DIALOG_GRUNTY_TOUCH_ICY_WATER, 0x9FC, 0, 0)}, + { FILEPROG_3_MUSIC_NOTE_TEXT, VER_SELECT(ASSET_D9C_DIALOG_MUSIC_NOTE_MEET, 0xA1A, 0, 0)}, + { FILEPROG_4_MUMBO_TOKEN_TEXT, VER_SELECT(ASSET_D9D_DIALOG_MUMBO_TOKEN_MEET, 0xA1B, 0, 0)}, + { FILEPROG_5_BLUE_EGG_TEXT, VER_SELECT(ASSET_D9E_DIALOG_BLUE_EGG_MEET, 0xA1C, 0, 0)}, + { FILEPROG_6_RED_FEATHER_TEXT, VER_SELECT(ASSET_D9F_DIALOG_RED_FEATHER_MEET, 0xA1D, 0, 0)}, + { FILEPROG_7_GOLD_FEATHER_TEXT, VER_SELECT(ASSET_DA0_DIALOG_GOLD_FEATHER_MEET, 0xA1E, 0, 0)}, + { FILEPROG_8_ORANGE_TEXT, VER_SELECT(ASSET_B46_DIALOG_CONGA_COLLECT_ORANGE, 0x964, 0, 0)}, + { FILEPROG_9_GOLD_BULLION_TEXT, VER_SELECT(ASSET_A21_DIALOG_BLUBBER_MEET, 0x921, 0, 0)}, + { FILEPROG_A_HONEYCOMB_TEXT, VER_SELECT(ASSET_DA1_DIALOG_HONEYCOMB_MEET, 0xA1F, 0, 0)}, + { FILEPROG_B_EMPTY_HONEYCOMB_TEXT, VER_SELECT(ASSET_DA2_DIALOG_EMPTY_HONEYCOMB_MEET, 0xA20, 0, 0)}, + { FILEPROG_C_EXTRA_LIFE_TEXT, VER_SELECT(ASSET_DA3_DIALOG_EXTRA_LIFE_MEET, 0xA21, 0, 0)}, + { FILEPROG_BE_CHEATO_BLUEEGGS, VER_SELECT(ASSET_FA8_EGG_CHEAT_ACTIVATION, 0xB0E, 0, 0)}, + { FILEPROG_BF_CHEATO_REDFEATHERS, VER_SELECT(ASSET_FA9_RED_FEATHER_CHEAT_ACTIVATION, 0xB0F, 0, 0)}, + { FILEPROG_C0_CHEATO_GOLDFEATHERS, VER_SELECT(ASSET_FAA_GOLD_FEATHER_CHEAT_ACTIVATION, 0xB10, 0, 0)}, + { FILEPROG_95_UNUSED_UNKNOWN_ITEM_COLLECT, VER_SELECT(ASSET_B50_DIALOG_BOTTLES_BACKPACK_STORE, 0x96E, 0, 0)}, + { FILEPROG_A7_NEAR_PUZZLE_PODIUM_TEXT, VER_SELECT(ASSET_F7B_DIALOG_BOTTLES_JIGSAW_PICTURE_MEET, 0xAE1, 0, 0)}, + { -1, -1 } +}; + +/* This progress IDs are not saved in the save file, like when Banjo goes near a Note door which requires more notes than the Banjo has. */ +/* Triggers a dialog every time after the game restarts. */ +MapProgressFlagToDialogID gVolatileFlagDialogMap[] = { + { VOLATILE_FLAG_9E_BETA_OILY_SCUM, VER_SELECT(ASSET_BA3_DIALOG_GRUNTY_TOUCH_OILY_WATER_2, 0x978, 0, 0)}, // (unused) + { VOLATILE_FLAG_9F_BETA_DIVE_IN_ICY_WATER, VER_SELECT(ASSET_CE8_DIALOG_GRUNTY_TOUCH_ICY_WATER_2, 0x9FD, 0, 0)}, // (unused) + { VOLATILE_FLAG_A0_FF_FIRST_ANSWER_RIGHT, VER_SELECT(ASSET_1032_DIALOG_FF_FIRST_ANSWER_CORRECT, 0xB3A, 0, 0)}, + { VOLATILE_FLAG_A1_FF_NEXT_ANSWER_RIGHT, VER_SELECT(ASSET_1033_DIALOG_FF_NEXT_ANSWER_CORRECT, 0xB3B, 0, 0)}, + { VOLATILE_FLAG_A2_FF_GRUNTY_ANSWER_RIGHT, VER_SELECT(ASSET_1034_DIALOG_FF_GRUNTY_ANSWER_CORRECT, 0xB3C, 0, 0)}, + { VOLATILE_FLAG_A3_FF_FIRST_ANSWER_WRONG, VER_SELECT(ASSET_1035_DIALOG_FF_FIRST_ANSWER_WRONG, 0xB3D, 0, 0)}, + { VOLATILE_FLAG_A4_FF_NEXT_ANSWER_WRONG, VER_SELECT(ASSET_1036_DIALOG_FF_NEXT_ANSWER_WRONG, 0xB3E, 0, 0)}, + { VOLATILE_FLAG_A5_FF_UNUSED, VER_SELECT(ASSET_1037_DIALOG_FF_CHOICE_IS_YOURS_UNUSED, 0xB3F, 0, 0)}, + { VOLATILE_FLAG_A6_FF_FOUND_HONEYCOMB, VER_SELECT(ASSET_1038_DIALOG_FF_GET_HONEYCOMB, 0xB40, 0, 0)}, + { VOLATILE_FLAG_A7_FF_FOUND_EXTRALIFE, VER_SELECT(ASSET_1039_DIALOG_FF_GET_EXTRA_LIFE, 0xB41, 0, 0)}, + { VOLATILE_FLAG_A8_FF_GOT_JOKER, VER_SELECT(ASSET_103A_DIALOG_FF_GET_JOKER, 0xB42, 0, 0)}, + { VOLATILE_FLAG_A9_FF_USED_JOKER, VER_SELECT(ASSET_103B_DIALOG_FF_USE_JOKER, 0xB43, 0, 0)}, + { VOLATILE_FLAG_AA_FF_LOW_HEALTH, VER_SELECT(ASSET_103C_DIALOG_FF_LOW_HEALTH, 0xB44, 0, 0)}, + { VOLATILE_FLAG_AB_LAST_LIFE_ON_SKULL, VER_SELECT(ASSET_103D_DIALOG_FF_LOW_HEALTH_ON_SKULL, 0xB45, 0, 0)}, + { VOLATILE_FLAG_AC_GV_TRAPDOOR_MISSED, VER_SELECT(ASSET_A88_DIALOG_GRUNTY_WATER_PYRAMID_DOOR_MISS, 0x944, 0, 0)}, + { VOLATILE_FLAG_AD_MMM_CHURCH_DOOR_MISSED, VER_SELECT(ASSET_AE2_DIALOG_GRUNTY_CHURCH_DOOR_MISS, 0x954, 0, 0)}, + { VOLATILE_FLAG_AE_BGS_WALKWAY_JIGGY_MISSED, VER_SELECT(ASSET_C8B_DIALOG_GRUNTY_LONG_SWITCH_MISS, 0x9CE, 0, 0)}, + { VOLATILE_FLAG_AF_BGS_MAZE_JIGGY_MISSED, VER_SELECT(ASSET_C8C_DIALOG_GRUNTY_SHORT_SWITCH_MISS, 0x9CF, 0, 0)}, + { VOLATILE_FLAG_B0_NOT_ENOUGH_NOTES, VER_SELECT(ASSET_FBD_DIALOG_GRUNTY_NOT_ENOUGH_NOTES, 0xB23, 0, 0)}, + { VOLATILE_FLAG_C2_NOBONUS_TEXT, VER_SELECT(ASSET_E36_DIALOG_BOTTLES_NO_BONUS, 0xA78, 0, 0)}, + { VOLATILE_FLAG_C5_WISHYWASHYBANJO_TEXT, VER_SELECT(ASSET_DB6_DIALOG_MUMBO_WISHYWASHY, 0xA34, 0, 0)}, + { -1, -1 } +}; + +static s32 __findIndex(MapProgressFlagToDialogID *map, s32 key) { + s32 i = 0; + + while (map[i].key >= 0) { + if (key == map[i].key) { + return i; + } + i++; + } + + return -1; +} + +/* Checks for a specific file progress flag and triggers a dialog only if the progress flag was not set and sets the progress flag */ +s32 showProgressFlagDialog(enum file_progress_e progress_flag, s32 arg1) { + s32 index; + + if (fileProgressFlag_get(progress_flag) != 0) { + return 0; + } else { + index = __findIndex(fileProgressDialogMap, progress_flag); + if (index != -1) { + if (gcdialog_showDialog(fileProgressDialogMap[index].value, arg1, 0, 0, 0, 0) != 0) { + fileProgressFlag_set(progress_flag, 1); + } + return fileProgressFlag_get(progress_flag); + } + return 0; + } +} + +void progressDialog_showDialogMaskZero(enum file_progress_e progress_flag){ + showProgressFlagDialog(progress_flag, 0); +} + +void progressDialog_showDialogMaskFour(enum file_progress_e progress_flag) { + showProgressFlagDialog(progress_flag, 4); +} + +/* Checks for a specific "volatile" progress flag and triggers a dialog only if the progress flag was not set and sets the progress flag */ +s32 progressDialog_setAndTriggerDialog(enum volatile_flags_e id, s32 arg1) { + s32 index; + + if (volatileFlag_get(id) != 0) { + return 0; + } else { + index = __findIndex(gVolatileFlagDialogMap, id); + if (index != -1) { + if (gcdialog_showDialog(gVolatileFlagDialogMap[index].value, arg1, 0, 0, 0, 0) != 0) { + volatileFlag_set(id, 1); + } + return volatileFlag_get(id); + } + return 0; + } +} + +// called for dialogs when banjo is not fast enough to reach a door or jiggy and for NOBONUS text +void progressDialog_setAndTriggerDialog_0(enum volatile_flags_e arg0) { + progressDialog_setAndTriggerDialog(arg0, 0); +} + +// called for FFQ dialogs +void progressDialog_setAndTriggerDialog_4(enum volatile_flags_e arg0) { + progressDialog_setAndTriggerDialog(arg0, 4); +} + +// called for WISHYWASHYBANJO dialog, mumbo jumbo speaking? +void progressDialog_setAndTriggerDialog_E(enum volatile_flags_e arg0) { + progressDialog_setAndTriggerDialog(arg0, 0xE); +} diff --git a/src/core2/dialog/progress_dialogs.c b/src/core2/dialog/progress_dialogs.c deleted file mode 100644 index 07089daf3..000000000 --- a/src/core2/dialog/progress_dialogs.c +++ /dev/null @@ -1,134 +0,0 @@ -#include -#include "functions.h" -#include "variables.h" - -typedef KEY_VALUE_PAIR(s16, s16) MapProgressFlagToDialogID; - -/* Mapping for file progess flags to Dialog IDs */ -MapProgressFlagToDialogID fileProgressDialogMap[] = { - { FILEPROG_AB_SWIM_OILY_WATER, 0xBA1}, - { FILEPROG_AC_DIVE_OILY_WATER, 0xBA2}, - { FILEPROG_AA_HAS_TOUCHED_CCW_BRAMBLE_FIELD, 0xCE6}, - { FILEPROG_F_HAS_TOUCHED_PIRANHA_WATER, 0xC85}, - { FILEPROG_A9_HAS_TOUCHED_RBB_OVEN, 0xBA0}, - { FILEPROG_10_HAS_TOUCHED_SAND_EEL_SAND, 0xA7E}, - { FILEPROG_14_HAS_TOUCHED_FP_ICY_WATER, 0xC11}, - { FILEPROG_F_HAS_TOUCHED_PIRANHA_WATER, 0xC85}, - { FILEPROG_86_HAS_TOUCHED_MMM_THORN_HEDGE, 0xAE1}, - { FILEPROG_DD_HAS_TOUCHED_CCW_ICY_WATER, 0xCE7}, - { FILEPROG_3_MUSIC_NOTE_TEXT, 0xD9C}, - { FILEPROG_4_MUMBO_TOKEN_TEXT, 0xD9D}, - { FILEPROG_5_BLUE_EGG_TEXT, 0xD9E}, - { FILEPROG_6_RED_FEATHER_TEXT, 0xD9F}, - { FILEPROG_7_GOLD_FEATHER_TEXT, 0xDA0}, - { FILEPROG_8_ORANGE_TEXT, 0xB46}, - { FILEPROG_9_GOLD_BULLION_TEXT, 0xA21}, - { FILEPROG_A_HONEYCOMB_TEXT, 0xDA1}, - { FILEPROG_B_EMPTY_HONEYCOMB_TEXT, 0xDA2}, - { FILEPROG_C_EXTRA_LIFE_TEXT, 0xDA3}, - { FILEPROG_BE_CHEATO_BLUEEGGS, 0xFA8}, - { FILEPROG_BF_CHEATO_REDFEATHERS, 0xFA9}, - { FILEPROG_C0_CHEATO_GOLDFEATHERS, 0xFAA}, - { FILEPROG_95_UNUSED_UNKNOWN_ITEM_COLLECT, 0xB50}, - { FILEPROG_A7_NEAR_PUZZLE_PODIUM_TEXT, 0xF7B}, - { -1, -1} -}; - -/* This progress IDs are not saved in the save file, like when Banjo goes near a Note door which requires more notes than the Banjo has. */ -/* Triggers a dialog every time after the game restarts. */ -MapProgressFlagToDialogID gVolatileFlagDialogMap[] = { - {VOLATILE_FLAG_9E_BETA_OILY_SCUM, 0xBA3}, // Oily scum (unused) - {VOLATILE_FLAG_9F_BETA_DIVE_IN_ICY_WATER, 0xCE8}, // Dive in icy water (unused) - {VOLATILE_FLAG_A0_FF_FIRST_ANSWER_RIGHT, 0x1032}, - {VOLATILE_FLAG_A1_FF_NEXT_ANSWER_RIGHT, 0x1033}, - {VOLATILE_FLAG_A2_FF_GRUNTY_ANSWER_RIGHT, 0x1034}, - {VOLATILE_FLAG_A3_FF_FIRST_ANSWER_WRONG, 0x1035}, - {VOLATILE_FLAG_A4_FF_NEXT_ANSWER_WRONG, 0x1036}, - {VOLATILE_FLAG_A5_FF_UNUSED, 0x1037}, // FF "the choice is yours" - {VOLATILE_FLAG_A6_FF_FOUND_HONEYCOMB, 0x1038}, - {VOLATILE_FLAG_A7_FF_FOUND_EXTRALIFE, 0x1039}, - {VOLATILE_FLAG_A8_FF_GOT_JOKER, 0x103A}, - {VOLATILE_FLAG_A9_FF_USED_JOKER, 0x103B}, - {VOLATILE_FLAG_AA_FF_LOW_HEALTH, 0x103C}, - {VOLATILE_FLAG_AB_LAST_LIFE_ON_SKULL, 0x103D}, - {VOLATILE_FLAG_AC_GV_TRAPDOOR_MISSED, 0xA88}, - {VOLATILE_FLAG_AD_MMM_CHURCH_DOOR_MISSED, 0xAE2}, - {VOLATILE_FLAG_AE_BGS_WALKWAY_JIGGY_MISSED, 0xC8B}, - {VOLATILE_FLAG_AF_BGS_MAZE_JIGGY_MISSED, 0xC8C}, - {VOLATILE_FLAG_B0_NOT_ENOUGH_NOTES, 0xFBD}, - {VOLATILE_FLAG_C2_NOBONUS_TEXT, 0xE36}, - {VOLATILE_FLAG_C5_WISHYWASHYBANJO_TEXT, 0xDB6}, - { -1, -1} -}; - -static s32 __findIndex(MapProgressFlagToDialogID *map, s32 key) { - s32 i = 0; - - while (map[i].key >= 0) { - if (key == map[i].key) { - return i; - } - i++; - } - - return -1; -} - -/* Checks for a specific file progress flag and triggers a dialog only if the progress flag was not set and sets the progress flag */ -s32 showProgressFlagDialog(enum file_progress_e progress_flag, s32 arg1) { - s32 index; - - if (fileProgressFlag_get(progress_flag) != 0) { - return 0; - } else { - index = __findIndex(fileProgressDialogMap, progress_flag); - if (index != -1) { - if (gcdialog_showDialog(fileProgressDialogMap[index].value, arg1, 0, 0, 0, 0) != 0) { - fileProgressFlag_set(progress_flag, 1); - } - return fileProgressFlag_get(progress_flag); - } - return 0; - } -} - -void progressDialog_showDialogMaskZero(enum file_progress_e progress_flag){ - showProgressFlagDialog(progress_flag, 0); -} - -void progressDialog_showDialogMaskFour(enum file_progress_e progress_flag) { - showProgressFlagDialog(progress_flag, 4); -} - -/* Checks for a specific "volatile" progress flag and triggers a dialog only if the progress flag was not set and sets the progress flag */ -s32 volatileFlag_setAndTriggerDialog(enum volatile_flags_e id, s32 arg1) { - s32 index; - - if (volatileFlag_get(id) != 0) { - return 0; - } else { - index = __findIndex(gVolatileFlagDialogMap, id); - if (index != -1) { - if (gcdialog_showDialog(gVolatileFlagDialogMap[index].value, arg1, 0, 0, 0, 0) != 0) { - volatileFlag_set(id, 1); - } - return volatileFlag_get(id); - } - return 0; - } -} - -// called for dialogs when banjo is not fast enough to reach a door or jiggy and for NOBONUS text -void volatileFlag_setAndTriggerDialog_0(enum volatile_flags_e arg0) { - volatileFlag_setAndTriggerDialog(arg0, 0); -} - -// called for FFQ dialogs -void volatileFlag_setAndTriggerDialog_4(enum volatile_flags_e arg0) { - volatileFlag_setAndTriggerDialog(arg0, 4); -} - -// called for WISHYWASHYBANJO dialog, mumbo jumbo speaking? -void volatileFlag_setAndTriggerDialog_E(enum volatile_flags_e arg0) { - volatileFlag_setAndTriggerDialog(arg0, 0xE); -} diff --git a/src/core2/displaylist_init.c b/src/core2/displaylist_init.c index 7ecdb6c46..8ada226cd 100644 --- a/src/core2/displaylist_init.c +++ b/src/core2/displaylist_init.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_8DC20.c #include "core1/core1.h" #include "functions.h" #include "variables.h" @@ -41,7 +42,7 @@ s32 D_803830A0; void func_80314BB0(Gfx **gfx, Mtx **mtx, Vtx **vtx, void * frame_buffer_1, void *frame_buffer_2) { // [port] GPU-side pause snapshot s32 pauseFb = port_getPauseFramebufferId(); - bool isCapture = (frame_buffer_1 == zBuffer_get()); + bool isCapture = (frame_buffer_1 == depthbuffer_getDataPtr()); gSPDisplayList((*gfx)++, D_8036C630); @@ -79,7 +80,7 @@ void func_80314BB0(Gfx **gfx, Mtx **mtx, Vtx **vtx, void * frame_buffer_1, void void func_80315084(Gfx **gfx, Mtx **mtx, Vtx **vtx){ gsworld_setEnableDraw(0); D_803830A0 = 2; - func_80314BB0(gfx, mtx, vtx, zBuffer_get(), gFramebuffers[getActiveFramebuffer()]); + func_80314BB0(gfx, mtx, vtx, depthbuffer_getDataPtr(), gFramebuffers[getActiveFramebuffer()]); port_mirror_markCapture(); } @@ -93,7 +94,7 @@ void func_80315110(Gfx **gfx, Mtx **mtx, Vtx **vtx){ else{ D_803830A0--; } - func_80314BB0(gfx, mtx, vtx, gFramebuffers[getActiveFramebuffer()], zBuffer_get()); + func_80314BB0(gfx, mtx, vtx, gFramebuffers[getActiveFramebuffer()], depthbuffer_getDataPtr()); } void func_803151D0(Gfx **gfx, Mtx **mtx, Vtx **vtx){ diff --git a/src/core2/fileselect.c b/src/core2/fileselect.c index 837441c61..bd5b6f451 100644 --- a/src/core2/fileselect.c +++ b/src/core2/fileselect.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_B5E00.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/freelist.c b/src/core2/fla.c similarity index 99% rename from src/core2/freelist.c rename to src/core2/fla.c index 2d50f492f..05c22d3fd 100644 --- a/src/core2/freelist.c +++ b/src/core2/fla.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/fla.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/flags_bitfield.c b/src/core2/flags_bitfield.c index 4a66d2da0..055ddee55 100644 --- a/src/core2/flags_bitfield.c +++ b/src/core2/flags_bitfield.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_98CB0.c #include #include "functions.h" #include "variables.h" @@ -5,10 +6,10 @@ void func_8031FFAC(void); void fileProgressFlag_set(enum file_progress_e index, s32 set); -s32 bitfield_get_bit(u8 *array, s32 index); -s32 bitfield_get_n_bits(u8 *array, s32 offset, s32 numBits); -void bitfield_set_bit(u8 *array, s32 index, s32 set); -void bitfield_set_n_bits(u8 *array, s32 startIndex, s32 set, s32 length); +s32 bitfieldarray_getBit(u8 *array, s32 index); +s32 bitfieldarray_getNBits(u8 *array, s32 offset, s32 numBits); +void bitfieldarray_setBit(u8 *array, s32 index, s32 set); +void bitfieldarray_setNBits(u8 *array, s32 startIndex, s32 set, s32 length); void volatileFlag_clear(void); void volatileFlag_set(enum volatile_flags_e index, s32 set); s32 fileProgressFlag_getN(enum file_progress_e offset, s32 numBits); @@ -117,11 +118,11 @@ void func_8031FEC0(void) { } bool fileProgressFlag_get(enum file_progress_e index) { - return bitfield_get_bit(gFileProgressFlags.unk8, index); + return bitfieldarray_getBit(gFileProgressFlags.unk8, index); } s32 fileProgressFlag_getN(enum file_progress_e offset, s32 numBits) { - return bitfield_get_n_bits(gFileProgressFlags.unk8, offset, numBits); + return bitfieldarray_getNBits(gFileProgressFlags.unk8, offset, numBits); } s32 fileProgressFlag_getAndSet(enum file_progress_e index, s32 set) { @@ -143,8 +144,8 @@ void func_8031FFAC(void) { } void fileProgressFlag_setEx(enum file_progress_e index, s32 set, s32 triggerEvent) { - s32 changed = bitfield_get_bit(gFileProgressFlags.unk8, index) != (set ? 1 : 0); - bitfield_set_bit(gFileProgressFlags.unk8, index, set); + s32 changed = bitfieldarray_getBit(gFileProgressFlags.unk8, index) != (set ? 1 : 0); + bitfieldarray_setBit(gFileProgressFlags.unk8, index, set); func_8031FC40(); func_8031FEC0(); if (triggerEvent && changed) { @@ -157,7 +158,7 @@ void fileProgressFlag_set(enum file_progress_e index, s32 set) { } void fileProgressFlag_setN(enum file_progress_e startIndex, s32 set, s32 length) { - bitfield_set_n_bits(gFileProgressFlags.unk8, startIndex, set, length); + bitfieldarray_setNBits(gFileProgressFlags.unk8, startIndex, set, length); func_8031FC40(); func_8031FEC0(); CALL_EVENT(OnGameFlagSet, ANCHOR_FLAGSPACE_FILE_PROGRESS, startIndex, set, length); @@ -169,7 +170,7 @@ void fileProgressFlag_getSizeAndPtr(s32 *size, u8 **addr) { } // Returns a single bit from a byte array -s32 bitfield_get_bit(u8 *array, s32 index) { +s32 bitfieldarray_getBit(u8 *array, s32 index) { s32 ret; if (array[index / 8] & (1 << (index & 7))) { ret = 1; @@ -180,18 +181,18 @@ s32 bitfield_get_bit(u8 *array, s32 index) { } // Extracts an integer of the given number of bits from a byte array at the starting bit offset -s32 bitfield_get_n_bits(u8 *array, s32 offset, s32 numBits) { +s32 bitfieldarray_getNBits(u8 *array, s32 offset, s32 numBits) { s32 ret = 0; s32 i; for (i = 0; i < numBits; i++) { - ret |= (bitfield_get_bit(array, offset + i) << i); + ret |= (bitfieldarray_getBit(array, offset + i) << i); } return ret; } // Sets or clears a single bit in a byte array -void bitfield_set_bit(u8 *array, s32 index, s32 set) { +void bitfieldarray_setBit(u8 *array, s32 index, s32 set) { if (set) { array[index / 8] |= (1 << (index & 7)); } else { @@ -200,11 +201,11 @@ void bitfield_set_bit(u8 *array, s32 index, s32 set) { } // Sets or clears a range of bits in a byte array -void bitfield_set_n_bits(u8 *array, s32 startIndex, s32 set, s32 length) { +void bitfieldarray_setNBits(u8 *array, s32 startIndex, s32 set, s32 length) { s32 i; for (i = 0; i < length; i++) { - bitfield_set_bit(array, startIndex + i, (1 << i) & set); + bitfieldarray_setBit(array, startIndex + i, (1 << i) & set); } } @@ -282,11 +283,11 @@ void func_803203A0(void) { } s32 volatileFlag_get(enum volatile_flags_e index) { - return bitfield_get_bit(gVolatileFlags.unk8, index); + return bitfieldarray_getBit(gVolatileFlags.unk8, index); } s32 volatileFlag_getN(enum volatile_flags_e index, s32 numBits) { - return bitfield_get_n_bits(gVolatileFlags.unk8, index, numBits); + return bitfieldarray_getNBits(gVolatileFlags.unk8, index, numBits); } s32 volatileFlag_getAndSet(enum volatile_flags_e index, s32 arg1) { @@ -307,8 +308,8 @@ void volatileFlag_clear(void) { } void volatileFlag_setEx(enum volatile_flags_e index, s32 set, s32 triggerEvent) { - s32 changed = bitfield_get_bit(gVolatileFlags.unk8, index) != (set ? 1 : 0); - bitfield_set_bit(gVolatileFlags.unk8, index, set); + s32 changed = bitfieldarray_getBit(gVolatileFlags.unk8, index) != (set ? 1 : 0); + bitfieldarray_setBit(gVolatileFlags.unk8, index, set); func_803202D0(); func_803203A0(); if (triggerEvent && changed) { @@ -321,7 +322,7 @@ void volatileFlag_set(enum volatile_flags_e index, s32 set) { } void volatileFlag_setN(enum volatile_flags_e startIndex, s32 set, s32 length) { - bitfield_set_n_bits(gVolatileFlags.unk8, startIndex, set, length); + bitfieldarray_setNBits(gVolatileFlags.unk8, startIndex, set, length); func_803202D0(); func_803203A0(); CALL_EVENT(OnGameFlagSet, ANCHOR_FLAGSPACE_VOLATILE, startIndex, set, length); diff --git a/src/core2/font/print.c b/src/core2/font/print.c index fe7722af4..0eb3d84ff 100644 --- a/src/core2/font/print.c +++ b/src/core2/font/print.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/print.c #include #include "core1/core1.h" #include "functions.h" @@ -6,6 +7,8 @@ #include "port/Patches/Patches.h" #include "port/ResourceHelpers.h" +#define PRINT_JP (ResourceMgr_IsJapanese()) + typedef struct{ s8 pad0[0x20]; } struct23s; @@ -29,17 +32,17 @@ typedef struct font_letter{ typedef struct map_font_texture_map{ s16 mapID; s16 assetId; -} MapFontTextureMap; +} MapToBoldFontTextureMap; typedef struct{ u8 firstLetter; u8 secondLetter; s8 xOffset; s8 yOffset; -}Struct_6DA30_0_s; +}BoldFontKerningData; /* .data */ -extern Struct_6DA30_0_s boldFontKernings[] = { +extern BoldFontKerningData boldFontKernings[] = { {'A', 'V', -3, 0}, {'W', 'A', -3, 0}, {'V', 'A', -3, 0}, @@ -68,16 +71,16 @@ extern Struct_6DA30_0_s boldFontKernings[] = { 0 }; -s32 D_80369068[] = {8, 16, 16, 0}; //max letter width +s32 maxFontLetterWidths[] = {8, 16, 16, 0}; //max letter width struct { - u8 unk0; - u8 unk1; - u8 unk2; - u8 unk3; + u8 r; + u8 g; + u8 b; + u8 a; } normalTextColor = {0xFF, 0xFF, 0xFF, 0XFF}; -MapFontTextureMap mapToBoldFontTextureMap[] ={ +MapToBoldFontTextureMap mapToBoldFontTextureMap[] ={ {MAP_1_SM_SPIRAL_MOUNTAIN, SPRITE_BOLD_FONT_BLUE_SPHERE_TEXTURE}, {MAP_2_MM_MUMBOS_MOUNTAIN, 0x6EF}, {0x3, 0x6EE}, @@ -198,28 +201,28 @@ Gfx D_80369238[] = { }; /* .bss */ -char D_80380AB0; -BKSprite *D_80380AB8[0x5]; +char print_sPreviousBoldLetter; +BKSprite *print_sFontSpriteAssets[0x5]; FontLetter *print_sFonts[4]; PrintBuffer *print_sPrintBuffer; PrintBuffer *print_sCurrentPtr; -s32 D_80380AE8; -s32 D_80380AEC; -s32 D_80380AF0; //print_sMonospaced -s32 D_80380AF4; -s32 D_80380AF8; -s32 D_80380AFC; -s32 D_80380B00; -s32 D_80380B04; +s32 print_sCurrentFont; +s32 print_sPreviousFont; +s32 print_sMonospacedModeEnabled; //print_sMonospaced +s32 print_sGradientModeEnabled; +s32 print_sGradient2ModeEnabled; +s32 print_sBrokenFontModeEnabled; +s32 print_sBackgroundModeEnabled; +s32 print_sUnknownMode; bool print_sInFontFormatMode; s32 D_80380B0C; -s32 D_80380B10; -s32 D_80380B14; -s32 D_80380B18; -s32 D_80380B1C; +s32 print_sShakyModeEnabled; +s32 print_sBilinearFilterModeEnabled; +s32 print_sBoldLetterFontFreeTimer; +s32 print_sCurrentBoldFontTexture; s8 D_80380B20[0x400]; -s8 D_80380F20[0x80]; +s8 print_sBoldFontLetterToSpriteMap[0x80]; s32 print_sDialogFontGlyphCount; // [port] actual glyph count from loaded font sprite @@ -300,7 +303,7 @@ void print_applyTextureToBoldFontLetter(BKSpriteTextureBlock *alphaMask, BKSprit FontLetter *print_getLettersFromFont(BKSprite *alphaMask, BKSprite *textureSprite){ BKSpriteFrame * font = sprite_getFramePtr(alphaMask, 0); BKSpriteTextureBlock *chunkPtr; - FontLetter * sp2C = bk_malloc((font->chunkCnt + 1)*sizeof(FontLetter)); + FontLetter * letters = bk_malloc((font->chunkCnt + 1)*sizeof(FontLetter)); u8* palDataPtr; u8* chunkDataPtr; s32 chunkSize; @@ -324,8 +327,8 @@ FontLetter *print_getLettersFromFont(BKSprite *alphaMask, BKSprite *textureSprit while((uintptr_t)chunkDataPtr % 8) chunkDataPtr++; - sp2C[i].sprite = chunkPtr; - sp2C[i].palette = palDataPtr; + letters[i].sprite = chunkPtr; + letters[i].palette = palDataPtr; chunkSize = chunkPtr->w*chunkPtr->h; chunkPtr = (BKSpriteTextureBlock *)(chunkDataPtr + chunkSize); } @@ -345,7 +348,7 @@ FontLetter *print_getLettersFromFont(BKSprite *alphaMask, BKSprite *textureSprit BKSpriteTextureBlock *copy = bk_malloc(copySize); memcpy(copy, chunkPtr, copySize); print_applyTextureToBoldFontLetter(copy, (BKSpriteTextureBlock *)(sprite_getFramePtr(textureSprite, 0) + 1)); - sp2C[i].sprite = copy; + letters[i].sprite = copy; CALL_EVENT(OnBoldFontLetterBuilt, copy, chunkPtr, (BKSpriteTextureBlock *)(sprite_getFramePtr(textureSprite, 0) + 1)); } @@ -360,7 +363,7 @@ FontLetter *print_getLettersFromFont(BKSprite *alphaMask, BKSprite *textureSprit { chunkPtr = (BKSpriteTextureBlock *) (font + 1); for( i = 0; i < font->chunkCnt; i++){ - sp2C[i].sprite = chunkPtr; + letters[i].sprite = chunkPtr; chunkDataPtr = (u8*)(chunkPtr + 1); chunkSize = chunkPtr->w*chunkPtr->h; while((uintptr_t)chunkDataPtr % 8) @@ -374,7 +377,7 @@ FontLetter *print_getLettersFromFont(BKSprite *alphaMask, BKSprite *textureSprit chunkPtr = (BKSpriteTextureBlock *)(font + 1); for( i = 0; i < font->chunkCnt; i++){ chunkDataPtr = (u8*)(chunkPtr + 1); - sp2C[i].sprite = chunkPtr; + letters[i].sprite = chunkPtr; chunkSize = chunkPtr->w*chunkPtr->h; while((uintptr_t)chunkDataPtr % 8) chunkDataPtr++; @@ -383,14 +386,14 @@ FontLetter *print_getLettersFromFont(BKSprite *alphaMask, BKSprite *textureSprit } break; }; - return sp2C; + return letters; } void print_free(void){ s32 i; for(i = 0; i< 5; i++){ - assetcache_release(D_80380AB8[i]); - D_80380AB8[i] = NULL; + assetcache_release(print_sFontSpriteAssets[i]); + print_sFontSpriteAssets[i] = NULL; if(i < 4){ bk_free(print_sFonts[i]); print_sFonts[i] = NULL; @@ -412,33 +415,33 @@ void print_setBoldFontTexture(s32 textureId){ CALL_EVENT(OnBoldFontReset); // [port] func_802546E4 reads bk_malloc HeapHeader, but assets now come from resource manager. // code_B3A80_func_8033BDAC is stubbed (returns 0), so always falls through to assetcache_get. - // tmp_a2 = func_802546E4(D_80380AB8[1]); + // tmp_a2 = func_802546E4(print_sFontSpriteAssets[1]); // if(tmp_a2 & 0xF) // tmp_a2 += 0x10 - (tmp_a2 & 0xF); - // if(!code_B3A80_func_8033BDAC(SPRITE_BOLD_FONT_NUMBERS_ALPHAMASK, D_80380AB8[1],tmp_a2)){ - assetcache_release(D_80380AB8[1]); - D_80380AB8[1] = assetcache_get(SPRITE_BOLD_FONT_NUMBERS_ALPHAMASK); + // if(!code_B3A80_func_8033BDAC(SPRITE_BOLD_FONT_NUMBERS_ALPHAMASK, print_sFontSpriteAssets[1],tmp_a2)){ + assetcache_release(print_sFontSpriteAssets[1]); + print_sFontSpriteAssets[1] = assetcache_get(SPRITE_BOLD_FONT_NUMBERS_ALPHAMASK); // } - if(D_80380AB8[3]){ + if(print_sFontSpriteAssets[3]){ // [port] Same as above — func_802546E4 unsafe on resource-manager pointers - // tmp_a2 = func_802546E4(D_80380AB8[3]); + // tmp_a2 = func_802546E4(print_sFontSpriteAssets[3]); // if(tmp_a2 & 0xF) // tmp_a2 += 0x10 - (tmp_a2 & 0xF); - // if(!code_B3A80_func_8033BDAC(SPRITE_BOLD_FONT_LETTERS_ALPHAMASK, D_80380AB8[3],tmp_a2)){ - assetcache_release(D_80380AB8[3]); - D_80380AB8[3] = assetcache_get(SPRITE_BOLD_FONT_LETTERS_ALPHAMASK); + // if(!code_B3A80_func_8033BDAC(SPRITE_BOLD_FONT_LETTERS_ALPHAMASK, print_sFontSpriteAssets[3],tmp_a2)){ + assetcache_release(print_sFontSpriteAssets[3]); + print_sFontSpriteAssets[3] = assetcache_get(SPRITE_BOLD_FONT_LETTERS_ALPHAMASK); // } }//L802F510C - D_80380AB8[4] = assetcache_get(textureId); + print_sFontSpriteAssets[4] = assetcache_get(textureId); bk_free(print_sFonts[1]); - print_sFonts[1] = print_getLettersFromFont(D_80380AB8[1], D_80380AB8[4]); - if(D_80380AB8[3]){ + print_sFonts[1] = print_getLettersFromFont(print_sFontSpriteAssets[1], print_sFontSpriteAssets[4]); + if(print_sFontSpriteAssets[3]){ bk_free(print_sFonts[3]); - print_sFonts[3] = print_getLettersFromFont(D_80380AB8[3], D_80380AB8[4]); + print_sFonts[3] = print_getLettersFromFont(print_sFontSpriteAssets[3], print_sFontSpriteAssets[4]); } - assetcache_release(D_80380AB8[4]); - D_80380AB8[4] = NULL; - D_80380B1C = textureId; + assetcache_release(print_sFontSpriteAssets[4]); + print_sFontSpriteAssets[4] = NULL; + print_sCurrentBoldFontTexture = textureId; } void print_resetBoldFontTexture(void){ @@ -452,29 +455,30 @@ void print_init(void){ int found; length = strlen(boldFontLetters); - D_80380AE8 = \ - D_80380AEC = \ - D_80380AF0 = \ - D_80380AF4 = \ - D_80380AF8 = \ - D_80380AFC = \ + print_sCurrentFont = \ + print_sPreviousFont = \ + print_sMonospacedModeEnabled = \ + print_sGradientModeEnabled = \ + print_sGradient2ModeEnabled = \ + print_sBrokenFontModeEnabled = \ print_sInFontFormatMode = \ - D_80380B04 = \ - D_80380B00 = \ - D_80380B10 = \ - D_80380B14 = 0; - D_80380AB0 = 0; + print_sUnknownMode = \ + print_sBackgroundModeEnabled = \ + print_sShakyModeEnabled = \ + print_sBilinearFilterModeEnabled = 0; + print_sPreviousBoldLetter = 0; func_802F7A2C(3); - D_80380AB8[0] = assetcache_get(SPRITE_DIALOG_FONT_ALPHAMASK); - D_80380AB8[1] = assetcache_get(SPRITE_BOLD_FONT_NUMBERS_ALPHAMASK); - D_80380AB8[4] = assetcache_get(print_getCurrentMapBoldFontTexture()); - print_sFonts[0] = print_getLettersFromFont(D_80380AB8[0], D_80380AB8[4]); - print_sDialogFontGlyphCount = sprite_getFramePtr(D_80380AB8[0], 0)->chunkCnt; + print_sFontSpriteAssets[0] = assetcache_get(SPRITE_DIALOG_FONT_ALPHAMASK); + print_sFontSpriteAssets[1] = assetcache_get(SPRITE_BOLD_FONT_NUMBERS_ALPHAMASK); + print_sFontSpriteAssets[4] = assetcache_get(print_getCurrentMapBoldFontTexture()); + print_sFonts[0] = print_getLettersFromFont(print_sFontSpriteAssets[0], print_sFontSpriteAssets[4]); + print_sDialogFontGlyphCount = sprite_getFramePtr(print_sFontSpriteAssets[0], 0)->chunkCnt; port_dialogFontHd_rebuild(); - print_sFonts[1] = print_getLettersFromFont(D_80380AB8[1], D_80380AB8[4]); - if (ResourceMgr_IsJapanese()) { - D_80380AB8[2] = assetcache_get(SPRITE_JP_DIALOG_FONT_ALPHAMASK); - print_sFonts[2] = print_getLettersFromFont(D_80380AB8[2], D_80380AB8[4]); + print_sFonts[1] = print_getLettersFromFont(print_sFontSpriteAssets[1], print_sFontSpriteAssets[4]); + if (PRINT_JP) { + // [port] JP font index 2 = the Japanese dialog font (sprite 1770, 256 I4 glyphs). + print_sFontSpriteAssets[2] = assetcache_get(SPRITE_JP_DIALOG_FONT_ALPHAMASK); + print_sFonts[2] = print_getLettersFromFont(print_sFontSpriteAssets[2], print_sFontSpriteAssets[4]); } print_sPrintBuffer = bk_malloc(0x20*sizeof(PrintBuffer)); print_clearPrintBufferStrings(); @@ -483,37 +487,37 @@ void print_init(void){ found = 0; for(j = 0; j < length && !found; j++){//L802F5304 if(boldFontLetters[j] == i){ - D_80380F20[i] = j; + print_sBoldFontLetterToSpriteMap[i] = j; found = 1; }//L802F531C }//L802F5330 if(!found) - D_80380F20[i] = -1; + print_sBoldFontLetterToSpriteMap[i] = -1; } - assetcache_release(D_80380AB8[4]); - D_80380AB8[4] = NULL; - D_80380B1C = print_getCurrentMapBoldFontTexture(); + assetcache_release(print_sFontSpriteAssets[4]); + print_sFontSpriteAssets[4] = NULL; + print_sCurrentBoldFontTexture = print_getCurrentMapBoldFontTexture(); } void print_updateBoldLetterFontDelayedFreeing(void){ - if(D_80380B18 > 0 && --D_80380B18 == 0){ - assetcache_release(D_80380AB8[3]); - D_80380AB8[3] = 0; + if(print_sBoldLetterFontFreeTimer > 0 && --print_sBoldLetterFontFreeTimer == 0){ + assetcache_release(print_sFontSpriteAssets[3]); + print_sFontSpriteAssets[3] = 0; bk_free(print_sFonts[3]); print_sFonts[3] = NULL; } } void print_freeBoldLetterFont(void){ - if(D_80380AB8[3]){ - assetcache_release(D_80380AB8[3]); - D_80380AB8[3] = NULL; + if(print_sFontSpriteAssets[3]){ + assetcache_release(print_sFontSpriteAssets[3]); + print_sFontSpriteAssets[3] = NULL; } if(print_sFonts[3]){ bk_free(print_sFonts[3]); print_sFonts[3] = NULL; } - D_80380B18 = 0; + print_sBoldLetterFontFreeTimer = 0; } void printbuffer_defrag(void){ @@ -527,158 +531,158 @@ void printbuffer_defrag(void){ //returns the pixel data and type for a given letter BKSpriteTextureBlock *print_getBoldFontLetterSprite(s32 letterId, s32 *fontType){ - if(D_80380AE8 != 1 || (D_80380AE8 == 1 && letterId < 0xA)){ - s32 slot = D_80380AE8; + if(print_sCurrentFont != 1 || (print_sCurrentFont == 1 && letterId < 0xA)){ + s32 slot = print_sCurrentFont; // [port] Let the language system remap the slot/letter (e.g. fall back to // the base font if the JP font slot is momentarily unloaded mid-swap). CALL_EVENT(ResolveBoldFontSlot, &slot, &letterId); - *fontType = D_80380AB8[slot]->type; + *fontType = print_sFontSpriteAssets[slot]->type; return print_sFonts[slot][letterId].sprite; } else{//L802F5510 - if(!D_80380AB8[3]){ - D_80380AB8[3] = assetcache_get(SPRITE_BOLD_FONT_LETTERS_ALPHAMASK); - D_80380AB8[4] = assetcache_get(D_80380B1C); - print_sFonts[3] = print_getLettersFromFont(D_80380AB8[3], D_80380AB8[4]); - assetcache_release(D_80380AB8[4]); - D_80380AB8[4] = NULL; + if(!print_sFontSpriteAssets[3]){ + print_sFontSpriteAssets[3] = assetcache_get(SPRITE_BOLD_FONT_LETTERS_ALPHAMASK); + print_sFontSpriteAssets[4] = assetcache_get(print_sCurrentBoldFontTexture); + print_sFonts[3] = print_getLettersFromFont(print_sFontSpriteAssets[3], print_sFontSpriteAssets[4]); + assetcache_release(print_sFontSpriteAssets[4]); + print_sFontSpriteAssets[4] = NULL; }//L802F5568 - D_80380B18 = 5; - *fontType = D_80380AB8[3]->type; + print_sBoldLetterFontFreeTimer = 5; + *fontType = print_sFontSpriteAssets[3]->type; return print_sFonts[3][letterId-10].sprite; } } //returns the letter's palette void *print_getCurrentFontPalette(u8 arg0){ - return print_sFonts[D_80380AE8][arg0].palette; + return print_sFonts[print_sCurrentFont][arg0].palette; } void _printbuffer_draw_letter(char letter, f32* xPtr, f32* yPtr, f32 arg3, Gfx **gfx, Mtx **mtx, Vtx **vtx){ static f32 left_margin; // u8 letter = arg0; - BKSpriteTextureBlock *sp214; + BKSpriteTextureBlock *letter_sprite; uintptr_t sp210; - s32 sp20C; - s32 t0; - s8 t1; - f32 sp200; - f32 f28; - f32 sp1F8; - s32 sp1F4; //font_type; + s32 letter_id; + s32 valid_letter; + s8 y_offset; + f32 x; + f32 y; + f32 letter_width; + s32 font_type; //font_type; int i; - t0 = 0; - sp200 = *xPtr; - f28 = *yPtr; - t1 = 0; + valid_letter = 0; + x = *xPtr; + y = *yPtr; + y_offset = 0; - if(!D_80380B04 && !letter){ + if(!print_sUnknownMode && !letter){ left_margin = 0.0f; }//L802F563C - switch(D_80380AE8){ + switch(print_sCurrentFont){ case 0: //L802F5678 if(letter >= '\x21' && letter < ('\x21' + print_sDialogFontGlyphCount)){ - sp20C = letter - '\x21'; - t0 = 1; + letter_id = letter - '\x21'; + valid_letter = 1; } break; case 1: //L802F56A0 - if((u8)letter < 0x80 && D_80380F20[(u8)letter] >= 0){ // [port] char is signed on MSVC; MIPS char is unsigned + if((u8)letter < 0x80 && print_sBoldFontLetterToSpriteMap[(u8)letter] >= 0){ // [port] char is signed on MSVC; MIPS char is unsigned for(i = 0; boldFontKernings[i].firstLetter != 0; i++){ - if(letter == boldFontKernings[i].secondLetter && D_80380AB0 == boldFontKernings[i].firstLetter){ - t1 = boldFontKernings[i].yOffset; + if(letter == boldFontKernings[i].secondLetter && print_sPreviousBoldLetter == boldFontKernings[i].firstLetter){ + y_offset = boldFontKernings[i].yOffset; break; } }//L802F5710 - sp20C = D_80380F20[(u8)letter]; - t0 = 1; - D_80380AB0 = (u8)letter; - f28 += (f32)t1*arg3; + letter_id = print_sBoldFontLetterToSpriteMap[(u8)letter]; + valid_letter = 1; + print_sPreviousBoldLetter = (u8)letter; + y += (f32)y_offset*arg3; }//L802F5738 break; case 2: //L802F5740 - sp20C = (u8)letter; - if(D_80380B04){ - t0 = 1; - sp20C += (D_80380B04 << 8) - 0x100; - D_80380B04 = 0; + letter_id = (u8)letter; + if(print_sUnknownMode){ + valid_letter = 1; + letter_id += (print_sUnknownMode << 8) - 0x100; + print_sUnknownMode = 0; } - else if(ResourceMgr_IsJapanese()){ - if(sp20C > 0 && sp20C != 0xFD && sp20C != 0x0F){ - t0 = 1; - if(sp20C == 0x36) - sp20C = 0xFD; + else if(PRINT_JP){ + if(letter_id > 0 && letter_id != 0xFD && letter_id != 0x0F){ + valid_letter = 1; + if(letter_id == 0x36) + letter_id = 0xFD; } } else{//L802F5764 - if(sp20C > 0 && sp20C < 0xfD) - t0 = 1; + if(letter_id > 0 && letter_id < 0xfD) + valid_letter = 1; } break; }//L802F5778 - if(!t0 || print_sInFontFormatMode){ + if(!valid_letter || print_sInFontFormatMode){ print_sInFontFormatMode = false; switch((u8)letter){ case '\x0F': // [port] JP font-2 word space; no-op for US/PAL - if(!ResourceMgr_IsJapanese()) + if(!PRINT_JP) break; // fallthrough case ' '://802F5818 - *xPtr += ((D_80380AF0) ? D_80369068[D_80380AE8]: D_80369068[D_80380AE8]*0.8) * arg3; + *xPtr += ((print_sMonospacedModeEnabled) ? maxFontLetterWidths[print_sCurrentFont]: maxFontLetterWidths[print_sCurrentFont]*0.8) * arg3; break; case 'b': //L802F5890 case '\x6D': // [port] PAL shifted b //toggle background - D_80380B00 = D_80380B00 ^ 1; + print_sBackgroundModeEnabled = print_sBackgroundModeEnabled ^ 1; break; case 'f': //L802F58A8 case '\x72': // [port] PAL shifted f - D_80380AEC = D_80380AE8 = D_80380AE8 ^ 1; + print_sPreviousFont = print_sCurrentFont = print_sCurrentFont ^ 1; break; case 'l': //L802F58BC - D_80380B10 = 0; + print_sShakyModeEnabled = 0; break; case 'h': //L802F58C8 case '\x73': // [port] PAL shifted h - D_80380B10 = 1; + print_sShakyModeEnabled = 1; break; case 'j': //L802F58D4 case '\x74': // [port] PAL shifted j - if(D_80380AFC == 0){ - D_80380AFC = 1; - D_80380AEC = D_80380AE8; - D_80380AE8 = 2; - // D_80380AE8 = 2; + if(print_sBrokenFontModeEnabled == 0){ + print_sBrokenFontModeEnabled = 1; + print_sPreviousFont = print_sCurrentFont; + print_sCurrentFont = 2; + // print_sCurrentFont = 2; } break; case 'e': //L802F58FC case '\x6F': // [port] PAL shifted e - if(D_80380AFC){ - D_80380AFC = 0; - D_80380AE8 = D_80380AEC; + if(print_sBrokenFontModeEnabled){ + print_sBrokenFontModeEnabled = 0; + print_sCurrentFont = print_sPreviousFont; } break; case 'p': //L802F5924 - D_80380AF0 = D_80380AF0 ^1; + print_sMonospacedModeEnabled = print_sMonospacedModeEnabled ^1; break; case 'q': //L802F593C - D_80380B14 = D_80380B14^1; - if(D_80380B14){ + print_sBilinearFilterModeEnabled = print_sBilinearFilterModeEnabled^1; + if(print_sBilinearFilterModeEnabled){ gDPSetTextureFilter((*gfx)++, G_TF_POINT); } else{//L802F5978 @@ -688,8 +692,8 @@ void _printbuffer_draw_letter(char letter, f32* xPtr, f32* yPtr, f32 arg3, Gfx * case 'v': //L802F59A0 //toggle letter gradient - D_80380AF4 ^= 1; - if(D_80380AF4){ + print_sGradientModeEnabled ^= 1; + if(print_sGradientModeEnabled){ viewport_setRenderViewportAndOrthoMatrix(gfx, mtx); gDPPipeSync((*gfx)++); gDPSetTexturePersp((*gfx)++, G_TP_PERSP); @@ -704,8 +708,8 @@ void _printbuffer_draw_letter(char letter, f32* xPtr, f32* yPtr, f32 arg3, Gfx * case 'd': //L802F5A8C case '\x6E': // [port] PAL shifted d - D_80380AF8 ^= 1; - if(D_80380AF8){ + print_sGradient2ModeEnabled ^= 1; + if(print_sGradient2ModeEnabled){ gDPPipeSync((*gfx)++); gDPSetCycleType((*gfx)++, G_CYC_2CYCLE); gDPSetRenderMode((*gfx)++, G_RM_PASS, G_RM_XLU_SURF2); @@ -726,81 +730,81 @@ void _printbuffer_draw_letter(char letter, f32* xPtr, f32* yPtr, f32 arg3, Gfx * break; case 0xfe://L802F5BF4 - D_80380B04 = 1; + print_sUnknownMode = 1; break; case 0xff://L802F5BFC - D_80380B04 = 2; + print_sUnknownMode = 2; break; default: break; } } else{//L802F5C08 - sp214 = print_getBoldFontLetterSprite(sp20C, &sp1F4); - if (D_80380B10 != 0) { - sp200 += randf2(-2.0f, 2.0f); - f28 += randf2(-2.0f, 2.0f); + letter_sprite = print_getBoldFontLetterSprite(letter_id, &font_type); + if (print_sShakyModeEnabled != 0) { + x += randf2(-2.0f, 2.0f); + y += randf2(-2.0f, 2.0f); } - sp1F8 = (D_80380AF0 != 0) ? D_80369068[D_80380AE8] : sp214->x; + letter_width = (print_sMonospacedModeEnabled != 0) ? maxFontLetterWidths[print_sCurrentFont] : letter_sprite->x; // temp_f2 = left_margin; // phi_f2 = temp_f2; if (left_margin == 0.0f) { - left_margin = -sp1F8 * 0.5; + left_margin = -letter_width * 0.5; } - sp200 += (left_margin + (sp1F8 - sp214->x) * 0.5); - f28 -= sp214->h*0.5; - sp210 = (uintptr_t)(sp214 + 1); + x += (left_margin + (letter_width - letter_sprite->x) * 0.5); + y -= letter_sprite->h*0.5; + sp210 = (uintptr_t)(letter_sprite + 1); while(sp210 % 8){ sp210++; } // [port] Resolve alt bold fonts const char* hdPath = NULL; - CALL_EVENT(ResolveSpriteHdPath, sp214, &hdPath); + CALL_EVENT(ResolveSpriteHdPath, letter_sprite, &hdPath); if (hdPath != NULL) { sp210 = (uintptr_t)hdPath; } const char* boldHdPath = NULL; - CALL_EVENT(ResolveBoldFontHd, sp214, &boldHdPath); + CALL_EVENT(ResolveBoldFontHd, letter_sprite, &boldHdPath); if (boldHdPath != NULL) { sp210 = (uintptr_t)boldHdPath; } - if (sp1F4 == SPRITE_TYPE_RGBA32) { - gDPLoadTextureTile((*gfx)++, sp210, G_IM_FMT_RGBA, G_IM_SIZ_32b, sp214->w, sp214->h, 0, 0, sp214->x-1, sp214->y - 1, 0, G_TX_CLAMP, G_TX_CLAMP, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOLOD); - } else if (sp1F4 == SPRITE_TYPE_IA8) { - gDPLoadTextureTile((*gfx)++, sp210, G_IM_FMT_IA, G_IM_SIZ_8b, sp214->w, sp214->h, 0, 0, sp214->x-1, sp214->y - 1, 0, G_TX_CLAMP, G_TX_CLAMP, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOLOD); - } else if (sp1F4 == SPRITE_TYPE_I8) { - gDPLoadTextureTile((*gfx)++, sp210, G_IM_FMT_I, G_IM_SIZ_8b, sp214->w, sp214->h, 0, 0, sp214->x-1, sp214->y - 1, 0, G_TX_CLAMP, G_TX_CLAMP, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOLOD); - } else if (sp1F4 == SPRITE_TYPE_I4) { - gDPLoadTextureTile_4b((*gfx)++, sp210, G_IM_FMT_I, sp214->w, sp214->h, 0, 0, sp214->x-1, sp214->y-1, 0, G_TX_CLAMP, G_TX_CLAMP, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOLOD); - } else if (sp1F4 == SPRITE_TYPE_CI8) { - void * pal = print_getCurrentFontPalette(sp20C); + if (font_type == SPRITE_TYPE_RGBA32) { + gDPLoadTextureTile((*gfx)++, sp210, G_IM_FMT_RGBA, G_IM_SIZ_32b, letter_sprite->w, letter_sprite->h, 0, 0, letter_sprite->x-1, letter_sprite->y - 1, 0, G_TX_CLAMP, G_TX_CLAMP, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOLOD); + } else if (font_type == SPRITE_TYPE_IA8) { + gDPLoadTextureTile((*gfx)++, sp210, G_IM_FMT_IA, G_IM_SIZ_8b, letter_sprite->w, letter_sprite->h, 0, 0, letter_sprite->x-1, letter_sprite->y - 1, 0, G_TX_CLAMP, G_TX_CLAMP, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOLOD); + } else if (font_type == SPRITE_TYPE_I8) { + gDPLoadTextureTile((*gfx)++, sp210, G_IM_FMT_I, G_IM_SIZ_8b, letter_sprite->w, letter_sprite->h, 0, 0, letter_sprite->x-1, letter_sprite->y - 1, 0, G_TX_CLAMP, G_TX_CLAMP, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOLOD); + } else if (font_type == SPRITE_TYPE_I4) { + gDPLoadTextureTile_4b((*gfx)++, sp210, G_IM_FMT_I, letter_sprite->w, letter_sprite->h, 0, 0, letter_sprite->x-1, letter_sprite->y-1, 0, G_TX_CLAMP, G_TX_CLAMP, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOLOD); + } else if (font_type == SPRITE_TYPE_CI8) { + void * pal = print_getCurrentFontPalette(letter_id); gDPLoadTLUT_pal256((*gfx)++, pal); - gDPLoadTextureTile((*gfx)++, sp210, G_IM_FMT_CI, G_IM_SIZ_8b, sp214->w, sp214->h, 0, 0, sp214->x-1, sp214->y-1, 0, G_TX_CLAMP, G_TX_CLAMP, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOLOD); + gDPLoadTextureTile((*gfx)++, sp210, G_IM_FMT_CI, G_IM_SIZ_8b, letter_sprite->w, letter_sprite->h, 0, 0, letter_sprite->x-1, letter_sprite->y-1, 0, G_TX_CLAMP, G_TX_CLAMP, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOLOD); gDPSetTextureLUT((*gfx)++, G_TT_RGBA16); }//L802F6570 - if (D_80380AF8 != 0) { + if (print_sGradient2ModeEnabled != 0) { s32 temp_t1; s32 phi_a0; temp_t1 = ((print_sCurrentPtr->topVertexAlpha - print_sCurrentPtr->y) - D_80380B0C) + 1; phi_a0 = - MAX(1 - D_80380B0C, MIN(0, temp_t1)); gDPSetTextureImage((*gfx)++, G_IM_FMT_I, G_IM_SIZ_8b, 32, &D_80380B20); - gDPSetTile((*gfx)++, G_IM_FMT_I, G_IM_SIZ_8b, (sp214->x + 8) >> 3, 0x0100, G_TX_LOADTILE, 0, G_TX_NOMIRROR | G_TX_CLAMP, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOMIRROR | G_TX_CLAMP, G_TX_NOMASK, G_TX_NOLOD); + gDPSetTile((*gfx)++, G_IM_FMT_I, G_IM_SIZ_8b, (letter_sprite->x + 8) >> 3, 0x0100, G_TX_LOADTILE, 0, G_TX_NOMIRROR | G_TX_CLAMP, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOMIRROR | G_TX_CLAMP, G_TX_NOMASK, G_TX_NOLOD); gDPLoadSync((*gfx)++); - gDPLoadTile((*gfx)++, G_TX_LOADTILE, 0 << G_TEXTURE_IMAGE_FRAC, (phi_a0) << G_TEXTURE_IMAGE_FRAC, (sp214->x) << G_TEXTURE_IMAGE_FRAC, (D_80380B0C - 1) << G_TEXTURE_IMAGE_FRAC); + gDPLoadTile((*gfx)++, G_TX_LOADTILE, 0 << G_TEXTURE_IMAGE_FRAC, (phi_a0) << G_TEXTURE_IMAGE_FRAC, (letter_sprite->x) << G_TEXTURE_IMAGE_FRAC, (D_80380B0C - 1) << G_TEXTURE_IMAGE_FRAC); gDPPipeSync((*gfx)++); - gDPSetTile((*gfx)++, G_IM_FMT_I, G_IM_SIZ_8b, ((sp214->x - 0 + 1)*G_IM_SIZ_8b_LINE_BYTES + 7) >> 3, 0x0100, 1, 0, G_TX_NOMIRROR | G_TX_CLAMP, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOMIRROR | G_TX_CLAMP, G_TX_NOMASK, G_TX_NOLOD); - gDPSetTileSize((*gfx)++, 1, 0 << G_TEXTURE_IMAGE_FRAC, (MAX(0, temp_t1) + phi_a0) << G_TEXTURE_IMAGE_FRAC, (sp214->x) << G_TEXTURE_IMAGE_FRAC, (MAX(0, temp_t1) - (1 - D_80380B0C))<x - 0 + 1)*G_IM_SIZ_8b_LINE_BYTES + 7) >> 3, 0x0100, 1, 0, G_TX_NOMIRROR | G_TX_CLAMP, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOMIRROR | G_TX_CLAMP, G_TX_NOMASK, G_TX_NOLOD); + gDPSetTileSize((*gfx)++, 1, 0 << G_TEXTURE_IMAGE_FRAC, (MAX(0, temp_t1) + phi_a0) << G_TEXTURE_IMAGE_FRAC, (letter_sprite->x) << G_TEXTURE_IMAGE_FRAC, (MAX(0, temp_t1) - (1 - D_80380B0C))<x - 1.0); - spD0 = sp214->y - 1.0; - temp_f26 = (f64) sp200 - (f32) gFramebufferWidth * 0.5; - spC0 = (f64)f28 - (f32)gFramebufferHeight*0.5 -0.5f; + temp_f24 = (letter_sprite->x - 1.0); + spD0 = letter_sprite->y - 1.0; + temp_f26 = (f64) x - (f32) gFramebufferWidth * 0.5; + spC0 = (f64)y - (f32)gFramebufferHeight*0.5 -0.5f; gSPVertex((*gfx)++, (uintptr_t)*vtx, 4, 0); for(iy = 0.0f; iy < 2.0; iy+= 1.0){ for(ix = 0.0f; ix < 2.0; ix += 1.0){ @@ -833,11 +837,11 @@ void _printbuffer_draw_letter(char letter, f32* xPtr, f32* yPtr, f32 arg3, Gfx * gSP1Quadrangle((*gfx)++, 0, 1, 3, 2, 0); } else{ - // [port] Wide variant: widescreen-anchored HUD text can start left of x=0 - // the Scis macro would CPU-clamp it to the 4:3 edge and crop the glyph. - gSPWideTextureRectangle((*gfx)++, (s32)(sp200*4.0f), (s32)(f28*4.0f), (s32)((sp200 + sp214->x*arg3)*4.0f), (s32)((f28 + sp214->y*arg3)*4.0f), 0, 0, 0, (s32)(1024.0f / arg3), (s32)(1024.0f / arg3)); + // [port] Wide variant: widescreen-anchored HUD text can start left of x=0; the Scis + // macro would CPU-clamp it to the 4:3 edge and crop the glyph. + gSPWideTextureRectangle((*gfx)++, (s32)(x*4.0f), (s32)(y*4.0f), (s32)((x + letter_sprite->x*arg3)*4.0f), (s32)((y + letter_sprite->y*arg3)*4.0f), 0, 0, 0, (s32)(1024.0f / arg3), (s32)(1024.0f / arg3)); } - *xPtr += sp1F8 * arg3; + *xPtr += letter_width * arg3; } } @@ -853,17 +857,17 @@ f32 print_calculateLetterXPos(u8 letter, f32* xPtr, f32 *yPtr, f32 arg3){ sp38 = *xPtr; var_v0 = false; sp34 = 0; - if (D_80380AE8 == 1) { + if (print_sCurrentFont == 1) { if (letter < 0x80) { - if (D_80380F20[letter] >= 0) { + if (print_sBoldFontLetterToSpriteMap[letter] >= 0) { for(i = 0; boldFontKernings[i].firstLetter != 0; i++) { - if ((boldFontKernings[i].secondLetter == letter) && (boldFontKernings[i].firstLetter == D_80380AB0)) { + if ((boldFontKernings[i].secondLetter == letter) && (boldFontKernings[i].firstLetter == print_sPreviousBoldLetter)) { sp34 = boldFontKernings[i].xOffset; break; } } - D_80380AB0 = letter; - sp44 = D_80380F20[letter]; + print_sPreviousBoldLetter = letter; + sp44 = print_sBoldFontLetterToSpriteMap[letter]; var_v0 = true; sp38 += sp34 * arg3; } @@ -874,15 +878,15 @@ f32 print_calculateLetterXPos(u8 letter, f32* xPtr, f32 *yPtr, f32 arg3){ } if (!var_v0 || print_sInFontFormatMode) { if (letter == ' ') { - var_f2 = (D_80380AF0) ? D_80369068[D_80380AE8] : 0.8*D_80369068[D_80380AE8]; + var_f2 = (print_sMonospacedModeEnabled) ? maxFontLetterWidths[print_sCurrentFont] : 0.8*maxFontLetterWidths[print_sCurrentFont]; } else{ return *xPtr; } } else { - if(D_80380AF0){ - var_f2 = D_80369068[D_80380AE8]; + if(print_sMonospacedModeEnabled){ + var_f2 = maxFontLetterWidths[print_sCurrentFont]; } else{ var_f2 = print_getBoldFontLetterSprite(sp44, &sp2C)->x; @@ -912,17 +916,17 @@ void printbuffer_draw(Gfx **gfx, Mtx **mtx, Vtx **vtx) { _printbuffer_draw_letter(0xFD, &_x, &_y, 1.0f, gfx, mtx, vtx); _printbuffer_draw_letter(print_sCurrentPtr->fmtString[j], &_x, &_y, 1.0f, gfx, mtx, vtx); } - if (D_80380B00 != 0) { - width = (strlen(print_sCurrentPtr->string) -1)*D_80369068[D_80380AE8]; + if (print_sBackgroundModeEnabled != 0) { + width = (strlen(print_sCurrentPtr->string) -1)*maxFontLetterWidths[print_sCurrentFont]; gDPPipeSync((*gfx)++); gDPSetPrimColor((*gfx)++, 0, 0, 0x00, 0x00, 0x00, 0x64); gDPSetCombineMode((*gfx)++, G_CC_PRIMITIVE, G_CC_PRIMITIVE); - gDPScisFillRectangle((*gfx)++, _x - D_80369068[D_80380AE8]/2 - 1.0f, _y - D_80369068[D_80380AE8]/2 - 1.0f, _x + width + D_80369068[D_80380AE8]/2, _y + D_80369068[D_80380AE8]/2 + 1.0f); + gDPScisFillRectangle((*gfx)++, _x - maxFontLetterWidths[print_sCurrentFont]/2 - 1.0f, _y - maxFontLetterWidths[print_sCurrentFont]/2 - 1.0f, _x + width + maxFontLetterWidths[print_sCurrentFont]/2, _y + maxFontLetterWidths[print_sCurrentFont]/2 + 1.0f); gDPPipeSync((*gfx)++); }//L802F73E8 - if ((D_80380AF8 == 0) && (D_80380AF4 == 0)) { - if (D_80380AE8 != 0) { + if ((print_sGradient2ModeEnabled == 0) && (print_sGradientModeEnabled == 0)) { + if (print_sCurrentFont != 0) { gDPSetCombineMode((*gfx)++, G_CC_DECALRGBA, G_CC_DECALRGBA); gDPSetPrimColor((*gfx)++, 0, 0, 0xFF, 0xFF, 0xFF, 0xFF); } else { @@ -930,7 +934,7 @@ void printbuffer_draw(Gfx **gfx, Mtx **mtx, Vtx **vtx) { gDPSetPrimColor((*gfx)++, 0, 0, print_sCurrentPtr->rgba[0], print_sCurrentPtr->rgba[1], print_sCurrentPtr->rgba[2], print_sCurrentPtr->rgba[3]); } } - if ((D_80380AE8 == 1) && ((f64) print_sCurrentPtr->scale < 0.0)) { + if ((print_sCurrentFont == 1) && ((f64) print_sCurrentPtr->scale < 0.0)) { for(j = 0; print_sCurrentPtr->string[j]; j++){ letter_x_coords[j] = print_calculateLetterXPos(print_sCurrentPtr->string[j], &_x, &_y, -print_sCurrentPtr->scale); } @@ -940,7 +944,7 @@ void printbuffer_draw(Gfx **gfx, Mtx **mtx, Vtx **vtx) { j--; } } else { - for(j = 0; (print_sCurrentPtr->string[j] != 0) || (D_80380B04 != 0); j++){ + for(j = 0; (print_sCurrentPtr->string[j] != 0) || (print_sUnknownMode != 0); j++){ _printbuffer_draw_letter(print_sCurrentPtr->string[j], &_x, &_y, print_sCurrentPtr->scale, gfx, mtx, vtx); } } @@ -972,10 +976,10 @@ void _printbuffer_push_new(s32 x, s32 y, u8 * string) { print_sCurrentPtr->fmtString[0] = (u8)0; print_sCurrentPtr->string = string; print_sCurrentPtr->scale = 1.0f; - print_sCurrentPtr->rgba[0] = (u8) normalTextColor.unk0; - print_sCurrentPtr->rgba[1] = (u8) normalTextColor.unk1; - print_sCurrentPtr->rgba[2] = (u8) normalTextColor.unk2; - print_sCurrentPtr->rgba[3] = (u8) normalTextColor.unk3; + print_sCurrentPtr->rgba[0] = (u8) normalTextColor.r; + print_sCurrentPtr->rgba[1] = (u8) normalTextColor.g; + print_sCurrentPtr->rgba[2] = (u8) normalTextColor.b; + print_sCurrentPtr->rgba[3] = (u8) normalTextColor.a; } void print_bold_overlapping(s32 x, s32 y, f32 arg2, u8* string){ @@ -1048,11 +1052,11 @@ void func_802F7A2C(s32 arg0) { } void text_setNormalTextColor(s32 arg0, s32 arg1, s32 arg2){ - normalTextColor.unk0 = arg0; - normalTextColor.unk1 = arg1; - normalTextColor.unk2 = arg2; + normalTextColor.r = arg0; + normalTextColor.g = arg1; + normalTextColor.b = arg2; } void text_setNormalTextAlpha(s32 arg0){ - normalTextColor.unk3 = arg0; + normalTextColor.a = arg0; } diff --git a/src/core2/font/render.c b/src/core2/font/render.c index 300f58e76..763994506 100644 --- a/src/core2/font/render.c +++ b/src/core2/font/render.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_5DBC0.c #include #include "functions.h" #include "variables.h" @@ -313,33 +314,33 @@ void func_802E57E0(struct5DBC0_1s *arg0, Gfx **gfx) { } } -void func_802E5C98(Gfx **gdl){ +void func_802E5C98(Gfx **gfx) { int i; - gDPPipeSync((*gdl)++); - gSPClearGeometryMode((*gdl)++, G_ZBUFFER | G_SHADE | G_CULL_BOTH | G_FOG | G_LIGHTING | G_TEXTURE_GEN | G_TEXTURE_GEN_LINEAR | G_LOD | G_SHADING_SMOOTH); - gSPTexture((*gdl)++, 0, 0, 0, G_TX_RENDERTILE, G_OFF); - gSPSetGeometryMode((*gdl)++, G_TEXTURE_GEN_LINEAR); - gDPSetCycleType((*gdl)++, G_CYC_1CYCLE); - gDPPipelineMode((*gdl)++, G_PM_NPRIMITIVE); - gDPSetTextureLOD((*gdl)++, G_TL_TILE); - gDPSetTextureLUT((*gdl)++, G_TT_NONE); - gDPSetTextureDetail((*gdl)++, G_TD_CLAMP); - gDPSetTexturePersp((*gdl)++, G_TP_NONE); - gDPSetTextureFilter((*gdl)++, G_TF_BILERP); - gDPSetTextureConvert((*gdl)++, G_TC_FILT); - gDPSetAlphaCompare((*gdl)++, G_AC_NONE); - gDPSetRenderMode((*gdl)++, G_RM_XLU_SURF, G_RM_XLU_SURF2); + gDPPipeSync((*gfx)++); + gSPClearGeometryMode((*gfx)++, G_ZBUFFER | G_SHADE | G_CULL_BOTH | G_FOG | G_LIGHTING | G_TEXTURE_GEN | G_TEXTURE_GEN_LINEAR | G_LOD | G_SHADING_SMOOTH); + gSPTexture((*gfx)++, 0, 0, 0, G_TX_RENDERTILE, G_OFF); + gSPSetGeometryMode((*gfx)++, G_TEXTURE_GEN_LINEAR); + gDPSetCycleType((*gfx)++, G_CYC_1CYCLE); + gDPPipelineMode((*gfx)++, G_PM_NPRIMITIVE); + gDPSetTextureLOD((*gfx)++, G_TL_TILE); + gDPSetTextureLUT((*gfx)++, G_TT_NONE); + gDPSetTextureDetail((*gfx)++, G_TD_CLAMP); + gDPSetTexturePersp((*gfx)++, G_TP_NONE); + gDPSetTextureFilter((*gfx)++, G_TF_BILERP); + gDPSetTextureConvert((*gfx)++, G_TC_FILT); + gDPSetAlphaCompare((*gfx)++, G_AC_NONE); + gDPSetRenderMode((*gfx)++, G_RM_XLU_SURF, G_RM_XLU_SURF2); for(i = 0; i < D_8037E900->unkC; i++){ D_8037E900->unk0[i].unk4 -= 0x10; - func_802E57E0(D_8037E900->unk0 + i, gdl); + func_802E57E0(D_8037E900->unk0 + i, gfx); D_8037E900->unk0[i].unk4 += 0x10; } - gDPSetTexturePersp((*gdl)++, G_TP_PERSP); + gDPSetTexturePersp((*gfx)++, G_TP_PERSP); } -void func_802E5F10(Gfx **gdl){ - func_802E5C98(gdl); +void func_802E5F10(Gfx **gfx) { + func_802E5C98(gfx); func_802E5188(); } diff --git a/src/core2/frame/auxbuffer.c b/src/core2/frame/auxbuffer.c index 2b8a35ce9..05e9808af 100644 --- a/src/core2/frame/auxbuffer.c +++ b/src/core2/frame/auxbuffer.c @@ -1,8 +1,10 @@ +// BanjoDecomp: core2/code_851D0.c #include #include "core1/core1.h" #include "functions.h" #include "variables.h" +// [port] GPU-side aux framebuffer for the picture box int gfx_create_framebuffer(unsigned int width, unsigned int height, unsigned int native_width, unsigned int native_height, unsigned char resize, bool force_fixed_aspect); @@ -18,8 +20,7 @@ s32 sAuxGpuFbId = -1; #define HORIZONTAL_MARGIN (((SCREEN_WIDTH) - IMAGE_WIDTH) / 2) #define VERTICAL_MARGIN (((SCREEN_HEIGHT) - IMAGE_HEIGHT) / 2) -/* .data */ -Gfx D_8036C450[] = { +Gfx sPictureBoxInitDL[] = { gsDPPipeSync(), gsSPClearGeometryMode(G_ZBUFFER | G_SHADE | G_CULL_BOTH | G_FOG | G_LIGHTING | G_TEXTURE_GEN | G_TEXTURE_GEN_LINEAR | G_LOD | G_SHADING_SMOOTH), gsSPSetGeometryMode(G_SHADE | G_TEXTURE_GEN_LINEAR | G_SHADING_SMOOTH), @@ -29,35 +30,36 @@ Gfx D_8036C450[] = { gsDPSetCombineLERP(TEXEL0, 0, PRIMITIVE_ALPHA, 0, 0, 0, 0, TEXEL0, TEXEL0, 0, PRIMITIVE_ALPHA, 0, 0, 0, 0, TEXEL0), gsDPSetTextureFilter(G_TF_POINT), gsDPSetTexturePersp(G_TP_NONE), - gsDPSetPrimColor(0, 0, 0x00, 0x00, 0x00, 0x78), + gsDPSetPrimColor(0, 0, 0, 0, 0, 120), gsSPEndDisplayList() }; -Gfx D_8036C4A8[] = { +Gfx sPictureBoxFinishDL[] = { gsDPPipeSync(), gsDPSetTextureFilter(G_TF_BILERP), gsDPSetTexturePersp(G_TP_PERSP), gsSPEndDisplayList() }; -/* .bss */ -s16 *D_80382450; -void *D_80382454; +s16 *sPictureBoxColorBuffer; +void *sPictureBoxColorBufferBase; -/* .code */ -void func_8030C160(void){ +void picturebox_func_8030C160(void) { func_8024F150(); } -void func_8030C180(void){ +void picturebox_func_8030C180(void) { func_8024F180(); } -void func_8030C1A0(void){ - if(D_80382454 == NULL){ - D_80382454 = D_80382450 = bk_malloc(IMAGE_WIDTH * IMAGE_HEIGHT * sizeof(u16) + 64); - while((uintptr_t)D_80382450 & 0x3F){ - D_80382450++; +void picturebox_init(void) { + if (sPictureBoxColorBufferBase == NULL) { + sPictureBoxColorBuffer = malloc(IMAGE_WIDTH * IMAGE_HEIGHT * sizeof(u16) + 64); + sPictureBoxColorBufferBase = sPictureBoxColorBuffer; + + // Make sure that the color buffer is aligned on a 64-byte boundary + while ((uintptr_t)sPictureBoxColorBuffer & 0x3F) { // [port] pointer-width + sPictureBoxColorBuffer++; } } if (sAuxGpuFbId < 0) { @@ -65,51 +67,52 @@ void func_8030C1A0(void){ } } -void func_8030C204(void){ - if(D_80382454){ - bk_free(D_80382454); - D_80382454 = NULL; +void picturebox_free(void) { + if (sPictureBoxColorBufferBase) { + free(sPictureBoxColorBufferBase); + sPictureBoxColorBufferBase = NULL; } - switch(getGameMode()){ + switch (getGameMode()) { case GAME_MODE_8_BOTTLES_BONUS: chBottlesBonus_func_802DEA8C(0, 0); break; + case GAME_MODE_A_SNS_PICTURE: func_802DF11C(0, 0); break; } } -void func_8030C27C(void){ - switch(getGameMode()){ +void picturebox_spawn(void) { + switch (getGameMode()) { case GAME_MODE_8_BOTTLES_BONUS: chBottlesBonus_spawn(0, 0); break; + case GAME_MODE_A_SNS_PICTURE: func_802DF090(0, 0); break; - } } -void func_8030C2D4(Gfx **gdl, Mtx **mptr, Vtx **vptr){ +void picturebox_resetScissorBoxAndFramebuffer(Gfx **gfx, Mtx **mtx, Vtx **vtx) { scissorBox_setDefault(); - func_80253640(gdl, gFramebuffers[getActiveFramebuffer()]); + setupFramebuffer(gfx, gFramebuffers[getActiveFramebuffer()]); } // [port] This function is not called anywhere // Draws a 160x128 image pointed to by D_80382450 into the center of the screen -void func_8030C33C(Gfx **gfx, Mtx **mtx, Vtx **vtx) { +void picturebox_draw(Gfx **gfx, Mtx **mtx, Vtx **vtx) { s32 x, y; // Set up the rendering state to draw the image - gSPDisplayList((*gfx)++, D_8036C450); + gSPDisplayList((*gfx)++, sPictureBoxInitDL); // Iterate over every tile in the image for (y = 0; y < TILE_COUNT_Y; y++) { for(x = 0; x < TILE_COUNT_X; x++){ // Load the current tile from the image - gDPLoadTextureTile((*gfx)++, osVirtualToPhysical(D_80382450), G_IM_FMT_IA, G_IM_SIZ_16b, IMAGE_WIDTH, IMAGE_HEIGHT, + gDPLoadTextureTile((*gfx)++, osVirtualToPhysical(sPictureBoxColorBuffer), G_IM_FMT_IA, G_IM_SIZ_16b, IMAGE_WIDTH, IMAGE_HEIGHT, TILE_SIZE * x, TILE_SIZE * y, TILE_SIZE * (x + 1) - 1, TILE_SIZE * (y + 1) - 1, 0, G_TX_NOMIRROR | G_TX_CLAMP, G_TX_NOMIRROR | G_TX_CLAMP, @@ -125,13 +128,14 @@ void func_8030C33C(Gfx **gfx, Mtx **mtx, Vtx **vtx) { } } // Reset the rendering state - gSPDisplayList((*gfx)++, D_8036C4A8); + gSPDisplayList((*gfx)++, sPictureBoxFinishDL); } -s16 *func_8030C704(void){ - return D_80382450; + +s16 *picturebox_getColorBuffer(void) { + return sPictureBoxColorBuffer; } -void scissorBox_setSmall(void){ - scissorBox_set(0, 160, 0, 128); +void picturebox_setScissorBox(void) { + scissorBox_set(0, IMAGE_WIDTH, 0, IMAGE_HEIGHT); } diff --git a/src/core2/frame/rendermem.c b/src/core2/frame/rendermem.c index b69c54ce6..9be844cea 100644 --- a/src/core2/frame/rendermem.c +++ b/src/core2/frame/rendermem.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_5C240.c #include #include "core1/core1.h" #include "functions.h" @@ -6,7 +7,7 @@ #include "bk_time.h" extern void func_8023DFF0(s32); -extern void comusicPlayer_update(void); +extern void coMusicPlayer_update(void); extern void func_802F1A10(void *, f32); extern void func_8033DC10(void); extern void func_8033DC18(void); @@ -44,11 +45,11 @@ void func_802E329C(s32 arg0, Gfx **gfx_begin, Gfx **gfx_end) { Vtx *vtx; Vtx *vtx_start; - getGraphicsStacks(&gfx, &mtx, &vtx); + graphicscache_swapAndGetStacks(&gfx, &mtx, &vtx); gfx_start = gfx; mtx_start = mtx; vtx_start = vtx; - scissorBox_SetForGameMode(&gfx, arg0); + setupFramebufferForGamemode(&gfx, arg0); if (D_8037E8C0.unk14 == 2) { drawRectangle2D(&gfx, 0, 0, (s32) (f32) gFramebufferWidth, (s32) (f32) gFramebufferHeight, 0, 0, 0); } @@ -112,8 +113,8 @@ void func_802E3580(void) { assetcache_release((void *)(intptr_t)D_8037E8C0.unkC); func_802F1884(D_8037E8C0.unk10); func_802E5F68(); - comusicPlayer_free(); - depthBuffer_stub(); + coMusicPlayer_free(); + depthbuffer_stub(); viMgr_func_8024BF94(2); } @@ -167,7 +168,7 @@ void func_802E35D8(void ) { return; } } - comusicPlayer_update(); + coMusicPlayer_update(); if (D_8037E8C0.unk14 == 0) { gcbound_alpha(D_8037E8C0.unk8); } diff --git a/src/core2/frame/texture_capture.c b/src/core2/frame/texture_capture.c index d3798e782..cd6140bd1 100644 --- a/src/core2/frame/texture_capture.c +++ b/src/core2/frame/texture_capture.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_77E50.c #include #include "core1/core1.h" #include "functions.h" diff --git a/src/core2/fx/enemy_shadow.c b/src/core2/fx/badShad.c similarity index 97% rename from src/core2/fx/enemy_shadow.c rename to src/core2/fx/badShad.c index 971b2e88c..d13e3ccc9 100644 --- a/src/core2/fx/enemy_shadow.c +++ b/src/core2/fx/badShad.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/ch/badShad.c #include #include "core1/core1.h" #include "functions.h" @@ -13,8 +14,8 @@ void func_802D729C(Actor *actor, f32 arg1); /* .data */ ActorInfo chBadShad = { - 0x9B, 0x108, 0x3BF, - 0x1, NULL, + MARKER_9B_MODEL_PLAYER_SHADOW, ACTOR_108_MODEL_PLAYER_SHADOW, ASSET_3BF_MODEL_PLAYER_SHADOW, + 0x1, NULL, chBadShad_update, actor_update_func_80326224, chBadShad_draw, 0, 0, 0.0f, 0 }; diff --git a/src/core2/fx/effect_spriteanim.c b/src/core2/fx/banjokazooiesign.c similarity index 61% rename from src/core2/fx/effect_spriteanim.c rename to src/core2/fx/banjokazooiesign.c index f1075c066..10398096e 100644 --- a/src/core2/fx/effect_spriteanim.c +++ b/src/core2/fx/banjokazooiesign.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/gc/banjokazooiesign.c #include #include "core1/core1.h" #include "functions.h" @@ -6,19 +7,20 @@ extern void actor_postdrawMethod(ActorMarker *); Actor *func_802DC7E0(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx); -void func_802DC900(Actor *this); +void gcBanjoKazooieSign_update(Actor *this); /* .data */ -f32 D_803680A0[3] = {0.0f, 0.0f, 0.0f}; -ActorInfo D_803680AC = { - 0x175, 0x1DC, 0x54D, +f32 gcBanjoKazooieSignPosition[3] = {0.0f, 0.0f, 0.0f}; + +ActorInfo gcBanjoKazooieSign = { + MARKER_175_BANJO_KAZOOIE_SIGN, ACTOR_1DC_BANJO_KAZOOIE_SIGN, ASSET_54D_MODEL_BANJO_KAZOOIE_SIGN, 0x1, NULL, - func_802DC900, actor_update_func_80326224, func_802DC7E0, + gcBanjoKazooieSign_update, actor_update_func_80326224, func_802DC7E0, 0, 0, 0.0f, 0 }; /* .bss */ -ActorMarker *D_8037DE60; +ActorMarker *gcBanjoKazooieSignMarker; /* .code */ Actor *func_802DC7E0(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx){ @@ -54,35 +56,35 @@ Actor *func_802DC7E0(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx){ return this; } -void func_802DC8F0(Actor *this){ - D_8037DE60 = NULL; +void gcBanjoKazooieSign_free(Actor *this){ + gcBanjoKazooieSignMarker = NULL; } -void func_802DC900(Actor *this){ +void gcBanjoKazooieSign_update(Actor *this){ if(!this->initialized){ this->initialized = true; this->depth_mode = MODEL_RENDER_DEPTH_NONE; actor_collisionOff(this); - marker_setFreeMethod(this->marker, func_802DC8F0); + marker_setFreeMethod(this->marker, gcBanjoKazooieSign_free); } } -void func_802DC960(void) { +void gcBanjoKazooieSign_spawn(void) { Actor *actor; - if (D_8037DE60 == 0) { - actor = actor_spawnWithYaw_f32(0x1DC, D_803680A0, 0); - D_8037DE60 = actor->marker; + if (gcBanjoKazooieSignMarker == NULL) { + actor = actor_spawnWithYaw_f32(ACTOR_1DC_BANJO_KAZOOIE_SIGN, gcBanjoKazooieSignPosition, 0); + gcBanjoKazooieSignMarker = actor->marker; } } void func_802DC9A4(s32 arg0, s32 arg1){ - if(D_8037DE60 == NULL){ - __spawnQueue_add_0(func_802DC960); + if(gcBanjoKazooieSignMarker == NULL){ + __spawnQueue_add_0(gcBanjoKazooieSign_spawn); } } void func_802DC9DC(s32 arg0, s32 arg1){ - if(D_8037DE60 != NULL){ - func_80326310(marker_getActor(D_8037DE60)); + if(gcBanjoKazooieSignMarker != NULL){ + func_80326310(marker_getActor(gcBanjoKazooieSignMarker)); } } diff --git a/src/core2/fx/projectile_manager.c b/src/core2/fx/commonParticle.c similarity index 99% rename from src/core2/fx/projectile_manager.c rename to src/core2/fx/commonParticle.c index 7cc4979b3..d4f534162 100644 --- a/src/core2/fx/projectile_manager.c +++ b/src/core2/fx/commonParticle.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/commonParticle.c #include "core2/commonParticle.h" #include #include "functions.h" diff --git a/src/core2/fx/cutscene_actors.c b/src/core2/fx/cutscene_actors.c index 2d3a70e33..850a98751 100644 --- a/src/core2/fx/cutscene_actors.c +++ b/src/core2/fx/cutscene_actors.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_59780.c #include #include "core1/core1.h" #include "functions.h" @@ -8,44 +9,44 @@ extern void actor_postdrawMethod(ActorMarker *); Actor *func_802E0738(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx); void func_802E07E0(Actor *this); -void func_802E08F0(Actor *this); +void chFireSparkle_update(Actor *this); /* .data */ -ActorAnimationInfo D_80368440[] = { +ActorAnimationInfo chFireSparkleAnimations[] = { {0, 0.0f}, {ASSET_98_ANIM_FIRE_SPARKLE, 1.2f} }; -ActorInfo D_80368450 = { +ActorInfo chFireSparkle = { MARKER_72_FIRE_SPARKLE, ACTOR_A2_FIRE_SPARKLE, ASSET_3AD_FIRE_SPARKLE, - 0x1, D_80368440, - func_802E08F0, actor_update_func_80326224, actor_draw, + 0x1, chFireSparkleAnimations, + chFireSparkle_update, actor_update_func_80326224, actor_draw, 0, 0, 0.0f, 0 }; -ActorInfo D_80368474 = { - 0x8C, 0xBC, 0x45C, +ActorInfo chBanjoCurtains = { + MARKER_8C_BANJOS_CURTAINS, ACTOR_BC_BANJOS_CURTAINS, ASSET_45C_MODEL_BANJOS_CURTAINS, 0, NULL, NULL, func_802E07E0, func_802E0738, 0, 0, 0.0f, 0 }; -ActorInfo D_80368498 = { - 0x8D, 0xBD, 0x45E, +ActorInfo chBanjoHouseDoor = { + MARKER_8D_BANJOS_HOUSE_DOOR, ACTOR_BD_BANJOS_HOUSE_DOOR, ASSET_45E_MODEL_BANJOS_HOUSE_DOOR, 0, NULL, NULL, func_802E07E0, func_802E0738, 0, 0, 0.0f, 0 }; -ActorInfo D_803684BC = { - 0x13D, 0x2F4, 0x46E, +ActorInfo chFishbowl = { + MARKER_13D_FISHBOWL, ACTOR_2F4_FISHBOWL, ASSET_46E_MODEL_FISHBOWL, 0, NULL, NULL, func_802E07E0, func_802E0738, 0, 0, 0.0f, 0 }; -ActorInfo D_803684E0 = { - 0x13E, 0x2F5, 0x46F, +ActorInfo chCuckooClock = { + MARKER_13E_CUCKOO_CLOCK, ACTOR_2F5_CUCKOO_CLOCK, ASSET_46F_MODEL_CUCKOO_CLOCK, 0, NULL, NULL, func_802E07E0, func_802E0738, 0, 0, 0.0f, 0 @@ -86,13 +87,13 @@ void func_802E0710(Actor *this){ } Actor *func_802E0738(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx){ - f32 sp34[3]; + f32 rotation[3]; Actor *this; - this = marker_getActorAndRotation(marker, sp34); + this = marker_getActorAndRotation(marker, rotation); modelRender_setPreDrawCallback( (model_render_pre_draw_callback_f)func_802E0710, (void *)this); modelRender_setPostDrawCallback((model_render_post_draw_callback_f)actor_postdrawMethod, (void *)marker); - modelRender_draw(gfx, mtx, this->position, sp34, this->scale, NULL, marker_loadModelBin(marker)); + modelRender_draw(gfx, mtx, this->position, rotation, this->scale, NULL, marker_loadModelBin(marker)); return this; } @@ -109,9 +110,9 @@ void func_802E07E0(Actor *this) { sp24 = 0; break; - case 0x451: - case 0x458: - case 0x532: + case ASSET_451_MODEL_GRUNTILDA: + case ASSET_458_MODEL_BANJO_TOP_SLEEPING: + case ASSET_532_MODEL_BANJO_KAZOOIE_CUTSCENES: sp24 = 1; break; } @@ -137,8 +138,8 @@ void func_802E07E0(Actor *this) { func_80361EE0(this); } -void func_802E08F0(Actor *this) { - f32 sp24[3]; +void chFireSparkle_update(Actor *this) { + f32 rotation[3]; this->marker->collidable = false; anctrl_setDuration(this->anctrl, this->unk5C); @@ -146,6 +147,6 @@ void func_802E08F0(Actor *this) { if (actor_animationIsAt(this, 0.99f) != 0) { marker_despawn(this->marker); } - viewport_getRotation_vec3f(sp24); - this->yaw = sp24[1]; + viewport_getRotation_vec3f(rotation); + this->yaw = rotation[1]; } diff --git a/src/core2/fx/drips.c b/src/core2/fx/drips.c index 580e85501..fa6ec221d 100644 --- a/src/core2/fx/drips.c +++ b/src/core2/fx/drips.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/ch/drips.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/fx/effect_colordata.c b/src/core2/fx/effect_colordata.c index b0b7b64f2..05ec9e930 100644 --- a/src/core2/fx/effect_colordata.c +++ b/src/core2/fx/effect_colordata.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_BE2C0.c #include #include "core1/core1.h" #include "functions.h" diff --git a/src/core2/fx/effect_debris.c b/src/core2/fx/effect_debris.c index 13f7acf9c..e9eb01123 100644 --- a/src/core2/fx/effect_debris.c +++ b/src/core2/fx/effect_debris.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_41460.c #include "functions.h" #include "variables.h" #include @@ -34,12 +35,49 @@ f32 D_80366330 = 0.5f; f32 D_80366334 = 30.0f; f32 D_80366338 = 150.0f; f32 D_8036633C = 25.0f; -ActorInfo D_80366340 = { 0x56, 0x4A, 0x0, 0x2, 0x0, func_802C8C5C, actor_update_func_80326224, func_802C8484, 0, 0, 0.0f, 0}; -ActorInfo D_80366364 = { 0x56, 0x4B, 0x0, 0x2, 0x0, func_802C8C5C, actor_update_func_80326224, func_802C8484, 0, 0, 0.0f, 0}; -ActorInfo D_80366388 = { 0x56, 0xD, 0x0, 0x2, 0x0, func_802C8C5C, actor_update_func_80326224, func_802C8484, 0, 0, 0.0f, 0}; -ActorInfo D_803663AC = { 0x56, 0x11F, 0x0, 0x2, 0x0, func_802C8C5C, actor_update_func_80326224, func_802C8484, 0, 0, 0.0f, 0}; -ActorInfo D_803663D0 = { 0x56, 0x14F, 0x0, 0x2, 0x0, func_802C8C5C, actor_update_func_80326224, func_802C8484, 0, 0, 0.0f, 0}; -ActorInfo D_803663F4 = { 0x56, 0x3AD, 0x0, 0x2, 0x0, func_802C8C5C, actor_update_func_80326224, func_802C8484, 0, 0, 0.0f, 0}; + +ActorInfo D_80366340 = { + MARKER_56_UNKNOWN, 0x4A, 0x0, + 0x2, NULL, + func_802C8C5C, actor_update_func_80326224, func_802C8484, + 0, 0, 0.0f, 0 +}; + +ActorInfo D_80366364 = { + MARKER_56_UNKNOWN, 0x4B, 0x0, + 0x2, NULL, + func_802C8C5C, actor_update_func_80326224, func_802C8484, + 0, 0, 0.0f, 0 +}; + +ActorInfo D_80366388 = { + MARKER_56_UNKNOWN, 0xD, 0x0, + 0x2, NULL, + func_802C8C5C, actor_update_func_80326224, func_802C8484, + 0, 0, 0.0f, 0 +}; + +ActorInfo D_803663AC = { + MARKER_56_UNKNOWN, 0x11F, 0x0, + 0x2, NULL, + func_802C8C5C, actor_update_func_80326224, func_802C8484, + 0, 0, 0.0f, 0 +}; + +ActorInfo D_803663D0 = { + MARKER_56_UNKNOWN, 0x14F, 0x0, + 0x2, NULL, + func_802C8C5C, actor_update_func_80326224, func_802C8484, + 0, 0, 0.0f, 0 +}; + +ActorInfo D_803663F4 = { + MARKER_56_UNKNOWN, 0x3AD, 0x0, + 0x2, NULL, + func_802C8C5C, actor_update_func_80326224, func_802C8484, + 0, 0, 0.0f, 0 +}; + s32 D_80366418[3] = {0,0,0}; /* .bss */ @@ -71,14 +109,14 @@ void func_802C83F0(Actor *actor) { Actor *func_802C8484(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx) { Struct25s *temp_s1; Struct24s *phi_s0; - f32 sp5C[3]; - Actor *sp58; + f32 rotation; + Actor *this; u32 phi_v1; s32 phi_s4; - sp58 = marker_getActorAndRotation(marker, sp5C); - temp_s1 = sp58->unk40; - phi_s4 = false; + this = marker_getActorAndRotation(marker, &rotation); + temp_s1 = (Struct25s*)this->unk40; + phi_s4 = FALSE; for(phi_s0 = temp_s1->begin; phi_s0 < temp_s1->current; phi_s0++){ if ((phi_s0->unk0 != 0) && (phi_s0->model_bin != NULL)) { // [port] Stable scope per piece. Expiry shrinks the range @@ -93,7 +131,7 @@ Actor *func_802C8484(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx) { if (phi_s4 == false) { marker_despawn(marker); } - return sp58; + return this; } Actor *func_802C8580(s32 position[3], s32 yaw, ActorInfo* actorInfo, u32 flags){ @@ -127,44 +165,44 @@ Actor *func_802C8580(s32 position[3], s32 yaw, ActorInfo* actorInfo, u32 flags){ s0->unk8[1] = 0.0f; s0->unk8[2] = 0.0f; switch(D_8037DD94){ - case 1: // 802C8740 - s0->unk30[0] = randf2(125.0f, 175.0f); - s0->unk30[1] = randf2(400.0f, 600.0f); - s0->unk30[2] = randf2(125.0f, 175.0f); - s0->model_bin = (BKModelBin *) assetcache_get(0x2e7); - s0->unk2C = 18.0f; - break; - case 2: // 802C87A8 - s0->model_bin = (BKModelBin *) assetcache_get(0x344); - s0->unk2C = 2.0f; - break; - case 4: // 802C87C4 - s0->model_bin = (BKModelBin *) assetcache_get(0x345); - s0->unk2C = 1.0f; - s0->unk30[0] = randf2(20.0f, 100.0f); - s0->unk30[1] = randf2(400.0f, 740.0f); - s0->unk30[2] = randf2(20.0f, 100.0f); - - s0->unk8[0] = randf2(0.0f, 30.0f); - s0->unk8[1] = 0.0f; - s0->unk8[2] = 0.0f; - break; - case 0: // 802C883C - if(0.5 < randf()) - s0->model_bin = (BKModelBin *) assetcache_get(0x2d1); - else - s0->model_bin = (BKModelBin *) assetcache_get(0x2e5); - - s0->unk2C = randf2(5.0f, 12.0f); - break; - case 3: // 802C88A0 - s0->model_bin = (BKModelBin *) assetcache_get(0x30e); - s0->unk2C = randf2(9.0f, 15.0f); - break; - case 5: // 802C88C8 - s0->model_bin = (BKModelBin *) assetcache_get(0x8a2); - s0->unk2C = 2.0f; - break; + case 1: // 802C8740 + s0->unk30[0] = randf2(125.0f, 175.0f); + s0->unk30[1] = randf2(400.0f, 600.0f); + s0->unk30[2] = randf2(125.0f, 175.0f); + s0->model_bin = (BKModelBin *) assetcache_get(0x2e7); + s0->unk2C = 18.0f; + break; + case 2: // 802C87A8 + s0->model_bin = (BKModelBin *) assetcache_get(0x344); + s0->unk2C = 2.0f; + break; + case 4: // 802C87C4 + s0->model_bin = (BKModelBin *) assetcache_get(0x345); + s0->unk2C = 1.0f; + s0->unk30[0] = randf2(20.0f, 100.0f); + s0->unk30[1] = randf2(400.0f, 740.0f); + s0->unk30[2] = randf2(20.0f, 100.0f); + + s0->unk8[0] = randf2(0.0f, 30.0f); + s0->unk8[1] = 0.0f; + s0->unk8[2] = 0.0f; + break; + case 0: // 802C883C + if(0.5 < randf()) + s0->model_bin = (BKModelBin *) assetcache_get(MODEL_ASSET_OFFSET); + else + s0->model_bin = (BKModelBin *) assetcache_get(0x2e5); + + s0->unk2C = randf2(5.0f, 12.0f); + break; + case 3: // 802C88A0 + s0->model_bin = (BKModelBin *) assetcache_get(0x30e); + s0->unk2C = randf2(9.0f, 15.0f); + break; + case 5: // 802C88C8 + s0->model_bin = (BKModelBin *) assetcache_get(0x8a2); + s0->unk2C = 2.0f; + break; }//L802C88E0 s0->unk3C = NULL; sp68[0] = (f32)position[0]; diff --git a/src/core2/fx/effect_ice.c b/src/core2/fx/effect_ice.c index ed50f683e..1b4378276 100644 --- a/src/core2/fx/effect_ice.c +++ b/src/core2/fx/effect_ice.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_54D50.c #include #include "functions.h" #include "variables.h" @@ -16,13 +17,14 @@ void func_802DC018(Actor *this); /* .data */ ActorInfo D_80367F30= { - 0x1F5, 0x1E5, 0, + MARKER_1F5_UNKNOWN, ACTOR_1E5_UNKNOWN, 0, 0, NULL, func_802DC018, actor_update_func_80326224, func_80325340, 0, 0, 0.0f, 0 }; s32 D_80367F54[3] = {0xff, 0xff, 0xff}; + ParticleSettingsScaleAndLifetimeDrawModeEmitCount D_80367F60 = { { {0.1f, 0.5f}, {1.0f, 1.5f}, {0.0f, 0.01f}, {0.5f, 1.4f}, 0.0f, 0.01f diff --git a/src/core2/fx/effect_jiggy.c b/src/core2/fx/effect_jiggy.c index db3d1fd68..711b94de1 100644 --- a/src/core2/fx/effect_jiggy.c +++ b/src/core2/fx/effect_jiggy.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_C0CF0.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/fx/effect_jiggy_list.c b/src/core2/fx/effect_jiggy_list.c index 2897b9748..6f0ef34d5 100644 --- a/src/core2/fx/effect_jiggy_list.c +++ b/src/core2/fx/effect_jiggy_list.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_ABC00.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/fx/effect_jiggy_spawn.c b/src/core2/fx/effect_jiggy_spawn.c index d94f7f52d..f50f5fa4f 100644 --- a/src/core2/fx/effect_jiggy_spawn.c +++ b/src/core2/fx/effect_jiggy_spawn.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_C0B80.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/fx/effect_modelparticle.c b/src/core2/fx/effect_modelparticle.c index 6247ae4d4..31e9bbbdb 100644 --- a/src/core2/fx/effect_modelparticle.c +++ b/src/core2/fx/effect_modelparticle.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_53C10.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/fx/effect_playerspray.c b/src/core2/fx/effect_playerspray.c index 2c71deae2..44d5f3f04 100644 --- a/src/core2/fx/effect_playerspray.c +++ b/src/core2/fx/effect_playerspray.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_B850.c #include #include "functions.h" #include "variables.h" @@ -14,7 +15,7 @@ void func_802927E0(f32 arg0, f32 arg1){ f32 sp18[3]; arg1 *= 0.51; - _player_getPosition(sp18); + playerPosition_get(sp18); sp18[1] += 10.0f; func_802589E4(sp24, arg0, arg1); sp24[1] = 40.0f; @@ -27,7 +28,7 @@ void func_80292864(f32 arg0, f32 arg1){ f32 sp1C[3]; ml_vec3f_assign(sp1C, 0.0f, 40.0f, 0.0f); - _player_getPosition(sp28); + playerPosition_get(sp28); func_802589E4(sp34, arg0, arg1); sp34[1] = 10.0f; sp28[0] += sp34[0]; sp28[1] += sp34[1]; sp28[2] += sp34[2]; @@ -39,7 +40,7 @@ void func_80292900(f32 arg0, f32 arg1){ f32 sp18[3]; arg1 *= 0.51; - _player_getPosition(sp18); + playerPosition_get(sp18); func_802589E4(sp24, arg0, arg1); sp24[1] = 40.0f; func_80352CF4(sp18, sp24, 10.0f, 150.0f); @@ -49,7 +50,7 @@ void func_80292974(f32 arg0, f32 arg1, f32 arg2){ f32 sp24[3]; f32 sp18[3]; arg1 *= 0.51; - _player_getPosition(sp18); + playerPosition_get(sp18); sp18[1] += 10.0f; func_802589E4(sp24, arg0, arg1); sp24[1] = arg2; diff --git a/src/core2/fx/effect_ripple.c b/src/core2/fx/effect_ripple.c index 34eb0566c..8348a55e4 100644 --- a/src/core2/fx/effect_ripple.c +++ b/src/core2/fx/effect_ripple.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_DB010.c #include #include "core1/core1.h" #include "functions.h" @@ -587,7 +588,7 @@ void func_80363330(Actor *this){ void func_80363388(struct_core2_DB010 *arg0, s32 arg1){ f32 sp2C[3]; s32 sp20[3]; - s32 tmp_v0 = codeA5BC0_getPositionAndReturnRadius(arg0, sp20); + s32 tmp_v0 = codeA5BC0_getPositionAndSelectorOrRadius(arg0, sp20); sp2C[0] = (f32)sp20[0]; sp2C[1] = (f32)sp20[1]; sp2C[2] = (f32)sp20[2]; diff --git a/src/core2/fx/effect_simplesprite.c b/src/core2/fx/effect_simplesprite.c index 1f317d764..f1d14fdef 100644 --- a/src/core2/fx/effect_simplesprite.c +++ b/src/core2/fx/effect_simplesprite.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_55180.c #include #include "core1/core1.h" #include "functions.h" diff --git a/src/core2/fx/effect_soundemit.c b/src/core2/fx/effect_soundemit.c index 7044b384a..118eb4db3 100644 --- a/src/core2/fx/effect_soundemit.c +++ b/src/core2/fx/effect_soundemit.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_D2180.c #include #include "functions.h" #include "variables.h" @@ -5,118 +6,173 @@ extern void func_802F82F4(struct3s *, f32, f32, f32, f32); typedef struct { - s16 unk0; + s16 startState; //u8 pad[0x2]; - int (*unk4)(Actor *); + bool (*shouldStartFunc)(Actor *); } Struct_Core2_D2180_0; typedef struct { Struct_Core2_D2180_0 *unk0; } ActorLocal_core2_D2180; -int func_80359110(Actor *); -int func_8035911C(Actor *); -int func_80359110(Actor *); -int func_80359160(Actor *); -int func_80359110(Actor *); -int func_803591A4(Actor *); -void func_8035933C(Actor *this); +bool weatherParticle_isAlwaysActive(Actor *); +bool weatherParticle_shouldStartCCWHubLeafFalling(Actor *); +bool weatherParticle_isAlwaysActive(Actor *); +bool weatherParticle_shouldStartCCWHubRainFalling(Actor *); +bool weatherParticle_isAlwaysActive(Actor *); +bool weatherParticle_shouldStartCCWHubSnowFalling(Actor *); +void weatherParticle_update(Actor *this); void func_80359424(Actor *this); void func_80359454(Actor *this); /* .data */ -Struct_Core2_D2180_0 D_80372940[] ={ - {2, func_80359110}, - {2, func_8035911C}, - {3, func_80359110}, - {3, func_80359160}, - {4, func_80359110}, - {4, func_803591A4} +enum weatherParticle_state_enum { + WEATHERPARTICLE_STATE_0_NOT_INIT, + WEATHERPARTICLE_STATE_1_IDLE, + WEATHERPARTICLE_STATE_2_LEAF_FALLING, + WEATHERPARTICLE_STATE_3_RAINING, + WEATHERPARTICLE_STATE_4_SNOWING }; -ActorInfo D_80372970 = { 0x1C1, 0x2AE, 0x0, 0, NULL, func_8035933C, NULL, func_80325340, 0, 0, 0.0f, 0}; -ActorInfo D_80372994 = { 0x1C1, 0x2AF, 0x0, 0, NULL, func_8035933C, NULL, func_80325340, 0, 0, 0.0f, 0}; -ActorInfo D_803729B8 = { 0x1C1, 0x2B0, 0x0, 0, NULL, func_8035933C, NULL, func_80325340, 0, 0, 0.0f, 0}; -ActorInfo D_803729DC = { 0x1C1, 0x2B1, 0x0, 0, NULL, func_8035933C, NULL, func_80325340, 0, 0, 0.0f, 0}; -ActorInfo D_80372A00 = { 0x1C1, 0x2B2, 0x0, 0, NULL, func_8035933C, NULL, func_80325340, 0, 0, 0.0f, 0}; -ActorInfo D_80372A24 = { 0x1C1, 0x2B3, 0x0, 0, NULL, func_8035933C, NULL, func_80325340, 0, 0, 0.0f, 0}; -ActorInfo D_80372A48 = { 0x1C1, 0x316, 0x0, 0, NULL, func_80359424, NULL, func_80325340, 0, 0, 0.0f, 0}; -ActorInfo D_80372A6C = { 0x1C1, 0x317, 0x0, 0, NULL, func_80359454, NULL, func_80325340, 0, 0, 0.0f, 0}; +Struct_Core2_D2180_0 D_80372940[] = { + {WEATHERPARTICLE_STATE_2_LEAF_FALLING, weatherParticle_isAlwaysActive}, + {WEATHERPARTICLE_STATE_2_LEAF_FALLING, weatherParticle_shouldStartCCWHubLeafFalling}, + {WEATHERPARTICLE_STATE_3_RAINING, weatherParticle_isAlwaysActive}, + {WEATHERPARTICLE_STATE_3_RAINING, weatherParticle_shouldStartCCWHubRainFalling}, + {WEATHERPARTICLE_STATE_4_SNOWING, weatherParticle_isAlwaysActive}, + {WEATHERPARTICLE_STATE_4_SNOWING, weatherParticle_shouldStartCCWHubSnowFalling} +}; + +ActorInfo leafEmitterCCWAutumn = { + 0x1C1, ACTOR_2AE_LEAF_EMITTER_CCW_AUTUMN, 0x0, + 0, NULL, + weatherParticle_update, NULL, func_80325340, + 0, 0, 0.0f, 0 +}; + +ActorInfo leafEmitterCCWHub = { + 0x1C1, ACTOR_2AF_LEAF_EMITTER_CCW_HUB, 0x0, + 0, NULL, + weatherParticle_update, NULL, func_80325340, + 0, 0, 0.0f, 0 +}; + +ActorInfo rainEmitterCCWSpring = { + 0x1C1, ACTOR_2B0_RAIN_EMITTER_CCW_SPRING, 0x0, + 0, NULL, + weatherParticle_update, NULL, func_80325340, + 0, 0, 0.0f, 0 +}; + +ActorInfo rainEmitterCCWHub = { + 0x1C1, ACTOR_2B1_RAIN_EMITTER_CCW_HUB, 0x0, + 0, NULL, + weatherParticle_update, NULL, func_80325340, + 0, 0, 0.0f, 0 +}; + +ActorInfo snowEmitterCCWWinter = { + 0x1C1, ACTOR_2B2_SNOW_EMITTER_CCW_WINTER, 0x0, + 0, NULL, + weatherParticle_update, NULL, func_80325340, + 0, 0, 0.0f, 0 +}; + +ActorInfo snowEmitterCCWHub = { + 0x1C1, ACTOR_2B3_SNOW_EMITTER_CCW_HUB, 0x0, + 0, NULL, + weatherParticle_update, NULL, func_80325340, + 0, 0, 0.0f, 0 +}; + +ActorInfo D_80372A48 = { + 0x1C1, ACTOR_316_UNKNOWN, 0x0, + 0, NULL, + func_80359424, NULL, func_80325340, + 0, 0, 0.0f, 0 +}; + +ActorInfo D_80372A6C = { + 0x1C1, ACTOR_317_UNKNOWN, 0x0, + 0, NULL, + func_80359454, NULL, func_80325340, + 0, 0, 0.0f, 0 +}; /* .code */ -int func_80359110(Actor *this){ - return true; +bool weatherParticle_isAlwaysActive(Actor *this){ + return TRUE; } -int func_8035911C(Actor *this){ +// Player's Z Position +bool weatherParticle_shouldStartCCWHubLeafFalling(Actor *this){ f32 plyr_pos[3]; player_getPosition(plyr_pos); return (plyr_pos[2] < -1700.0f); } -int func_80359160(Actor *this){ +bool weatherParticle_shouldStartCCWHubRainFalling(Actor *this){ f32 plyr_pos[3]; player_getPosition(plyr_pos); return (1700.0f < plyr_pos[2]); } -int func_803591A4(Actor *this){ +bool weatherParticle_shouldStartCCWHubSnowFalling(Actor *this){ f32 plyr_pos[3]; player_getPosition(plyr_pos); return (1700.0f < plyr_pos[0]); } -void func_803591E8(Actor *this, s32 next_state){ +void weatherParticle_setState(Actor *this, s32 next_state){ ActorLocal_core2_D2180 * local = (ActorLocal_core2_D2180 *) &this->local; + struct3s *sp20; // [port] pointer-width - if(next_state == 2) + if(next_state == WEATHERPARTICLE_STATE_2_LEAF_FALLING) func_802F8C90(func_802F7C38()); - if(this->state == 2) + if(this->state == WEATHERPARTICLE_STATE_2_LEAF_FALLING) func_802F8CB0(func_802F7C38()); - if(next_state == 3){ - struct3s *rain = func_802F7C7C(); - func_802F8338(rain); - if(local->unk0->unk4 == func_80359110) { - func_802F82F4(rain, 5.0f, 30.0f, 5.0f, 30.0f); - } + if(next_state == WEATHERPARTICLE_STATE_3_RAINING){ + sp20 = func_802F7C7C(); + func_802F8338(sp20); + if(local->unk0->shouldStartFunc == weatherParticle_isAlwaysActive) + func_802F82F4(sp20, 5.0f, 30.0f, 5.0f, 30.0f); } - if(this->state == 3) + if(this->state == WEATHERPARTICLE_STATE_3_RAINING) func_802F8358(func_802F7C7C()); - if(next_state == 4){ + if(next_state == WEATHERPARTICLE_STATE_4_SNOWING){ func_802F7CC0(); func_802F90F4(); } - if(this->state == 4){ + if(this->state == WEATHERPARTICLE_STATE_4_SNOWING){ func_802F7CC0(); func_802F9114(); } - this->state = next_state; } -void func_8035933C(Actor *this){ +void weatherParticle_update(Actor *this){ ActorLocal_core2_D2180 * local = (ActorLocal_core2_D2180 *) &this->local; if(!this->volatile_initialized){ - this->volatile_initialized = true; - local->unk0 = D_80372940 + (this->modelCacheIndex - 0x2AE); - func_803591E8(this, 1); + this->volatile_initialized = TRUE; + local->unk0 = D_80372940 + (this->modelCacheIndex - ACTOR_2AE_LEAF_EMITTER_CCW_AUTUMN); + weatherParticle_setState(this, WEATHERPARTICLE_STATE_1_IDLE); } - if(this->state == 1){ - if(local->unk0->unk4(this)){ - func_803591E8(this, local->unk0->unk0); + if(this->state == WEATHERPARTICLE_STATE_1_IDLE){ + if(local->unk0->shouldStartFunc(this)){ + weatherParticle_setState(this, local->unk0->startState); } } - if(this->state != 1){ - if(!local->unk0->unk4(this)){ - func_803591E8(this, 1); + if(this->state != WEATHERPARTICLE_STATE_1_IDLE){ + if(!local->unk0->shouldStartFunc(this)){ + weatherParticle_setState(this, WEATHERPARTICLE_STATE_1_IDLE); } } } diff --git a/src/core2/fx/effect_sparkleemit.c b/src/core2/fx/effect_sparkleemit.c index 3cdf83c99..e3127d1b4 100644 --- a/src/core2/fx/effect_sparkleemit.c +++ b/src/core2/fx/effect_sparkleemit.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_50490.c #include #include "functions.h" #include "variables.h" @@ -16,7 +17,9 @@ f32 D_80367A84 = 30.0f; f32 D_80367A88 = 150.0f; f32 D_80367A8C = 25.0f; s32 D_80367A90[4] = {250, 250, 250, 120}; -s32 D_80367AA0 = 0; + +enum dust_emitter_type_e D_80367AA0 = DUST_EMITTER_TYPE_DUST; + f32 D_80367AA4[3] = {0.0f, 0.0f, 0.0f}; ActorInfo D_80367AB0 = { diff --git a/src/core2/fx/effect_eggshatter.c b/src/core2/fx/eggshatter.c similarity index 98% rename from src/core2/fx/effect_eggshatter.c rename to src/core2/fx/eggshatter.c index 19dfb5f76..88b7db8e4 100644 --- a/src/core2/fx/effect_eggshatter.c +++ b/src/core2/fx/eggshatter.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/eggshatter.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/fx/effect_generic.c b/src/core2/fx/explosionripple.c similarity index 94% rename from src/core2/fx/effect_generic.c rename to src/core2/fx/explosionripple.c index a52c26a49..73edc1542 100644 --- a/src/core2/fx/effect_generic.c +++ b/src/core2/fx/explosionripple.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/ch/explosionripple.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/fx/firefx.c b/src/core2/fx/firefx.c index 3e60f8000..8942b86e1 100644 --- a/src/core2/fx/firefx.c +++ b/src/core2/fx/firefx.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/ch/firefx.c #include #include "core1/core1.h" #include "functions.h" diff --git a/src/core2/fx/droplet.c b/src/core2/fx/piranhaWaterParticles.c similarity index 94% rename from src/core2/fx/droplet.c rename to src/core2/fx/piranhaWaterParticles.c index 67a61fb79..d26d8c98f 100644 --- a/src/core2/fx/droplet.c +++ b/src/core2/fx/piranhaWaterParticles.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/ch/piranhaWaterParticles.c #include #include "core1/core1.h" #include "functions.h" @@ -8,7 +9,7 @@ extern ParticleEmitter *func_802F4094(f32 pos[3], f32 arg1); void chPiranhaWaterParticles_update(Actor *this); /* .data */ -ActorInfo D_80367C60 = { +ActorInfo chPiranhaWaterParticles = { 0x15E, 0x188, 0x0, 0, NULL, chPiranhaWaterParticles_update, actor_update_func_80326224, func_80325340, diff --git a/src/core2/fx/projectile_anim.c b/src/core2/fx/projectile_anim.c index 3e74868fa..92137d625 100644 --- a/src/core2/fx/projectile_anim.c +++ b/src/core2/fx/projectile_anim.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_CBD10.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/fx/projectile_blueegg.c b/src/core2/fx/projectile_blueegg.c index 3c5323449..20abf395c 100644 --- a/src/core2/fx/projectile_blueegg.c +++ b/src/core2/fx/projectile_blueegg.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_CC1E0.c #include #include "functions.h" #include "variables.h" @@ -106,7 +107,7 @@ s32 func_803531C8(u8 projectile_indx, s32 arg1){ func_8038685C(other_marker); break; - case MARKER_BB_UNKNOWN: //L803533E4 //"BIG_JINXYHEAD" + case MARKER_BB_JINXY_HEAD_SANDYBUTT: //L803533E4 other_actor = marker_getActor(other_marker); *(s32 *)&other_actor->local = 1; commonParticle_setCurrentInUseFalse(); @@ -119,9 +120,9 @@ s32 func_803531C8(u8 projectile_indx, s32 arg1){ break; case MARKER_AB_RUBEES_EGG_POT: //L80353434 - if (collisionTri_isHitFromAbove_marker(egg_position, other_marker, 0x1E) && (func_8038E178() < func_8038E184())) { + if (collisionTri_isHitFromAbove_marker(egg_position, other_marker, 0x1E) && (func_8038E178() < rubeeEggPot_getEggGoal())) { commonParticle_setCurrentInUseFalse(); - func_8038E140(); + rubeeEggPot_addedEggToPot(); } break; @@ -180,7 +181,7 @@ void fxegg_head_spawn(void){ func_8033EA40(0, 20.0f); func_8033EA40(1, 0.0f); func_8033EA40(2, 0.0f); - _player_getPosition(sp50); + playerPosition_get(sp50); sp50[1] += spawnHeight; ml_vec3f_copy(sp68, sp50); player_getRotation(sp44); @@ -290,7 +291,7 @@ void fxegg_ass_spawn(void) { func_8033EA40(1, 0); func_8033EA40(0, 20.0f); func_8033EA40(2, 0); - _player_getPosition(marker); + playerPosition_get(marker); player_getRotation(sp30); sp30[1] = mlNormalizeAngle(sp30[1] + 180.0f); func_80256E24(sp48, 0.0f, sp30[1], 0.0f, 0.0f, -18.0f); diff --git a/src/core2/fx/projectile_render.c b/src/core2/fx/projectile_render.c index 54d8ccfce..cb562833c 100644 --- a/src/core2/fx/projectile_render.c +++ b/src/core2/fx/projectile_render.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_CD6E0.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/fx/projectile_smoke.c b/src/core2/fx/projectile_smoke.c index 4dd750152..2e2a78cb6 100644 --- a/src/core2/fx/projectile_smoke.c +++ b/src/core2/fx/projectile_smoke.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_CF090.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/fx/projectile_sparkle.c b/src/core2/fx/projectile_sparkle.c index 4bc192573..8157fcd69 100644 --- a/src/core2/fx/projectile_sparkle.c +++ b/src/core2/fx/projectile_sparkle.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_CECD0.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/fx/projectile_spawnfx.c b/src/core2/fx/projectile_spawnfx.c index 5f943c7b3..c7b154631 100644 --- a/src/core2/fx/projectile_spawnfx.c +++ b/src/core2/fx/projectile_spawnfx.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_CD3F0.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/fx/projectile_system.c b/src/core2/fx/projectile_system.c index ef858ca10..509b6321f 100644 --- a/src/core2/fx/projectile_system.c +++ b/src/core2/fx/projectile_system.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_B8860.c #include "core1/core1.h" #include "functions.h" #include "variables.h" diff --git a/src/core2/fx/effect_ripple_spawn.c b/src/core2/fx/ripple.c similarity index 99% rename from src/core2/fx/effect_ripple_spawn.c rename to src/core2/fx/ripple.c index f30debf76..32677ab4f 100644 --- a/src/core2/fx/effect_ripple_spawn.c +++ b/src/core2/fx/ripple.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/fx/ripple.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/fx/effect_sparkle.c b/src/core2/fx/shoesparkle.c similarity index 50% rename from src/core2/fx/effect_sparkle.c rename to src/core2/fx/shoesparkle.c index 84150fdad..b48ee8009 100644 --- a/src/core2/fx/effect_sparkle.c +++ b/src/core2/fx/shoesparkle.c @@ -1,53 +1,57 @@ +// BanjoDecomp: core2/fx/shoesparkle.c #include #include "functions.h" #include "variables.h" typedef struct{ - s32 unk0; + s32 frameCount; } ActorLocal_Core2_3EAD0; -void func_802C5A60(Actor *this); +void fxShoeSparkle_update(Actor *this); /* .data */ -s32 D_80365F30[] = { +s32 fxShoeSparkleFrames[] = { 1, 1, 2, 2, 3, 4, 5, 6, 7, 7, 8, 8 }; -ActorInfo D_80365F60 = { - 0x58, 0x4E, ASSET_7DE_SPRITE_SHOE_SPARKLES, + +#define MAX_FRAME_COUNT 12 + +ActorInfo fxWadingBootsTouchSparkle = { + MARKER_58_WADING_BOOTS_TOUCH_SPARKLE, ACTOR_4E_WADING_BOOTS_TOUCH_SPARKLE, ASSET_7DE_SPRITE_SHOE_SPARKLES, 0, NULL, - func_802C5A60, actor_update_func_80326224, fxTouchSparkle_draw, + fxShoeSparkle_update, actor_update_func_80326224, fxTouchSparkle_draw, 0, 0, 0.0f, 0 }; -ActorInfo D_80365F84 = { +ActorInfo fxTurboTrainersTouchSparkle = { 0x59, 0x4F, ASSET_7DE_SPRITE_SHOE_SPARKLES, 0, NULL, - func_802C5A60, actor_update_func_80326224, fxTouchSparkle_draw, + fxShoeSparkle_update, actor_update_func_80326224, fxTouchSparkle_draw, 0, 0, 0.0f, 0 }; /* .code */ -void func_802C5A60(Actor *this){ +void fxShoeSparkle_update(Actor *this){ // Spawns a sparkle sprite when touching turbo trainers or wading boots ActorLocal_Core2_3EAD0 *local = (ActorLocal_Core2_3EAD0*)&this->local; if(!this->initialized){ switch(this->marker->id){ - case 0x58: + case MARKER_58_WADING_BOOTS_TOUCH_SPARKLE: suSetSpriteScale(this, 0.35f); break; - case 0x59: + case MARKER_59_TURBO_TRAINERS_TOUCH_SPARKLE: suSetSpriteScale(this, 0.4f); break; } this->marker->propPtr->isMirrored = 0.5 < randf(); - this->position_y += 100.0*this->scale; + this->position_y += 100.0 * this->scale; actor_collisionOff(this); this->initialized = true; }//L802C5B60 - this->marker->propPtr->frame = D_80365F30[local->unk0]; - local->unk0++; - if(local->unk0 >= 0xC) + this->marker->propPtr->frame = fxShoeSparkleFrames[local->frameCount]; + local->frameCount++; + if(local->frameCount >= MAX_FRAME_COUNT) marker_despawn(this->marker); } diff --git a/src/core2/fx/shrapnel.c b/src/core2/fx/shrapnel.c index b112945c6..225f2a28d 100644 --- a/src/core2/fx/shrapnel.c +++ b/src/core2/fx/shrapnel.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/ch/shrapnel.c #include #include "functions.h" #include "variables.h" @@ -156,7 +157,7 @@ void chshrapnel_update(Actor *this) { this->unk1C[2] = this->position[2]; this->unk1C[1] = func_80309B24(this->position) - 15.0f; this->position[1] = this->unk1C[1] - (sinf(this->lifetime_value * 4.0f) * 10.0f); - _player_getPosition(player_position); + playerPosition_get(player_position); switch (this->state) { case 1: chShrapnel_func_802D0A38(this); diff --git a/src/core2/fx/effect_sparkle_spawn.c b/src/core2/fx/sparkle.c similarity index 99% rename from src/core2/fx/effect_sparkle_spawn.c rename to src/core2/fx/sparkle.c index 5d0d0d4f3..dfd8fe4da 100644 --- a/src/core2/fx/effect_sparkle_spawn.c +++ b/src/core2/fx/sparkle.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/fx/sparkle.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/fx/whipcrack.c b/src/core2/fx/whipcrack.c index 92b8d56f0..72cddba8b 100644 --- a/src/core2/fx/whipcrack.c +++ b/src/core2/fx/whipcrack.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/ch/whipcrack.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/gameSelect.c b/src/core2/gameSelect.c index 22c1322a7..c1faffbc6 100644 --- a/src/core2/gameSelect.c +++ b/src/core2/gameSelect.c @@ -1,11 +1,13 @@ +// BanjoDecomp: core2/ch/gameSelect.c #include #include "functions.h" #include "variables.h" +#include "ch/gameSelect.h" #include "core2/modelRender.h" #include "core2/gc/zoombox.h" -#include "core2/quiz_storage.h" +#include "core2/quiz/storage.h" #include "port/Romhack/RomhackConfig.h" #include "port/Patches/Patches.h" @@ -71,7 +73,7 @@ ActorAnimationInfo banjoGameboyAnimations[] = { {0x24F, 0.6f}, {0x24D, 2.0f} }; -ActorInfo D_80365E58 = { 0xE4, 0x195, 0x532, 0x1, banjoGameboyAnimations, gameSelect_initAndUpdate, actor_update_func_80326224, gameSelect_zoomboxDraw, 0, 0, 0.0f, 0}; +ActorInfo gameSelect_banjoSleeping = { 0xE4, 0x195, 0x532, 0x1, banjoGameboyAnimations, gameSelect_initAndUpdate, actor_update_func_80326224, gameSelect_zoomboxDraw, 0, 0, 0.0f, 0}; ActorAnimationInfo D_80365E7C[] = { {0x000, 0.0f}, @@ -81,7 +83,7 @@ ActorAnimationInfo D_80365E7C[] = { {0x252, 0.67f}, {0x250, 4.5f}, }; -ActorInfo D_80365EAC = { 0xE5, 0x196, 0x532, 0x1, D_80365E7C, gameSelect_update, actor_update_func_80326224, gameSelect_draw, 0, 0, 0.0f, 0}; +ActorInfo gameSelect_banjoGameboy = { 0xE5, 0x196, 0x532, 0x1, D_80365E7C, gameSelect_update, actor_update_func_80326224, gameSelect_draw, 0, 0, 0.0f, 0}; ActorAnimationInfo D_80365ED0[] = { {0x000, 0.0f}, @@ -91,12 +93,19 @@ ActorAnimationInfo D_80365ED0[] = { {0x24C, 1.0f}, {0x24A, 1.0f} }; -ActorInfo D_80365F00 = { 0xE6, 0x197, 0x532, 0x1, D_80365ED0, gameSelect_update, actor_update_func_80326224, gameSelect_draw, 0, 0, 0.0f, 0}; +ActorInfo gameSelect_banjoCooking = { 0xE6, 0x197, 0x532, 0x1, D_80365ED0, gameSelect_update, actor_update_func_80326224, gameSelect_draw, 0, 0, 0.0f, 0}; +// Yes, Gaming Chair is before Kitchen +enum chgameselect_savefile_e { + CH_GAME_SELECT_SAVEFILE_0_BED, + CH_GAME_SELECT_SAVEFILE_1_GAMING_CHAIR, + CH_GAME_SELECT_SAVEFILE_2_KITCHEN +}; + /* .bss */ s32 mm_hut_smash_count; -u32 CH_TREASUREHUNT_PUZZLE_CURRENT_STEP; +u32 chtreasureHunt_puzzleCurrentStep; struct FF_StorageStruct* ffStorage; s32 mmhut_smashCount; u8 gCompletedBottlesBonusGames[7]; // bottle bonus puzzle? @@ -131,16 +140,16 @@ f32 D_8037DD34; /* .code */ Actor *gameSelect_draw(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx){ s32 sp1C = marker->id - 0xe4; - func_8033A45C(3, sp1C); - func_8033A45C(1, 1); - func_8033A45C(4, 1); - func_8033A45C(9, 1); - func_8033A45C(5, 0); - func_8033A45C(8, 0); - func_8033A45C(6, 0); - func_8033A45C(7, 0); - func_8033A45C(0xC, 1); - func_8033A45C(0xF, 1); + modelRender_setAppendageVisibility(3, sp1C); + modelRender_setAppendageVisibility(1, 1); + modelRender_setAppendageVisibility(4, 1); + modelRender_setAppendageVisibility(9, 1); + modelRender_setAppendageVisibility(5, 0); + modelRender_setAppendageVisibility(8, 0); + modelRender_setAppendageVisibility(6, 0); + modelRender_setAppendageVisibility(7, 0); + modelRender_setAppendageVisibility(0xC, 1); + modelRender_setAppendageVisibility(0xF, 1); if(sp1C == D_80365E00){ modelRender_setEnvColor(0xFF, 0xFF, 0xFF, 0xFF); } @@ -215,13 +224,13 @@ void setGameInformationZoombox(s32 gamenum){ strcpy(upperTextLine, ""); strcat(upperTextLine, sGamePrefix[lang]); switch(gamenum){ - case 0: //L802C4820 + case CH_GAME_SELECT_SAVEFILE_0_BED: //L802C4820 strIToA(upperTextLine, 1); break; - case 1: //L802C4838 + case CH_GAME_SELECT_SAVEFILE_1_GAMING_CHAIR: //L802C4838 strIToA(upperTextLine, 3); break; - case 2: //L802C484C + case CH_GAME_SELECT_SAVEFILE_2_KITCHEN: //L802C484C strIToA(upperTextLine, 2); break; }//L802C4858 @@ -250,13 +259,13 @@ void setGameInformationZoombox(s32 gamenum){ strcpy(upperTextLine, ""); strcat(upperTextLine, sGamePrefix[lang]); switch (gamenum){ - case 0: + case CH_GAME_SELECT_SAVEFILE_0_BED: strIToA(upperTextLine, 1); break; - case 1: + case CH_GAME_SELECT_SAVEFILE_1_GAMING_CHAIR: strIToA(upperTextLine, 3); break; - case 2: + case CH_GAME_SELECT_SAVEFILE_2_KITCHEN: strIToA(upperTextLine, 2); break; }//L802C4A40 @@ -349,7 +358,7 @@ void gameSelect_update(Actor *this){ __spawnQueue_add_1((GenFunction_1)spawnGameSelectProps, (uintptr_t)this->marker); func_802C7318(this); this->unk130 = func_802C71F0; - if(sp84 == 0){ + if(sp84 == CH_GAME_SELECT_SAVEFILE_0_BED){ func_802C75A0(this, 1); func_802C74F4(this, 0, 1.0f); func_802C74F4(this, 1, 1.0f); @@ -370,20 +379,20 @@ void gameSelect_update(Actor *this){ case 2: case 5: switch(sp84){ - case 0://L802C4D8C + case CH_GAME_SELECT_SAVEFILE_0_BED://L802C4D8C if(actor_animationIsAt(this, 0.1f)) sfxsource_play(SFX_5D_BANJO_RAAOWW, 8000); if(actor_animationIsAt(this, 0.7f)) sfxsource_play(SFX_5E_BANJO_PHEWWW, 8000); break; - case 1://L802C4DD0 + case CH_GAME_SELECT_SAVEFILE_1_GAMING_CHAIR://L802C4DD0 if(randf() < 0.1){ // if(randf() < D_80376118){ gcsfx_playWithPitch(MIN(2.0f, randf() *3.0f) + 311.0f, 1.0f, 12000); } break; - case 2://L802C4E74 + case CH_GAME_SELECT_SAVEFILE_2_KITCHEN://L802C4E74 if(randf() < 0.03){ gcsfx_playWithPitch(0x3ed, randf()*0.3 + 0.7, 15000); } @@ -394,7 +403,7 @@ void gameSelect_update(Actor *this){ if(!func_8038AAB0()){ switch(this->state){ case 1://L802C4F10 - if(sp84 == 1){ + if(sp84 == CH_GAME_SELECT_SAVEFILE_1_GAMING_CHAIR){ sfxsource_play(SFX_136_GAMEBOY_STARTUP, 15000); timedFunc_set_3(0.25f, (GenFunction_3)comusic_8025AB44, COMUSIC_73_GAMEBOY, -1, 2000); func_8025A58C(0, 2000); @@ -404,7 +413,7 @@ void gameSelect_update(Actor *this){ func_8025A58C(-1, 2000); } - if(sp84 == 2){ + if(sp84 == CH_GAME_SELECT_SAVEFILE_2_KITCHEN){ D_8037DD28 = func_802F9AA8(SFX_12B_BOILING_AND_BUBBLING); func_802F9F80(D_8037DD28, 0.5f, 9000000000.0f, 0.5f); func_802F9DB8(D_8037DD28, 0.9f, 0.9f, 0.0f); @@ -462,7 +471,7 @@ void gameSelect_update(Actor *this){ } else{//L802C511C sp44 = 0.0f; - if(this->state == 4 && (sp84 == 0 || sp84 == 1)) + if(this->state == 4 && (sp84 == CH_GAME_SELECT_SAVEFILE_0_BED || sp84 == CH_GAME_SELECT_SAVEFILE_1_GAMING_CHAIR)) sp44 = 0.25f; if(chmole_learnedAllSpiralMountainAbilities() && fileProgressFlag_get(FILEPROG_BD_ENTER_LAIR_CUTSCENE)){ timedFunc_set_2(sp44, (GenFunction_2)warp_lairEnterLairFromSMLevel, 0, 0); @@ -493,22 +502,22 @@ void gameSelect_update(Actor *this){ if(gameFile_isNotEmpty(sp84)){ if(randf() < 0.1){ switch(sp84){ - case 0://L802C52B8 + case CH_GAME_SELECT_SAVEFILE_0_BED://L802C52B8 sfxsource_play(SFX_31_BANJO_OHHWAAOOO, 28000); - gcsfx_playAtSampleRate(SFX_135_CARTOONY_SPRING); + gcsfx_play(SFX_135_CARTOONY_SPRING); timedFunc_set_2(0.4f, (GenFunction_2)sfxsource_play, SFX_13A_GLASS_BREAKING_7, 0x7fff); timedFunc_set_2(0.9f, (GenFunction_2)sfxsource_play, SFX_150_PORCELAIN_CRASH, 0x7fff); timedFunc_set_2(1.0f, (GenFunction_2)sfxsource_play, SFX_151_CAT_MEOW, 0x7fff); break; - case 1://L802C5320 + case CH_GAME_SELECT_SAVEFILE_1_GAMING_CHAIR://L802C5320 timedFunc_set_2(0.4f, (GenFunction_2)sfxsource_play, SFX_31_BANJO_OHHWAAOOO, 28000); timedFunc_set_2(0.2f, (GenFunction_2)sfxsource_play, SFX_E_SHOCKSPRING_BOING, 28000); - gcsfx_playAtSampleRate(SFX_2D_KABOING); + gcsfx_play(SFX_2D_KABOING); break; - case 2://L802C5364 + case CH_GAME_SELECT_SAVEFILE_2_KITCHEN://L802C5364 timedFunc_set_2(0.15f, (GenFunction_2)sfxsource_play, SFX_32_BANJO_EGHEE, 28000); sfxsource_play(SFX_3F6_RUBBING, 28000); - gcsfx_playAtSampleRate(SFX_8F_SNOWBALL_FLYING); + gcsfx_play(SFX_8F_SNOWBALL_FLYING); break; }//L802C5394 subaddie_set_state(this, 4); @@ -522,10 +531,10 @@ void gameSelect_update(Actor *this){ sfxsource_play(SFX_4F_BANJO_WAHOO, 28000); subaddie_set_state(this, 3); }//L802C53E8 - if(sp84 == 0) + if(sp84 == CH_GAME_SELECT_SAVEFILE_0_BED) func_802C75A0(this, 2); - if(sp84 == 1) + if(sp84 == CH_GAME_SELECT_SAVEFILE_1_GAMING_CHAIR) comusic_8025AB44(COMUSIC_73_GAMEBOY, 0, 4000); func_8025A58C(0, 0x1f4); @@ -538,28 +547,28 @@ void gameSelect_update(Actor *this){ if(sp54[0] < 0.0f){ D_8037DCEC = 1; switch(D_80365E00){ - case 0: + case CH_GAME_SELECT_SAVEFILE_0_BED: D_8037DCEC = 0; break; - case 1: - D_80365E00 = 2; + case CH_GAME_SELECT_SAVEFILE_1_GAMING_CHAIR: + D_80365E00 = CH_GAME_SELECT_SAVEFILE_2_KITCHEN; break; - case 2: - D_80365E00 = 0; + case CH_GAME_SELECT_SAVEFILE_2_KITCHEN: + D_80365E00 = CH_GAME_SELECT_SAVEFILE_0_BED; break; } } else{//L802C54D4 D_8037DCEC = 1; switch(D_80365E00){ - case 0: - D_80365E00 = 2; + case CH_GAME_SELECT_SAVEFILE_0_BED: + D_80365E00 = CH_GAME_SELECT_SAVEFILE_2_KITCHEN; break; - case 1: + case CH_GAME_SELECT_SAVEFILE_1_GAMING_CHAIR: D_8037DCEC = 0; break; - case 2: - D_80365E00 = 1; + case CH_GAME_SELECT_SAVEFILE_2_KITCHEN: + D_80365E00 = CH_GAME_SELECT_SAVEFILE_1_GAMING_CHAIR; break; } }//L802C550C @@ -633,8 +642,8 @@ void gameSelect_initAndUpdate(Actor * this){ D_8037DCEC = 0; debugScoreStates(); clearScoreStates(); - D_8037DCE8 = 0; - D_80365E00 = 0; + D_8037DCE8 = CH_GAME_SELECT_SAVEFILE_0_BED; + D_80365E00 = CH_GAME_SELECT_SAVEFILE_0_BED; cameraPositions[1][0] = D_80365DD0[0][0]; cameraPositions[1][1] = D_80365DD0[0][1]; cameraPositions[1][2] = D_80365DD0[0][2]; diff --git a/src/core2/gameloop.c b/src/core2/gameloop.c index 8ce87f1ca..fb92b7c44 100644 --- a/src/core2/gameloop.c +++ b/src/core2/gameloop.c @@ -1,8 +1,12 @@ +// BanjoDecomp: core2/code_5C870.c #include #include "core1/core1.h" #include "functions.h" #include "variables.h" +extern void Graphics_PushFrame(Gfx* data); +extern void Framebuffer_ReadbackGPU(int bufferIndex); + #include "gc/gctransition.h" #include "bk_time.h" #include "port/Patches/Patches.h" @@ -15,10 +19,10 @@ extern void func_8025A2B0(void); extern void func_8025A430(s32, s32, s32); extern void gsworld_setEnableUpdate(s32); extern void func_8034BB90(void); -extern void func_8030C27C(void); +extern void picturebox_spawn(void); extern void func_80321C34(void); extern void func_8030ED0C(void); -extern void comusicPlayer_update(void); +extern void coMusicPlayer_update(void); enum transition_e { TRANSITION_0_NONE @@ -111,50 +115,46 @@ void func_802E38E8(enum map_e map, s32 exit, s32 reset_on_load){ void func_802E398C(s32 arg0) { gsworld_free(); func_8030ED0C(); - comusicPlayer_update(); + coMusicPlayer_update(); if (arg0 != 0) { func_802E3854(); } } -void func_802E39D0(Gfx **gdl, Mtx **mptr, Vtx **vptr, s32 framebuffer_idx, s32 arg4){ - Mtx* m_start = *mptr; - Vtx* v_start = *vptr; +void func_802E39D0(Gfx **gfx, Mtx **mtx, Vtx **vtx, s32 framebuffer_idx, bool arg4) { + Mtx* mtx_start = *mtx; + Vtx* vtx_start = *vtx; - scissorBox_SetForGameMode(gdl, framebuffer_idx); + setupFramebufferForGamemode(gfx, framebuffer_idx); D_8037E8E0.unkC = false; port_mirror_beginScene(); - gsworld_draw(gdl, mptr, vptr); - CALL_EVENT(OnWorldDraw, gdl, mptr, vptr); + gsworld_draw(gfx, mtx, vtx); + CALL_EVENT(OnWorldDraw, gfx, mtx, vtx); port_mirror_endScene(); - port_mirror_undoProjection(gdl, mptr); + port_mirror_undoProjection(gfx, mtx); if (port_shouldCaptureTransition()) { - port_captureTransitionFb(gdl); + port_captureTransitionFb(gfx); } if(!arg4){ func_802E67AC(); func_802E3BD0(getActiveFramebuffer()); func_802E67C4(); - func_802E5F10(gdl); + func_802E5F10(gfx); } - if( D_8037E8E0.game_mode == GAME_MODE_A_SNS_PICTURE - && D_8037E8E0.unk19 != 6 - && D_8037E8E0.unk19 != 5 - ){ - gctransition_draw(gdl, mptr, vptr); + + if ((D_8037E8E0.game_mode == GAME_MODE_A_SNS_PICTURE) && (D_8037E8E0.unk19 != 6) && (D_8037E8E0.unk19 != 5)) { + gctransition_draw(gfx, mtx, vtx); } // [port] Return rendering to main FB after scene draw + transitions for // SNS/Bottles modes. Must come AFTER gctransition_draw so the transition // fade renders into the aux FB (visible on the picture), not the main FB. if (D_8037E8E0.game_mode == GAME_MODE_8_BOTTLES_BONUS || D_8037E8E0.game_mode == GAME_MODE_A_SNS_PICTURE) { - gsSPResetFB((*gdl)++); + gsSPResetFB((*gfx)++); } - if( D_8037E8E0.game_mode == GAME_MODE_8_BOTTLES_BONUS - || D_8037E8E0.game_mode == GAME_MODE_A_SNS_PICTURE - ){ - func_8030C2D4(gdl, mptr, vptr); + if ((D_8037E8E0.game_mode == GAME_MODE_8_BOTTLES_BONUS) || (D_8037E8E0.game_mode == GAME_MODE_A_SNS_PICTURE)) { + picturebox_resetScissorBoxAndFramebuffer(gfx, mtx, vtx); } // [port] Skip all HUD/overlay draws while pause menu is capturing the @@ -163,42 +163,39 @@ void func_802E39D0(Gfx **gdl, Mtx **mptr, Vtx **vptr, s32 framebuffer_idx, s32 a bool capturing = gcpausemenu_isCapturing(); if(!game_is_frozen() && gsworld_getEnableDraw() && !capturing){ - func_8032D474(gdl, mptr, vptr); + core2_A5BC0_drawScreenOverlayMarkers(gfx, mtx, vtx); } - gcpausemenu_draw(gdl, mptr, vptr); + gcpausemenu_draw(gfx, mtx, vtx); if(!game_is_frozen() && !capturing){ - dummy_func_8025AFC0(gdl, mptr, vptr); + dummy_func_8025AFC0(gfx, mtx, vtx); } if (!capturing) { - gcdialog_draw(gdl, mptr, vptr); + gcdialog_draw(gfx, mtx, vtx); } if(!game_is_frozen() && !capturing){ - itemPrint_draw(gdl, mptr, vptr); + itemPrint_draw(gfx, mtx, vtx); } if (!capturing) { - printbuffer_draw(gdl, mptr, vptr); + printbuffer_draw(gfx, mtx, vtx); } - if( D_8037E8E0.game_mode != GAME_MODE_A_SNS_PICTURE - || D_8037E8E0.unk19 == 6 - || D_8037E8E0.unk19 == 5 - ){ - gctransition_draw(gdl, mptr, vptr); + if ((D_8037E8E0.game_mode != GAME_MODE_A_SNS_PICTURE) || (D_8037E8E0.unk19 == 6) || (D_8037E8E0.unk19 == 5)) { + gctransition_draw(gfx, mtx, vtx); } // [port] Populate gFramebuffers from the GPU via gDPReadFB at native resolution. // Transitions and particles read from gFramebuffers during game logic. // On N64, gFramebuffers was the render target directly; on PC the GPU renders // to its own buffer, so we read it back here when requested. if (port_consumeReadbackRequest()) { - gDPReadFB((*gdl)++, 0, (u16 *)gFramebuffers[getActiveFramebuffer()], + gDPReadFB((*gfx)++, 0, (u16 *)gFramebuffers[getActiveFramebuffer()], 0, 0, gFramebufferWidth, gFramebufferHeight, 1); } - core1_15B30_finishDList(gdl); - osWritebackDCache(m_start, sizeof(Mtx)*( *mptr - m_start)); - osWritebackDCache(v_start, sizeof(Vtx)*( *vptr - v_start)); + core1_15B30_finishDList(gfx); + osWritebackDCache(mtx_start, sizeof(Mtx)*( *mtx - mtx_start)); + osWritebackDCache(vtx_start, sizeof(Vtx)*( *vtx - vtx_start)); } void func_802E3BD0(s32 frame_buffer_indx){ @@ -229,10 +226,10 @@ void game_setMode(enum game_mode_e next_mode, s32 arg1){ //L802E3C84 if(next_mode == GAME_MODE_8_BOTTLES_BONUS || next_mode == GAME_MODE_A_SNS_PICTURE){ - func_8030C1A0(); + picturebox_init(); } else{ - func_8030C204(); + picturebox_free(); }//L802E3CB4 D_8037E8E0.game_mode = next_mode; @@ -318,26 +315,21 @@ s32 func_802E3F80(void){ return D_8037E8E0.unk0; } -extern void Graphics_PushFrame(Gfx* data); -extern void Framebuffer_ReadbackGPU(int bufferIndex); - -void game_draw(s32 arg0){ - Gfx *gfx; - Gfx *gfx_start; - Gfx *sp2C; +void game_draw(bool arg0) { + Gfx *gfx, *gfx_start, *gfx_end; Mtx *mtx; Mtx *mtx_start; Vtx *vtx; Vtx *vtx_start; - if(arg0) { + if (arg0) { scissorBox_setDefault(); } - getGraphicsStacks(&gfx, &mtx, &vtx); + graphicscache_swapAndGetStacks(&gfx, &mtx, &vtx); - if(D_8037E8E0.unkC == 1){ - getGraphicsStacks(&gfx, &mtx, &vtx); + if (D_8037E8E0.unkC == TRUE) { // BUG: Compares explicit for integral value of TRUE, instead for true-ness + graphicscache_swapAndGetStacks(&gfx, &mtx, &vtx); } gfx_start = gfx; @@ -355,11 +347,11 @@ void game_draw(s32 arg0){ Framebuffer_ReadbackGPU(getActiveFramebuffer()); if(D_8037E8E0.unkC == 0){ - sp2C = gfx; + gfx_end = gfx; viMgr_func_8024C1DC(); - core1_15B30_addF3DEXTaskData_40000000(gfx_start, sp2C); + core1_15B30_addF3DEXTaskData_40000000(gfx_start, gfx_end); - if(arg0) { + if (arg0) { scissorBox_setDefault(); } } @@ -420,13 +412,13 @@ void func_802E4170(void){ timedFuncQueue_free(); func_802F9C48(); modelRender_free(); - depthBuffer_stub(); + depthbuffer_stub(); func_802E398C(0); func_8030AFD8(0); func_80321854(); debugScoreStates(); animCache_free(); - comusicPlayer_free(); + coMusicPlayer_free(); func_8030D8DC(); } @@ -435,12 +427,12 @@ void func_802E4214(enum map_e map_id){ D_8037E8E0.unk19 = D_8037E8E0.unk18 = 0; D_8037E8E0.map = D_8037E8E0.exit = D_8037E8E0.unk17 = 0; D_8037E8E0.unk1B = D_8037E8E0.unk1A = 0; - D_8037E8E0.unkC = 0; + D_8037E8E0.unkC = FALSE; D_8037E8E0.unk1C = 0; savedata_init(); sns_save_and_update_global_data(); func_8030D86C(); - comusicPlayer_init(); + coMusicPlayer_init(); func_80322764(); timedFuncQueue_init(); func_802F9CD8(); @@ -452,7 +444,7 @@ void func_802E4214(enum map_e map_id){ func_802E5F38(); defragManager_init(); modelRender_init(); - func_80253428(1); + depthbuffer_enable(TRUE); animCache_init(); viewport_reset(); viewport_setNearAndFar(1.0f, 10000.0f); @@ -592,11 +584,11 @@ bool func_802E4424(void) { sp1C = gsworld_update(); func_80321C34(); func_8030ED0C(); - comusicPlayer_update(); + coMusicPlayer_update(); switch (D_8037E8E0.game_mode) { case GAME_MODE_8_BOTTLES_BONUS: case GAME_MODE_A_SNS_PICTURE: - func_8030C27C(); + picturebox_spawn(); /* fallthrough */ case GAME_MODE_7_ATTRACT_DEMO: /* fallthrough */ @@ -685,7 +677,7 @@ s32 game_defrag(void){ gcpausemenu_defrag(); switch(overlayManager_getLoadedID()){ case OVERLAY_2_WHALE: - func_803894A0(); + maClanker_defrag(); break; case OVERLAY_D_WITCH: code_C9E70_defrag(); diff --git a/src/core2/gamestate.c b/src/core2/gamestate.c index 10cf40cbb..4baef7311 100644 --- a/src/core2/gamestate.c +++ b/src/core2/gamestate.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_BEF20.c #include #include "core1/core1.h" #include "functions.h" @@ -29,7 +30,7 @@ bool func_80347A4C(void); /* .code */ void func_80345EB0(enum item_e item){ if(func_802FAFE8(item)){ - item_adjustByDiffWithHud(item, (s32)(-time_getDelta()*60.0f * 1.1)); + item_adjustByDiffWithHud(item, (s32)(-time_getDelta()*(float)(FRAMERATE) * 1.1)); }else{ code_73640_printItemCount(item); } @@ -93,7 +94,7 @@ s32 item_adjustByDiff(enum item_e item, s32 diff, s32 no_hud, s32 triggerEvent){ sp34 = ((fileProgressFlag_get(FILEPROG_B9_DOUBLE_HEALTH))? 2 : 1); D_80385F30[ITEM_15_HEALTH_TOTAL] = MIN(sp34*8, D_80385F30[ITEM_15_HEALTH_TOTAL]); D_80385F30[ITEM_14_HEALTH]= MIN(D_80385F30[ITEM_15_HEALTH_TOTAL], D_80385F30[ITEM_14_HEALTH]); - D_80385F30[ITEM_17_AIR] = MIN(3600, D_80385F30[ITEM_17_AIR]); + D_80385F30[ITEM_17_AIR] = MIN(VER_SELECT(3600, 3000, 0, 0), D_80385F30[ITEM_17_AIR]); D_80385F30[ITEM_25_MUMBO_TOKEN_TOTAL] = D_80385F30[ITEM_1C_MUMBO_TOKEN]; D_80385F30[ITEM_16_LIFE] = MIN(0xFF, D_80385F30[ITEM_16_LIFE]); @@ -222,7 +223,7 @@ void item_setItemsStartCounts(void){ D_80385F30[ITEM_10_GOLD_FEATHER] = 0; D_80385F30[ITEM_14_HEALTH] = D_80385F30[ITEM_15_HEALTH_TOTAL] = 5; D_80385F30[ITEM_16_LIFE] = 3; - D_80385F30[ITEM_17_AIR] = 3600; + D_80385F30[ITEM_17_AIR] = VER_SELECT(3600, 3000, 0, 0); D_80385F30[ITEM_1C_MUMBO_TOKEN] = 0; D_80385F30[0x2B] = 0; D_80385F30[ITEM_26_JIGGY_TOTAL] = 0; @@ -242,7 +243,7 @@ void itemscore_levelReset(enum level_e level){ D_80385F30[ITEM_C_NOTE] = 0; D_80385F30[ITEM_E_JIGGY] = jiggyscore_leveltotal(level); D_80385F30[ITEM_12_JINJOS] = 0; - D_80385F30[ITEM_17_AIR] = 3600; + D_80385F30[ITEM_17_AIR] = VER_SELECT(3600, 3000, 0, 0); D_80385F30[ITEM_18_GOLD_BULLIONS] = 0; D_80385F30[ITEM_19_ORANGE] = 0; D_80385F30[ITEM_23_ACORNS] = 0; @@ -325,16 +326,16 @@ void func_803465E4(void){ D_80385FEC = MAX(0.0, D_80385FEC - time_getDelta()); }//L80346870 if( (!is_in_polluted_or_winter_water && is_underwater) || (is_in_polluted_or_winter_water && is_on_water_surface) ){//L80346894 - item_adjustByDiffWithHud(ITEM_17_AIR, (s32)((f64)((-time_getDelta())*60.0f)*1.1)); + item_adjustByDiffWithHud(ITEM_17_AIR, (s32)((f64)((-time_getDelta())*(float)(FRAMERATE))*1.1)); } else{ if(is_in_polluted_or_winter_water && is_underwater){//L803468D8 - item_adjustByDiffWithHud(ITEM_17_AIR, (s32)(f64)((-time_getDelta()*60.0f)*2.1)); + item_adjustByDiffWithHud(ITEM_17_AIR, (s32)(f64)((-time_getDelta()*(float)(FRAMERATE))*2.1)); }//L80346930 if(!is_in_polluted_or_winter_water || D_80385FEC == 0.0f){ - if(!D_80385FE4 && D_80385F30[ITEM_17_AIR] < 3600){ - item_adjustByDiffWithHud(ITEM_17_AIR, (s32)(((time_getDelta()*60.0f)*100.0)*1.1)); - D_80385F30[ITEM_17_AIR] = MIN(D_80385F30[ITEM_17_AIR], 3600); + if(!D_80385FE4 && D_80385F30[ITEM_17_AIR] < VER_SELECT(3600, 3000, 0, 0)){ + item_adjustByDiffWithHud(ITEM_17_AIR, (s32)(((time_getDelta()*(float)(FRAMERATE))*100.0)*1.1)); + D_80385F30[ITEM_17_AIR] = MIN(D_80385F30[ITEM_17_AIR], VER_SELECT(3600, 3000, 0, 0)); } } } @@ -390,7 +391,7 @@ void func_80346CA8(void) { if (D_80385FE4) { D_80385FE0 = true; D_80385F30[ITEM_14_HEALTH] = D_80385F30[ITEM_15_HEALTH_TOTAL]; - D_80385F30[ITEM_17_AIR] = 60*60; + D_80385F30[ITEM_17_AIR] = VER_SELECT(3600, 3000, 0, 0); } } @@ -432,16 +433,16 @@ void func_80346DB4(s32 note_count) { if (D_80385FF0[level_id] < note_count) { D_80385FF0[level_id] = note_count; if ((level_get() == LEVEL_1_MUMBOS_MOUNTAIN) && (note_count == 50)) { - gcdialog_showDialog(0xF74, 4, NULL, NULL, NULL, NULL); + gcdialog_showDialog(VER_SELECT(0xF74, 0xADA, 0, 0), 4, NULL, NULL, NULL, NULL); } - if (note_count == notesMax) { - gcdialog_showDialog(0xF78, 4, NULL, NULL, NULL, NULL); + if (note_count == 100) { + gcdialog_showDialog(VER_SELECT(0xF78, 0xADE, 0, 0), 4, NULL, NULL, NULL, NULL); } if (note_count == 1) { levelSpecificFlags_set(LEVEL_FLAG_34_UNKNOWN, true); } - if (!levelSpecificFlags_get(LEVEL_FLAG_34_UNKNOWN) && (gcdialog_showDialog(0xF76, 0, NULL, NULL, NULL, NULL))) { - levelSpecificFlags_set(LEVEL_FLAG_34_UNKNOWN, true); + if (!levelSpecificFlags_get(LEVEL_FLAG_34_UNKNOWN) && (gcdialog_showDialog(VER_SELECT(0xF76, 0xADC, 0, 0), 0, NULL, NULL, NULL, NULL))) { + levelSpecificFlags_set(LEVEL_FLAG_34_UNKNOWN, TRUE); } if (volatileFlag_get(VOLATILE_FLAG_17) == 0) { volatileFlag_set(VOLATILE_FLAG_17, 1); diff --git a/src/core2/context/bound.c b/src/core2/gc/bound.c similarity index 98% rename from src/core2/context/bound.c rename to src/core2/gc/bound.c index e179bf95a..54bd56587 100644 --- a/src/core2/context/bound.c +++ b/src/core2/gc/bound.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/gc/bound.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/context/dialog.c b/src/core2/gc/dialog.c similarity index 97% rename from src/core2/context/dialog.c rename to src/core2/gc/dialog.c index 548508dfd..2a1deaa18 100644 --- a/src/core2/context/dialog.c +++ b/src/core2/gc/dialog.c @@ -1,7 +1,9 @@ +// BanjoDecomp: core2/gc/dialog.c #include #include "core1/core1.h" #include "functions.h" #include "variables.h" +#include "dialog.h" #include "core2/gc/zoombox.h" @@ -136,7 +138,7 @@ void gcdialog_init(void) { g_Dialog.unk128_3 = true; } -static void _gcdialog_freeZoomboxes(void){ +static void freeZoomboxes(void){ s32 i; for(i =0; i < 2; i++){ gczoombox_free(g_Dialog.zoombox[i]); @@ -167,7 +169,7 @@ void clearDialog(void){ func_80347A14(1); } if(!g_Dialog.unk11A[0].unk0_7 && !g_Dialog.unk11A[1].unk0_7){ - _gcdialog_freeZoomboxes(); + freeZoomboxes(); } g_Dialog.unk130 = -1; g_Dialog.unk128_15 = 0; @@ -244,7 +246,7 @@ void gcdialog_draw(Gfx **gfx, Mtx **mtx, Vtx **vtx){ } } -void gcdialog_setState(s32 next_state){ +void dialog_setState(s32 next_state){ s32 i; s32 j; s32 v0 = 6; @@ -322,7 +324,7 @@ void newZoomboxCallback(GcZoomboxSprite portrait_id, s32 arg1){ break; case 3: //L8030F7BC - gcdialog_setState(2); + dialog_setState(2); break; case 4: //L8030F7CC @@ -331,7 +333,7 @@ void newZoomboxCallback(GcZoomboxSprite portrait_id, s32 arg1){ if(g_Dialog.unk12C_25 == 0){ temp_a0 = ((g_Dialog.unk11A[0].unk0_7) ? 1 : 0); temp_v0 = ((g_Dialog.unk11A[1].unk0_7) ? 1 : 0); - gcdialog_setState((temp_v0 + temp_a0) ? 8 : 5); + dialog_setState((temp_v0 + temp_a0) ? 8 : 5); }//L8030F980 break; } @@ -340,7 +342,7 @@ void newZoomboxCallback(GcZoomboxSprite portrait_id, s32 arg1){ if(temp_v0 > (s32)g_Dialog.unk12C_29){ g_Dialog.unk12C_29++; if(g_Dialog.unk128_15 == g_Dialog.unk12C_29 + g_Dialog.unk12C_27){ - gcdialog_setState(8); + dialog_setState(8); } } break; @@ -348,11 +350,11 @@ void newZoomboxCallback(GcZoomboxSprite portrait_id, s32 arg1){ case 6: //L8030F8FC g_Dialog.unk12C_27++; if(g_Dialog.unk12C_27 == g_Dialog.unk128_15){ - gcdialog_setState(7); + dialog_setState(7); }//L8030F964 if(g_Dialog.unk128_15 == g_Dialog.unk12C_29 + g_Dialog.unk12C_27){ - gcdialog_setState(8); + dialog_setState(8); } break; }//L8030F984 @@ -361,7 +363,7 @@ void newZoomboxCallback(GcZoomboxSprite portrait_id, s32 arg1){ #define CMD(i) (g_Dialog.string_list[g_Dialog.u8_s.active_zoombox] + i) #define CMD2(i) (&g_Dialog.string_list[g_Dialog.u8_s.active_zoombox][i]) -void gcdialog_update(void) { +void dialog_update(void) { s32 i; s32 spA8; s32 controller_face_buttons[6]; @@ -389,10 +391,10 @@ void gcdialog_update(void) { } } if (spA8 == 2) { - gcdialog_setState(7); + dialog_setState(7); } else if (g_Dialog.u8_s.unk12C_31 == g_Dialog.u8_s.unk128_15) { g_Dialog.u8_s.unk12C_31 = 0; - gcdialog_setState(2); + dialog_setState(2); } break; @@ -417,7 +419,7 @@ void gcdialog_update(void) { case -1: // Choice g_Dialog.unk11A[g_Dialog.u8_s.active_zoombox].unk0_7 = 2; - gcdialog_setState(4); + dialog_setState(4); break; case -4: // Close @@ -476,7 +478,7 @@ void gcdialog_update(void) { case -3: g_Dialog.unk11A[g_Dialog.u8_s.active_zoombox].unk0_7 = 0; - gcdialog_setState(4); + dialog_setState(4); break; default: @@ -564,7 +566,7 @@ void gcdialog_update(void) { g_Dialog.string_index[g_Dialog.u8_s.active_zoombox]++; } - gcdialog_setState(3); + dialog_setState(3); } break; } @@ -573,7 +575,7 @@ void gcdialog_update(void) { case 3: if ((g_Dialog.u8_s.unk128_31 & 1) && controller_face_buttons[FACE_BUTTON(BUTTON_B)] == 1u) { - gcdialog_setState(6); + dialog_setState(6); break; } @@ -585,7 +587,7 @@ void gcdialog_update(void) { break; } - gcdialog_setState(6); + dialog_setState(6); break; case 4: // Waiting for player to make choice @@ -596,13 +598,13 @@ void gcdialog_update(void) { } if (g_Dialog.u8_s.unk12C_23 != -1) { - gcdialog_setState(g_Dialog.unk11A[g_Dialog.u8_s.active_zoombox].unk0_7 ? 8 : 5); + dialog_setState(g_Dialog.unk11A[g_Dialog.u8_s.active_zoombox].unk0_7 ? 8 : 5); } break; case 7: case 8: - gcdialog_setState(0); + dialog_setState(0); break; } @@ -717,7 +719,7 @@ void loadAndCreateDialogs(s32 text_id, s32 arg1, ActorMarker *marker, void(*call g_Dialog.unk140 = arg4; g_Dialog.unk144 = arg5; g_Dialog.unk138 = (marker != NULL )? ((marker->unk5C)? marker->unk5C : -1) : 0; - gcdialog_setState(((func_802E4A08() || volatileFlag_get(VOLATILE_FLAG_1F_IN_CHARACTER_PARADE)) && g_Dialog.unk128_3) ? 6 : 1); + dialog_setState(((func_802E4A08() || volatileFlag_get(VOLATILE_FLAG_1F_IN_CHARACTER_PARADE)) && g_Dialog.unk128_3) ? 6 : 1); //L803109EC } @@ -816,7 +818,7 @@ void func_80310D2C(void){ g_Dialog.unk12C_15--; }else{//L80310F88 - gcdialog_update(); + dialog_update(); }//L80310F98 if( ( g_Dialog.state != 0 && g_Dialog.state != 5 && g_Dialog.state != 7) || ((!g_Dialog.state && (g_Dialog.unk11A[0].unk0_7 || g_Dialog.unk11A[1].unk0_7))) @@ -962,7 +964,7 @@ void func_803114D0(void){ s32 i; if(gcdialog_hasCurrentTextId()){ - gcdialog_setState(6); + dialog_setState(6); }else{ if(g_Dialog.state != 6){ g_Dialog.unk12C_25 = 0; @@ -986,7 +988,7 @@ int func_803115C4(s32 next_state){ if(gcdialog_getCurrentTextId() != next_state){ return 0; }else{ - gcdialog_setState(6); + dialog_setState(6); return 1; } } diff --git a/src/core2/gc/dialog.h b/src/core2/gc/dialog.h new file mode 100644 index 000000000..191a0fea6 --- /dev/null +++ b/src/core2/gc/dialog.h @@ -0,0 +1,22 @@ +// BanjoDecomp: core2/gc/dialog.h +#ifndef BANJO_KAZOOIE_GC_DIALOG_H +#define BANJO_KAZOOIE_GC_DIALOG_H + +enum { + DIALOG_BOTTOM = 0, + DIALOG_TOP = 1 +}; + +typedef enum { + DIALOG_STATE_0 = 0, + DIALOG_STATE_1 = 1, + DIALOG_STATE_2 = 2, + DIALOG_STATE_3 = 3, + DIALOG_WAITING_FOR_PLAYER_CHOICE = 4, + DIALOG_STATE_5 = 5, + DIALOG_STATE_6 = 6, + DIALOG_STATE_7 = 7, + DIALOG_STATE_8 = 8 +} DialogState; + +#endif // BANJO_KAZOOIE_GC_DIALOG_H diff --git a/src/core2/context/enter_text_trigger.c b/src/core2/gc/enter_text_trigger.c similarity index 78% rename from src/core2/context/enter_text_trigger.c rename to src/core2/gc/enter_text_trigger.c index 3c83c50c9..c089e8337 100644 --- a/src/core2/context/enter_text_trigger.c +++ b/src/core2/gc/enter_text_trigger.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_53A10.c #include #include "functions.h" #include "variables.h" @@ -5,8 +6,9 @@ void func_802DAA14(Actor *this); /* .data */ //000E0EE0 -ActorInfo D_80367E70= { - 0x21B, 0x351, 0, +// lair dialog object? +ActorInfo D_80367E70 = { + MARKER_21B_UNKNOWN, ACTOR_351_UNKNOWN, 0, 0, NULL, func_802DAA14, actor_update_func_80326224, func_80325340, 0, 0, 0.0f, 0 @@ -16,16 +18,17 @@ ActorInfo D_80367E70= { /* .code */ void func_802DA9A0(ActorMarker *caller, enum asset_e text_id, s32 arg2){ enum file_progress_e flag; - enum file_progress_e tmp; + enum file_progress_e flag_tmp; + if(level_get() == LEVEL_A_MAD_MONSTER_MANSION){ flag = FILEPROG_15_ENTER_MMM_TEXT; } else{ if(gsworld_getMap() == MAP_69_GL_MM_LOBBY) - tmp = FILEPROG_97_ENTERED_LAIR_TEXT; + flag_tmp = FILEPROG_97_ENTERED_LAIR_TEXT; else - tmp = FILEPROG_98_EXITED_LEVEL_TEXT; - flag = tmp; + flag_tmp = FILEPROG_98_EXITED_LEVEL_TEXT; + flag = flag_tmp; } fileProgressFlag_set(flag, 1); FUNC_8030E624(SFX_EA_GRUNTY_LAUGH_1, 1.0f, 30000); @@ -69,13 +72,13 @@ void func_802DAA14(Actor *this){ if(!this->has_met_before){ if(level_get() == LEVEL_A_MAD_MONSTER_MANSION){ - text_id = ASSET_ADC_DIALOG_GRUNTY_ENTER_SHED; + text_id = VER_SELECT(ASSET_ADC_DIALOG_GRUNTY_ENTER_SHED, 0x94E, 0, 0); } else{ if(gsworld_getMap() == MAP_69_GL_MM_LOBBY) - tmp = ASSET_F66_DIALOG_UNKNOWN; + tmp = VER_SELECT(ASSET_F66_DIALOG_UNKNOWN, 0xACC, 0, 0); else - tmp = ASSET_F67_DIALOG_UNKNOWN; + tmp = VER_SELECT(ASSET_F67_DIALOG_UNKNOWN, 0xACD, 0, 0); text_id = tmp; } gcdialog_showDialog(text_id, 4, NULL, this->marker, func_802DA9A0, NULL); diff --git a/src/core2/context/gameover.c b/src/core2/gc/gameoversign.c similarity index 85% rename from src/core2/context/gameover.c rename to src/core2/gc/gameoversign.c index 3ace29792..9e63caa9e 100644 --- a/src/core2/context/gameover.c +++ b/src/core2/gc/gameoversign.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/gc/gameoversign.c #include #include "core1/core1.h" #include "functions.h" @@ -7,14 +8,15 @@ extern void actor_postdrawMethod(ActorMarker *); Actor *func_802DC320(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx); -void func_802DC45C(Actor *this); +void gcGameOverSign_update(Actor *this); /* .data */ f32 D_80368040[3] = {0.0f, 0.0f, 0.0f}; -ActorInfo D_8036804C = { + +ActorInfo gcGameOverSign = { MARKER_174_GAME_OVER, ACTOR_1DB_GAME_OVER, ASSET_54C_MODEL_GAME_OVER, 0x1, NULL, - func_802DC45C, actor_update_func_80326224, func_802DC320, + gcGameOverSign_update, actor_update_func_80326224, func_802DC320, 0, 0, 0.0f, 0 }; @@ -56,23 +58,23 @@ Actor *func_802DC320(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx){ } -void func_802DC430(Actor * this){ +void gcGameOverSign_free(Actor * this){ D_8037DE40 = NULL; func_8025A7DC(COMUSIC_31_GAME_OVER); } -void func_802DC45C(Actor *this){ +void gcGameOverSign_update(Actor *this){ if(!this->initialized){ this->initialized = true; this->depth_mode = MODEL_RENDER_DEPTH_NONE; func_803262E4(this); actor_collisionOff(this); - marker_setFreeMethod(this->marker, func_802DC430); + marker_setFreeMethod(this->marker, gcGameOverSign_free); } } -void func_802DC4C4(void) { +void gcGameOverSign_spawn(void) { Actor *actor; if (D_8037DE40 == 0) { actor = actor_spawnWithYaw_f32(ACTOR_1DB_GAME_OVER, D_80368040, 0); @@ -85,7 +87,7 @@ void func_802DC4C4(void) { void func_802DC528(NodeProp *arg0, ActorMarker *arg1){ if(D_8037DE40 == NULL){ - __spawnQueue_add_0(func_802DC4C4); + __spawnQueue_add_0(gcGameOverSign_spawn); } } @@ -99,7 +101,7 @@ void func_802DC560(NodeProp *arg0, ActorMarker *arg1){ void func_802DC5B8(void){ if(D_8037DE40 != NULL){ - func_802DC45C(marker_getActor(D_8037DE40)); + gcGameOverSign_update(marker_getActor(D_8037DE40)); func_80326894(marker_getActor(D_8037DE40)); } } diff --git a/src/core2/context/overlay_copyright.c b/src/core2/gc/overlaycopyright.c similarity index 97% rename from src/core2/context/overlay_copyright.c rename to src/core2/gc/overlaycopyright.c index d0b34563c..132d5f048 100644 --- a/src/core2/context/overlay_copyright.c +++ b/src/core2/gc/overlaycopyright.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/ch/overlaycopyright.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/context/overlay_nocontroller.c b/src/core2/gc/overlaynocontroller.c similarity index 97% rename from src/core2/context/overlay_nocontroller.c rename to src/core2/gc/overlaynocontroller.c index 95a51d662..b0f1e3d26 100644 --- a/src/core2/context/overlay_nocontroller.c +++ b/src/core2/gc/overlaynocontroller.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/ch/overlaynocontroller.c #include #include "core1/core1.h" #include "functions.h" @@ -17,8 +18,10 @@ ActorAnimationInfo D_80368150[] ={ {0x286, 1.1f}, {0x287, 1.6f} }; + f32 D_80368168[3] = {0.0f, 0.0f, 0.0f}; -ActorInfo D_80368174 = { + +ActorInfo chOverlayNoController = { MARKER_178_NO_CONTROLLER_OVERLAY, ACTOR_1DF_NO_CONTROLLER_OVERLAY, ASSET_55D_MODEL_NO_CONTROLLER_OVERLAY, 0x0, D_80368150, chOverlayNoController_update, actor_update_func_80326224, chOverlayNoController_draw, diff --git a/src/core2/context/overlay_pressstart.c b/src/core2/gc/overlaypressstart.c similarity index 94% rename from src/core2/context/overlay_pressstart.c rename to src/core2/gc/overlaypressstart.c index ebba0e6cc..8ac99b3ab 100644 --- a/src/core2/context/overlay_pressstart.c +++ b/src/core2/gc/overlaypressstart.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/ch/overlaypressstart.c #include #include "core1/core1.h" #include "functions.h" @@ -16,7 +17,7 @@ void chOverlayPressStart_update(Actor *this); /* .data */ -ActorAnimationInfo D_80368100[] = { +ActorAnimationInfo chOverlayPressStartAnimations[] = { {0, 0.0f}, {0x284, 1.6f}, {0x285, 1.6f} @@ -24,9 +25,9 @@ ActorAnimationInfo D_80368100[] = { f32 D_80368118[3] = {0.0f, 0.0f, 0.0f}; -ActorInfo D_80368124 = { +ActorInfo chOverlayPressStart = { MARKER_177_PRESS_START_OVERLAY, ACTOR_1DE_PRESS_START_OVERLAY, ASSET_55C_MODEL_PRESS_START_OVERLAY, - 0x0, D_80368100, + 0x0, chOverlayPressStartAnimations, chOverlayPressStart_update, actor_update_func_80326224, chOverlayPressStart_draw, 0, 0, 0.0f, 0 }; diff --git a/src/core2/context/parade.c b/src/core2/gc/parade.c similarity index 99% rename from src/core2/context/parade.c rename to src/core2/gc/parade.c index c2dc549cb..87d83a3ac 100644 --- a/src/core2/context/parade.c +++ b/src/core2/gc/parade.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/gc/parade.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/context/pause_menu.c b/src/core2/gc/pauseMenu.c similarity index 99% rename from src/core2/context/pause_menu.c rename to src/core2/gc/pauseMenu.c index 3180bf448..20c2063d4 100644 --- a/src/core2/context/pause_menu.c +++ b/src/core2/gc/pauseMenu.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/gc/pauseMenu.c #include #include "core1/core1.h" #include "functions.h" @@ -1548,9 +1549,9 @@ void gcpausemenu_draw(Gfx **gfx, Mtx **mtx, Vtx **vtx) { sp80[2] = 0.0f; for (var_s0_2 = 0; var_s0_2 < 7; var_s0_2++) { - func_8033A45C(var_s0_2 + 1, 0); + modelRender_setAppendageVisibility(var_s0_2 + 1, 0); } - func_8033A45C(i, 1); + modelRender_setAppendageVisibility(i, 1); modelRender_setDepthMode(MODEL_RENDER_DEPTH_NONE); modelRender_setAlpha(D_80383010.sns_alpha); modelRender_draw(gfx, mtx, sp98, sp8C, 0.8f, sp80, D_80383010.sns_egg_model); diff --git a/src/core2/context/pictureframe.c b/src/core2/gc/pictureframe.c similarity index 89% rename from src/core2/context/pictureframe.c rename to src/core2/gc/pictureframe.c index 483d22a7b..57a7486c3 100644 --- a/src/core2/context/pictureframe.c +++ b/src/core2/gc/pictureframe.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_581D0.c #include #include "functions.h" #include "variables.h" @@ -11,8 +12,11 @@ void func_802DF2C4(Actor *this); f32 D_80368360[3] = {0.0f, 0.0f, 0.0f}; s32 D_8036836C[4] = {0x60, 0x60, 0x60, 0xFF}; s32 D_8036837C[4] = {0xFF, 0xFF, 0xFF, 0xFF}; + +// Asset is blank white rectangle +// Appears during Bottles Bonus ActorInfo D_8036838C = { - 0x17B, 0x2B5, 0x472, + MARKER_17B_UNKNOWN, ACTOR_2B5_UNKNOWN, ASSET_472_UNKNOWN, 0, NULL, func_802DF2C4, actor_update_func_80326224, func_80325340, 0, 0, 0.0f, 0 @@ -28,7 +32,7 @@ Actor *func_802DF160(Gfx **gfx, Mtx **mtx, Vtx **vtx) { void *sp38; this = marker_getActor(D_8037E000); - sp38 = func_8030C704(); + sp38 = picturebox_getColorBuffer(); modelRender_setDepthMode(MODEL_RENDER_DEPTH_FULL); gDPSetTextureFilter((*gfx)++, G_TF_BILERP); port_readAuxFbToCpu(gfx); @@ -45,15 +49,17 @@ Actor *func_802DF160(Gfx **gfx, Mtx **mtx, Vtx **vtx) { void func_802DF270(void){ Actor *this; if(D_8037E000 == NULL){ - this = actor_spawnWithYaw_f32(0x2B5, D_80368360, 0); + this = actor_spawnWithYaw_f32(ACTOR_2B5_UNKNOWN, D_80368360, 0); D_8037E000 = this->marker; } } +// free void func_802DF2B4(Actor *this){ D_8037E000 = NULL; } +// update void func_802DF2C4(Actor *this) { s32 temp_fp; s32 i; @@ -61,7 +67,6 @@ void func_802DF2C4(Actor *this) { Struct70s *temp_v0; s32 val; - temp_fp = chBottlesBonusCursor_func_802E06B4() - 0x15; if (!this->initialized) { this->initialized = true; diff --git a/src/core2/context/map_info.c b/src/core2/gc/section.c similarity index 99% rename from src/core2/context/map_info.c rename to src/core2/gc/section.c index fb2d95f52..cc38fb812 100644 --- a/src/core2/context/map_info.c +++ b/src/core2/gc/section.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/gc/section.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/context/sky.c b/src/core2/gc/sky.c similarity index 90% rename from src/core2/context/sky.c rename to src/core2/gc/sky.c index 021c6205e..8c728bfd3 100644 --- a/src/core2/context/sky.c +++ b/src/core2/gc/sky.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/gc/sky.c #include #include "core1/core1.h" #include "functions.h" @@ -84,30 +85,30 @@ MapSkyInfo * sky_getMapSkyInfo(enum map_e map_id){ return v1; } -void sky_draw(Gfx **gfx, Mtx **mtx, Vtx **vtx){ +void sky_draw(Gfx **gfx, Mtx **mtx, Vtx **vtx) { int i; f32 position[3]; f32 rotation[3]; - BKModelBin *iAsset; + BKModelBin *sky_model_bin; viewport_setNearAndFar(5.0f, 15000.0f); - if(gcSky.model_bins[0]){ - drawRectangle2D(gfx, 0, 0, (s32)(f32) gFramebufferWidth, (s32)(f32)gFramebufferHeight, 0, 0, 0); + + if (gcSky.model_bins[0]) { + drawRectangle2D(gfx, 0, 0, (f32) gFramebufferWidth, (f32) gFramebufferHeight, 0, 0, 0); viewport_setRenderViewportAndPerspectiveMatrix(gfx, mtx); viewport_getPosition_vec3f(position); - for(i = 0; i < 3; i++){ - iAsset = gcSky.model_bins[i]; - if(iAsset){ + for (i = 0; i < 3; i++) { + sky_model_bin = gcSky.model_bins[i]; + if (sky_model_bin) { rotation[0] = 0.0f; rotation[1] = gcSky.sky_info->sky_list[i].rotation_speed * gcSky.timer; rotation[2] = 0.0f; - modelRender_draw(gfx, mtx, position, rotation, gcSky.sky_info->sky_list[i].scale, NULL, iAsset); + modelRender_draw(gfx, mtx, position, rotation, gcSky.sky_info->sky_list[i].scale, NULL, sky_model_bin); } } + } else { + drawRectangle2D(gfx, 0, 0, (f32) gFramebufferWidth, (f32) gFramebufferHeight, 0, 0, 0); } - else{//L8030B200 - drawRectangle2D(gfx, 0, 0, (s32)(f32) gFramebufferWidth, (s32)(f32)gFramebufferHeight, 0, 0, 0); - }//L8030B254 } void sky_free(void){ diff --git a/src/core2/context/transition.c b/src/core2/gc/transition.c similarity index 95% rename from src/core2/context/transition.c rename to src/core2/gc/transition.c index ea1ea1248..05d7588ea 100644 --- a/src/core2/context/transition.c +++ b/src/core2/gc/transition.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/gc/transition.c #include #include "core1/core1.h" #include "functions.h" @@ -241,7 +242,7 @@ void gctransition_defrag(void){ s_current_transition.model_ptr = defrag_asset(s_current_transition.model_ptr); } -void gctransition_draw(Gfx **gdl, Mtx **mptr, Vtx **vptr){ +void gctransition_draw(Gfx **gfx, Mtx **mtx, Vtx **vtx) { f32 vp_position[3]; f32 vp_rotation[3]; f32 percentage; @@ -270,31 +271,31 @@ void gctransition_draw(Gfx **gdl, Mtx **mptr, Vtx **vptr){ viewport_setPosition_vec3f(vp_position); //viewport_getPosition_vec3f viewport_setRotation_vec3f(vp_rotation); //viewport_getRotation_vec3f viewport_update(); //camera_updateNormal - viewport_setRenderViewportAndPerspectiveMatrix(gdl, mptr); + viewport_setRenderViewportAndPerspectiveMatrix(gfx, mtx); sp58[0] = 0.0f; sp58[1] = 0.0f; sp58[2] = 0.0f; if(s_current_transition.anctrl != NULL){ - gDPSetTextureFilter((*gdl)++, G_TF_POINT); - gDPSetColorDither((*gdl)++, G_CD_DISABLE); + gDPSetTextureFilter((*gfx)++, G_TF_POINT); + gDPSetColorDither((*gfx)++, G_CD_DISABLE); anctrl_drawSetup(s_current_transition.anctrl, sp58, 1); modelRender_setDepthMode(MODEL_RENDER_DEPTH_FULL); } // [port] Widescreen transition scaling is applied by the port listener f32 transitionScale = 1.0f; - CALL_EVENT(OnTransitionModelScale, gdl, mptr, + CALL_EVENT(OnTransitionModelScale, gfx, mtx, s_current_transition.transistion_info != NULL ? s_current_transition.transistion_info->uid : 0, &transitionScale); //complex animation (from animation bin file) if(s_current_transition.state == 1 || s_current_transition.state == 6){ - modelRender_draw(gdl, mptr, sp58, vp_rotation, transitionScale, 0, s_current_transition.model_ptr); + modelRender_draw(gfx, mtx, sp58, vp_rotation, 1.0f, 0, s_current_transition.model_ptr); if(s_current_transition.anctrl != NULL){ - gDPSetTextureFilter((*gdl)++, G_TF_BILERP); - gDPSetColorDither((*gdl)++, G_CD_MAGICSQ); + gDPSetTextureFilter((*gfx)++, G_TF_BILERP); + gDPSetColorDither((*gfx)++, G_CD_MAGICSQ); } return; } @@ -311,7 +312,7 @@ void gctransition_draw(Gfx **gdl, Mtx **mptr, Vtx **vptr){ vp_rotation[2] = s_current_transition.rotation - 90.0f*percentage; scale = percentage*s_current_transition.transistion_info->scale + 0.1; } - modelRender_draw(gdl, mptr, sp58, vp_rotation, scale * transitionScale, 0, s_current_transition.model_ptr); + modelRender_draw(gfx, mtx, sp58, vp_rotation, scale, 0, s_current_transition.model_ptr); } else if(s_current_transition.state == TRANSITION_STATE_5_FADE_OUT){//L8030B9EC switch (s_current_transition.transistion_info->uid) @@ -332,7 +333,7 @@ void gctransition_draw(Gfx **gdl, Mtx **mptr, Vtx **vptr){ break; } if(!(s_current_transition.substate < 3) || s_current_transition.transistion_info->uid != 0x11){ - modelRender_draw(gdl, mptr, sp58, vp_rotation, scale * transitionScale, 0, s_current_transition.model_ptr); + modelRender_draw(gfx, mtx, sp58, vp_rotation, scale, 0, s_current_transition.model_ptr); } else{ modelRender_reset(); @@ -344,14 +345,14 @@ void gctransition_draw(Gfx **gdl, Mtx **mptr, Vtx **vptr){ gcbound_reset(); gcbound_alpha((1.0f - percentage)*255.0f + 0.5); gcbound_color(0,0,0); - gcbound_draw(gdl); + gcbound_draw(gfx); } else if(s_current_transition.state == TRANSITION_STATE_3_BLACK_OUT){//L8030BB6C //fade out black (i.e. get more black) gcbound_reset(); gcbound_alpha(percentage*255.0f + 0.5); gcbound_color(0,0,0); - gcbound_draw(gdl); + gcbound_draw(gfx); } else if(s_current_transition.state == TRANSITION_STATE_7_WHITE_IN){//L8030BBD8 //fade in white (i.e. get less white) @@ -359,23 +360,23 @@ void gctransition_draw(Gfx **gdl, Mtx **mptr, Vtx **vptr){ gcbound_reset(); gcbound_alpha(percentage*255.0f + 0.5); gcbound_color(0xff,0xff,0xff); - gcbound_draw(gdl); + gcbound_draw(gfx); } else if(s_current_transition.state == TRANSITION_STATE_8_WHITE_OUT){//L8030BC8C //fade out white (i.e. get more white) gcbound_reset(); gcbound_alpha(percentage*255.0f + 0.5); gcbound_color(0xff,0xff,0xff); - gcbound_draw(gdl); + gcbound_draw(gfx); }//L8030BD00 else{ } if(s_current_transition.anctrl != NULL){ - gDPSetTextureFilter((*gdl)++, G_TF_BILERP); + gDPSetTextureFilter((*gfx)++, G_TF_BILERP); } viewport_restoreState(); - viewport_setRenderViewportAndPerspectiveMatrix(gdl, mptr); + viewport_setRenderViewportAndPerspectiveMatrix(gfx, mtx); } @@ -414,7 +415,7 @@ void gctransition_8030BE3C(void){ void gctransition_8030BE60(void){ TransitionInfo *tmp_a1; tmp_a1 = _gctranstion_8030B400(_gctranstion_get_map_transition_info(gsworld_getMap())->out_index); - func_8030C180(); + picturebox_func_8030C180(); _gctranstion_changeState(tmp_a1->state, tmp_a1); } @@ -503,7 +504,7 @@ void gctransition_update(void){ }//L8030C104 _gctranstion_changeState(s_current_transition.transistion_info->next_state, 0); if(s_current_transition.state == TRANSITION_STATE_4_FADE_IN) - func_8030C180(); + picturebox_func_8030C180(); if(s_current_transition.anctrl != NULL) gsworld_update(); diff --git a/src/core2/context/zoombox.c b/src/core2/gc/zoombox.c similarity index 99% rename from src/core2/context/zoombox.c rename to src/core2/gc/zoombox.c index 40b629804..114913a89 100644 --- a/src/core2/context/zoombox.c +++ b/src/core2/gc/zoombox.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/gc/zoombox.c #include #include "core1/core1.h" #include "core1/core1.h" @@ -418,9 +419,9 @@ gczoomboxPortraitInfo D_8036C6C0[] = { {SFX_FA_GRUNTLING_NOISE_2, 20000, 1.3f}, {SFX_FB_GRUNTLING_NOISE_3, 20000, 1.3f} }}, - {0x084A, 0xF2, 0x0A, {{SFX_6E_VILE_EGH, 20000, 1.0f}}}, - {0x084B, 0xF2, 0x0A, {{SFX_6E_VILE_EGH, 20000, 1.0f}}}, - {0x084C, 0xF2, 0x0A, {{SFX_6E_VILE_EGH, 20000, 1.0f}}}, + {0x084A, VER_SELECT(0xF2, 0xF0, 0, 0), VER_SELECT(0x0A, 0x05, 0, 0), {{VER_SELECT(SFX_6E_VILE_EGH, SFX_C3_HEGH, 0, 0), 20000, 1.0f}}}, + {0x084B, VER_SELECT(0xF2, 0xF0, 0, 0), VER_SELECT(0x0A, 0x05, 0, 0), {{VER_SELECT(SFX_6E_VILE_EGH, SFX_C3_HEGH, 0, 0), 20000, VER_SELECT(1.0f, 1.1f, 0.0f, 0.0f)}}}, + {0x084C, VER_SELECT(0xF2, 0xF0, 0, 0), VER_SELECT(0x0A, 0x05, 0, 0), {{VER_SELECT(SFX_6E_VILE_EGH, SFX_C3_HEGH, 0, 0), 20000, VER_SELECT(1.0f, 0.9f, 0.0f, 0.0f)}}}, }; s32 D_8036D924[] = { 70, 35, 18, 9, 4, 2, 1}; diff --git a/src/core2/actor_cubebounds.c b/src/core2/gccube.c similarity index 99% rename from src/core2/actor_cubebounds.c rename to src/core2/gccube.c index 24f96b19f..d67d989a6 100644 --- a/src/core2/actor_cubebounds.c +++ b/src/core2/gccube.c @@ -1,10 +1,12 @@ +// BanjoDecomp: core2/gccube.c #include #include "core1/core1.h" #include "functions.h" #include "variables.h" +#include "bk_math.h" // [port] TUPLE macros #include -#include "bk_math.h" +#include "math.h" #include "prop.h" #include "port/Patches/Patches.h" @@ -50,7 +52,7 @@ void func_80308EC8(void); bool func_80308F54(s32 cube_index); extern ActorInfo D_803675F0; -extern ActorInfo D_80367838; +extern ActorInfo gWorldExitPad; /* .data */ s32 sSpawnableActorSize = 0; //0x8036A9B0 @@ -388,19 +390,19 @@ void func_80302C94(Gfx **gfx, Mtx **mtx, Vtx **vtx) { s32 sp38[3]; f32 temp_f18; +#if ANTI_TAMPER if (!mapSpecificFlags_validateCRC1()) return; +#endif func_8032D3A8(); viewport_getPosition_vec3f(vp_position); viewport_getRotation_vec3f(vp_rotation); - func_80256664(vp_rotation); + ml_vec3f_clamp_deg360(vp_rotation); cube_positionToIndices(vp_cube_indices, vp_position); - vp_cube_indices[0] -= sCubeList.min[0];\ - vp_cube_indices[1] -= sCubeList.min[1];\ - vp_cube_indices[2] -= sCubeList.min[2]; + TUPLE_DIFF(vp_cube_indices, sCubeList.min) func_80308EC8(); - sp44[0] = sp44[1] = sp44[2] = 0; + TUPLE_SET(sp44, 0) sp38[0] = sCubeList.width[0] - 1;\ sp38[1] = sCubeList.width[1] - 1;\ sp38[2] = sCubeList.width[2] - 1; @@ -539,7 +541,7 @@ static Cube *__code7AF80_getCubeAtPosition(s32 position[3]) { (position[2] - sCubeList.min[2]) * sCubeList.stride[1]; } -Cube *cube_atPosition_s32(s32 position[3]) { +Cube *cubeList_GetCubeAtPosition_s32(s32 position[3]) { s32 sp1C[3]; s32 i; // Cube *out; @@ -563,13 +565,13 @@ Cube *cube_atPosition_s32(s32 position[3]) { + diff[2]*sCubeList.stride[1]; } -Cube *cube_atPosition_f32(f32 position[3]){ +Cube *cubeList_GetCubeAtPosition_f32(f32 position[3]){ s32 pos_s32[3]; pos_s32[0] = (s32)position[0]; pos_s32[1] = (s32)position[1]; pos_s32[2] = (s32)position[2]; - return cube_atPosition_s32(pos_s32); + return cubeList_GetCubeAtPosition_s32(pos_s32); } Cube *func_8030364C(void){ @@ -1082,7 +1084,7 @@ void nodeprop_getPosition(NodeProp *nodeProp, f32 dst[3]) { TUPLE_ASSIGN(dst, nodeProp->x, nodeProp->y, nodeProp->z) } -u32 nodeprop_getYaw(NodeProp *nodeProp) { +u32 nodeProp_getYaw(NodeProp *nodeProp) { return nodeProp->yaw; } @@ -1329,7 +1331,7 @@ void func_8030578C(void){ && (sSpawnableActorList != NULL) ){ for(i = 0; i < sSpawnableActorSize - 1; i++){ - if(sSpawnableActorList[i].infoPtr == &D_80367838){ + if(sSpawnableActorList[i].infoPtr == &gWorldExitPad){ sSpawnableActorList[i].infoPtr = &D_803675F0; sSpawnableActorList[i].spawnFunc = actor_new; sSpawnableActorList[i].unk8 = 0; @@ -2062,8 +2064,8 @@ void func_80307CA0(ActorMarker *marker) { for(i = 0; cubePtrList[i] != NULL; i++) { for(node_idx = 0; node_idx < cubePtrList[i]->unk0_4; node_idx++){ node = codeA5BC0_getPropNodeAtIndex(cubePtrList[i], node_idx); - if (codeA5BC0_getNodePropUnkA(node) == marker_bitfield) { - node_radius = codeA5BC0_getPositionAndReturnRadius(node, node_position); + if (codeA5BC0_getNodePropMarkerId(node) == marker_bitfield) { + node_radius = codeA5BC0_getPositionAndSelectorOrRadius(node, node_position); if( ((node_position[0] - node_radius) < marker_position[0]) && (marker_position[0] < (node_position[0] + node_radius)) && ((node_position[1] - node_radius) < marker_position[1]) && (marker_position[1] < (node_position[1] + node_radius)) && ((node_position[2] - node_radius) < marker_position[2]) && (marker_position[2] < (node_position[2] + node_radius)) @@ -2478,7 +2480,7 @@ void func_80308D2C(Gfx **gfx, Mtx **mtx, Vtx **vtx) { cube = &sCubeList.cubes[D_80382150[phi_s4]]; if (viewport_cube_isInFrustum(cube)) { viewport_getPosition_vec3w(vp_pos); - vp_cube_index = cube_atPosition_s32(vp_pos) - sCubeList.cubes; + vp_cube_index = cubeList_GetCubeAtPosition_s32(vp_pos) - sCubeList.cubes; for(phi_s0 = 0; (phi_s0 < D_80382150[phi_s4 + 1]) && (vp_cube_index != D_80382150[phi_s0 + 2]); phi_s0++) { } if (phi_s0 < D_80382150[phi_s4 + 1]) { diff --git a/src/core2/score_honeycomb.c b/src/core2/honeycombscore.c similarity index 97% rename from src/core2/score_honeycomb.c rename to src/core2/honeycombscore.c index 420d64983..6667b3310 100644 --- a/src/core2/score_honeycomb.c +++ b/src/core2/honeycombscore.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/honeycombscore.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/inventory_slots.c b/src/core2/inventory_slots.c index 7feea4b74..f2cdc3383 100644 --- a/src/core2/inventory_slots.c +++ b/src/core2/inventory_slots.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_9D760.c #include #include "functions.h" #include "variables.h" @@ -11,7 +12,7 @@ void func_80324700(u8* self){ for(i_ptr = self; i_ptr < self + 0x10; i_ptr++){ if(*i_ptr != 0xFF){ - func_8033A45C((i_ptr - self) + 1, *i_ptr); + modelRender_setAppendageVisibility((i_ptr - self) + 1, *i_ptr); } } } diff --git a/src/core2/score_jiggy.c b/src/core2/jiggyscore.c similarity index 98% rename from src/core2/score_jiggy.c rename to src/core2/jiggyscore.c index 32bfbc41b..a24f92fb8 100644 --- a/src/core2/score_jiggy.c +++ b/src/core2/jiggyscore.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/jiggyscore.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/level/specificflags.c b/src/core2/level/levelspecificflags.c similarity index 92% rename from src/core2/level/specificflags.c rename to src/core2/level/levelspecificflags.c index e31343008..69a066baf 100644 --- a/src/core2/level/specificflags.c +++ b/src/core2/level/levelspecificflags.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/levelspecificflags.c #include #include "functions.h" #include "variables.h" @@ -78,12 +79,12 @@ void _levelSpecificFlags_updateCRC2(void) { s32 levelSpecificFlags_get(s32 i){ CALL_CANCELLABLE_RETURN_EVENT(OnGetLevelSpecificFlag, i) { - return bitfield_get_bit(D_80383320.unk8, i); + return bitfieldarray_getBit(D_80383320.unk8, i); } } s32 levelSpecificFlags_getN(s32 i, s32 n){ - return bitfield_get_n_bits(D_80383320.unk8, i, n); + return bitfieldarray_getNBits(D_80383320.unk8, i, n); } s32 levelSpecificFlags_getSet(s32 arg0, s32 arg1){ @@ -102,8 +103,8 @@ void levelSpecificFlags_clear(void){ } void levelSpecificFlags_setEx(s32 index, s32 val, s32 triggerEvent){ - s32 changed = bitfield_get_bit(D_80383320.unk8, index) != (val ? 1 : 0); - bitfield_set_bit(D_80383320.unk8, index, val); + s32 changed = bitfieldarray_getBit(D_80383320.unk8, index) != (val ? 1 : 0); + bitfieldarray_setBit(D_80383320.unk8, index, val); _levelSpecificFlags_updateCRC1(); _levelSpecificFlags_updateCRC2(); if (triggerEvent && changed) { @@ -116,7 +117,7 @@ void levelSpecificFlags_set(s32 index, s32 val){ } void levelSpecificFlags_setN(s32 index, s32 val, s32 n){ - bitfield_set_n_bits(D_80383320.unk8, index, val, n); + bitfieldarray_setNBits(D_80383320.unk8, index, val, n); _levelSpecificFlags_updateCRC1(); _levelSpecificFlags_updateCRC2(); CALL_EVENT(OnGameFlagSet, ANCHOR_FLAGSPACE_LEVEL_SPECIFIC, index, val, n); diff --git a/src/core2/level/lightconfig.c b/src/core2/level/lightconfig.c index 84fbe73ec..3ccea6f57 100644 --- a/src/core2/level/lightconfig.c +++ b/src/core2/level/lightconfig.c @@ -1,4 +1,4 @@ -// BanjoDecomp: code_35520.c -> lightconfig.c +// BanjoDecomp: core2/code_35520.c // This file defines the distances for type-4 camera nodes (the normal 3rd person view camera?) for each map #include #include "functions.h" diff --git a/src/core2/level/metadata.c b/src/core2/level/metadata.c index 83b8e9b7d..553039d23 100644 --- a/src/core2/level/metadata.c +++ b/src/core2/level/metadata.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_117D0.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/map/audioconfig.c b/src/core2/map/audioconfig.c index ac373dd69..b32268d2d 100644 --- a/src/core2/map/audioconfig.c +++ b/src/core2/map/audioconfig.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_9D640.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/map/cutscene_skip.c b/src/core2/map/cutscene_skip.c index 3938f7cbf..029d3f28c 100644 --- a/src/core2/map/cutscene_skip.c +++ b/src/core2/map/cutscene_skip.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_956B0.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/map/cutscene_triggers.c b/src/core2/map/cutscene_triggers.c index 2520d1d60..b734f1179 100644 --- a/src/core2/map/cutscene_triggers.c +++ b/src/core2/map/cutscene_triggers.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_9B180.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/map/envcolor.c b/src/core2/map/envcolor.c index 595d620b8..b4f62ae65 100644 --- a/src/core2/map/envcolor.c +++ b/src/core2/map/envcolor.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_94780.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/map/exit.c b/src/core2/map/exit.c index d90dfa235..565369751 100644 --- a/src/core2/map/exit.c +++ b/src/core2/map/exit.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_C4320.c #include #include "functions.h" #include "variables.h" @@ -44,9 +45,9 @@ extern Struct_core2_C4320_0 D_80371F44[] = { extern Struct_core2_C4320_0 D_80371F70 = {MAP_41_FP_BOGGYS_IGLOO, 6, 0x5D, 7, 8, 3}; extern Struct_core2_C4320_0 D_80371F78[] ={ - {MAP_7_TTC_TREASURE_TROVE_COVE, 0, 0x5F, 6, 9, 9}, - {MAP_27_FP_FREEZEEZY_PEAK, 0, 0x5F, 9, 9, 9}, - {MAP_12_GV_GOBIS_VALLEY, 0, 0x5F, 9, 5, 9} + {MAP_7_TTC_TREASURE_TROVE_COVE, 0, VER_SELECT(0x5F, 0x5E, 0, 0), 6, 9, 9}, + {MAP_27_FP_FREEZEEZY_PEAK, 0, VER_SELECT(0x5F, 0x5E, 0, 0), 9, 9, 9}, + {MAP_12_GV_GOBIS_VALLEY, 0, VER_SELECT(0x5F, 0x5E, 0, 0), 9, 5, 9} }; extern s32 D_80371F8C = 0xA; //attract demo count diff --git a/src/core2/map/gsworld.c b/src/core2/map/gsworld.c index 137f7fdb4..ab377fdad 100644 --- a/src/core2/map/gsworld.c +++ b/src/core2/map/gsworld.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/gsworld.c #include #include "core1/core1.h" #include "functions.h" @@ -13,11 +14,12 @@ extern u8 D_80370250 = 0; /* .bss */ -struct { - s32 unk0; - s32 map_4; - s32 unk8; -}sGsWorldData; +struct gsworld_data_s { + s32 unk0; // probably game_mode_e + enum map_e map; + s32 exit; +}; +struct gsworld_data_s sGsWorldData; s32 D_803835DC; u32 sEnableDraw; @@ -38,15 +40,15 @@ extern Struct64s *func_8032994C(void); extern void func_802F2ED0(Struct64s *, Gfx **, Mtx **, Vtx **); /* .code */ -void gsworld_draw(Gfx** gdl, Mtx **mptr, Vtx **vptr) { +void gsworld_draw(Gfx** gfx, Mtx **mtx, Vtx **vtx) { f32 sp44; f32 sp40; if (sEnableDraw == 0) { - drawRectangle2D(gdl, 0, 0, gFramebufferWidth, gFramebufferHeight, 0, 0, 0); - func_802BBD2C(&sp44, &sp40); + drawRectangle2D(gfx, 0, 0, gFramebufferWidth, gFramebufferHeight, 0, 0, 0); + core2_34790_getClipDistances(&sp44, &sp40); viewport_setNearAndFar(sp44, sp40); - viewport_setRenderViewportAndPerspectiveMatrix(gdl, mptr); + viewport_setRenderViewportAndPerspectiveMatrix(gfx, mtx); return; } // Lighthouse [port] Crashing here, not sure what this is. @@ -55,87 +57,87 @@ void gsworld_draw(Gfx** gdl, Mtx **mptr, Vtx **vptr) { // } spawnQueue_unlock(); FrameInterpolation_RecordOpenChild("sky", 0); - sky_draw(gdl, mptr, vptr); + sky_draw(gfx, mtx, vtx); FrameInterpolation_RecordCloseChild(); - func_802BBD2C(&sp44, &sp40); + core2_34790_getClipDistances(&sp44, &sp40); viewport_setNearAndFar(sp44, sp40); - viewport_setRenderViewportAndPerspectiveMatrix(gdl, mptr); + viewport_setRenderViewportAndPerspectiveMatrix(gfx, mtx); if (mapModel_has_xlu_bin() != 0) { FrameInterpolation_RecordOpenChild("map_opa", 0); - mapModel_opa_draw(gdl, mptr, vptr); + mapModel_opa_draw(gfx, mtx, vtx); FrameInterpolation_RecordCloseChild(); if (game_is_frozen() == 0) { - leveloverlay_drawCallback(gdl, mptr, vptr); + leveloverlay_drawCallback(gfx, mtx, vtx); } if (game_is_frozen() == 0) { FrameInterpolation_RecordOpenChild("player", 0); - player_draw(gdl, mptr, vptr); + player_draw(gfx, mtx, vtx); FrameInterpolation_RecordCloseChild(); - CALL_EVENT(OnPlayerDraw, gdl, mptr, vptr); + CALL_EVENT(OnPlayerDraw, gfx, mtx, vtx); } if (game_is_frozen() == 0) { - func_80302C94(gdl, mptr, vptr); + func_80302C94(gfx, mtx, vtx); } if (game_is_frozen() == 0) { FrameInterpolation_RecordOpenChild("jiggylist", 0); - jiggylist_draw(gdl, mptr, vptr); + jiggylist_draw(gfx, mtx, vtx); FrameInterpolation_RecordCloseChild(); } if (game_is_frozen() == 0) { - func_803500D8(gdl, mptr, vptr); + func_803500D8(gfx, mtx, vtx); } if (game_is_frozen() == 0) { - func_802F2ED0(func_8032994C(), gdl, mptr, vptr); + func_802F2ED0(func_8032994C(), gfx, mtx, vtx); } if (game_is_frozen() == 0) { FrameInterpolation_RecordOpenChild("part_pass0", 0); - partEmitMgr_drawPass0(gdl, mptr, vptr); + partEmitMgr_drawPass0(gfx, mtx, vtx); FrameInterpolation_RecordCloseChild(); } if (game_is_frozen() == 0) { FrameInterpolation_RecordOpenChild("map_xlu", 0); - mapModel_xlu_draw(gdl, mptr, vptr); + mapModel_xlu_draw(gfx, mtx, vtx); FrameInterpolation_RecordCloseChild(); } - if (game_is_frozen() == 0) { - func_8032D3D8(gdl, mptr, vptr); + if (!game_is_frozen()) { + core2_A5BC0_drawUnknownMarkers(gfx, mtx, vtx); } if (game_is_frozen() == 0) { FrameInterpolation_RecordOpenChild("part_pass1", 0); - partEmitMgr_drawPass1(gdl, mptr, vptr); + partEmitMgr_drawPass1(gfx, mtx, vtx); FrameInterpolation_RecordCloseChild(); } if (game_is_frozen() == 0) { - func_8034F6F0(gdl, mptr, (s32)(intptr_t)vptr); + func_8034F6F0(gfx, mtx, (s32)(intptr_t)vtx); } - func_802D520C(gdl, mptr, vptr); + func_802D520C(gfx, mtx, vtx); } else { FrameInterpolation_RecordOpenChild("map_opa", 0); - mapModel_opa_draw(gdl, mptr, vptr); + mapModel_opa_draw(gfx, mtx, vtx); FrameInterpolation_RecordCloseChild(); - leveloverlay_drawCallback(gdl, mptr, vptr); - func_8034F6F0(gdl, mptr, (s32)(intptr_t)vptr); + leveloverlay_drawCallback(gfx, mtx, vtx); + func_8034F6F0(gfx, mtx, (s32)(intptr_t)vtx); FrameInterpolation_RecordOpenChild("player", 0); - player_draw(gdl, mptr, vptr); + player_draw(gfx, mtx, vtx); FrameInterpolation_RecordCloseChild(); - CALL_EVENT(OnPlayerDraw, gdl, mptr, vptr); - func_80302C94(gdl, mptr, vptr); - func_8032D3D8(gdl, mptr, vptr); + CALL_EVENT(OnPlayerDraw, gfx, mtx, vtx); + func_80302C94(gfx, mtx, vtx); + core2_A5BC0_drawUnknownMarkers(gfx, mtx, vtx); FrameInterpolation_RecordOpenChild("jiggylist", 0); - jiggylist_draw(gdl, mptr, vptr); + jiggylist_draw(gfx, mtx, vtx); FrameInterpolation_RecordCloseChild(); - func_803500D8(gdl, mptr, vptr); - func_802F2ED0(func_8032994C(), gdl, mptr, vptr); - func_802D520C(gdl, mptr, vptr); + func_803500D8(gfx, mtx, vtx); + func_802F2ED0(func_8032994C(), gfx, mtx, vtx); + func_802D520C(gfx, mtx, vtx); FrameInterpolation_RecordOpenChild("part_draw", 0); - partEmitMgr_draw(gdl, mptr, vptr); + partEmitMgr_draw(gfx, mtx, vtx); FrameInterpolation_RecordCloseChild(); } if (game_is_frozen() == 0) { - func_80350818(gdl, mptr, vptr); + func_80350818(gfx, mtx, vtx); } if (game_is_frozen() == 0) { - func_802BBD0C(gdl, mptr, vptr); + func_802BBD0C(gfx, mtx, vtx); } spawnQueue_lock(); } @@ -144,15 +146,15 @@ void gsworld_stub1(s32 arg0, s32 arg1, s32 arg2){ } enum map_e gsworld_getMap(void){ - return sGsWorldData.map_4; + return sGsWorldData.map; } s32 gsworld_getExit(){ - return sGsWorldData.unk8; + return sGsWorldData.exit; } void gsworld_transitionToExit(s32 arg0) { - transitionToMap(sGsWorldData.map_4, arg0, 1); + transitionToMap(sGsWorldData.map, arg0, 1); } s32 gsworld_getUnk0(){ @@ -214,9 +216,9 @@ void gsworld_free(void) { itemPrint_free(); } dialogBin_terminate(); - func_802986D0(); - if (func_80322914() == 0) { - func_8024F7C4(func_803226E8(sGsWorldData.map_4)); + playerModel_free(); + if (!func_80322914()) { + func_8024F7C4(func_803226E8(sGsWorldData.map)); } core1_7090_release(); AnimTextureListCache_free(); @@ -228,12 +230,12 @@ void gsworld_free(void) { void gsworld_set(enum map_e arg0, s32 arg1, s32 arg2) { sGsWorldData.unk0 = 3; - CALL_EVENT(OnMapLoad, sGsWorldData.map_4, arg0, arg1); - sGsWorldData.map_4 = arg0; + CALL_EVENT(OnMapLoad, sGsWorldData.map, arg0, arg1); + sGsWorldData.map = arg0; // [port] Drop the prev tree; the next sub-frame would otherwise lerp // the old map's geometry against the new one's. FrameInterpolation_DontInterpolateCamera(); - sGsWorldData.unk8 = arg1; + sGsWorldData.exit = arg1; leveloverlay_init(); gsworld_setEnableUpdate(1); gsworld_setEnableDraw(1); @@ -243,15 +245,15 @@ void gsworld_set(enum map_e arg0, s32 arg1, s32 arg2) { func_8038E7C4(); } if (func_80322914() == 0) { - func_8024F764(func_803226E8(sGsWorldData.map_4)); + func_8024F764(func_803226E8(sGsWorldData.map)); } func_80320B84(); AnimTextureListCache_init(); func_8034C97C(); func_8030A078(); func_8031B718(); - func_80298700(); - if (func_802E4A08() == 0) { + playerModel_set(); + if (!func_802E4A08()) { itemPrint_init(); } dialogBin_initialize(); @@ -300,7 +302,7 @@ void gsworld_set(enum map_e arg0, s32 arg1, s32 arg2) { func_80350174(); gcparade_init(); func_80351998(); - func_802BC2CC(sGsWorldData.unk8); + func_802BC2CC(sGsWorldData.exit); func_802D63D4(); func_80255A04(); func_802D6948(); @@ -314,11 +316,11 @@ void gsworld_set(enum map_e arg0, s32 arg1, s32 arg2) { void gsworld_reload(void) { gsworld_free(); - gsworld_set(sGsWorldData.map_4, sGsWorldData.unk8, 1); + gsworld_set(sGsWorldData.map, sGsWorldData.exit, 1); } void gsworld_stub2(void) { - gsworld_stub3(sGsWorldData.map_4); + gsworld_stub3(sGsWorldData.map); } void gsworld_setUnk0(s32 arg0) { @@ -340,7 +342,7 @@ s32 gsworld_update(void) { s32 phi_v1; s32 phi_v0; - codeCF5F0_forgetAllAbilitiesExceptClawSwipeIfChecksumsFail(); + codeCF5F0_triggerAntiTamperMeasurement(); func_802D5628(); itemPrint_update(); if (getGameMode() != GAME_MODE_4_PAUSED) { @@ -403,7 +405,7 @@ s32 gsworld_update(void) { func_803306C8(1); func_8032AD7C(1); func_80322490(); - if (map_getLevel(sGsWorldData.map_4) == LEVEL_D_CUTSCENE) { + if (map_getLevel(sGsWorldData.map) == LEVEL_D_CUTSCENE) { func_802C79C4(); } func_8032AABC(); diff --git a/src/core2/map/list.c b/src/core2/map/list.c index 7ee10a629..c2e0b0487 100644 --- a/src/core2/map/list.c +++ b/src/core2/map/list.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_12F30.c #include #include "functions.h" #include "variables.h" @@ -125,7 +126,7 @@ void func_80299EC0(f32 arg0[3]) { } else { sp78 = 250; } - _player_getPosition(spEC); + playerPosition_get(spEC); sp6C = func_8029463C(); spC8 = func_802946A8(); if (spC8 == NULL) { diff --git a/src/core2/map/loadzone.c b/src/core2/map/loadzone.c index 1ab7baf3c..c26f81e0e 100644 --- a/src/core2/map/loadzone.c +++ b/src/core2/map/loadzone.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_A960.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/map/model.c b/src/core2/map/mapModel.c similarity index 93% rename from src/core2/map/model.c rename to src/core2/map/mapModel.c index 8cb5f4c68..09517ffb5 100644 --- a/src/core2/map/model.c +++ b/src/core2/map/mapModel.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/mapModel.c #include #include "functions.h" #include "variables.h" @@ -11,7 +12,7 @@ extern BKCollisionTriangle *func_802E92AC(BKCollisionList *, BKVertexList *, f32 extern s32 bkmodelunk14list_func_802EC394(BKModelUnk14List *arg0, f32 position[3], f32 rotation[3], f32 scale, f32 arg4[3], f32 arg5[3], s32 arg6); extern void vtxList_getBounds_s32(BKVertexList *, s32[3], s32[3]); extern void func_802F7BC0(Gfx **, Mtx **, Vtx **); -extern void func_8033A45C(s32, s32); +extern void modelRender_setAppendageVisibility(s32, s32); extern Vec3fArray *vec3fArray_defrag(Vec3fArray *this); extern Vec3fArray *vec3fArray_new(void); extern void func_8034C6DC(BKModel *arg0); @@ -260,101 +261,101 @@ f32 func_80308FDC(f32 arg0[3], u32 arg1) { void mapModel_opa_draw(Gfx **gfx, Mtx **mtx, Vtx **vtx) { s32 temp_a0; if (func_80320708() && levelSpecificFlags_validateCRC2() && dummy_func_80320248()) { - if (mapModel_getOpaModelId() == ASSET_14CF_MODEL_SM_SPIRAL_MOUNTAIN_OPA) { - func_8033A45C(1, 0); - func_8033A45C(2, 1); + if (mapModel_getOpaModelId() == VER_SELECT(ASSET_14CF_MODEL_SM_SPIRAL_MOUNTAIN_OPA, 0xD2D, 0, 0)) { + modelRender_setAppendageVisibility(1, 0); + modelRender_setAppendageVisibility(2, 1); } switch (gsworld_getMap()) { /* irregular */ case MAP_88_CS_SPIRAL_MOUNTAIN_6: if (mapSpecificFlags_get(0) != 0) { - func_8033A45C(1, 1); - func_8033A45C(2, 0); + modelRender_setAppendageVisibility(1, 1); + modelRender_setAppendageVisibility(2, 0); } break; case MAP_12_GV_GOBIS_VALLEY: - func_8033A45C(1, levelSpecificFlags_get(LEVEL_FLAG_6_GV_UNKNOWN) ? 1 : 0); - func_8033A45C(2, jiggyscore_isCollected(JIGGY_42_GV_WATER_PYRAMID) ? 0 : 1); - func_8033A45C(5, jiggyscore_isCollected(JIGGY_42_GV_WATER_PYRAMID) ? 1 : 0); + modelRender_setAppendageVisibility(1, levelSpecificFlags_get(LEVEL_FLAG_6_GV_UNKNOWN) ? 1 : 0); + modelRender_setAppendageVisibility(2, jiggyscore_isCollected(JIGGY_42_GV_WATER_PYRAMID) ? 0 : 1); + modelRender_setAppendageVisibility(5, jiggyscore_isCollected(JIGGY_42_GV_WATER_PYRAMID) ? 1 : 0); break; case MAP_14_GV_SANDYBUTTS_MAZE: - func_8033A45C(5, (player_movementGroup() == BSGROUP_4_LOOK) ? 1 : 0); + modelRender_setAppendageVisibility(5, (player_movementGroup() == BSGROUP_4_LOOK) ? 1 : 0); break; case MAP_E_MM_MUMBOS_SKULL: - func_8033A45C(1, 1); - func_8033A45C(5, 1); + modelRender_setAppendageVisibility(1, 1); + modelRender_setAppendageVisibility(5, 1); break; case MAP_47_BGS_MUMBOS_SKULL: - func_8033A45C(1, 2); - func_8033A45C(5, 2); + modelRender_setAppendageVisibility(1, 2); + modelRender_setAppendageVisibility(5, 2); break; case MAP_48_FP_MUMBOS_SKULL: - func_8033A45C(1, 3); - func_8033A45C(5, 3); + modelRender_setAppendageVisibility(1, 3); + modelRender_setAppendageVisibility(5, 3); break; case MAP_30_MMM_MUMBOS_SKULL: - func_8033A45C(1, 4); - func_8033A45C(5, 4); + modelRender_setAppendageVisibility(1, 4); + modelRender_setAppendageVisibility(5, 4); break; case MAP_4A_CCW_SPRING_MUMBOS_SKULL: - func_8033A45C(1, 5); - func_8033A45C(5, 5); + modelRender_setAppendageVisibility(1, 5); + modelRender_setAppendageVisibility(5, 5); break; case MAP_4B_CCW_SUMMER_MUMBOS_SKULL: - func_8033A45C(1, 6); - func_8033A45C(5, 6); + modelRender_setAppendageVisibility(1, 6); + modelRender_setAppendageVisibility(5, 6); break; case MAP_4C_CCW_AUTUMN_MUMBOS_SKULL: - func_8033A45C(1, 7); - func_8033A45C(5, 7); + modelRender_setAppendageVisibility(1, 7); + modelRender_setAppendageVisibility(5, 7); break; case MAP_4D_CCW_WINTER_MUMBOS_SKULL: - func_8033A45C(1, 8); - func_8033A45C(5, 8); + modelRender_setAppendageVisibility(1, 8); + modelRender_setAppendageVisibility(5, 8); break; case MAP_5E_CCW_SPRING_NABNUTS_HOUSE: case MAP_5F_CCW_SUMMER_NABNUTS_HOUSE: case MAP_60_CCW_AUTUMN_NABNUTS_HOUSE: - func_8033A45C(1, 1); - func_8033A45C(2, 0); + modelRender_setAppendageVisibility(1, 1); + modelRender_setAppendageVisibility(2, 0); break; case MAP_61_CCW_WINTER_NABNUTS_HOUSE: - func_8033A45C(1, 0); - func_8033A45C(2, 1); + modelRender_setAppendageVisibility(1, 0); + modelRender_setAppendageVisibility(2, 1); break; case MAP_1D_MMM_CELLAR: - func_8033A45C(1, actorArray_findActorFromActorId(0x191) ? 0 : 1); + modelRender_setAppendageVisibility(1, actorArray_findActorFromActorId(0x191) ? 0 : 1); break; case MAP_7C_CS_INTRO_BANJOS_HOUSE_1: case MAP_89_CS_INTRO_BANJOS_HOUSE_2: case MAP_8A_CS_INTRO_BANJOS_HOUSE_3: case MAP_8C_SM_BANJOS_HOUSE: case MAP_91_FILE_SELECT: - func_8033A45C(5, 1); + modelRender_setAppendageVisibility(5, 1); break; case MAP_7B_CS_INTRO_GL_DINGPOT_1: case MAP_81_CS_INTRO_GL_DINGPOT_2: - func_8033A45C(4, 0); - func_8033A45C(5, 0); - func_8033A45C(6, 0); + modelRender_setAppendageVisibility(4, 0); + modelRender_setAppendageVisibility(5, 0); + modelRender_setAppendageVisibility(6, 0); break; case MAP_82_CS_ENTERING_GL_MACHINE_ROOM: case MAP_83_CS_GAME_OVER_MACHINE_ROOM: case MAP_84_CS_UNUSED_MACHINE_ROOM: - func_8033A45C(4, 1); - func_8033A45C(5, 1); - func_8033A45C(6, 1); + modelRender_setAppendageVisibility(4, 1); + modelRender_setAppendageVisibility(5, 1); + modelRender_setAppendageVisibility(6, 1); break; case MAP_93_GL_DINGPOT: - func_8033A45C(4, 1); - func_8033A45C(5, 1); - func_8033A45C(6, (jigsawPicture_isJigsawPictureComplete(0xA) || fileProgressFlag_get(FILEPROG_E2_DOOR_OF_GRUNTY_OPEN) || volatileFlag_get(VOLATILE_FLAG_C1_IN_FINAL_CHARACTER_PARADE))); + modelRender_setAppendageVisibility(4, 1); + modelRender_setAppendageVisibility(5, 1); + modelRender_setAppendageVisibility(6, (jigsawPicture_isJigsawPictureComplete(0xA) || fileProgressFlag_get(FILEPROG_E2_DOOR_OF_GRUNTY_OPEN) || volatileFlag_get(VOLATILE_FLAG_C1_IN_FINAL_CHARACTER_PARADE))); break; } modelRender_setRefPoints(mapModel.unk24); @@ -376,7 +377,7 @@ void mapModel_xlu_draw(Gfx **gfx, Mtx **mtx, Vtx **vtx) { if (mapModel.model_bin_xlu != NULL) { if (gsworld_getMap() == MAP_1D_MMM_CELLAR) { - func_8033A45C(1, (actorArray_findActorFromActorId(0x191) != NULL) ? 0 : 1); + modelRender_setAppendageVisibility(1, (actorArray_findActorFromActorId(0x191) != NULL) ? 0 : 1); } modelRender_setDepthMode(MODEL_RENDER_DEPTH_COMPARE); temp_a0 = mapModel.unk4; diff --git a/src/core2/map/savestate.c b/src/core2/map/mapsavestate.c similarity index 99% rename from src/core2/map/savestate.c rename to src/core2/map/mapsavestate.c index 9e1aa4cce..a84578949 100644 --- a/src/core2/map/savestate.c +++ b/src/core2/map/mapsavestate.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/mapsavestate.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/map/specificflags.c b/src/core2/map/mapspecificflags.c similarity index 98% rename from src/core2/map/specificflags.c rename to src/core2/map/mapspecificflags.c index f371735de..e6df70f0d 100644 --- a/src/core2/map/specificflags.c +++ b/src/core2/map/mapspecificflags.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/mapspecificflags.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/map/overlay.c b/src/core2/map/overlay.c index c37d3e3bf..9146ee351 100644 --- a/src/core2/map/overlay.c +++ b/src/core2/map/overlay.c @@ -1,4 +1,4 @@ -// BanjoDecomp: code_9B990.c -> overlay.c (level overlay callbacks) +// BanjoDecomp: core2/code_9B990.c #include #include "functions.h" #include "variables.h" @@ -164,22 +164,22 @@ static void leveloverlay_MMM_unk14(s32 arg0, s32 arg1) { } static void leveloverlay_CC_draw(Gfx **gfx, Mtx **mtx, Vtx **vtx) { - CC_func_80388760(gfx, mtx, vtx); + maClanker_draw(gfx, mtx, vtx); } static void leveloverlay_CC_release(void) { - func_80388CB4(); - func_803880D4(); + maClanker_release(); + maClankerRings_release(); } static void leveloverlay_CC_init(void) { - func_80388D54(); - func_80388104(); + maClanker_init(); + maClankerRings_init(); } static void leveloverlay_CC_update(void) { - CC_func_80388F4C(); - func_8038817C(); + maClanker_update(); + maClankerRings_update(); } static void leveloverlay_CC_unk14(s32 arg0, s32 arg1) {} @@ -372,7 +372,8 @@ void leveloverlay_debug(void) {} void leveloverlay_init(void) { int i; enum overlay_e overlay_id; - func_80356714(); + + codeCF5F0_init(); overlay_id = overlayManager_getLoadedID(); sActiveCallbacks.init = NULL; sActiveCallbacks.update = NULL; diff --git a/src/core2/map/warp_dispatch.c b/src/core2/map/warp_dispatch.c index 98c6c7e0b..e2fbc601e 100644 --- a/src/core2/map/warp_dispatch.c +++ b/src/core2/map/warp_dispatch.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_AD110.c #include #include "functions.h" #include "variables.h" @@ -554,12 +555,12 @@ void func_80334448(NodeProp *arg0, ActorMarker *arg1) { s32 warpIdx; s32 warpDest; - switch(codeA5BC0_getNodePropBit6(arg0)) { + switch(codeA5BC0_getNodePropCategory(arg0)) { case 3: // warp (L80334480) global_timer_time = globalTimer_getTime(); if ((codeA5BC0_getNodePropUnkC(arg0) + 1) != global_timer_time) { // [port] BB romhacks remap warp destinations via BKCF config - warpIdx = codeA5BC0_getNodePropUnk8(arg0); + warpIdx = codeA5BC0_getNodePropActorId(arg0); warpDest = port_getRomhackWarpDest(warpIdx); CALL_EVENT(OnWarpDispatch, warpIdx, warpDest); if (warpDest >= 0) { @@ -572,7 +573,7 @@ void func_80334448(NodeProp *arg0, ActorMarker *arg1) { break; case 4: // radius trigger like camera (L803344E0) - sRadiusTriggers[codeA5BC0_getNodePropUnk8(arg0)](arg0, arg1); + sRadiusTriggers[codeA5BC0_getNodePropActorId(arg0)](arg0, arg1); break; case 0: //L80334508 diff --git a/src/core2/map/world_reset.c b/src/core2/map/world_reset.c index 93cfd6f83..5859154cb 100644 --- a/src/core2/map/world_reset.c +++ b/src/core2/map/world_reset.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_9A740.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/matrix_interp.c b/src/core2/matrix_interp.c index fe09ea19b..812af806c 100644 --- a/src/core2/matrix_interp.c +++ b/src/core2/matrix_interp.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_C3A40.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/model/lighting.c b/src/core2/model/lighting.c index f5d86ff0f..0ed2de3c2 100644 --- a/src/core2/model/lighting.c +++ b/src/core2/model/lighting.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_66490.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/model/mesh_dataaccess.c b/src/core2/model/mesh_dataaccess.c index 27c9a16ca..58253b248 100644 --- a/src/core2/model/mesh_dataaccess.c +++ b/src/core2/model/mesh_dataaccess.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_63410.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/model/meshbounds.c b/src/core2/model/meshbounds.c index 2575ffe6d..cfe91eb90 100644 --- a/src/core2/model/meshbounds.c +++ b/src/core2/model/meshbounds.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_B8080.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/model/render.c b/src/core2/model/modelRender.c similarity index 99% rename from src/core2/model/render.c rename to src/core2/model/modelRender.c index 87cbd446a..fde1ef513 100644 --- a/src/core2/model/render.c +++ b/src/core2/model/modelRender.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/modelRender.c #include #include "core1/core1.h" #include "functions.h" @@ -154,7 +155,7 @@ void modelRender_geoCmd_DRAWDIST(Gfx **, Mtx **, struct bk_geo_cmd_s *); void modelRender_geoCmd_UnkE(Gfx **, Mtx **, struct bk_geo_cmd_s *); void modelRender_geoCmd_CAMERA(Gfx **, Mtx **, struct bk_geo_cmd_s *); void modelRender_executeGeoCmds(Gfx **, Mtx **, BKGeoCmd *); -void func_8033A45C(s32 arg0, s32 arg1); +void modelRender_setAppendageVisibility(s32 arg0, s32 arg1); // Sets up 2 cycle mode Gfx setup2CycleDL[] = @@ -690,8 +691,8 @@ void modelRender_reset(void){ D_803837B0.unk0 = 0; sSecondaryModelData.model_id = 0; modelRenderDepthMode = MODEL_RENDER_DEPTH_NONE; - func_8033A45C(1,1); - func_8033A45C(2,0); + modelRender_setAppendageVisibility(1,1); + modelRender_setAppendageVisibility(2,0); if(D_80383758.unk18){ viewport_setPosition_vec3f(D_80383758.unk1C); viewport_setRotation_vec3f(D_80383758.unk28); @@ -1538,8 +1539,8 @@ void modelRender_setRefPoints(Vec3fArray *arg0){ modelRenderRefPoints = arg0; } -void func_8033A45C(s32 arg0, s32 arg1){ - D_80383658[arg0] = arg1; +void modelRender_setAppendageVisibility(s32 appendage_id, s32 appendage_visibility){ + D_80383658[appendage_id] = appendage_visibility; } void modelRender_func_8033A470(s32 arg0, s32 arg1){ diff --git a/src/core2/model/rendernormal.c b/src/core2/model/rendernormal.c index 5f3355085..f3502200e 100644 --- a/src/core2/model/rendernormal.c +++ b/src/core2/model/rendernormal.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_5FB00.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/model/skinning.c b/src/core2/model/skinning.c index 2d08038a8..e924e029f 100644 --- a/src/core2/model/skinning.c +++ b/src/core2/model/skinning.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_637D0.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/model/vertex_brightness.c b/src/core2/model/vertex_brightness.c index 908d1260e..056e99524 100644 --- a/src/core2/model/vertex_brightness.c +++ b/src/core2/model/vertex_brightness.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_C8360.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/mumbo_transforms.c b/src/core2/mumbo.c similarity index 80% rename from src/core2/mumbo_transforms.c rename to src/core2/mumbo.c index a495a1ef9..2eb4c9d11 100644 --- a/src/core2/mumbo_transforms.c +++ b/src/core2/mumbo.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/ch/mumbo.c #include #include "functions.h" #include "variables.h" @@ -25,7 +26,7 @@ ActorAnimationInfo D_80367490[] = { {ASSET_180_ANIM_MUMBO_ROTATE, 0.7f}, }; -ActorInfo D_803674E0 = { +ActorInfo chMumbo = { MARKER_6_MUMBO, ACTOR_7_MUMBO, ASSET_3C6_MODEL_MUMBO, 0x1, D_80367490, chMumbo_update, actor_update_func_80326224, chMumbo_draw, @@ -54,17 +55,17 @@ static bool __chMumbo_actorExists(enum actor_e actorId) { enum transformation_e func_802D16AC(void) { s32 ret = TRANSFORM_2_TERMITE; - __chMumbo_actorExists(0x1F); - if (__chMumbo_actorExists(0x20)) { + __chMumbo_actorExists(ACTOR_1F_UNUSED); + if (__chMumbo_actorExists(ACTOR_20_TRANSFORM_PUMPKIN)) { ret = TRANSFORM_3_PUMPKIN; } - if (__chMumbo_actorExists(0x21)) { + if (__chMumbo_actorExists(ACTOR_21_TRANSFORM_CROC)) { ret = TRANSFORM_5_CROC; } - if (__chMumbo_actorExists(0x22)) { + if (__chMumbo_actorExists(ACTOR_22_TRANSFORM_WALRUS)) { ret = TRANSFORM_4_WALRUS; } - if (__chMumbo_actorExists(0x23)) { + if (__chMumbo_actorExists(ACTOR_23_TRANSFORM_BEE)) { ret = TRANSFORM_6_BEE; } return ret; @@ -149,24 +150,24 @@ static void __chMumbo_textCallback(ActorMarker *caller, enum asset_e text_id, s3 this = marker_getActor(caller); switch(text_id){ - case ASSET_D8F_DIALOG_MUMBO_MEET: //L802D1A04 - gcdialog_showDialog((this->unk38_0) ? ASSET_DAA_DIALOG_MUMBO_HAS_ENOUGH_TOKENS : ASSET_DAB_DIALOG_MUMBO_NOT_ENOUGH_TOKENS, 0xe, this->position, this->marker, __chMumbo_textCallback, NULL); + case VER_SELECT(ASSET_D8F_DIALOG_MUMBO_MEET, 0xA0D, 0, 0): //L802D1A04 + gcdialog_showDialog((this->unk38_0) ? VER_SELECT(ASSET_DAA_DIALOG_MUMBO_HAS_ENOUGH_TOKENS, 0xA28, 0, 0) : VER_SELECT(ASSET_DAB_DIALOG_MUMBO_NOT_ENOUGH_TOKENS, 0xA29, 0, 0), 0xe, this->position, this->marker, __chMumbo_textCallback, NULL); return; - case ASSET_D90_DIALOG_MUMBO_MAGIC_PAID_FOR: //L802D1A40 - fileProgressFlag_set(FILEPROG_12_HAS_TRANSFORMED_BEFORE, true); - gcdialog_showDialog(ASSET_D8F_DIALOG_MUMBO_MEET + D_8037DDF0, 4, NULL, NULL, NULL, NULL); + case VER_SELECT(ASSET_D90_DIALOG_MUMBO_MAGIC_PAID_FOR, 0xA0E, 0, 0): //L802D1A40 + fileProgressFlag_set(FILEPROG_12_HAS_TRANSFORMED_BEFORE, TRUE); + gcdialog_showDialog(VER_SELECT(ASSET_D8F_DIALOG_MUMBO_MEET, 0xA0D, 0, 0) + D_8037DDF0, 4, NULL, NULL, NULL, NULL); gcpausemenu_80314AC8(1); break; - case ASSET_DAA_DIALOG_MUMBO_HAS_ENOUGH_TOKENS: //L802D1A7C /* fall-through */ - fileProgressFlag_set(FILEPROG_DC_HAS_HAD_ENOUGH_TOKENS_BEFORE, true); - case ASSET_DAB_DIALOG_MUMBO_NOT_ENOUGH_TOKENS: //L802D1A88 + case VER_SELECT(ASSET_DAA_DIALOG_MUMBO_HAS_ENOUGH_TOKENS, 0xA28, 0, 0): //L802D1A7C /* fall-through */ + fileProgressFlag_set(FILEPROG_DC_HAS_HAD_ENOUGH_TOKENS_BEFORE, TRUE); + case VER_SELECT(ASSET_DAB_DIALOG_MUMBO_NOT_ENOUGH_TOKENS, 0xA29, 0, 0): //L802D1A88 func_8028F918(0); break; - case ASSET_DAF_DIALOG_MUMBO_TREX_MISTAKE: //L802D1A98 - this->has_met_before = false; + case VER_SELECT(ASSET_DAF_DIALOG_MUMBO_TREX_MISTAKE, 0xA2D, 0, 0): //L802D1A98 + this->has_met_before = FALSE; if(this->unk38_31 != 0){ coMusicPlayer_playMusic(COMUSIC_2B_DING_B, 28000); item_adjustByDiffWithHud(ITEM_1C_MUMBO_TOKEN, -this->unk38_31); @@ -175,9 +176,9 @@ static void __chMumbo_textCallback(ActorMarker *caller, enum asset_e text_id, s3 subaddie_set_state_with_direction(this, 5, 0.0f, 1); return; - case ASSET_DB0_DIALOG_MUMBO_MISTAKE_0: //L802D1AF8 - case ASSET_DB1_DIALOG_MUMBO_MISTAKE_1: //L802D1AF8 - case ASSET_DB2_DIALOG_MUMBO_MISTAKE_2: //L802D1AF8 + case VER_SELECT(ASSET_DB0_DIALOG_MUMBO_MISTAKE_0, 0xA2E, 0, 0): //L802D1AF8 + case VER_SELECT(ASSET_DB1_DIALOG_MUMBO_MISTAKE_1, 0xA2F, 0, 0): //L802D1AF8 + case VER_SELECT(ASSET_DB2_DIALOG_MUMBO_MISTAKE_2, 0xA30, 0, 0): //L802D1AF8 D_8037DDF0 = this->unk10_12; this->unk10_12 = 1; if(this->unk38_31){ @@ -185,7 +186,7 @@ static void __chMumbo_textCallback(ActorMarker *caller, enum asset_e text_id, s3 item_adjustByDiffWithHud(ITEM_1C_MUMBO_TOKEN, -this->unk38_31); } - case ASSET_DAE_DIALOG_MUMBO_TREX_START: //L802D1B48 + case VER_SELECT(ASSET_DAE_DIALOG_MUMBO_TREX_START, 0xA2C, 0, 0): //L802D1B48 subaddie_set_state_with_direction(this, 5, 0.0f, 1); return; @@ -198,24 +199,24 @@ static void __chMumbo_textCallback(ActorMarker *caller, enum asset_e text_id, s3 void chMumbo_func_802D1B8C(Actor *this, enum transformation_e transform_id) { if (this->unk10_12 != 0) { - gcdialog_showDialog(fileProgressFlag_getN(FILEPROG_BB_MUMBO_MISTAKE_INDEX, 2) + ASSET_DAF_DIALOG_MUMBO_TREX_MISTAKE, 0xE, this->position, this->marker, __chMumbo_textCallback, NULL); + gcdialog_showDialog(fileProgressFlag_getN(FILEPROG_BB_MUMBO_MISTAKE_INDEX, 2) + VER_SELECT(ASSET_DAF_DIALOG_MUMBO_TREX_MISTAKE, 0xA2D, 0, 0), 0xE, this->position, this->marker, __chMumbo_textCallback, NULL); return; } if (fileProgressFlag_get(FILEPROG_12_HAS_TRANSFORMED_BEFORE)) { if (this->velocity[0] == 0.0f) { - gcdialog_showDialog(transform_id + ASSET_D8F_DIALOG_MUMBO_MEET, 6, this->position, this->marker, __chMumbo_textCallback, NULL); + gcdialog_showDialog(transform_id + VER_SELECT(ASSET_D8F_DIALOG_MUMBO_MEET, 0xA0D, 0, 0), 6, this->position, this->marker, __chMumbo_textCallback, NULL); return; } if (gsworld_getMap() == MAP_7A_GL_CRYPT && transform_id == TRANSFORM_3_PUMPKIN && !fileProgressFlag_get(FILEPROG_F7_HAS_TRANSFORMED_IN_CRYPT)) { - gcdialog_showDialog(ASSET_DAD_DIALOG_MUMBO_XFORM_IN_CRYPT, 6, this->position, this->marker, __chMumbo_textCallback, NULL); - fileProgressFlag_set(FILEPROG_F7_HAS_TRANSFORMED_IN_CRYPT, true); + gcdialog_showDialog(VER_SELECT(ASSET_DAD_DIALOG_MUMBO_XFORM_IN_CRYPT, 0xA2B, 0, 0), 6, this->position, this->marker, __chMumbo_textCallback, NULL); + fileProgressFlag_set(FILEPROG_F7_HAS_TRANSFORMED_IN_CRYPT, TRUE); return; } gcpausemenu_80314AC8(1); subaddie_set_state(this, 4U); return; } - gcdialog_showDialog(ASSET_D90_DIALOG_MUMBO_MAGIC_PAID_FOR, 0xE, this->position, this->marker, __chMumbo_textCallback, NULL); + gcdialog_showDialog(VER_SELECT(ASSET_D90_DIALOG_MUMBO_MAGIC_PAID_FOR, 0xA0E, 0, 0), 0xE, this->position, this->marker, __chMumbo_textCallback, NULL); } void chMumbo_update(Actor *this) { @@ -288,8 +289,8 @@ void chMumbo_update(Actor *this) { && !volatileFlag_get(VOLATILE_FLAG_1F_IN_CHARACTER_PARADE) ) { subaddie_set_state(this, 3); - gcdialog_showDialog(ASSET_D8F_DIALOG_MUMBO_MEET, 0xE, this->position, this->marker, __chMumbo_textCallback, NULL); - fileProgressFlag_set(FILEPROG_11_HAS_MET_MUMBO, true); + gcdialog_showDialog(VER_SELECT(ASSET_D8F_DIALOG_MUMBO_MEET, 0xA0D, 0, 0), 0xE, this->position, this->marker, __chMumbo_textCallback, NULL); + fileProgressFlag_set(FILEPROG_11_HAS_MET_MUMBO, TRUE); break; } @@ -299,8 +300,8 @@ void chMumbo_update(Actor *this) { && this->unk38_0 ){ subaddie_set_state(this, 3); - gcdialog_showDialog(ASSET_DAA_DIALOG_MUMBO_HAS_ENOUGH_TOKENS, 0xE, this->position, this->marker, __chMumbo_textCallback, NULL); - fileProgressFlag_set(FILEPROG_DC_HAS_HAD_ENOUGH_TOKENS_BEFORE, true); + gcdialog_showDialog(VER_SELECT(ASSET_DAA_DIALOG_MUMBO_HAS_ENOUGH_TOKENS, 0xA28, 0, 0), 0xE, this->position, this->marker, __chMumbo_textCallback, NULL); + fileProgressFlag_set(FILEPROG_DC_HAS_HAD_ENOUGH_TOKENS_BEFORE, TRUE); break; } @@ -317,7 +318,7 @@ void chMumbo_update(Actor *this) { sp48 = (gsworld_getMap() == MAP_7A_GL_CRYPT) ? chMumbo_withinHorzDistToPlayer(0x442, 0, 0x3C) : chMumbo_withinHorzDistToPlayer(0, -0x5A, 0x3C); if( sp48 && player_movementGroup() == BSGROUP_0_NONE - && func_8028F20C() + && player_isStableWithExtraSteps() && func_8028EFC8() ){ controller_copyFaceButtons(0, face_buttons); @@ -337,7 +338,7 @@ void chMumbo_update(Actor *this) { && randf() < 0.01 && sp48 ) { - gcdialog_showDialog(ASSET_DAE_DIALOG_MUMBO_TREX_START, 6, NULL, this->marker, __chMumbo_textCallback, NULL); + gcdialog_showDialog(VER_SELECT(ASSET_DAE_DIALOG_MUMBO_TREX_START, 0xA2C, 0, 0), 6, NULL, this->marker, __chMumbo_textCallback, NULL); fileProgressFlag_set(FILEPROG_BA_HAS_SEEN_TREX_TEXT, 1); this->has_met_before = true; subaddie_set_state(this, 3); @@ -366,7 +367,7 @@ void chMumbo_update(Actor *this) { break; } coMusicPlayer_playMusic(COMUSIC_2C_BUZZER, 22000); - if ((levelSpecificFlags_get(LEVEL_FLAG_3E_UNKNOWN) == false) && (gcdialog_showDialog(ASSET_DAC_DIALOG_MUMBO_FAIL_TO_BUY, 0, NULL, NULL, NULL, NULL) != 0)) { + if ((levelSpecificFlags_get(LEVEL_FLAG_3E_UNKNOWN) == FALSE) && (gcdialog_showDialog(VER_SELECT(ASSET_DAC_DIALOG_MUMBO_FAIL_TO_BUY, 0xA2A, 0, 0), 0, NULL, NULL, NULL, NULL) != 0)) { levelSpecificFlags_set(LEVEL_FLAG_3E_UNKNOWN, 1); } } @@ -396,8 +397,8 @@ void chMumbo_update(Actor *this) { && (player_getTransformation() != TRANSFORM_1_BANJO) && (player_getTransformation() != TRANSFORM_7_WISHWASHY)) ) { - func_8028FB88(TRANSFORM_1_BANJO); - } else if (func_8028FB88(D_8037DDF0)) { + player_transform(TRANSFORM_1_BANJO); + } else if (player_transform(D_8037DDF0)) { if (D_8037DDF0 != TRANSFORM_7_WISHWASHY) { if (fileProgressFlag_getAndSet(__bkProgId_from_transformationId(D_8037DDF0), true)) { this->velocity[0] = 1.0f; @@ -424,7 +425,7 @@ void chMumbo_update(Actor *this) { } if (this->has_met_before) { subaddie_set_state(this, 3); - gcdialog_showDialog(ASSET_DAF_DIALOG_MUMBO_TREX_MISTAKE, 6, NULL, this->marker, __chMumbo_textCallback, NULL); + gcdialog_showDialog(VER_SELECT(ASSET_DAF_DIALOG_MUMBO_TREX_MISTAKE, 0xA2D, 0, 0), 6, NULL, this->marker, __chMumbo_textCallback, NULL); break; } gcpausemenu_80314AC8(1); @@ -441,8 +442,8 @@ void chMumbo_update(Actor *this) { sp48 = chMumbo_withinHorzDistToPlayer(0, -0x6B, 0xBC); } if (sp48 != 0) { - gcdialog_showDialog(ASSET_DA7_DIALOG_MUMBO_CCW_SUMMER, 7, NULL, NULL, NULL, NULL); - volatileFlag_set(VOLATILE_FLAG_11, true); + gcdialog_showDialog(VER_SELECT(ASSET_DA7_DIALOG_MUMBO_CCW_SUMMER, 0xA25, 0, 0), 7, NULL, NULL, NULL, NULL); + volatileFlag_set(VOLATILE_FLAG_11, TRUE); } } actor_loopAnimation(this); @@ -457,8 +458,8 @@ void chMumbo_update(Actor *this) { sp48 = chMumbo_withinHorzDistToPlayer(0, -0x6B, 0xBC); } if (sp48 != 0) { - gcdialog_showDialog(ASSET_DA8_DIALOG_MUMBO_CCW_AUTUMN, 7, NULL, NULL, NULL, NULL); - volatileFlag_set(VOLATILE_FLAG_12, true); + gcdialog_showDialog(VER_SELECT(ASSET_DA8_DIALOG_MUMBO_CCW_AUTUMN, 0xA26, 0, 0), 7, NULL, NULL, NULL, NULL); + volatileFlag_set(VOLATILE_FLAG_12, TRUE); } } actor_loopAnimation(this); @@ -489,12 +490,12 @@ Actor *chMumbo_draw(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx) { f32 sp44[3]; f32* sp38 = D_80367510; - func_8033A45C(4, (this->lifetime_value == 0.0f)); - func_8033A45C(5, (this->lifetime_value == 1.0f)); - func_8033A45C(6, (this->lifetime_value == 0.0f)); - func_8033A45C(7, (this->lifetime_value == 1.0f)); - func_8033A45C(8, (this->lifetime_value == 2.0f)); - func_8033A45C(9, 0); + modelRender_setAppendageVisibility(4, (this->lifetime_value == 0.0f)); + modelRender_setAppendageVisibility(5, (this->lifetime_value == 1.0f)); + modelRender_setAppendageVisibility(6, (this->lifetime_value == 0.0f)); + modelRender_setAppendageVisibility(7, (this->lifetime_value == 1.0f)); + modelRender_setAppendageVisibility(8, (this->lifetime_value == 2.0f)); + modelRender_setAppendageVisibility(9, 0); out = actor_draw(marker, gfx, mtx, vtx); if( marker->unk14_21 && out->state == 8){ if( actor_animationIsAt(out, 0.2f) @@ -518,7 +519,7 @@ void chMumbo_detransformWarn(NodeProp *arg0, ActorMarker *arg1){ if(D_8037DDF3) return; - gcdialog_showDialog(fileProgressFlag_getAndSet(FILEPROG_83_MAGIC_GET_WEAK_TEXT, true) ? ASSET_F5C_DIALOG_MUMBO_MAGIC_GET_WEAK_ABREV : ASSET_F5B_DIALOG_MUMBO_MAGIC_GET_WEAK_FULL, 0xe, NULL, NULL, NULL, NULL); + gcdialog_showDialog(fileProgressFlag_getAndSet(FILEPROG_83_MAGIC_GET_WEAK_TEXT, TRUE) ? VER_SELECT(ASSET_F5C_DIALOG_MUMBO_MAGIC_GET_WEAK_ABREV, 0xAC2, 0, 0) : VER_SELECT(ASSET_F5B_DIALOG_MUMBO_MAGIC_GET_WEAK_FULL, 0xAC1, 0, 0), 0xe, NULL, NULL, NULL, NULL); } void chMumbo_detransformTrigger(NodeProp *arg0, ActorMarker *arg1){ @@ -526,9 +527,9 @@ void chMumbo_detransformTrigger(NodeProp *arg0, ActorMarker *arg1){ xform = player_getTransformation(); if(xform == TRANSFORM_1_BANJO || xform == TRANSFORM_7_WISHWASHY || D_8037DDF1) return; - gcdialog_showDialog(fileProgressFlag_getAndSet(FILEPROG_84_MAGIC_ALL_GONE_TEXT, true) ? ASSET_F5E_DIALOG_MUMBO_MAGIC_RUN_OUT_ABREV: ASSET_F5D_DIALOG_MUMBO_MAGIC_RUN_OUT_FULL, 0xe, NULL, NULL, NULL, NULL); + gcdialog_showDialog(fileProgressFlag_getAndSet(FILEPROG_84_MAGIC_ALL_GONE_TEXT, TRUE) ? VER_SELECT(ASSET_F5E_DIALOG_MUMBO_MAGIC_RUN_OUT_ABREV, 0xAC4, 0, 0): VER_SELECT(ASSET_F5D_DIALOG_MUMBO_MAGIC_RUN_OUT_FULL, 0xAC3, 0, 0), 0xe, NULL, NULL, NULL, NULL); D_8037DDF1++; - func_8028FB88(TRANSFORM_1_BANJO); + player_transform(TRANSFORM_1_BANJO); } void func_802D2CB8(void){ diff --git a/src/core2/score_mumbo.c b/src/core2/mumboscore.c similarity index 97% rename from src/core2/score_mumbo.c rename to src/core2/mumboscore.c index e0d6a820e..d0a0b8248 100644 --- a/src/core2/score_mumbo.c +++ b/src/core2/mumboscore.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/mumboscore.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/demo_ctrl.c b/src/core2/mumboshandwithpicture.c similarity index 69% rename from src/core2/demo_ctrl.c rename to src/core2/mumboshandwithpicture.c index d7f4f15cb..206a7b634 100644 --- a/src/core2/demo_ctrl.c +++ b/src/core2/mumboshandwithpicture.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/ch/mumboshandwithpicture.c #include #include "functions.h" #include "variables.h" @@ -7,25 +8,25 @@ extern void chBottlesBonus_func_802DD080(Gfx **, Mtx **); extern void func_80311714(s32); #include "port/Patches/Patches.h" -Actor *func_802DEC00(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx); -void func_802DEE1C(Actor *this); +Actor *chMumbosHandWithPicture_draw(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx); +void chMumbosHandWithPicture_update(Actor *this); /* .data */ -ActorAnimationInfo D_80368300[] ={ +ActorAnimationInfo chMumbosHandWithPictureAnimations[] ={ {0x000, 0.0f}, - {0x2C7, 0.6f}, - {0x2C6, 3.0f}, - {0x2C8, 0.6f}, - {0x2C8, 0.6f}, - {0x2C6, 9e+09}, + {ASSET_2C7_ANIM_MUMBOS_HAND_WITH_PICTURE, 0.6f}, + {ASSET_2C6_ANIM_MUMBOS_HAND_WITH_PICTURE, 3.0f}, + {ASSET_2C8_ANIM_MUMBOS_HAND_WITH_PICTURE, 0.6f}, + {ASSET_2C8_ANIM_MUMBOS_HAND_WITH_PICTURE, 0.6f}, + {ASSET_2C6_ANIM_MUMBOS_HAND_WITH_PICTURE, 9e+09}, }; f32 D_80368330[3] = {0.0f, 0.0f, 0.0f}; -ActorInfo D_8036833C = { - 0x294, 0x19B, ASSET_56D_MUMBOS_HAND_WITH_PICTURE, - 0x1, D_80368300, - func_802DEE1C, actor_update_func_80326224, func_802DEC00, +ActorInfo chMumbosHandWithPicture = { + MARKER_294_MUMBOS_HAND_WITH_PICTURE, ACTOR_19B_MUMBOS_HAND_WITH_PICTURE, ASSET_56D_MUMBOS_HAND_WITH_PICTURE, + 0x1, chMumbosHandWithPictureAnimations, + chMumbosHandWithPicture_update, actor_update_func_80326224, chMumbosHandWithPicture_draw, 0, 0, 0.0f, 0 }; @@ -36,7 +37,7 @@ BKModelBin *D_8037DFE8; f32 D_8037DFF0[3]; /* .code */ -Actor *func_802DEC00(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx){ +Actor *chMumbosHandWithPicture_draw(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx){ Actor *this; f32 sp58[3]; f32 sp4C[3]; @@ -44,7 +45,7 @@ Actor *func_802DEC00(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx){ this = marker_getActor(marker); - sp48 = func_8030C704(); + sp48 = picturebox_getColorBuffer(); if ((sp48 == 0) || (getGameMode() != GAME_MODE_A_SNS_PICTURE)) return this; @@ -62,13 +63,13 @@ Actor *func_802DEC00(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx){ D_8037DFF0[1] = 270.0f; D_8037DFF0[2] = 0.0f; // [port] Draw the background picture and Mumbo's hand without depth testing. - // On N64, func_80253190 cleared the hardware depth buffer between the two draws + // On N64, depthbuffer_clear cleared the hardware depth buffer between the two draws // via CPU-accessible memory. On PC, the GBI depth fill may not translate to a // GPU depth clear, causing the hand to fail depth tests against the 3D scene. modelRender_setDepthMode(MODEL_RENDER_DEPTH_NONE); modelRender_draw(gfx, mtx, sp58, NULL, 1.0f, sp4C, D_8037DFE8); gDPSetColorDither((*gfx)++, G_CD_DISABLE); - func_80253190(gfx); + depthbuffer_clear(gfx); port_readAuxFbToCpu(gfx); gDPSetTextureFilter((*gfx)++, G_TF_BILERP); gSPSegment((*gfx)++, 0x04, osVirtualToPhysical(sp48)); @@ -95,11 +96,11 @@ void func_802DEDDC(Actor *this){ } -void func_802DEE1C(Actor *this) { - s32 sp4C; - s32 sp48; - s32 sp44; - f32 sp38; +void chMumbosHandWithPicture_update(Actor *this) { + enum level_e level_id_1; + enum asset_e text_id; + enum level_e level_id_2; + f32 time; if (!this->initialized) { this->initialized = true; @@ -107,33 +108,33 @@ void func_802DEE1C(Actor *this) { marker_setFreeMethod(this->marker, func_802DEDDC); actor_playAnimationOnce(this); if (D_8037DFE8 == NULL) { - D_8037DFE8 = assetcache_get(0x56E); + D_8037DFE8 = assetcache_get(ASSET_56E_HAMMERHEAD_BEACH_SCENERY); } - sp4C = map_getLevel(gsworld_getMap()); - sp44 = sp4C == D_8037DFE4; - if (sp44) { + level_id_1 = map_getLevel(gsworld_getMap()); + level_id_2 = level_id_1 == D_8037DFE4; + if (level_id_2) { subaddie_set_state_with_direction(this, 2, 0.0f, 1); actor_loopAnimation(this); } - switch(sp4C){ + switch(level_id_1){ case LEVEL_2_TREASURE_TROVE_COVE: - sp48 = sp44 + 0xE39; + text_id = level_id_2 + 0xE39; // 0xE3B break; case LEVEL_5_FREEZEEZY_PEAK: - sp48 = sp44 + 0xE3B; + text_id = level_id_2 + 0xE3B; // 0xE40 break; case LEVEL_7_GOBIS_VALLEY: default: - sp48 = sp44 + 0xE3D; + text_id = level_id_2 + 0xE3D; // 0xE44 break; } - sp38 = (f32) ((f64) (sp44 + 1) * 0.75); - timedFunc_set_1(sp38, (GenFunction_1)func_80311714, 0); - func_80324DBC(sp38, sp48, 0x80, NULL, NULL, NULL, NULL); - timedFunc_set_1(sp38, (GenFunction_1)func_80311714, 1); - D_8037DFE4 = sp4C; + time = (f32) ((f64) (level_id_2 + 1) * 0.75); + timedFunc_set_1(time, func_80311714, 0); + func_80324DBC(time, text_id, 0x80, NULL, NULL, NULL, NULL); + timedFunc_set_1(time, func_80311714, 1); + D_8037DFE4 = level_id_1; } switch(this->state){ case 1: diff --git a/src/core2/camera/firstpersoncamera.c b/src/core2/nc/1p.c similarity index 74% rename from src/core2/camera/firstpersoncamera.c rename to src/core2/nc/1p.c index 1c1af0010..89539d0cc 100644 --- a/src/core2/camera/firstpersoncamera.c +++ b/src/core2/nc/1p.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/nc/ba/1p.c #include #include "functions.h" #include "variables.h" @@ -5,7 +6,7 @@ extern void func_802BD780(f32[3], f32[3], f32, f32, f32, f32); -void ncFirstPersonCamera_setState(enum nc_first_person_state state); +void ncba1p_setState(enum nc_first_person_state state); /* .bss */ struct{ @@ -20,11 +21,11 @@ struct{ } D_8037DC60; /* .code */ -bool __ncFirstPersonCamera_fullyZoomedIn(void) { +bool __ncba1p_fullyZoomedIn(void) { return (ml_vec3f_distance(D_8037DC60.position, D_8037DC60.zoomed_in_position) < 40.0f); } -void __ncFirstPersonCamera_getPositionAndRotation_entering(f32 arg0[3], f32 arg1[3]) { +void __ncba1p_getPositionAndRotation_entering(f32 arg0[3], f32 arg1[3]) { s32 i; ml_sub_delta_time(&D_8037DC60.transistion_timer); @@ -33,9 +34,9 @@ void __ncFirstPersonCamera_getPositionAndRotation_entering(f32 arg0[3], f32 arg1 D_8037DC60.rotation[i] = mlNormalizeAngle(D_8037DC60.zoomed_out_rotation[i] + func_80257CF8(D_8037DC60.transistion_timer, 0.5f, 0.0f, 0.0f, mlDiffDegF(D_8037DC60.zoomed_in_rotation[i], D_8037DC60.zoomed_out_rotation[i]))); } if (D_8037DC60.transistion_timer == 0.0f) { - ncFirstPersonCamera_setState(FIRSTPERSON_STATE_2_IDLE); + ncba1p_setState(FIRSTPERSON_STATE_2_IDLE); } - if (__ncFirstPersonCamera_fullyZoomedIn() && func_8028F150()) { + if (__ncba1p_fullyZoomedIn() && func_8028F150()) { player_setModelVisible(0); } ml_vec3f_copy(arg0, D_8037DC60.position); @@ -43,7 +44,7 @@ void __ncFirstPersonCamera_getPositionAndRotation_entering(f32 arg0[3], f32 arg1 } -void __ncFirstPersonCamera_getPositionAndRotation_exiting(f32 arg0[3], f32 arg1[3]) { +void __ncba1p_getPositionAndRotation_exiting(f32 arg0[3], f32 arg1[3]) { s32 i; ml_sub_delta_time(&D_8037DC60.transistion_timer); @@ -52,9 +53,9 @@ void __ncFirstPersonCamera_getPositionAndRotation_exiting(f32 arg0[3], f32 arg1[ D_8037DC60.rotation[i] = mlNormalizeAngle(D_8037DC60.zoomed_in_rotation[i] + func_80257CF8(D_8037DC60.transistion_timer, 1.0f, 0.5f, 0.0f, mlDiffDegF(arg1[i], D_8037DC60.zoomed_in_rotation[i]))); } if (D_8037DC60.transistion_timer == 0.0f) { - ncFirstPersonCamera_setState(FIRSTPERSON_STATE_4_DONE); + ncba1p_setState(FIRSTPERSON_STATE_4_DONE); } - if (!__ncFirstPersonCamera_fullyZoomedIn() && !func_8028F150()) { + if (!__ncba1p_fullyZoomedIn() && !func_8028F150()) { player_setModelVisible(1); } ml_vec3f_copy(arg0, D_8037DC60.position); @@ -62,7 +63,7 @@ void __ncFirstPersonCamera_getPositionAndRotation_exiting(f32 arg0[3], f32 arg1[ } -void __ncFirstPersonCamera_getPositionAndRotation_idle(f32 arg0[3], f32 arg1[3]) { +void __ncba1p_getPositionAndRotation_idle(f32 arg0[3], f32 arg1[3]) { ml_vec3f_copy(D_8037DC60.position, D_8037DC60.zoomed_in_position); func_802BD780(D_8037DC60.zoomed_in_rotation, D_8037DC60.rotation, 10.0f, 20.0f, 120.0f, 200.0f); D_8037DC60.rotation[2] = 0.0f; @@ -70,7 +71,7 @@ void __ncFirstPersonCamera_getPositionAndRotation_idle(f32 arg0[3], f32 arg1[3]) ml_vec3f_copy(arg1, D_8037DC60.rotation); } -void ncFirstPersonCamera_reset(void){ +void ncba1p_reset(void){ ml_vec3f_clear(D_8037DC60.position); ml_vec3f_clear(D_8037DC60.rotation); ml_vec3f_clear(D_8037DC60.zoomed_in_position); @@ -80,23 +81,23 @@ void ncFirstPersonCamera_reset(void){ D_8037DC60.state = 0; } -void ncFirstPersonCamera_getPositionAndRotation(f32 position[3], f32 rotation[3]) { +void ncba1p_getPositionAndRotation(f32 position[3], f32 rotation[3]) { switch (D_8037DC60.state) { case FIRSTPERSON_STATE_1_ENTER: - __ncFirstPersonCamera_getPositionAndRotation_entering(position, rotation); + __ncba1p_getPositionAndRotation_entering(position, rotation); break; case FIRSTPERSON_STATE_2_IDLE: - __ncFirstPersonCamera_getPositionAndRotation_idle(position, rotation); + __ncba1p_getPositionAndRotation_idle(position, rotation); break; case FIRSTPERSON_STATE_3_EXIT: - __ncFirstPersonCamera_getPositionAndRotation_exiting(position, rotation); + __ncba1p_getPositionAndRotation_exiting(position, rotation); /* fallthrough */ case FIRSTPERSON_STATE_4_DONE: break; } } -void ncFirstPersonCamera_setState(enum nc_first_person_state next_state) { +void ncba1p_setState(enum nc_first_person_state next_state) { if (next_state == FIRSTPERSON_STATE_1_ENTER) { if (D_8037DC60.state == FIRSTPERSON_STATE_3_EXIT) { ml_vec3f_copy(D_8037DC60.zoomed_out_position, D_8037DC60.position); @@ -115,20 +116,20 @@ void ncFirstPersonCamera_setState(enum nc_first_person_state next_state) { D_8037DC60.state = next_state; } -void ncFirstPersonCamera_setZoomedOutPosition(f32 src[3]){ +void ncba1p_setZoomedOutPosition(f32 src[3]){ ml_vec3f_copy(D_8037DC60.zoomed_in_position, src); } -void ncFirstPersonCamera_setZoomedOutRotation(f32 src[3]){ +void ncba1p_setZoomedOutRotation(f32 src[3]){ D_8037DC60.zoomed_in_rotation[0] = mlNormalizeAngle(src[0]); D_8037DC60.zoomed_in_rotation[1] = mlNormalizeAngle(src[1]); D_8037DC60.zoomed_in_rotation[2] = mlNormalizeAngle(src[2]); } -void ncFirstPersonCamera_getZoomedInRotation(f32 dst[3]){ +void ncba1p_getZoomedInRotation(f32 dst[3]){ ml_vec3f_copy(dst, D_8037DC60.zoomed_in_rotation); } -s32 ncFirstPersonCamera_getState(void){ +s32 ncba1p_getState(void){ return D_8037DC60.state; } diff --git a/src/core2/camera/camera_debug_freecam.c b/src/core2/nc/camera_debug_freecam.c similarity index 98% rename from src/core2/camera/camera_debug_freecam.c rename to src/core2/nc/camera_debug_freecam.c index bf8b1e8a1..cc4a1fa1b 100644 --- a/src/core2/camera/camera_debug_freecam.c +++ b/src/core2/nc/camera_debug_freecam.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core1/stub_2FA0.c #include #include "core1/core1.h" #include "functions.h" diff --git a/src/core2/camera/camera_ease.c b/src/core2/nc/camera_ease.c similarity index 96% rename from src/core2/camera/camera_ease.c rename to src/core2/nc/camera_ease.c index c76d52edd..b343b3edd 100644 --- a/src/core2/camera/camera_ease.c +++ b/src/core2/nc/camera_ease.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_3B2C0.c #include #include "functions.h" #include "variables.h" @@ -29,7 +30,7 @@ void func_802C22B4(void){ s_state = 0; } - +// something for dynamic camera void func_802C22C0(f32 target_position[3], f32 target_rotation[3]){ f32 tmpf_1[3]; f32 tmpf_2[3]; diff --git a/src/core2/camera/camera_focus.c b/src/core2/nc/camera_focus.c similarity index 96% rename from src/core2/camera/camera_focus.c rename to src/core2/nc/camera_focus.c index 519e2266f..70624ae3f 100644 --- a/src/core2/camera/camera_focus.c +++ b/src/core2/nc/camera_focus.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_33C30.c #include #include "core1/core1.h" #include "functions.h" diff --git a/src/core2/camera/camera_focustarget.c b/src/core2/nc/camera_focustarget.c similarity index 97% rename from src/core2/camera/camera_focustarget.c rename to src/core2/nc/camera_focustarget.c index 45911191c..c708c734e 100644 --- a/src/core2/camera/camera_focustarget.c +++ b/src/core2/nc/camera_focustarget.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_F8EAF0.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/camera/camera_fog.c b/src/core2/nc/camera_fog.c similarity index 98% rename from src/core2/camera/camera_fog.c rename to src/core2/nc/camera_fog.c index fa2bc7f4e..b20ee5d5f 100644 --- a/src/core2/camera/camera_fog.c +++ b/src/core2/nc/camera_fog.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_37E50.c #include #include "core1/core1.h" #include "functions.h" diff --git a/src/core2/camera/camera_motor1.c b/src/core2/nc/camera_motor1.c similarity index 94% rename from src/core2/camera/camera_motor1.c rename to src/core2/nc/camera_motor1.c index cb37c274d..ea43f777a 100644 --- a/src/core2/camera/camera_motor1.c +++ b/src/core2/nc/camera_motor1.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_33F90.c #include #include "functions.h" #include "variables.h" @@ -73,6 +74,7 @@ s16 D_8036502C[] = { 0, -1, 0, 4, 0x12, 5, s16 D_8036503C[] = { 0, -1, 0, 0, -4, 0x1E}; s16 D_80365048[] = { 0, -1, 0, 2, 0x23, 1, 0x46, -6, -1, 0x46}; s16 D_8036505C[] = { 0, -1, 0, 1, 0x1A, -6, -1, 0x1A}; +#if VERSION == VERSION_USA_1_0 s16 D_8036506C[] = { 0, -1, 0, 0xC, 0xD, 0xD, 0x20, 0x3, 0x34, -6, -1, 0x39}; s16 D_80365084[] = { 0, -1, 0, 0, 0x13, 1, 0x30, 0xD, -4, 0x53}; s16 D_80365098[] = { 0, -1, 0, 6, 0xD, 7, 0x20, 0x14, -4, 0x39}; @@ -82,6 +84,17 @@ s16 D_803650D4[] = { 0, -1, 0, 3, 0xD, 4, 0x20, 0x13, s16 D_803650E8[] = { 0, -1, 0, 0, 0xD, 1, 0x20, 0x4, -4, 0x39}; s16 D_803650FC[] = { 0, -1, 0, 0, 0xD, 1, 0x20, 0xD, -4, 0x41}; s16 D_80365110[] = { 0, -1, 0, 3, 0xD, 4, 0x20, 0x20, -4, 0x39}; +#elif VERSION == VERSION_PAL +s16 D_8036506C[] = { 0, -1, 0, 0xC, 0xD, 0xD, 0x28, 0x3, 0x46, -6, -1, 0x4B}; +s16 D_80365084[] = { 0, -1, 0, 0, 0x13, 1, 0x38, 0xD, -4, 0x65}; +s16 D_80365098[] = { 0, -1, 0, 6, 0xD, 7, 0x28, 0x14, -4, 0x49}; +s16 D_803650AC[] = { 0, -1, 0, 2, 0xD, 3, 0x28, 0xB, -4, 0x49}; +s16 D_803650C0[] = { 0, -1, 0, 0, 0xD, 1, 0x26, 0xC, -4, 0x48}; +s16 D_803650D4[] = { 0, -1, 0, 3, 0xD, 4, 0x26, 0x13, -4, 0x48}; +s16 D_803650E8[] = { 0, -1, 0, 0, 0xD, 1, 0x26, 0x4, -4, 0x48}; +s16 D_803650FC[] = { 0, -1, 0, 0, 0xD, 1, 0x26, 0xD, -4, 0x50}; +s16 D_80365110[] = { 0, -1, 0, 3, 0xD, 4, 0x26, 0x20, -4, 0x48}; +#endif s16 D_80365124[] = { 0, -1, 0, 2, 0xF, 3, -4, 0x28}; s16 D_80365134[] = { 0, -1, 0, 5, 0xC, 6, -4, 0x21}; s16 D_80365144[] = { 0, -1, 0, 0, 0xC, 1, -4, 0x21}; diff --git a/src/core2/camera/camera_motor2.c b/src/core2/nc/camera_motor2.c similarity index 99% rename from src/core2/camera/camera_motor2.c rename to src/core2/nc/camera_motor2.c index 0675f3b4d..0be2a6be9 100644 --- a/src/core2/camera/camera_motor2.c +++ b/src/core2/nc/camera_motor2.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_34310.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/camera/camera_nodemanager.c b/src/core2/nc/camera_nodemanager.c similarity index 96% rename from src/core2/camera/camera_nodemanager.c rename to src/core2/nc/camera_nodemanager.c index 20063fcc1..4502df634 100644 --- a/src/core2/camera/camera_nodemanager.c +++ b/src/core2/nc/camera_nodemanager.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_34790.c #include #include "core1/core1.h" #include "functions.h" @@ -64,7 +65,7 @@ bool func_802BB720(s32 arg0, f32 arg1[3], f32 arg2[3], s32 *arg3) { if (temp_v0 != NULL) { nodeprop_getPosition(temp_v0, arg1); *arg3 = nodeprop_getScale(temp_v0); - temp_f6 = (f32) nodeprop_getYaw(temp_v0) - 180.0f; + temp_f6 = (f32) nodeProp_getYaw(temp_v0) - 180.0f; arg2[0] = 0.0f;\ arg2[1] = mlNormalizeAngle(temp_f6);\ arg2[2] = 0.0f; @@ -124,7 +125,7 @@ void func_802BBA84(void) { mapModel_getBounds((s32 *)min, (s32 *)max); viewport_getPosition_vec3f(vp_position); viewport_getRotation_vec3f(vp_rotation); - viewport_getLookbk_vector(sp48); + viewport_getLookVector(sp48); D_8037D8CC = (f32) coords_func_8033EAF8((s32*)min, (s32*)max, vp_position, sp48); D_8037D8CC += 100.0f; if (D_8037D8CC < 1000.0f) { @@ -186,9 +187,9 @@ void func_802BBD0C(Gfx **gdl, Mtx **mptr, Vtx **vptr){ func_802BEE2C(gdl, mptr, vptr); } -void func_802BBD2C(f32 *arg0, f32 *arg1){ - *arg0 = D_8037D8C8; - *arg1 = D_8037D8CC; +void core2_34790_getClipDistances(f32 *near, f32 *far) { + *near = D_8037D8C8; + *far = D_8037D8CC; } f32 func_802BBD48(void) { @@ -376,7 +377,7 @@ bool func_802BC428(void){ } void func_802BC434(f32 arg0[3], f32 arg1[3], f32 arg2[3]) { - func_8025727C(arg1[0], arg1[1], arg1[2], arg2[0], arg2[1], arg2[2], &arg0[0], &arg0[1]); + ml_horizontal_and_vertical_angles(arg1[0], arg1[1], arg1[2], arg2[0], arg2[1], arg2[2], &arg0[0], &arg0[1]); arg0[0] = mlNormalizeAngle(-arg0[0]); arg0[2] = 0.0f; } diff --git a/src/core2/camera/camera_position.c b/src/core2/nc/camera_position.c similarity index 98% rename from src/core2/camera/camera_position.c rename to src/core2/nc/camera_position.c index 1c51a3142..e35048052 100644 --- a/src/core2/camera/camera_position.c +++ b/src/core2/nc/camera_position.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_379B0.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/camera/camera_set.c b/src/core2/nc/camera_set.c similarity index 98% rename from src/core2/camera/camera_set.c rename to src/core2/nc/camera_set.c index 93253ea10..123270faf 100644 --- a/src/core2/camera/camera_set.c +++ b/src/core2/nc/camera_set.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_CB610.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/camera/cameranode_type1.c b/src/core2/nc/cameranode_type1.c similarity index 99% rename from src/core2/camera/cameranode_type1.c rename to src/core2/nc/cameranode_type1.c index b80596118..5b70fcaa1 100644 --- a/src/core2/camera/cameranode_type1.c +++ b/src/core2/nc/cameranode_type1.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_336F0.c #include #include diff --git a/src/core2/camera/cameranode_type2.c b/src/core2/nc/cameranode_type2.c similarity index 98% rename from src/core2/camera/cameranode_type2.c rename to src/core2/nc/cameranode_type2.c index 06905a8ba..43df38fbf 100644 --- a/src/core2/camera/cameranode_type2.c +++ b/src/core2/nc/cameranode_type2.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_33AB0.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/camera/cameranode_type3.c b/src/core2/nc/cameranode_type3.c similarity index 99% rename from src/core2/camera/cameranode_type3.c rename to src/core2/nc/cameranode_type3.c index fcdd6a99f..9c2cf231b 100644 --- a/src/core2/camera/cameranode_type3.c +++ b/src/core2/nc/cameranode_type3.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_33310.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/camera/cameranode_type4.c b/src/core2/nc/cameranode_type4.c similarity index 96% rename from src/core2/camera/cameranode_type4.c rename to src/core2/nc/cameranode_type4.c index 0fb4df6c7..36763a654 100644 --- a/src/core2/camera/cameranode_type4.c +++ b/src/core2/nc/cameranode_type4.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_33250.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/camera/cameranodelist.c b/src/core2/nc/cameranodelist.c similarity index 99% rename from src/core2/camera/cameranodelist.c rename to src/core2/nc/cameranodelist.c index ce809a9e8..0e7d7d472 100644 --- a/src/core2/camera/cameranodelist.c +++ b/src/core2/nc/cameranodelist.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/nc/cameranodelist.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/camera/dynamicCamD.c b/src/core2/nc/die.c similarity index 73% rename from src/core2/camera/dynamicCamD.c rename to src/core2/nc/die.c index 61f3413c3..c0d636a87 100644 --- a/src/core2/camera/dynamicCamD.c +++ b/src/core2/nc/die.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/nc/ba/die.c #include #include "functions.h" #include "variables.h" @@ -6,18 +7,18 @@ f32 D_80365D90 = 30.0f; /* .code */ -void ncDynamicCamD_init(void){ +void ncbadie_init(void){ func_802BE244(4.0f, 16.0f); func_802BE230(1.4f, 14.0f); } -void ncDynamicCamD_end(void){} +void ncbadie_end(void){} -void ncDynamicCamD_func_802BF2C0(f32 arg0){ +void ncbadie_func_802BF2C0(f32 arg0){ D_80365D90 = arg0; } -void ncDynamicCamD_update(void) { +void ncbadie_update(void) { f32 sp54[3]; f32 sp48[3]; f32 sp3C[3]; @@ -36,7 +37,7 @@ void ncDynamicCamD_update(void) { ncDynamicCamera_getPosition(sp54); player_getPosition(sp3C); sp3C[1] += D_80365D90; - func_8025727C(sp3C[0], sp3C[1], sp3C[2], sp54[0], sp54[1], sp54[2], &sp48[0], &sp48[1]); + ml_horizontal_and_vertical_angles(sp3C[0], sp3C[1], sp3C[2], sp54[0], sp54[1], sp54[2], &sp48[0], &sp48[1]); sp48[0] = mlNormalizeAngle(-sp48[0]); func_802BD904(sp48); } diff --git a/src/core2/nc/dynamicCam1.c b/src/core2/nc/dynamicCam1.c new file mode 100644 index 000000000..eab3d2703 --- /dev/null +++ b/src/core2/nc/dynamicCam1.c @@ -0,0 +1,50 @@ +// BanjoDecomp: core2/nc/dynamicCam1.c +#include +#include "functions.h" +#include "variables.h" + +extern f32 func_802BD51C(void); +extern f32 player_getYaw(void); +extern void func_802BD870(f32, f32, f32, f32); + +void ncDynamicCam1_init(void){ + func_802BD870(12.0f, 10.0f, 120.0f, 120.0f); +} + +void ncDynamicCam1_end(void){} + +void ncDynamicCam1_update(void) { + f32 sp8C[3]; + f32 new_camera_position[3]; + f32 current_camera_position[3]; + f32 dst[3]; + f32 angles[3]; + f32 sp50[3]; + f32 position_z; + f32 phi; + f32 time_delta; + f32 sp40; + f32 sp3C; + + ncDynamicCamera_getPosition(current_camera_position); + func_802BD4C0(sp8C); + sp3C = func_802BD8D4(); + time_delta = time_getDelta(); + ml_vec3f_diff_copy(sp50, current_camera_position, sp8C); + position_z = sqrtf((sp50[0] * sp50[0]) + (sp50[2] * sp50[2])); + position_z += ml_clamp_abs_f((sp3C - position_z) * time_delta * 2, time_delta * 120.0f); + func_8025801C(sp50, &phi); + sp40 = ml_clamp_abs_f(mlDiffDegF(mlNormalizeAngle(180.0f + player_getYaw()), phi) * (time_delta * 1), time_delta * 50.0f); + phi = mlNormalizeAngle(phi + sp40); + func_80256E24(dst, 0.0f, phi, 0.0f, 0.0f, position_z); + ml_vec3f_add(new_camera_position, sp8C, dst); + new_camera_position[1] = current_camera_position[1] + ((func_802BD51C() - current_camera_position[1]) * time_delta * 2); + ncDynamicCamera_setPosition(new_camera_position); + ml_horizontal_and_vertical_angles( + sp8C[0], sp8C[1], sp8C[2], + new_camera_position[0], new_camera_position[1], new_camera_position[2], + &angles[0], &angles[1]); + angles[0] = -angles[0]; + angles[2] = 0.0f; + func_802BD720(angles); +} diff --git a/src/core2/camera/dynamicCam10.c b/src/core2/nc/dynamicCam10.c similarity index 96% rename from src/core2/camera/dynamicCam10.c rename to src/core2/nc/dynamicCam10.c index 8382589b0..745b7bb67 100644 --- a/src/core2/camera/dynamicCam10.c +++ b/src/core2/nc/dynamicCam10.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/nc/dynamicCam10.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/camera/dynamicCam11.c b/src/core2/nc/dynamicCam11.c similarity index 98% rename from src/core2/camera/dynamicCam11.c rename to src/core2/nc/dynamicCam11.c index 1861a0905..755caf4cb 100644 --- a/src/core2/camera/dynamicCam11.c +++ b/src/core2/nc/dynamicCam11.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/nc/dynamicCam11.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/camera/dynamicCam12.c b/src/core2/nc/dynamicCam12.c similarity index 99% rename from src/core2/camera/dynamicCam12.c rename to src/core2/nc/dynamicCam12.c index 4d788f602..fddad612a 100644 --- a/src/core2/camera/dynamicCam12.c +++ b/src/core2/nc/dynamicCam12.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/nc/dynamicCam12.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/camera/dynamicCam13.c b/src/core2/nc/dynamicCam13.c similarity index 98% rename from src/core2/camera/dynamicCam13.c rename to src/core2/nc/dynamicCam13.c index 0798d448b..854c54545 100644 --- a/src/core2/camera/dynamicCam13.c +++ b/src/core2/nc/dynamicCam13.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/nc/dynamicCam13.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/camera/dynamicCam3.c b/src/core2/nc/dynamicCam3.c similarity index 81% rename from src/core2/camera/dynamicCam3.c rename to src/core2/nc/dynamicCam3.c index 6d0cbc1a4..6c81bdf20 100644 --- a/src/core2/camera/dynamicCam3.c +++ b/src/core2/nc/dynamicCam3.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/nc/dynamicCam3.c #include #include "functions.h" #include "variables.h" @@ -38,11 +39,11 @@ void ncDynamicCam3_update(void) { sp30 = time_getDelta(); if (sp30); ml_vec3f_diff_copy(sp40, sp64, sp7C); - sp3C = gu_sqrtf(sp40[0]*sp40[0] + sp40[2]*sp40[2]); - sp3C += func_80259198(sp30*(sp34 - sp3C)*2 , sp30 * 800.0f); - func_8025727C(sp7C[0], sp7C[1], sp7C[2], sp64[0], sp64[1], sp64[2], &sp4C[0], &sp4C[1]); + sp3C = sqrtf(sp40[0]*sp40[0] + sp40[2]*sp40[2]); + sp3C += ml_clamp_abs_f(sp30*(sp34 - sp3C)*2 , sp30 * 800.0f); + ml_horizontal_and_vertical_angles(sp7C[0], sp7C[1], sp7C[2], sp64[0], sp64[1], sp64[2], &sp4C[0], &sp4C[1]); sp40[1] = sp30 * 0.77 * mlDiffDegF(mlNormalizeAngle(player_getYaw() + 180.0f), sp4C[1]); - sp40[1] = func_80259198(sp40[1], sp30 * 300.0f); + sp40[1] = ml_clamp_abs_f(sp40[1], sp30 * 300.0f); sp4C[1] = mlNormalizeAngle(sp4C[1] + sp40[1]); func_80256E24(sp58, 0.0f, sp4C[1], 0.0f, 0.0f, sp3C); sp70[0] = sp7C[0] + sp58[0]; diff --git a/src/core2/camera/dynamicCam5.c b/src/core2/nc/dynamicCam5.c similarity index 87% rename from src/core2/camera/dynamicCam5.c rename to src/core2/nc/dynamicCam5.c index 8e9875cc9..668b3f58d 100644 --- a/src/core2/camera/dynamicCam5.c +++ b/src/core2/nc/dynamicCam5.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/nc/dynamicCam5.c #include #include "functions.h" #include "variables.h" @@ -36,7 +37,7 @@ void ncDynamicCam5_update(void) { ml_vec3f_diff_copy(sp68, sp74, sp50); func_802BE190(sp68); ncDynamicCamera_getPosition(sp68); - func_8025727C(sp74[0], sp74[1], sp74[2], sp68[0], sp68[1], sp68[2], &sp38[0], &sp38[1]); + ml_horizontal_and_vertical_angles(sp74[0], sp74[1], sp74[2], sp68[0], sp68[1], sp68[2], &sp38[0], &sp38[1]); sp38[0] = -sp38[0]; sp38[2] = 0.0f; func_802BD904(sp38); diff --git a/src/core2/camera/dynamicCam8.c b/src/core2/nc/dynamicCam8.c similarity index 97% rename from src/core2/camera/dynamicCam8.c rename to src/core2/nc/dynamicCam8.c index b39d0d3ec..81df36cbc 100644 --- a/src/core2/camera/dynamicCam8.c +++ b/src/core2/nc/dynamicCam8.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/nc/dynamicCam8.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/camera/dynamicCam9.c b/src/core2/nc/dynamicCam9.c similarity index 86% rename from src/core2/camera/dynamicCam9.c rename to src/core2/nc/dynamicCam9.c index 99de86932..947415fa3 100644 --- a/src/core2/camera/dynamicCam9.c +++ b/src/core2/nc/dynamicCam9.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/nc/dynamicCam9.c #include #include "functions.h" #include "variables.h" @@ -36,7 +37,7 @@ void ncDynamicCam9_func_802C0A60(f32 arg0[3]) { f32 sp30[3]; func_802BD4C0(sp54); - func_8025727C(sp54[0], sp54[1], sp54[2], D_8037DBB0[0], D_8037DBB0[1], D_8037DBB0[2], &sp30[0], &sp30[1]); + ml_horizontal_and_vertical_angles(sp54[0], sp54[1], sp54[2], D_8037DBB0[0], D_8037DBB0[1], D_8037DBB0[2], &sp30[0], &sp30[1]); sp30[1] = mlNormalizeAngle(sp30[1] - 60.0f); func_80256E24(sp48, 0.0f, sp30[1], 0.0f, 0.0f, D_8037DBC0); ml_vec3f_add(arg0, D_8037DBB0, sp48); @@ -58,9 +59,9 @@ void ncDynamicCam9_func_802C0B70(f32 arg0[3], f32 arg1[3]) { sp3C[0] *= dt * 1.5; sp3C[1] *= dt * 1.0; sp3C[2] *= dt * 1.5; - sp3C[0] = func_80259198(sp3C[0], dt * 1000.0); - sp3C[1] = func_80259198(sp3C[1], dt * 1000.0); - sp3C[2] = func_80259198(sp3C[2], dt * 1000.0); + sp3C[0] = ml_clamp_abs_f(sp3C[0], dt * 1000.0); + sp3C[1] = ml_clamp_abs_f(sp3C[1], dt * 1000.0); + sp3C[2] = ml_clamp_abs_f(sp3C[2], dt * 1000.0); ml_vec3f_add(arg0, sp30, sp3C); ncDynamicCamera_setPosition(arg0); } @@ -78,7 +79,7 @@ void ncDynamicCam9_func_802C0C5C(f32 arg0[3], f32 arg1[3]) { ml_vec3f_scale(sp3C, ml_map_f(sp38, 0.4f, 0.75f, 0.5f, 1.0f)); ml_vec3f_add(sp54, D_8037DBB0, sp3C); sp54[1] = sp48[1] + (sp54[1] - sp48[1]) * 0.4; - func_8025727C(sp54[0], sp54[1], sp54[2], arg1[0], arg1[1], arg1[2], &arg0[0], &arg0[1]); + ml_horizontal_and_vertical_angles(sp54[0], sp54[1], sp54[2], arg1[0], arg1[1], arg1[2], &arg0[0], &arg0[1]); arg0[0] = mlNormalizeAngle(-arg0[0]); arg0[2] = 0.0f; } diff --git a/src/core2/camera/dynamicCamA.c b/src/core2/nc/dynamicCamA.c similarity index 98% rename from src/core2/camera/dynamicCamA.c rename to src/core2/nc/dynamicCamA.c index 08006c4c9..c4cc76801 100644 --- a/src/core2/camera/dynamicCamA.c +++ b/src/core2/nc/dynamicCamA.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/nc/dynamicCamA.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/camera/dynamicCamB.c b/src/core2/nc/dynamicCamB.c similarity index 98% rename from src/core2/camera/dynamicCamB.c rename to src/core2/nc/dynamicCamB.c index 83bc5f4bc..e7a70b6a6 100644 --- a/src/core2/camera/dynamicCamB.c +++ b/src/core2/nc/dynamicCamB.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/nc/dynamicCamB.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/camera/dynamicCamC.c b/src/core2/nc/dynamicCamC.c similarity index 91% rename from src/core2/camera/dynamicCamC.c rename to src/core2/nc/dynamicCamC.c index f31d482b1..338dae9ac 100644 --- a/src/core2/camera/dynamicCamC.c +++ b/src/core2/nc/dynamicCamC.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/nc/dynamicCamC.c #include #include "functions.h" #include "variables.h" @@ -69,7 +70,7 @@ void ncDynamicCamC_update(void) { ncDynamicCamera_getPosition(sp54); player_getPosition(sp3C); sp3C[1] += 100.0f; - func_8025727C(sp3C[0], sp3C[1], sp3C[2], sp54[0], sp54[1], sp54[2], &sp48[0], &sp48[1]); + ml_horizontal_and_vertical_angles(sp3C[0], sp3C[1], sp3C[2], sp54[0], sp54[1], sp54[2], &sp48[0], &sp48[1]); sp48[0] = mlNormalizeAngle(-sp48[0]); func_802BD904(sp48); } diff --git a/src/core2/camera/dynamicCamF.c b/src/core2/nc/dynamicCamF.c similarity index 95% rename from src/core2/camera/dynamicCamF.c rename to src/core2/nc/dynamicCamF.c index 4656ce03c..0ec2ec401 100644 --- a/src/core2/camera/dynamicCamF.c +++ b/src/core2/nc/dynamicCamF.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/nc/dynamicCamF.c #include #include "core1/core1.h" #include "functions.h" diff --git a/src/core2/camera/dynamicCamera.c b/src/core2/nc/dynamicCamera.c similarity index 85% rename from src/core2/camera/dynamicCamera.c rename to src/core2/nc/dynamicCamera.c index 76e27e4f5..e35337ede 100644 --- a/src/core2/camera/dynamicCamera.c +++ b/src/core2/nc/dynamicCamera.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/nc/dynamicCamera.c #include #include "core1/core1.h" #include "functions.h" @@ -31,10 +32,33 @@ void func_802BD8EC(f32 arg0); f32 D_80365CD0[] = {0.0f}; f32 D_80365CD4[] = {0.0f, -25.0f, 25.0f, -50.0f, 50.0f, -80.0f, 80.0f, -120.0f, 120.0f, -140.0f, 140.0f}; f32 D_80365D00[] = {0.0f, 20.0f, 40.0f, 60.0f, 80.0f, 100.0f, 120.0f, 140.0f, 160.0f, 180.0f, 200.0f, 220.0f, 240.0f, 260.0f, 280.0f, 300.0f, 320.0f, 340.0f}; + Struct_core2_356B0_0 D_80365D48 = {D_80365CD0, 1}; Struct_core2_356B0_0 D_80365D50 = {D_80365CD4, 11}; Struct_core2_356B0_0 D_80365D58 = {D_80365D00, 18}; +enum ncdynamiccamera_state_e { + NCDYNAMICCAMERA_STATE_0_NOT_INIT, + NCDYNAMICCAMERA_STATE_1_UNK, + NCDYNAMICCAMERA_STATE_2_UNK, + NCDYNAMICCAMERA_STATE_3_UNK, + NCDYNAMICCAMERA_STATE_4_UNK, + NCDYNAMICCAMERA_STATE_5_UNK, + NCDYNAMICCAMERA_STATE_6_UNK, + NCDYNAMICCAMERA_STATE_7_UNK, + NCDYNAMICCAMERA_STATE_8_UNK, + NCDYNAMICCAMERA_STATE_9_UNK, + NCDYNAMICCAMERA_STATE_A_UNK, + NCDYNAMICCAMERA_STATE_B_UNK, + NCDYNAMICCAMERA_STATE_C_UNK, + NCDYNAMICCAMERA_STATE_D_UNK, + NCDYNAMICCAMERA_STATE_E_UNK, + NCDYNAMICCAMERA_STATE_F_UNK, + NCDYNAMICCAMERA_STATE_10_UNK, + NCDYNAMICCAMERA_STATE_11_UNK, + NCDYNAMICCAMERA_STATE_12_UNK, + NCDYNAMICCAMERA_STATE_13_UNK +}; /* .bss */ s32 D_8037D940; @@ -207,7 +231,7 @@ void func_802BCBD4(void) { func_802BD870(10.0f, 10.0f, 120.0f, 120.0f); func_802BE230(1.4f, 14.0f); func_802BD840(); - ncFirstPersonCamera_reset(); + ncba1p_reset(); func_802C0120(); func_802C2258(); func_802C0F4C(); @@ -275,8 +299,9 @@ void func_802BCE94(void){ } void ncDynamicCamera_update(void){ - f32 sp24[3]; - f32 sp18[3]; + f32 position[3]; + f32 rotation[3]; + if(!cameraUpdateEnabled) return; @@ -287,73 +312,73 @@ void ncDynamicCamera_update(void){ func_802BCA58(); switch(dynamicCameraState){ - case 1:// L802BCF3C + case NCDYNAMICCAMERA_STATE_1_UNK:// L802BCF3C ncDynamicCam1_update(); func_802BCE94(); break; - case 3:// L802BCF54 + case NCDYNAMICCAMERA_STATE_3_UNK:// L802BCF54 ncDynamicCam3_update(); break; - case 4:// L802BCF64 - ncDynamicCam4_update(); + case NCDYNAMICCAMERA_STATE_4_UNK:// L802BCF64 + ncbafly_update(); func_802BCE94(); break; - case 5:// L802BCF7C + case NCDYNAMICCAMERA_STATE_5_UNK:// L802BCF7C ncDynamicCam5_update(); func_802BCE94(); break; - case 6:// L802BCF94 + case NCDYNAMICCAMERA_STATE_6_UNK:// L802BCF94 func_802BCE94(); break; - case 8:// L802BCFA4 + case NCDYNAMICCAMERA_STATE_8_UNK:// L802BCFA4 ncDynamicCam8_update(); break; - case 9:// L802BCFB4 + case NCDYNAMICCAMERA_STATE_9_UNK:// L802BCFB4 ncDynamicCam9_update(); func_802BCE94(); break; - case 0xA:// L802BCFCC + case NCDYNAMICCAMERA_STATE_A_UNK:// L802BCFCC ncDynamicCamA_update(); break; - case 0xB:// L802BCFDC + case NCDYNAMICCAMERA_STATE_B_UNK:// L802BCFDC ncDynamicCamB_update(); break; - case 0xC:// L802BCFEC + case NCDYNAMICCAMERA_STATE_C_UNK:// L802BCFEC ncDynamicCamC_update(); func_802BCE94(); break; - case 0xD:// L802BD004 - ncDynamicCamD_update(); + case NCDYNAMICCAMERA_STATE_D_UNK:// L802BD004 + ncbadie_update(); func_802BCE94(); break; - case 0xF:// L802BD01C + case NCDYNAMICCAMERA_STATE_F_UNK:// L802BD01C ncDynamicCamF_update(); break; - case 0x10:// L802BD02C + case NCDYNAMICCAMERA_STATE_10_UNK:// L802BD02C ncDynamicCam10_update(); break; - case 0x11:// L802BD03C + case NCDYNAMICCAMERA_STATE_11_UNK:// L802BD03C ncDynamicCam11_update(); break; - case 0x12:// L802BD04C + case NCDYNAMICCAMERA_STATE_12_UNK:// L802BD04C ncDynamicCam12_update(); break; - case 0x13:// L802BD05C + case NCDYNAMICCAMERA_STATE_13_UNK:// L802BD05C ncDynamicCam13_update(); break; @@ -365,14 +390,14 @@ void ncDynamicCamera_update(void){ port_modernCamera_update(); break; }//// L802BD064 - ml_vec3f_copy(sp24, cameraPosition); - ml_vec3f_copy(sp18, cameraRotation); - func_802C22C0(sp24, sp18); + ml_vec3f_copy(position, cameraPosition); + ml_vec3f_copy(rotation, cameraRotation); + func_802C22C0(position, rotation); if(dynamicCameraInFirstPerson){ - ncFirstPersonCamera_getPositionAndRotation(sp24, sp18); + ncba1p_getPositionAndRotation(position, rotation); } - viewport_setPosition_vec3f(sp24); - viewport_setRotation_vec3f(sp18); + viewport_setPosition_vec3f(position); + viewport_setRotation_vec3f(rotation); } int ncDynamicCamera_getState(void){ @@ -384,126 +409,126 @@ void ncDynamicCamera_setState(s32 state){ return; switch(dynamicCameraState){ - case 0x1://L802BD114 + case NCDYNAMICCAMERA_STATE_1_UNK://L802BD114 ncDynamicCam1_end(); break; - case 0x3://L802BD124 + case NCDYNAMICCAMERA_STATE_3_UNK://L802BD124 ncDynamicCam3_end(); break; - case 0x4://L802BD134 - ncDynamicCam4_end(); + case NCDYNAMICCAMERA_STATE_4_UNK://L802BD134 + ncbafly_end(); break; - case 0x5://L802BD144 + case NCDYNAMICCAMERA_STATE_5_UNK://L802BD144 ncDynamicCam5_end(); break; - case 0x8://L802BD154 + case NCDYNAMICCAMERA_STATE_8_UNK://L802BD154 ncDynamicCam8_end(); break; - case 0x9://L802BD164 + case NCDYNAMICCAMERA_STATE_9_UNK://L802BD164 ncDynamicCam9_end(); break; - case 0xa://L802BD174 + case NCDYNAMICCAMERA_STATE_A_UNK://L802BD174 ncDynamicCamA_end(); break; - case 0xb://L802BD184 + case NCDYNAMICCAMERA_STATE_B_UNK://L802BD184 ncDynamicCamB_end(); break; - case 0xc://L802BD194 + case NCDYNAMICCAMERA_STATE_C_UNK://L802BD194 ncDynamicCamC_end(); break; - case 0xd://L802BD1A4 - ncDynamicCamD_end(); + case NCDYNAMICCAMERA_STATE_D_UNK://L802BD1A4 + ncbadie_end(); break; - case 0xf://L802BD1B4 + case NCDYNAMICCAMERA_STATE_F_UNK://L802BD1B4 ncDynamicCamF_end(); break; - case 0x10://L802BD1C4 + case NCDYNAMICCAMERA_STATE_10_UNK://L802BD1C4 ncDynamicCam10_end(); break; - case 0x11://L802BD1D4 + case NCDYNAMICCAMERA_STATE_11_UNK://L802BD1D4 ncDynamicCam11_end(); break; - case 0x12://L802BD1E4 + case NCDYNAMICCAMERA_STATE_12_UNK://L802BD1E4 ncDynamicCam12_end(); break; - case 0x13://L802BD1F4 + case NCDYNAMICCAMERA_STATE_13_UNK://L802BD1F4 ncDynamicCam13_end(); break; }//L802BD1FC switch (state) { - case 0x1: //L802BD224 + case NCDYNAMICCAMERA_STATE_1_UNK: //L802BD224 ncDynamicCam1_init(); break; - case 0x3: //L802BD234 + case NCDYNAMICCAMERA_STATE_3_UNK: //L802BD234 ncDynamicCam3_init(); break; - case 0x4: //L802BD244 - ncDynamicCam4_init(); + case NCDYNAMICCAMERA_STATE_4_UNK: //L802BD244 + ncbafly_init(); break; - case 0x5: //L802BD254 + case NCDYNAMICCAMERA_STATE_5_UNK: //L802BD254 ncDynamicCam5_init(); break; - case 0x8: //L802BD264 + case NCDYNAMICCAMERA_STATE_8_UNK: //L802BD264 ncDynamicCam8_init(); break; - case 0x9: //L802BD274 + case NCDYNAMICCAMERA_STATE_9_UNK: //L802BD274 ncDynamicCam9_init(); break; - case 0xa: //L802BD284 + case NCDYNAMICCAMERA_STATE_A_UNK: //L802BD284 ncDynamicCamA_init(); break; - case 0xb: //L802BD294 + case NCDYNAMICCAMERA_STATE_B_UNK: //L802BD294 ncDynamicCamB_init(); break; - case 0xc: //L802BD2A4 + case NCDYNAMICCAMERA_STATE_C_UNK: //L802BD2A4 ncDynamicCamC_init(); break; - case 0xd: //L802BD2B4 - ncDynamicCamD_init(); + case NCDYNAMICCAMERA_STATE_D_UNK: //L802BD2B4 + ncbadie_init(); break; - case 0xf: //L802BD2C4 + case NCDYNAMICCAMERA_STATE_F_UNK: //L802BD2C4 ncDynamicCamF_init(); break; - case 0x10: //L802BD2D4 + case NCDYNAMICCAMERA_STATE_10_UNK: //L802BD2D4 ncDynamicCam10_init(); break; - case 0x11: //L802BD2E4 + case NCDYNAMICCAMERA_STATE_11_UNK: //L802BD2E4 ncDynamicCam11_init(); break; - case 0x12: //L802BD2F4 + case NCDYNAMICCAMERA_STATE_12_UNK: //L802BD2F4 dynamicCam12_init(); break; - case 0x13: //L802BD304 + case NCDYNAMICCAMERA_STATE_13_UNK: //L802BD304 ncDynamicCam13_init(); break; } @@ -586,8 +611,8 @@ void func_802BD610(f32 arg0[3], f32 arg1[3], f32 arg2, f32 arg3, f32 arg4, f32 a sp24[1] = mlDiffDegF(arg0[1], arg1[1]); sp24[0] *= 0.003333 * D_8037D984; sp24[1] *= 0.003333 * D_8037D988; - sp24[0] = func_80259198(sp24[0], D_8037D98C * 0.003333); - sp24[1] = func_80259198(sp24[1], D_8037D990 * 0.003333); + sp24[0] = ml_clamp_abs_f(sp24[0], D_8037D98C * 0.003333); + sp24[1] = ml_clamp_abs_f(sp24[1], D_8037D990 * 0.003333); sp24[2] = 0.0f; arg1[0] = mlNormalizeAngle(arg1[0] + sp24[0]); arg1[1] = mlNormalizeAngle(arg1[1] + sp24[1]); @@ -955,7 +980,7 @@ void func_802BE720(void){ ncDynamicCamera_setState(sp34); ml_vec3f_clear(D_8037D9C8); ml_vec3f_clear(D_8037D9E0); - ncFirstPersonCamera_reset(); + ncba1p_reset(); } void func_802BE794(void){ @@ -997,11 +1022,11 @@ void func_802BE894(f32 position[3], f32 rotation[3]){ void ncDynamicCamera_enterFirstPerson(void){ dynamicCameraInFirstPerson = true; - ncFirstPersonCamera_setState(FIRSTPERSON_STATE_1_ENTER); - ncFirstPersonCamera_setZoomedOutPosition(cameraPosition); - ncFirstPersonCamera_setZoomedOutRotation(cameraRotation); + ncba1p_setState(FIRSTPERSON_STATE_1_ENTER); + ncba1p_setZoomedOutPosition(cameraPosition); + ncba1p_setZoomedOutRotation(cameraRotation); } void ncDynamicCamera_exitFirstPerson(void){ - ncFirstPersonCamera_setState(FIRSTPERSON_STATE_3_EXIT); + ncba1p_setState(FIRSTPERSON_STATE_3_EXIT); } diff --git a/src/core2/camera/dynamicCam4.c b/src/core2/nc/fly.c similarity index 70% rename from src/core2/camera/dynamicCam4.c rename to src/core2/nc/fly.c index 8fca9dc40..8ea98dafd 100644 --- a/src/core2/camera/dynamicCam4.c +++ b/src/core2/nc/fly.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/nc/ba/fly.c #include #include "functions.h" #include "variables.h" @@ -6,8 +7,8 @@ extern f32 player_getYaw(void); extern f32 player_getPitch(void); extern void func_802BD870(f32, f32, f32, f32); -void ncDynamicCam4_func_802BFE50(f32 arg0, f32 arg1, f32 arg2); -void ncDynamicCam4_func_802BFE74(bool); +void ncbafly_func_802BFE50(f32 arg0, f32 arg1, f32 arg2); +void ncbafly_func_802BFE74(bool); /* .bss */ f32 D_8037DB10; @@ -17,19 +18,19 @@ f32 D_8037DB1C; f32 D_8037DB20; /* .code */ -void ncDynamicCam4_init(void) { +void ncbafly_init(void) { func_802BD870(10.0f, 20.0f, 120.0f, 200.0f); if (gsworld_getMap() == MAP_90_GL_BATTLEMENTS) { - ncDynamicCam4_func_802BFE50(10.0f, 800.0f, 1350.0f); + ncbafly_func_802BFE50(10.0f, 800.0f, 1350.0f); } else { - ncDynamicCam4_func_802BFE50(2.0f, 800.0f, 350.0f); + ncbafly_func_802BFE50(2.0f, 800.0f, 350.0f); } - ncDynamicCam4_func_802BFE74(0); + ncbafly_func_802BFE74(0); } -void ncDynamicCam4_end(void){} +void ncbafly_end(void){} -void ncDynamicCam4_update(void) { +void ncbafly_update(void) { f32 sp84[3]; f32 sp78[3]; f32 sp6C[3]; @@ -57,8 +58,8 @@ void ncDynamicCam4_update(void) { ml_vec3f_diff_copy(sp48, sp6C, sp84); sp44 = gu_sqrtf(sp48[0]*sp48[0] + sp48[1]*sp48[1] + sp48[2]*sp48[2]); temp_f10 = (sp3C - sp44) * sp38; - sp44 += func_80259198(temp_f10 * D_8037DB10, sp38 * D_8037DB14); - func_8025727C(sp84[0], sp84[1], sp84[2], sp6C[0], sp6C[1], sp6C[2], &sp54[0], &sp54[1]); + sp44 += ml_clamp_abs_f(temp_f10 * D_8037DB10, sp38 * D_8037DB14); + ml_horizontal_and_vertical_angles(sp84[0], sp84[1], sp84[2], sp6C[0], sp6C[1], sp6C[2], &sp54[0], &sp54[1]); if ((sp34 > 180.0f) && (sp34 < 360.0f)) { sp34 = ml_min_f(100.0f, (f32) ((f64) (360.0f - sp34) * 1.4)); } @@ -67,27 +68,27 @@ void ncDynamicCam4_update(void) { sp48[2] = 0.0f; sp48[0] = (f32) ((f64) sp48[0] * ((f64) sp38 * 0.8)); sp48[1] = sp48[1] * (sp38 * D_8037DB1C); - sp48[0] = func_80259198(sp48[0], sp38 * 40.0f); - sp48[1] = func_80259198(sp48[1], sp38 * D_8037DB20); + sp48[0] = ml_clamp_abs_f(sp48[0], sp38 * 40.0f); + sp48[1] = ml_clamp_abs_f(sp48[1], sp38 * D_8037DB20); sp54[0] = mlNormalizeAngle(sp54[0] + sp48[0]); sp54[1] = mlNormalizeAngle(sp54[1] + sp48[1]); func_80256E24(sp60, -sp54[0], sp54[1], 0.0f, 0.0f, sp44); ml_vec3f_add(sp78, sp84, sp60); ncDynamicCamera_setPosition(sp78); - func_8025727C(sp84[0], sp84[1], sp84[2], sp78[0], sp78[1], sp78[2], &sp54[0], &sp54[1]); + ml_horizontal_and_vertical_angles(sp84[0], sp84[1], sp84[2], sp78[0], sp78[1], sp78[2], &sp54[0], &sp54[1]); sp54[0] = -sp54[0]; sp54[2] = 0.0f; func_802BD720(sp54); } -void ncDynamicCam4_func_802BFE50(f32 arg0, f32 arg1, f32 arg2){ +void ncbafly_func_802BFE50(f32 arg0, f32 arg1, f32 arg2){ D_8037DB10 = arg0; D_8037DB14 = arg1; D_8037DB18 = arg2; } -void ncDynamicCam4_func_802BFE74(bool arg0) { +void ncbafly_func_802BFE74(bool arg0) { if (arg0) { D_8037DB1C = 6.0f; D_8037DB20 = 270.0f; diff --git a/src/core2/camera/randomCamera.c b/src/core2/nc/randomCamera.c similarity index 97% rename from src/core2/camera/randomCamera.c rename to src/core2/nc/randomCamera.c index 36ddf5871..7916a5c10 100644 --- a/src/core2/camera/randomCamera.c +++ b/src/core2/nc/randomCamera.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/nc/randomCamera.c #include #include "core1/core1.h" #include "functions.h" diff --git a/src/core2/camera/staticCamera.c b/src/core2/nc/staticCamera.c similarity index 96% rename from src/core2/camera/staticCamera.c rename to src/core2/nc/staticCamera.c index f62fb0147..58e88e284 100644 --- a/src/core2/camera/staticCamera.c +++ b/src/core2/nc/staticCamera.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/nc/staticCamera.c #include #include "core1/core1.h" #include "functions.h" @@ -19,7 +20,7 @@ void ncStaticCamera_init(void){ void ncStaticCamera_end(void){} void ncStaticCamera_rotateToTarget(f32 target[3]){ - func_8025727C( + ml_horizontal_and_vertical_angles( target[0], target[1], target[2], ncStaticCameraPosition[0], ncStaticCameraPosition[1], ncStaticCameraPosition[2], &ncStaticCameraRotation[0], &ncStaticCameraRotation[1] diff --git a/src/core2/particle/factory.c b/src/core2/particle/commonParticleTypeMap.c similarity index 98% rename from src/core2/particle/factory.c rename to src/core2/particle/commonParticleTypeMap.c index 592db456e..d187c709b 100644 --- a/src/core2/particle/factory.c +++ b/src/core2/particle/commonParticleTypeMap.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/commonParticleTypeMap.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/particle/colordefault.c b/src/core2/particle/dustemitter.c similarity index 98% rename from src/core2/particle/colordefault.c rename to src/core2/particle/dustemitter.c index 524dfd6aa..2dc63ae76 100644 --- a/src/core2/particle/colordefault.c +++ b/src/core2/particle/dustemitter.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/dustemitter.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/particle/emitter1.c b/src/core2/particle/emitter1.c index b3edf8f32..ea01aca00 100644 --- a/src/core2/particle/emitter1.c +++ b/src/core2/particle/emitter1.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_6CD20.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/particle/emitter2.c b/src/core2/particle/emitter2.c index 28df752af..6be9fcee8 100644 --- a/src/core2/particle/emitter2.c +++ b/src/core2/particle/emitter2.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_6CEC0.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/particle/emitterstruct.c b/src/core2/particle/emitterstruct.c index f0e136c48..06c8cffb9 100644 --- a/src/core2/particle/emitterstruct.c +++ b/src/core2/particle/emitterstruct.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_CB050.c #include #include "functions.h" #include "variables.h" @@ -64,7 +65,7 @@ void func_80352114(Struct_core2_CB050_0 *arg0, Struct68s *arg1, f32 arg2) { arg0->unk64 = (f32) (arg0->unk64 + arg2); player_getPosition(player_position); if( (func_80294660() == 0x100) - && func_8028F20C() + && player_isStableWithExtraSteps() && (ml_vec3f_length_sq(player_position, arg0->unk4C) < 50000.0f) ) { sp58 = arg0->unk4C[0] - player_position[0]; diff --git a/src/core2/particle/initcallback.c b/src/core2/particle/initcallback.c index 7afb94169..e00fb760e 100644 --- a/src/core2/particle/initcallback.c +++ b/src/core2/particle/initcallback.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_CBBF0.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/particle/lifescale.c b/src/core2/particle/lifescale.c index a2ca784cb..d08fd8ee2 100644 --- a/src/core2/particle/lifescale.c +++ b/src/core2/particle/lifescale.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_6A4B0.c #include #include "core1/core1.h" #include "functions.h" diff --git a/src/core2/particle/particle.c b/src/core2/particle/particle.c index 025830472..731152222 100644 --- a/src/core2/particle/particle.c +++ b/src/core2/particle/particle.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/particle.c #include #include "core1/core1.h" #include "functions.h" diff --git a/src/core2/particle/accel.c b/src/core2/particle/particleemittermanager.c similarity index 98% rename from src/core2/particle/accel.c rename to src/core2/particle/particleemittermanager.c index 47aac78e1..e501e9c7b 100644 --- a/src/core2/particle/accel.c +++ b/src/core2/particle/particleemittermanager.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/particleemittermanager.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/particle/positionset.c b/src/core2/particle/positionset.c index 1d493cc40..5bd1eecd4 100644 --- a/src/core2/particle/positionset.c +++ b/src/core2/particle/positionset.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_CD0A0.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/particle/samplerate.c b/src/core2/particle/samplerate.c index ee9ebdf7a..4774b0c0c 100644 --- a/src/core2/particle/samplerate.c +++ b/src/core2/particle/samplerate.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_6D490.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/particle/scale1.c b/src/core2/particle/scale1.c index 79802f1d3..13e9c8f2b 100644 --- a/src/core2/particle/scale1.c +++ b/src/core2/particle/scale1.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_66D90.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/particle/scale2.c b/src/core2/particle/scale2.c index 7fded4f8c..d6bac730b 100644 --- a/src/core2/particle/scale2.c +++ b/src/core2/particle/scale2.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_66FB0.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/particle/spawn.c b/src/core2/particle/spawn.c index 8b467a3ca..a2c1eb9fa 100644 --- a/src/core2/particle/spawn.c +++ b/src/core2/particle/spawn.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_6D030.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/particle/typeindex.c b/src/core2/particle/typeindex.c index 88a45f0b9..5feded98f 100644 --- a/src/core2/particle/typeindex.c +++ b/src/core2/particle/typeindex.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_6AEF0.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/particle/velocityrange.c b/src/core2/particle/velocityrange.c index e810851a5..45bbcbf13 100644 --- a/src/core2/particle/velocityrange.c +++ b/src/core2/particle/velocityrange.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_6B030.c #include "core1/core1.h" #include "functions.h" #include "variables.h" diff --git a/src/core2/particle/velocityset.c b/src/core2/particle/velocityset.c index 83d883c84..5728381ee 100644 --- a/src/core2/particle/velocityset.c +++ b/src/core2/particle/velocityset.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_6D270.c #include #include "core1/core1.h" #include "functions.h" diff --git a/src/core2/playerutils.c b/src/core2/playerutils.c index 524aa9a47..6fc927ff6 100644 --- a/src/core2/playerutils.c +++ b/src/core2/playerutils.c @@ -40,7 +40,7 @@ s32 can_climb(void){ return ability_hasLearned(ABILITY_5_CLIMB); } -int can_dive(void){ +bool can_dive(void){ return ability_hasLearned(ABILITY_F_DIVE) && !isPlayerInHazard() && 100.0f < floor_getCurrentFloorYPosition() - func_80294438(); @@ -50,7 +50,7 @@ s32 can_egg(void){ return ability_hasLearned(ABILITY_6_EGGS); } -int can_feathery_flap(void){ +bool can_feathery_flap(void){ return baflag_isFalse(BA_FLAG_12_HAS_FLAPPED) && baflag_isFalse(BA_FLAG_5_HAS_PECKED) && ability_hasLearned(ABILITY_7_FEATHERY_FLAP); @@ -68,18 +68,18 @@ s32 can_control_jump_height(void){ return ability_hasLearned(ABILITY_A_HOLD_A_JUMP_HIGHER); } -int can_peck(void){ +bool can_peck(void){ return baflag_isFalse(BA_FLAG_5_HAS_PECKED) && baflag_isFalse(BA_FLAG_12_HAS_FLAPPED) && ability_hasLearned(ABILITY_B_RATATAT_RAP); } -int func_8028ABB8(void){ +bool func_8028ABB8(void){ if(baflag_isTrue(BA_FLAG_14_LOSE_BOGGY_RACE) || baflag_isTrue(BA_FLAG_19_SHOULD_TRANSFORM)) - return 0; + return false; if(bs_getState() == BS_56_RECOIL) - return 0; - return 1; + return false; + return true; } s32 can_roll(void){ @@ -106,32 +106,32 @@ s32 can_wonderwing(void){ return ability_hasLearned(ABILITY_12_WONDERWING); } -int can_view_first_person(void){ +bool can_view_first_person(void){ if( gsworld_getMap() == MAP_27_FP_FREEZEEZY_PEAK && mapSpecificFlags_get(0xd)){ - return 0; + return false; } - if(ncFirstPersonCamera_getState() == FIRSTPERSON_STATE_3_EXIT) - return 0; + if(ncba1p_getState() == FIRSTPERSON_STATE_3_EXIT) + return false; if(!player_isStable() && !player_inWater()) - return 0; - return 1; + return false; + return true; } -int dummy_player_is_ant(void){ +bool dummy_player_is_ant(void){ return bsant_inSet(bs_getState()); } -int dummy_player_is_pumpkin(void){ +bool dummy_player_is_pumpkin(void){ return bspumpkin_inSet(bs_getState()); } -int func_8028ADB4(void){ +bool func_8028ADB4(void){ return func_8032190C() && gsworld_getMap() != MAP_1_SM_SPIRAL_MOUNTAIN; } -int wishyWashyFlag_get(void){ +bool wishyWashyFlag_get(void){ return volatileFlag_get(VOLATILE_FLAG_9D_SANDCASTLE_WISHY_WASHY); } @@ -141,7 +141,7 @@ bool dummy_player_withinIdealYaw(void) { f32 position[3]; f32 ideal_yaw; - _player_getPosition(position); + playerPosition_get(position); ideal_yaw = yaw_getIdeal(); right_angle = viewport_adjustAngleToRight(position, 90.0f); left_angle = viewport_adjustAngleToRight(position, 270.0f); @@ -153,37 +153,37 @@ bool dummy_player_withinIdealYaw(void) { } } -bool func_8028AED4(f32 arg0[3], f32 arg1) { - f32 position[3]; - f32 sp28; +bool func_8028AED4(f32 src_position[3], f32 arg1) { + f32 player_position[3]; + f32 yaw; u16 sp26; u16 sp24; s32 temp_v1; s32 phi_a0; - _player_getPosition(position); - func_80257F18(arg0, position, &sp28); - sp26 = (u16) (sp28 * 182.044444); + playerPosition_get(player_position); + func_80257F18(src_position, player_position, &yaw); + sp26 = (u16) (yaw * 182.044444); sp24 = (u16) (player_getYaw() * 182.044444); sp26 = (u16)((sp26 - sp24)); - temp_v1 = 0x8000 - sp26; + temp_v1 = 0x8000 - sp26; // Flip sign? phi_a0 = (temp_v1 >= 0) ? temp_v1 : -temp_v1; return (phi_a0 < arg1 * 182.044444); } -int player_shouldFall(void){ - return (60.0f < player_getYPosition() - func_80294438()); +bool player_shouldFall(void){ + return (60.0f < playerPosition_getY() - func_80294438()); } -int player_isInHorizontalRadius(f32 arg0[3], f32 arg1){ +bool player_isInHorizontalRadius(f32 arg0[3], f32 arg1){ f32 sp1C[3]; - _player_getPosition(sp1C); + playerPosition_get(sp1C); return ml_vec3f_point_within_horizontal_distance(sp1C, arg0[0], arg0[2], arg1); } s32 func_8028B120(void){return 0;} -int player_isOnDangerousGround(void){ +bool player_isOnDangerousGround(void){ return baflag_isTrue(BA_FLAG_13_TOUCHING_DANGEROUS_GROUND); } @@ -194,29 +194,29 @@ bool player_isInRBB(void){ bool player_isInVerticalRange(f32 position[3], f32 range) { f32 plyr_pos[3]; - _player_getPosition(plyr_pos); + playerPosition_get(plyr_pos); return (((position[1] - range) <= plyr_pos[1]) && (plyr_pos[1] <= (position[1] + range))); } -int player_shouldSlideTrot(void){ +bool player_shouldSlideTrot(void){ return stateTimer_isActive(STATE_TIMER_6_UNKNOWN) || (1.0 == get_slope_timer() && func_80294610(0x40)); } bool func_8028B254(s32 arg0) { - return (player_isStable() || (baphysics_get_vertical_velocity() < 0.0f && (player_getYPosition() - func_80294438()) < (f32) arg0)); + return (player_isStable() || (baphysics_get_vertical_velocity() < 0.0f && (playerPosition_getY() - func_80294438()) < (f32) arg0)); } -int player_isStable(void){ +bool player_isStable(void){ return D_8037BF60 && baphysics_get_vertical_velocity() < 0.0f; } -int player_isSliding(void){ +bool player_isSliding(void){ return stateTimer_isActive(STATE_TIMER_5_UNKNOWN) || 1.0 == get_slope_timer(); } -int func_8028B394(void){ +bool func_8028B394(void){ return func_8029CF20(4); } @@ -261,15 +261,15 @@ bool player_isSwimming(void){ return out; } -int func_8028B4C4(void){ +bool func_8028B4C4(void){ return 135.0f < mlAbsF(mlDiffDegF(yaw_getIdeal(), yaw_get())); } -int player_inWater(void){ +bool player_inWater(void){ return D_8037BF61; } -int func_8028B528(void){ +bool func_8028B528(void){ return D_8037BF62; } @@ -290,9 +290,9 @@ void func_8028B59C(void) { sp24 = D_8037BF61; if (D_8037BF61) { - D_8037BF61 = (func_80294554() && player_getYPosition() < ((floor_getCurrentFloorYPosition() - 50.0f) + 2.0f)); + D_8037BF61 = (func_80294554() && playerPosition_getY() < ((floor_getCurrentFloorYPosition() - 50.0f) + 2.0f)); } else { - D_8037BF61 = (func_80294554() && player_getYPosition() < ((floor_getCurrentFloorYPosition() - 50.0f) - 2.0f)); + D_8037BF61 = (func_80294554() && playerPosition_getY() < ((floor_getCurrentFloorYPosition() - 50.0f) - 2.0f)); } if (gsworld_getMap() == MAP_6_TTC_NIPPERS_SHELL) { D_8037BF61 = false; diff --git a/src/core2/prop_assetcache.c b/src/core2/propModelList.c similarity index 99% rename from src/core2/prop_assetcache.c rename to src/core2/propModelList.c index 9db6a69a2..7dd8feb07 100644 --- a/src/core2/prop_assetcache.c +++ b/src/core2/propModelList.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/propModelList.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/quiz/game.c b/src/core2/quiz/game.c index bd961da9d..3a45fd3a1 100644 --- a/src/core2/quiz/game.c +++ b/src/core2/quiz/game.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_4C020.c #include "core1/core1.h" #include "functions.h" #include "variables.h" @@ -15,25 +16,25 @@ extern void gcquiz_func_80319EA4(void); extern void port_lairWater_onRiseTrigger(int32_t waterMap, int32_t levelFlag); extern int32_t port_lairWater_targetLevel(int32_t map, int32_t flagLevel); -void func_802D3D54(Actor *this); -void func_802D3DA4(Actor *this); -Actor *func_802D3F48(ActorMarker *this, Gfx **gdl, Mtx **mptr, Vtx **arg3); -void func_802D3FD4(Actor *this); -Actor *func_802D41C4(ActorMarker *this, Gfx **gdl, Mtx **mptr, Vtx **arg3); -void func_802D4250(Actor *this); -void func_802D4388(Actor *this); -Actor *func_802D4588(ActorMarker *this, Gfx **gdl, Mtx **mptr, Vtx **arg3); -void func_802D4680(Actor *this); -void func_802D4B94(Actor *this); -void func_802D4BBC(Actor *this); -void func_802D4BE4(Actor *this); -void func_802D4C0C(Actor *this); -void func_802D4C34(Actor *this); -void func_802D4C5C(Actor *this); -void func_802D4C84(Actor *this); -void func_802D4CAC(Actor *this); -void func_802D4CD4(Actor *this); -void func_802D68F0(s32 seconds); +void chMMMBreakableWooden_update(Actor *this); +void gWorldExitPad_update(Actor *this); +Actor *gWorldExitPad_draw(ActorMarker *this, Gfx **gdl, Mtx **mptr, Vtx **arg3); +void chSnsEgg_update(Actor *this); +Actor *chSnsEgg_draw(ActorMarker *this, Gfx **gdl, Mtx **mptr, Vtx **arg3); +void chIceKey_update(Actor *this); +void chMumboSwitch_update(Actor *this); +Actor *chMumboSwitch_draw(ActorMarker *this, Gfx **gdl, Mtx **mptr, Vtx **arg3); +void chFFTeleportPad_Update(Actor *this); +void chMMWitchSwitch_update(Actor *this); +void chCCWitchSwitch_update(Actor *this); +void chBGSWitchSwitch_update(Actor *this); +void chGVWitchSwitch_update(Actor *this); +void chMMMWitchSwitch_update(Actor *this); +void chTTCWitchSwitch_update(Actor *this); +void chRBBWitchSwitch_update(Actor *this); +void chCCWWitchSwitch_update(Actor *this); +void chFPWitchSwitch_update(Actor *this); +void code_4C020_setHourglassTimer(s32 seconds); typedef struct { s16 unk0; @@ -56,7 +57,7 @@ f32 D_803676A4 = 0.0f; s32 D_803676A8 = 0; u8 D_803676AC = 0; -ActorAnimationInfo D_803676B0[] = { +ActorAnimationInfo gSwitchAnimations[] = { {0x000, 0.0f}, {0x000, 0.0f}, {ASSET_D4_ANIM_SWITCH_DOWN, 0.15f}, @@ -81,24 +82,67 @@ ActorAnimationInfo D_803676B0[] = { {ASSET_217_ANIM_UNKNOWN, 0.3f} }; -ActorInfo D_80367760 = { 0x26E, 0x2D9, 0x3B4, 0x1, NULL, func_802D3D54, actor_update_func_80326224, actor_drawFullDepth, 0, 0, 0.0f, 0}; -ActorInfo D_80367784 = { 0x26F, 0x2DA, 0x3B5, 0x1, NULL, func_802D3D54, actor_update_func_80326224, actor_drawFullDepth, 0, 0, 0.0f, 0}; -ActorInfo D_803677A8 = { MARKER_168_ICE_KEY, ACTOR_25D_ICE_KEY, ASSET_50C_MODEL_ICE_KEY, 0x1, NULL, func_802D4250, actor_update_func_80326224, actor_drawFullDepth, 0, 0, 0.0f, 0}; -ActorInfo D_803677CC = { 0x233, 0x23D, 0x4DD, 0x12, D_803676B0, func_802D4388, actor_update_func_80326224, func_802D4588, 0, 0, 0.0f, 0}; -ActorInfo D_803677F0 = { 0x16A, 0x242, 0x0, 0x0, NULL, func_802D4680, NULL, func_80325340, 0, 0, 0.0f, 0}; -ActorInfo D_80367814 = { MARKER_169_SNS_EGG, ACTOR_25E_SNS_EGG, ASSET_50D_MODEL_SNS_EGG, 0x1, NULL, func_802D3FD4, NULL, func_802D41C4, 0, 0, 0.0f, 0}; -ActorInfo D_80367838 = { 0x265, 0x2E4, 0x55A, 0x1, NULL, func_802D3DA4, NULL, func_802D3F48, 0, 0, 0.0f, 0}; -ActorInfo D_8036785C = { MARKER_103_MM_WITCH_SWITCH, ACTOR_204_MM_WITCH_SWITCH, ASSET_4DC_MODEL_WITCH_SWITCH, 0x1, D_803676B0, func_802D4B94, actor_update_func_80326224, actor_draw, 0, 0, 0.0f, 0}; -ActorInfo D_80367880 = { MARKER_104_MMM_WITCH_SWITCH, ACTOR_206_MMM_WITCH_SWITCH, ASSET_4DC_MODEL_WITCH_SWITCH, 0x1, D_803676B0, func_802D4C34, actor_update_func_80326224, actor_draw, 0, 0, 0.0f, 0}; -ActorInfo D_803678A4 = { MARKER_105_TTC_WITCH_SWITCH, ACTOR_208_TTC_WITCH_SWITCH, ASSET_4DC_MODEL_WITCH_SWITCH, 0x1, D_803676B0, func_802D4C5C, actor_update_func_80326224, actor_draw, 0, 0, 0.0f, 0}; -ActorInfo D_803678C8 = { MARKER_106_RBB_WITCH_SWITCH, ACTOR_20B_RBB_WITCH_SWITCH, ASSET_4DC_MODEL_WITCH_SWITCH, 0x1, D_803676B0, func_802D4C84, actor_update_func_80326224, actor_draw, 0, 0, 0.0f, 0}; -ActorInfo D_803678EC = { MARKER_22A_CCW_WITCH_SWITCH, ACTOR_237_CCW_WITCH_SWITCH, ASSET_4DC_MODEL_WITCH_SWITCH, 0x1, D_803676B0, func_802D4CAC, actor_update_func_80326224, actor_draw, 0, 0, 0.0f, 0}; -ActorInfo D_80367910 = { MARKER_22B_FP_WITCH_SWITCH, ACTOR_239_FP_WITCH_SWITCH, ASSET_4DC_MODEL_WITCH_SWITCH, 0x1, D_803676B0, func_802D4CD4, actor_update_func_80326224, actor_draw, 0, 0, 0.0f, 0}; -ActorInfo D_80367934 = { MARKER_166_CC_WITCH_SWITCH, ACTOR_25B_CC_WITCH_SWITCH, ASSET_4DC_MODEL_WITCH_SWITCH, 0x1, D_803676B0, func_802D4BBC, actor_update_func_80326224, actor_draw, 0, 0, 0.0f, 0}; -ActorInfo D_80367958 = { MARKER_162_BGS_WITCH_SWITCH, ACTOR_257_BGS_WITCH_SWITCH, ASSET_4DC_MODEL_WITCH_SWITCH, 0x1, D_803676B0, func_802D4BE4, actor_update_func_80326224, actor_draw, 0, 0, 0.0f, 0}; -ActorInfo D_8036797C = { MARKER_161_GV_WITCH_SWITCH, ACTOR_256_GV_WITCH_SWITCH, ASSET_4DC_MODEL_WITCH_SWITCH, 0x1, D_803676B0, func_802D4C0C, actor_update_func_80326224, actor_draw, 0, 0, 0.0f, 0}; +ActorInfo D_80367760 = { + MARKER_26E_UNKNOWN, ACTOR_2D9_UNKNOWN, ASSET_3B4_MODEL_UNUSED, + 0x1, NULL, + chMMMBreakableWooden_update, actor_update_func_80326224, actor_drawFullDepth, + 0, 0, 0.0f, 0 +}; + +ActorInfo D_80367784 = { + MARKER_26F_UNKNOWN, ACTOR_2DA_UNKNOWN, ASSET_3B5_MODEL_UNUSED, + 0x1, NULL, + chMMMBreakableWooden_update, actor_update_func_80326224, actor_drawFullDepth, + 0, 0, 0.0f, 0 +}; + +ActorInfo chIceKey = { + MARKER_168_ICE_KEY, ACTOR_25D_ICE_KEY, ASSET_50C_MODEL_ICE_KEY, + 0x1, NULL, + chIceKey_update, actor_update_func_80326224, actor_drawFullDepth, + 0, 0, 0.0f, 0 +}; + +ActorInfo chMumboSwitch = { + MARKER_233_MUMBO_SWITCH, ACTOR_23D_MUMBO_SWITCH, ASSET_4DD_MODEL_MUMBO_SWITCH, + 0x12, gSwitchAnimations, + chMumboSwitch_update, actor_update_func_80326224, chMumboSwitch_draw, + 0, 0, 0.0f, 0 +}; + +ActorInfo chFFTeleportPad = { + MARKER_16A_FF_TELEPORT_PAD, ACTOR_242_FF_TELEPORT_PAD, 0x0, + 0x0, NULL, + chFFTeleportPad_Update, NULL, func_80325340, + 0, 0, 0.0f, 0 +}; + +ActorInfo chSnsEgg = { + MARKER_169_SNS_EGG, ACTOR_25E_SNS_EGG, ASSET_50D_MODEL_SNS_EGG, + 0x1, NULL, + chSnsEgg_update, NULL, chSnsEgg_draw, + 0, 0, 0.0f, 0 +}; + +ActorInfo gWorldExitPad = { + MARKER_265_WORLD_EXIT_PAD, ACTOR_2E4_WORLD_EXIT_PAD, ASSET_55A_MODEL_WORLD_EXIT_PAD, + 0x1, NULL, + gWorldExitPad_update, NULL, gWorldExitPad_draw, + 0, 0, 0.0f, 0 +}; + +ActorInfo chMMWitchSwitch = { MARKER_103_MM_WITCH_SWITCH, ACTOR_204_MM_WITCH_SWITCH, ASSET_4DC_MODEL_WITCH_SWITCH, 0x1, gSwitchAnimations, chMMWitchSwitch_update, actor_update_func_80326224, actor_draw, 0, 0, 0.0f, 0}; +ActorInfo chMMMWitchSwitch = { MARKER_104_MMM_WITCH_SWITCH, ACTOR_206_MMM_WITCH_SWITCH, ASSET_4DC_MODEL_WITCH_SWITCH, 0x1, gSwitchAnimations, chMMMWitchSwitch_update, actor_update_func_80326224, actor_draw, 0, 0, 0.0f, 0}; +ActorInfo chTTCWitchSwitch = { MARKER_105_TTC_WITCH_SWITCH, ACTOR_208_TTC_WITCH_SWITCH, ASSET_4DC_MODEL_WITCH_SWITCH, 0x1, gSwitchAnimations, chTTCWitchSwitch_update, actor_update_func_80326224, actor_draw, 0, 0, 0.0f, 0}; +ActorInfo chRBBWitchSwitch = { MARKER_106_RBB_WITCH_SWITCH, ACTOR_20B_RBB_WITCH_SWITCH, ASSET_4DC_MODEL_WITCH_SWITCH, 0x1, gSwitchAnimations, chRBBWitchSwitch_update, actor_update_func_80326224, actor_draw, 0, 0, 0.0f, 0}; +ActorInfo chCCWWitchSwitch = { MARKER_22A_CCW_WITCH_SWITCH, ACTOR_237_CCW_WITCH_SWITCH, ASSET_4DC_MODEL_WITCH_SWITCH, 0x1, gSwitchAnimations, chCCWWitchSwitch_update, actor_update_func_80326224, actor_draw, 0, 0, 0.0f, 0}; +ActorInfo chFPWitchSwitch = { MARKER_22B_FP_WITCH_SWITCH, ACTOR_239_FP_WITCH_SWITCH, ASSET_4DC_MODEL_WITCH_SWITCH, 0x1, gSwitchAnimations, chFPWitchSwitch_update, actor_update_func_80326224, actor_draw, 0, 0, 0.0f, 0}; +ActorInfo chCCWitchSwitch = { MARKER_166_CC_WITCH_SWITCH, ACTOR_25B_CC_WITCH_SWITCH, ASSET_4DC_MODEL_WITCH_SWITCH, 0x1, gSwitchAnimations, chCCWitchSwitch_update, actor_update_func_80326224, actor_draw, 0, 0, 0.0f, 0}; +ActorInfo chBGSWitchSwitch = { MARKER_162_BGS_WITCH_SWITCH, ACTOR_257_BGS_WITCH_SWITCH, ASSET_4DC_MODEL_WITCH_SWITCH, 0x1, gSwitchAnimations, chBGSWitchSwitch_update, actor_update_func_80326224, actor_draw, 0, 0, 0.0f, 0}; +ActorInfo chGVWitchSwitch = { MARKER_161_GV_WITCH_SWITCH, ACTOR_256_GV_WITCH_SWITCH, ASSET_4DC_MODEL_WITCH_SWITCH, 0x1, gSwitchAnimations, chGVWitchSwitch_update, actor_update_func_80326224, actor_draw, 0, 0, 0.0f, 0}; s32 D_803679A0[4] = {0x87, 0x87, 0x87, 0xA0}; + s16 D_803679B0[] = { FILEPROG_5_BLUE_EGG_TEXT, FILEPROG_90_PAID_TERMITE_COST, @@ -118,6 +162,7 @@ Struct_core2_4C020_0 D_803679C8[] = { {-580, 0, 1550, 2200}, {150, 460, 1625, 2100}, }; + s16 D_803679E0[] = {-50, -100, 200}; /* .bss */ @@ -151,14 +196,16 @@ void func_802D2FB0(Actor *this, s32 arg1, s32 arg2, s32 arg3, f32 arg4, s32 arg5 // collision function if player shoots egg at spider webs void func_802D3138(ActorMarker *marker, ActorMarker *other_marker) { - if(marker->id == MARKER_224_BREAKABLE_FLOOR_COBWEB || marker->id == MARKER_225_BREAKABLE_WALL_COBWEB) { + if(marker->id == MARKER_224_BREAKABLE_FLOOR_COBWEB + || marker->id == MARKER_225_BREAKABLE_WALL_COBWEB) + { comusic_playTrack(COMUSIC_2B_DING_B); } } // called from collision die function below, set according file flag and despawns object -void func_802D317C(ActorMarker *marker, enum file_progress_e prog_flag_id) { - fileProgressFlag_set(prog_flag_id, true); +void code_4C020_breakableObjectSetFlag(ActorMarker *marker, enum file_progress_e prog_flag_id) { + fileProgressFlag_set(prog_flag_id, TRUE); marker_despawn(marker); } @@ -166,215 +213,216 @@ extern void port_breakable_broadcastBreak(s32 markerId, s32 x, s32 y, s32 z); extern s32 port_breakable_isBroken(s32 map, s32 markerId, s32 x, s32 y, s32 z); // collision die function for several objects in Lair -void func_802D31AC(ActorMarker *arg0, ActorMarker * arg1) { - Actor *sp2C; - - sp2C = marker_getActor(arg0); - arg0->collidable = false; - switch (arg0->id) { - case 0x9F: - case 0xA0: - case 0xFF: - gcsfx_playAtSampleRate(SFX_82_METAL_BREAK); - subaddie_set_state(sp2C, 4); - port_breakable_broadcastBreak(arg0->id, (s32)sp2C->position[0], (s32)sp2C->position[1], (s32)sp2C->position[2]); +void code_4C020_breakableObjectSfx(ActorMarker *marker, ActorMarker *other_marker) { + Actor *actor; + + actor = marker_getActor(marker); + marker->collidable = FALSE; + switch (marker->id) { + case MARKER_9F_CHURCH_GATE_LEFT_LOCK: + case MARKER_A0_HEDGE_GATE_RIGHT_LOCK_1: + case MARKER_FF_HEDGE_GATE_RIGHT_LOCK_2: + gcsfx_play(SFX_82_METAL_BREAK); + subaddie_set_state(actor, 4); + port_breakable_broadcastBreak(marker->id, (s32)actor->position[0], (s32)actor->position[1], (s32)actor->position[2]); break; - case 0x17D: + case MARKER_17D_IRON_GATE_NO_LOCK: FUNC_8030E624(SFX_82_METAL_BREAK, 0.7f, 32736); FUNC_8030E624(SFX_82_METAL_BREAK, 0.6f, 32736); - func_802D2FB0(sp2C, 0x14, -0x1E, 0x190, 3.0f, 0x15E, 0x50, 0x96); - sp2C->lifetime_value = 1.0f; + func_802D2FB0(actor, 0x14, -0x1E, 0x190, 3.0f, 0x15E, 0x50, 0x96); + actor->lifetime_value = 1.0f; fileProgressFlag_set(FILEPROG_A5_LAIR_CRYPT_GATE_OPEN, 1); break; case MARKER_109_BREAKABLE_BRICK_WALL: func_8030E6D4(SFX_114_BRICKWALL_BREAKING); - sfxsource_play(SFX_11_WOOD_BREAKING_1, 28000); - subaddie_set_state_looped(sp2C, 9); - fileProgressFlag_set((sp2C->actorTypeSpecificField == 1) ? FILEPROG_C8_LAIR_BRICKWALL_TO_WADINGBOOTS_BROKEN : FILEPROG_C9_LAIR_BRICKWALL_TO_SHOCKJUMP_PAD_BROKEN, true); + gcsfx_playAtSampleRate(SFX_11_WOOD_BREAKING_1, 28000); + subaddie_set_state_looped(actor, 9); + fileProgressFlag_set((actor->actorTypeSpecificField == 1) ? FILEPROG_C8_LAIR_BRICKWALL_TO_WADINGBOOTS_BROKEN : FILEPROG_C9_LAIR_BRICKWALL_TO_SHOCKJUMP_PAD_BROKEN, TRUE); break; - case 0x107: - gcsfx_playAtSampleRate(SFX_82_METAL_BREAK); - func_802EE278(sp2C, 0xE, 0xF, 0x46, 0.8f, 0.7f); - port_breakable_broadcastBreak(arg0->id, (s32)sp2C->position[0], (s32)sp2C->position[1], (s32)sp2C->position[2]); - marker_despawn(arg0); + case MARKER_107_ENGINE_ROOM_DOOR: + gcsfx_play(SFX_82_METAL_BREAK); + func_802EE278(actor, 0xE, 0xF, 0x46, 0.8f, 0.7f); + port_breakable_broadcastBreak(marker->id, (s32)actor->position[0], (s32)actor->position[1], (s32)actor->position[2]); + marker_despawn(marker); break; case MARKER_224_BREAKABLE_FLOOR_COBWEB: comusic_playTrack(COMUSIC_2B_DING_B); - gcsfx_playWithPitch(SFX_129_SWOOSH, (sp2C->scale < 0.45) ? 1.0 : 0.8, 0x7FF8); - subaddie_set_state_looped(sp2C, 0xC); - func_802D2FB0(sp2C, 8, -0x3C, 0xC8, 2.0f, 0xFA, 0x3C, 0x64); - fileProgressFlag_set((sp2C->actorTypeSpecificField== 1) ? FILEPROG_CB_LAIR_COBWEB_OVER_FLIGHTPAD_BROKEN : FILEPROG_CC_LAIR_COBWEB_OVER_GREEN_CAULDRON_BROKEN, 1); + gcsfx_playWithPitch(SFX_129_SWOOSH, (actor->scale < 0.45) ? 1.0 : 0.8, 0x7FF8); + subaddie_set_state_looped(actor, 0xC); + func_802D2FB0(actor, 8, -0x3C, 0xC8, 2.0f, 0xFA, 0x3C, 0x64); + fileProgressFlag_set((actor->actorTypeSpecificField== 1) ? FILEPROG_CB_LAIR_COBWEB_OVER_FLIGHTPAD_BROKEN : FILEPROG_CC_LAIR_COBWEB_OVER_GREEN_CAULDRON_BROKEN, 1); break; case MARKER_225_BREAKABLE_WALL_COBWEB: comusic_playTrack(COMUSIC_2B_DING_B); - gcsfx_playAtSampleRate(SFX_129_SWOOSH); - subaddie_set_state_looped(sp2C, 0xF); - func_802D2FB0(sp2C, 0xE, -0x3C, 0xC8, 2.0f, 0xFA, 0x3C, 0x64); + gcsfx_play(SFX_129_SWOOSH); + subaddie_set_state_looped(actor, 0xF); + func_802D2FB0(actor, 0xE, -0x3C, 0xC8, 2.0f, 0xFA, 0x3C, 0x64); fileProgressFlag_set(FILEPROG_CA_COBWEB_BLOCKING_PURPLE_CAULDRON_BROKEN, 1); break; - case 0x163: - if (sp2C->unk10_12 == 0) { - sp2C->unk10_12 = true; + case MARKER_163_CRYPT_COFFIN_LID: + if (actor->unk10_12 == 0) { + actor->unk10_12 = TRUE; timed_playSfx(0.5f, SFX_3F9_UNKNOWN, 1.0f, 32000); FUNC_8030E624(SFX_114_BRICKWALL_BREAKING, 0.8f, 32000); } break; - case 0x9A: - case 0x9C: - case 0x9D: - case 0x9E: - case 0xA1: - case 0xE7: - case 0xEA: - case 0x108: - case 0x263: - if ((arg0->id == 0x9D) || (arg0->id == 0xE7)) { + case MARKER_9A_1881_BARREL_TOP: + case MARKER_9C_SHACK_DOOR: + case MARKER_9D_MANSION_DOOR: + case MARKER_9E_CELLAR_HATCH: + case MARKER_A1_BLUBBER_SHIP_TOP_HATCH: + case MARKER_E7_DINING_DOOR: + case MARKER_EA_LIGHTHOUSE_DOOR: + case MARKER_108_CABIN_CLOSET_DOOR: + case MARKER_263_CCW_WHIPCRACK_ROOM_DOOR: + if ((marker->id == MARKER_9D_MANSION_DOOR) || (marker->id == MARKER_E7_DINING_DOOR)) { levelSpecificFlags_set(LEVEL_FLAG_2E_MMM_UNKNOWN, 1); } - if (arg0->id == 0x263) { + if (marker->id == MARKER_263_CCW_WHIPCRACK_ROOM_DOOR) { levelSpecificFlags_set(LEVEL_FLAG_38_CCW_UNKNOWN, 1); } - func_802D2FB0(sp2C, 5, -0x28, 0xC8, 0.85f, 0xDC, 0x3C, 0x64); - gcsfx_playAtSampleRate(SFX_D_EGGSHELL_BREAKING); - gcsfx_playAtSampleRate(SFX_11_WOOD_BREAKING_1); - switch (arg0->id) { - case 0x9E: - func_802EE278(sp2C, 0xD, 9, 0x82, 0.34f, 1.0f); + func_802D2FB0(actor, 5, -0x28, 0xC8, 0.85f, 0xDC, 0x3C, 0x64); + gcsfx_play(SFX_D_EGGSHELL_BREAKING); + gcsfx_play(SFX_11_WOOD_BREAKING_1); + switch (marker->id) { + case MARKER_9E_CELLAR_HATCH: + func_802EE278(actor, 0xD, 9, 0x82, 0.34f, 1.0f); break; - case 0x9D: - case 0xE7: - case 0x108: - func_802EE278(sp2C, 7, 6, 0x32, 0.4f, 1.1f); - func_802EE278(sp2C, 7, 6, 0xB4, 0.4f, 1.1f); + case MARKER_9D_MANSION_DOOR: + case MARKER_E7_DINING_DOOR: + case MARKER_108_CABIN_CLOSET_DOOR: + func_802EE278(actor, 7, 6, 0x32, 0.4f, 1.1f); + func_802EE278(actor, 7, 6, 0xB4, 0.4f, 1.1f); break; - case 0x9A: - case 0x9C: - case 0x263: - func_802EE278(sp2C, 7, 0xA, 0x82, 0.3f, 0.8f); + case MARKER_9A_1881_BARREL_TOP: + case MARKER_9C_SHACK_DOOR: + case MARKER_263_CCW_WHIPCRACK_ROOM_DOOR: + func_802EE278(actor, 7, 0xA, 0x82, 0.3f, 0.8f); break; - case 0xA1: - func_802EE278(sp2C, 7, 9, 0x82, 0.3f, 0.6f); + case MARKER_A1_BLUBBER_SHIP_TOP_HATCH: + func_802EE278(actor, 7, 9, 0x82, 0.3f, 0.6f); break; - case 0xEA: - func_802EE278(sp2C, 3, 9, 0x82, 0.21f, 0.8f); + case MARKER_EA_LIGHTHOUSE_DOOR: + func_802EE278(actor, 3, 9, 0x82, 0.21f, 0.8f); break; default: - func_802EE278(sp2C, 7, 0x19, 0x82, 0.17f, 0.8f); + func_802EE278(actor, 7, 0x19, 0x82, 0.17f, 0.8f); break; } - port_breakable_broadcastBreak(arg0->id, (s32)sp2C->position[0], (s32)sp2C->position[1], (s32)sp2C->position[2]); - marker_despawn(arg0); + port_breakable_broadcastBreak(marker->id, (s32)actor->position[0], (s32)actor->position[1], (s32)actor->position[2]); + marker_despawn(marker); break; - case 0x11F: - gcsfx_playAtSampleRate(SFX_D9_WOODEN_CRATE_BREAKING_1); - func_802EE2E8(sp2C, 7, 9, 0x78, 0.43f, 1.3f, 3.0f); - func_802EE2E8(sp2C, 3, 6, 0x78, 0.43f, 1.3f, 3.0f); - func_802D317C(arg0, FILEPROG_C5_RAREWARE_BOX_BROKEN); + case MARKER_11F_RAREWARE_BOX: + gcsfx_play(SFX_D9_WOODEN_CRATE_BREAKING_1); + func_802EE2E8(actor, 7, 9, 0x78, 0.43f, 1.3f, 3.0f); + func_802EE2E8(actor, 3, 6, 0x78, 0.43f, 1.3f, 3.0f); + code_4C020_breakableObjectSetFlag(marker, FILEPROG_C5_RAREWARE_BOX_BROKEN); break; - case 0x11A: - gcsfx_playAtSampleRate(SFX_82_METAL_BREAK); - func_802EE278(sp2C, 0xE, 0xD, 0x32, 0.8f, 0.9f); - func_802EE278(sp2C, 0xE, 0xD, 0xAA, 0.8f, 0.9f); - func_802D317C(arg0, FILEPROG_C2_GRATE_TO_RBB_PUZZLE_OPEN); + case MARKER_11A_GRATE_TO_RBB_PUZZLE: + gcsfx_play(SFX_82_METAL_BREAK); + func_802EE278(actor, 0xE, 0xD, 0x32, 0.8f, 0.9f); + func_802EE278(actor, 0xE, 0xD, 0xAA, 0.8f, 0.9f); + code_4C020_breakableObjectSetFlag(marker, FILEPROG_C2_GRATE_TO_RBB_PUZZLE_OPEN); break; - case 0x118: - gcsfx_playAtSampleRate(SFX_82_METAL_BREAK); - func_802EE278(sp2C, 0xE, 0xD, 0x50, 1.2f, 0.9f); - func_802EE278(sp2C, 0xE, 0xD, 0xB4, 1.2f, 0.9f); - func_802D317C(arg0, FILEPROG_CD_GRATE_TO_WATER_SWITCH_3_OPEN); + case MARKER_118_GRATE_TO_LEVEL_3_WATER_SWITCH: + gcsfx_play(SFX_82_METAL_BREAK); + func_802EE278(actor, 0xE, 0xD, 0x50, 1.2f, 0.9f); + func_802EE278(actor, 0xE, 0xD, 0xB4, 1.2f, 0.9f); + code_4C020_breakableObjectSetFlag(marker, FILEPROG_CD_GRATE_TO_WATER_SWITCH_3_OPEN); break; - case 0x119: - gcsfx_playAtSampleRate(SFX_82_METAL_BREAK); - func_802EE278(sp2C, 0xE, 9, 0x50, 1.2f, 0.9f); - func_802EE278(sp2C, 0xE, 9, 0xAA, 1.2f, 0.9f); - func_802EE278(sp2C, 0xE, 9, 0x104, 1.2f, 0.9f); - func_802D317C(arg0, FILEPROG_CE_GRATE_TO_MMM_PUZZLE_OPEN); + case MARKER_119_GRATE_BETWEEN_MMM_AND_RBB_PUZZLES: + gcsfx_play(SFX_82_METAL_BREAK); + func_802EE278(actor, 0xE, 9, 0x50, 1.2f, 0.9f); + func_802EE278(actor, 0xE, 9, 0xAA, 1.2f, 0.9f); + func_802EE278(actor, 0xE, 9, 0x104, 1.2f, 0.9f); + code_4C020_breakableObjectSetFlag(marker, FILEPROG_CE_GRATE_TO_MMM_PUZZLE_OPEN); break; - case 0x22D: - case 0x22E: - gcsfx_playAtSampleRate(SFX_82_METAL_BREAK); - gcsfx_playAtSampleRate(SFX_B6_GLASS_BREAKING_1); - func_802EE278(sp2C, 4, 0x23, 0x1E, 0.7f, 0.6f); - port_breakable_broadcastBreak(arg0->id, (s32)sp2C->position[0], (s32)sp2C->position[1], (s32)sp2C->position[2]); - marker_despawn(arg0); + case MARKER_22D_SHIP_SHADOW_WINDOW: + case MARKER_22E_SHIP_SUNNY_WINDOW: + gcsfx_play(SFX_82_METAL_BREAK); + gcsfx_play(SFX_B6_GLASS_BREAKING_1); + func_802EE278(actor, 4, 0x23, 0x1E, 0.7f, 0.6f); + port_breakable_broadcastBreak(marker->id, (s32)actor->position[0], (s32)actor->position[1], (s32)actor->position[2]); + marker_despawn(marker); break; - case 0x123: - case 0x1F2: - case 0x1F3: - case 0x235: - case 0x236: - case 0x237: - case 0x238: - case 0x239: - gcsfx_playAtSampleRate(SFX_13A_GLASS_BREAKING_7); - func_802EE278(sp2C, 4, 0x2D, 0x82, 1.0f, 1.0f); - if (arg0->id == 0x1F3) { - func_802EE278(sp2C, 4, 0x2D, 0x104, 1.0f, 1.0f); + case MARKER_123_WINDOW: + case MARKER_1F2_WIDE_WINDOW: + case MARKER_1F3_TALL_WINDOW: + case MARKER_235_CRACKED_SKYLIGHT: + case MARKER_236_CCW_UNKNOWN_NABNUT_WINDOW: + case MARKER_237_CCW_AUTUMN_NABNUT_WINDOW: + case MARKER_238_CCW_WINTER_NABNUT_WINDOW: + case MARKER_239_CCW_UNKNOWN_NABNUT_WINDOW: + gcsfx_play(SFX_13A_GLASS_BREAKING_7); + func_802EE278(actor, 4, 0x2D, 0x82, 1.0f, 1.0f); + if (marker->id == MARKER_1F3_TALL_WINDOW) { + func_802EE278(actor, 4, 0x2D, 0x104, 1.0f, 1.0f); } - port_breakable_broadcastBreak(arg0->id, (s32)sp2C->position[0], (s32)sp2C->position[1], (s32)sp2C->position[2]); - marker_despawn(arg0); + port_breakable_broadcastBreak(marker->id, (s32)actor->position[0], (s32)actor->position[1], (s32)actor->position[2]); + marker_despawn(marker); break; - case 0x11E: - gcsfx_playAtSampleRate(SFX_B6_GLASS_BREAKING_1); - func_802EE278(sp2C, 4, 0x32, 0x50, 1.0f, 1.4f); - func_802EE278(sp2C, 4, 0x32, 0xA0, 1.0f, 1.4f); - func_802EE278(sp2C, 4, 0x1E, 0xF0, 0.8f, 1.1f); - func_802D317C(arg0, FILEPROG_C3_ICE_BALL_TO_CHEATO_BROKEN); + case MARKER_11E_ICE_BALL_TO_CHEATO: + gcsfx_play(SFX_B6_GLASS_BREAKING_1); + func_802EE278(actor, 4, 0x32, 0x50, 1.0f, 1.4f); + func_802EE278(actor, 4, 0x32, 0xA0, 1.0f, 1.4f); + func_802EE278(actor, 4, 0x1E, 0xF0, 0.8f, 1.1f); + code_4C020_breakableObjectSetFlag(marker, FILEPROG_C3_ICE_BALL_TO_CHEATO_BROKEN); break; case MARKER_121_GLASS_EYE: - gcsfx_playAtSampleRate(SFX_B6_GLASS_BREAKING_1); - func_802EE2E8(sp2C, 1, 0x32, 0x14, 1.2f, 1.4f, 2.2f); - func_802EE2E8(sp2C, 1, 0x3C, 0x64, 1.6f, 1.8f, 2.2f); - func_802EE2E8(sp2C, 1, 0x32, 0xB4, 1.2f, 1.4f, 2.2f); - func_802D317C(arg0, FILEPROG_C4_STATUE_EYE_BROKEN); + gcsfx_play(SFX_B6_GLASS_BREAKING_1); + func_802EE2E8(actor, 1, 0x32, 0x14, 1.2f, 1.4f, 2.2f); + func_802EE2E8(actor, 1, 0x3C, 0x64, 1.6f, 1.8f, 2.2f); + func_802EE2E8(actor, 1, 0x32, 0xB4, 1.2f, 1.4f, 2.2f); + code_4C020_breakableObjectSetFlag(marker, FILEPROG_C4_STATUE_EYE_BROKEN); break; - case 0x164: - case 0x165: - if (sp2C->unk1C[1] == sp2C->position[1]) { - sfxsource_play(SFX_9B_BOULDER_BREAKING_1, 25000); - sp2C->unk1C[0] = 1.0f; + case MARKER_164_GL_GRUNTY_FLOOR_PICTURE_EYE_1: + case MARKER_165_GL_GRUNTY_FLOOR_PICTURE_EYE_2: + if (actor->unk1C[1] == actor->position[1]) { + gcsfx_playAtSampleRate(SFX_9B_BOULDER_BREAKING_1, 25000); + actor->unk1C[0] = 1.0f; } break; default: - gcsfx_playAtSampleRate(SFX_D_EGGSHELL_BREAKING); - gcsfx_playAtSampleRate(SFX_11_WOOD_BREAKING_1); - marker_despawn(arg0); + gcsfx_play(SFX_D_EGGSHELL_BREAKING); + gcsfx_play(SFX_11_WOOD_BREAKING_1); + marker_despawn(marker); break; } } -void func_802D3CC8(ActorMarker *marker){ - func_802D31AC(marker, NULL); +// unused +void code_4C020_unusedBreakableObjectSfx(ActorMarker *marker){ + code_4C020_breakableObjectSfx(marker, NULL); } // used as init function void func_802D3CE8(Actor *this){ if(!this->initialized){ - marker_setCollisionScripts(this->marker, NULL, func_802D3138, func_802D31AC); - this->marker->propPtr->unk8_3 = true; - this->initialized = true; + marker_setCollisionScripts(this->marker, NULL, func_802D3138, code_4C020_breakableObjectSfx); + this->marker->propPtr->unk8_3 = TRUE; + this->initialized = TRUE; if (port_breakable_isBroken((s32)gsworld_getMap(), this->marker->id, (s32)this->position[0], (s32)this->position[1], (s32)this->position[2])) { marker_despawn(this->marker); @@ -430,7 +478,7 @@ void port_breakable_remoteBreak(s32 progressFlag) { (fieldSel == 2 && actor->actorTypeSpecificField == 1)) { continue; } - func_802D31AC(actor->marker, NULL); + code_4C020_breakableObjectSfx(actor->marker, NULL); return; } } @@ -449,7 +497,7 @@ void port_breakable_remoteBreakAt(s32 markerId, s32 x, s32 y, s32 z) { if ((s32)actor->position[0] != x || (s32)actor->position[1] != y || (s32)actor->position[2] != z) { continue; } - func_802D31AC(actor->marker, NULL); + code_4C020_breakableObjectSfx(actor->marker, NULL); return; } } @@ -473,7 +521,7 @@ void port_breakable_despawnBrokenRestores(s32 map) { } } -void func_802D3D54(Actor *this){ +void chMMMBreakableWooden_update(Actor *this){ func_802D3CE8(this); } @@ -483,8 +531,8 @@ void func_802D3D74(Actor *this){ actor_collisionOff(this); } -void func_802D3DA4(Actor *this) { - f32 sp24[3]; +void gWorldExitPad_update(Actor *this) { + f32 player_position[3]; s32 phi_v0; // [port] anti-tamper: dereferences raw N64 physical address 0x22C — crashes on PC @@ -500,20 +548,29 @@ void func_802D3DA4(Actor *this) { this->marker->propPtr->unk8_3 = true; this->unk38_31 = 0; } - player_getPosition(sp24); - phi_v0 = ((this->position[1] - 5.0f) <= sp24[1]) && (sp24[1] <= (this->position[1] + 30.0f)) - && (((sp24[0] - this->position[0])*(sp24[0] - this->position[0]) + (sp24[2] - this->position[2])*(sp24[2] - this->position[2])) < 3025.0f); + player_getPosition(player_position); + phi_v0 = + ( + (this->position[1] - 5.0f) <= player_position[1]) + && (player_position[1] <= (this->position[1] + 30.0f) + ) + && (( + (player_position[0] - this->position[0]) + * (player_position[0] - this->position[0]) + + (player_position[2] - this->position[2]) + * (player_position[2] - this->position[2]) + ) < 3025.0f); if ((this->unk38_31 == 0) && (phi_v0 == 0)) { this->unk38_31 = 1; } if ((this->unk38_31 == 1) && (phi_v0 == 1) - && func_8028F20C() && (func_8028F66C(BS_INTR_37) == 2)) { + && player_isStableWithExtraSteps() && (func_8028F66C(BS_INTR_37) == 2)) { this->unk38_31 = 2; } } -Actor *func_802D3F48(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx){ +Actor *gWorldExitPad_draw(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx){ s32 phi_s2; Actor *this; s32 i; @@ -521,12 +578,12 @@ Actor *func_802D3F48(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx){ this = marker_getActor(marker); phi_s2 = this->actorTypeSpecificField; for(i = 0; i < 9; i++){ - func_8033A45C(i + 1, i+1 == phi_s2); + modelRender_setAppendageVisibility(i + 1, i + 1 == phi_s2); } return actor_drawFullDepth(marker, gfx, mtx, vtx); } -void func_802D3FD4(Actor *this){ +void chSnsEgg_update(Actor *this){ if(!this->initialized){ this->initialized = true; func_802D3CE8(this); @@ -580,21 +637,21 @@ void func_802D3FD4(Actor *this){ } } -Actor *func_802D41C4(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx){ - s32 sp2C; +Actor *chSnsEgg_draw(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx){ + s32 actor_type_specific_field; Actor *this; s32 i; this = marker_getActor(marker); - sp2C = this->actorTypeSpecificField; + actor_type_specific_field = this->actorTypeSpecificField; for(i = 0; i < 6; i++){ - func_8033A45C(i+1, false); + modelRender_setAppendageVisibility(i + 1, FALSE); } - func_8033A45C(sp2C, true); + modelRender_setAppendageVisibility(actor_type_specific_field, TRUE); return actor_drawFullDepth(marker, gfx, mtx, vtx); } -void func_802D4250(Actor *this){ +void chIceKey_update(Actor *this){ if(!this->initialized){ this->initialized = true; func_802D3CE8(this); @@ -614,8 +671,7 @@ void func_802D4250(Actor *this){ bool func_802D42F8(Actor *this) { s32 i; - for(i = 0; D_803679B0[i] != -1 && this->actorTypeSpecificField != D_803679B0[i]; i+=2){ - } + for(i = 0; D_803679B0[i] != -1 && this->actorTypeSpecificField != D_803679B0[i]; i+=2){} if (D_803679B0[i] == -1) { return false; @@ -626,10 +682,10 @@ bool func_802D42F8(Actor *this) { } -void func_802D4388(Actor *this){ +void chMumboSwitch_update(Actor *this){ func_802D3CE8(this); this->unk38_0 = BOOL(gsworld_getMap() == MAP_7A_GL_CRYPT || item_getCount(ITEM_1C_MUMBO_TOKEN) >= this->actorTypeSpecificField || func_802D42F8(this)); - mapSpecificFlags_set(0x1F, (func_8028F20C() && func_8028FB48(0x78000000)) || player_movementGroup() == BSGROUP_D_TRANSFORMING); + mapSpecificFlags_set(0x1F, (player_isStableWithExtraSteps() && func_8028FB48(0x78000000)) || player_movementGroup() == BSGROUP_D_TRANSFORMING); switch(this->state){ case 0x12: //L802D4468 if(this->unk38_0 && mapSpecificFlags_get(0x1F)){ @@ -661,11 +717,11 @@ void func_802D4388(Actor *this){ mapSpecificFlags_set(0x1F, false); } -Actor *func_802D4588(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx) { +Actor *chMumboSwitch_draw(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx) { s32 phi_a1; phi_a1 = (marker_getActor(marker)->unk38_0) ? ((globalTimer_getTime() & 4) != 0) ? 1 : 2 : 2; - func_8033A45C(1, phi_a1); + modelRender_setAppendageVisibility(1, phi_a1); return actor_draw(marker, gfx, mtx, vtx); } @@ -682,7 +738,7 @@ void func_802D4614(enum map_e map_id){ timedFunc_set_2(1.0f, (GenFunction_2) func_8031CC40, map_id, 2); } -void func_802D4680(Actor *this){ +void chFFTeleportPad_Update(Actor *this){ f32 sp1C[3]; player_getPosition(sp1C); @@ -694,7 +750,7 @@ void func_802D4680(Actor *this){ } break; case 1: - if(ml_vec3f_horizontal_distance_zero_likely(this->position, sp1C) < 150.0f && func_8028F20C()){ + if(ml_vec3f_horizontal_distance_zero_likely(this->position, sp1C) < 150.0f && player_isStableWithExtraSteps()){ if(player_movementGroup() == BSGROUP_0_NONE || player_movementGroup() == BSGROUP_8_TROT){ if(gsworld_getMap() == MAP_8E_GL_FURNACE_FUN){ volatileFlag_set(VOLATILE_FLAG_0_IN_FURNACE_FUN_QUIZ, 0); @@ -790,39 +846,39 @@ void func_802D4AC0(Actor *this, s32 arg1, enum file_progress_e arg2) { } -void func_802D4B94(Actor *this){ +void chMMWitchSwitch_update(Actor *this){ func_802D4AC0(this, 0x4000b6, FILEPROG_18_MM_WITCH_SWITCH_JIGGY_PRESSED); } -void func_802D4BBC(Actor *this){ +void chCCWitchSwitch_update(Actor *this){ func_802D4AC0(this, 0x4000bc, FILEPROG_9A_CC_WITCH_SWITCH_PRESSED); } -void func_802D4BE4(Actor *this){ +void chBGSWitchSwitch_update(Actor *this){ func_802D4AC0(this, 0x4000bd, FILEPROG_9F_BGS_WITCH_SWITCH_JIGGY_PRESSED); } -void func_802D4C0C(Actor *this){ +void chGVWitchSwitch_update(Actor *this){ func_802D4AC0(this, 0x4000be, FILEPROG_A0_GV_WITCH_SWITCH_JIGGY_PRESSED); } -void func_802D4C34(Actor *this){ +void chMMMWitchSwitch_update(Actor *this){ func_802D4AC0(this, 0x4000b7, FILEPROG_19_MMM_WITCH_SWITCH_JIGGY_PRESSED); } -void func_802D4C5C(Actor *this){ +void chTTCWitchSwitch_update(Actor *this){ func_802D4AC0(this, 0x4000b8, FILEPROG_1A_TTC_WITCH_SWITCH_JIGGY_PRESSED); } -void func_802D4C84(Actor *this){ +void chRBBWitchSwitch_update(Actor *this){ func_802D4AC0(this, 0x4000b9, FILEPROG_1C_RBB_WITCH_SWITCH_JIGGY_PRESSED); } -void func_802D4CAC(Actor *this){ +void chCCWWitchSwitch_update(Actor *this){ func_802D4AC0(this, 0x4000ba, FILEPROG_46_CCW_WITCH_SWITCH_JIGGY_PRESSED); } -void func_802D4CD4(Actor *this){ +void chFPWitchSwitch_update(Actor *this){ if(gsworld_getMap() == MAP_27_FP_FREEZEEZY_PEAK){ if(maSlalom_isActive()){ this->unk58_0 = false; @@ -952,7 +1008,7 @@ void func_802D5260(void) { && !levelSpecificFlags_get(LEVEL_FLAG_3D_LAIR_UNKNOWN) && !levelSpecificFlags_get(LEVEL_FLAG_3C_LAIR_UNKNOWN) ) { - func_802D68F0(30); + code_4C020_setHourglassTimer(30); item_set(ITEM_6_HOURGLASS, true); levelSpecificFlags_set(LEVEL_FLAG_3D_LAIR_UNKNOWN, true); } @@ -1163,7 +1219,7 @@ void func_802D5628(void){ func_802D5178(LEVEL_FLAG_22_MMM_OPEN, 0x2E, 0x36, MAP_75_GL_MMM_LOBBY, 0xC, 0x6, ACTOR_228_MMM_ENTRANCE_DOOR, 0xA); func_802D5178(LEVEL_FLAG_24_CCW_OPEN, 0x30, 0x37, MAP_79_GL_CCW_LOBBY, 0xF, 0xB, ACTOR_234_CCW_ENTRANCE_DOOR, 0xA); func_802D5178(LEVEL_FLAG_20_FP_OPEN, 0x2C, 0x38, MAP_6F_GL_FP_LOBBY, 0x11, 0xA, ACTOR_235_FP_ENTRANCE_DOOR_LEFT, 0xA); - func_802D5178(LEVEL_FLAG_3F_LAIR_GRUNTY_DOOR_OPEN, 0xE2, 0x40, MAP_93_GL_DINGPOT, 0x10, 0xA, ACTOR_2E5_DOOR_OF_GRUNTY, 0x28); + func_802D5178(LEVEL_FLAG_3F_LAIR_GRUNTY_DOOR_OPEN, 0xE2, 0x40, MAP_93_GL_DINGPOT, 0x10, 0xA, ACTOR_2E5_LARGE_DOOR_TO_FINAL_BATTLE, 0x28); if(volatileFlag_get(VOLATILE_FLAG_18)){ if(!fileProgressFlag_get(FILEPROG_99_PAST_50_NOTE_DOOR_TEXT)){ gcdialog_showDialogConditional(0xF75, 0xE, NULL, NULL, NULL, NULL, (s32(*)(ActorMarker*,s32,s32))func_802D5140); @@ -1357,7 +1413,7 @@ void func_802D6494(void){ if( (!D_80367684 || (D_80367684 && (gsworld_getMap() == D_80367684))) ){ switch(D_803676A0){ - case ACTOR_2E5_DOOR_OF_GRUNTY: + case ACTOR_2E5_LARGE_DOOR_TO_FINAL_BATTLE: break; case ACTOR_20E_MM_ENTRANCE_DOOR:// L802D6510 FUNC_8030E624(SFX_6B_LOCKUP_OPENING, 0.6f, 32000); @@ -1476,7 +1532,7 @@ int func_802D68B4(void){ //BREAK???? //set_hourglass_timer_seconds -void func_802D68F0(s32 seconds){ +void code_4C020_setHourglassTimer(s32 seconds){ item_set(ITEM_0_HOURGLASS_TIMER, seconds*60 - 1); } diff --git a/src/core2/quiz/minigamemanager.c b/src/core2/quiz/minigame.c similarity index 98% rename from src/core2/quiz/minigamemanager.c rename to src/core2/quiz/minigame.c index 64bac6e59..f757868dc 100644 --- a/src/core2/quiz/minigamemanager.c +++ b/src/core2/quiz/minigame.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/minigame.c #include #include "functions.h" #include "variables.h" @@ -109,7 +110,7 @@ void __chMinigame_textCallback1(ActorMarker *marker, enum asset_e text_id, s32 a void __chMinigame_transformToCroc(ActorMarker *marker, enum asset_e text_id, s32 arg2){ if(arg2 == 1){ - func_8028FB88(TRANSFORM_5_CROC); + player_transform(TRANSFORM_5_CROC); } } diff --git a/src/core2/quiz/questionmanager.c b/src/core2/quiz/questionmanager.c index 98c01add9..1fcac24dc 100644 --- a/src/core2/quiz/questionmanager.c +++ b/src/core2/quiz/questionmanager.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_91E10.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/quiz/bitfield.c b/src/core2/quiz/quizquestionaskedbitfield.c similarity index 81% rename from src/core2/quiz/bitfield.c rename to src/core2/quiz/quizquestionaskedbitfield.c index cd7d27584..466c4a9d7 100644 --- a/src/core2/quiz/bitfield.c +++ b/src/core2/quiz/quizquestionaskedbitfield.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/quizquestionaskedbitfield.c #include #include "functions.h" #include "variables.h" @@ -9,7 +10,7 @@ u8* quizQuestionAskedBitfield; /* .code */ bool quizQuestionAskedBitfield_get(s32 index){ - return bitfield_get_bit(quizQuestionAskedBitfield, index); + return bitfieldarray_getBit(quizQuestionAskedBitfield, index); } void quizQuestionAskedBitfield_free(void){ @@ -26,7 +27,7 @@ void quizQuestionAskedBitfield_init(void){ } void quizQuestionAskedBitfield_set(s32 index, bool value){ - bitfield_set_bit(quizQuestionAskedBitfield, index, value); + bitfieldarray_setBit(quizQuestionAskedBitfield, index, value); } void quizQuestionAskedBitfield_defrag(void){ diff --git a/src/core2/quiz/storage.c b/src/core2/quiz/storage.c index 1bface1cc..34b7d3cc4 100644 --- a/src/core2/quiz/storage.c +++ b/src/core2/quiz/storage.c @@ -1,8 +1,9 @@ +// BanjoDecomp: core2/code_C9E70.c #include #include "functions.h" #include "variables.h" -#include "core2/quiz_storage.h" +#include "core2/quiz/storage.h" extern struct FF_StorageStruct *ffStorage; diff --git a/include/core2/quiz_storage.h b/src/core2/quiz/storage.h similarity index 85% rename from include/core2/quiz_storage.h rename to src/core2/quiz/storage.h index 039ff0c82..300fe5e03 100644 --- a/include/core2/quiz_storage.h +++ b/src/core2/quiz/storage.h @@ -1,5 +1,9 @@ -#ifndef __CORE2_QUIZ_STORAGE_H__ -#define __CORE2_QUIZ_STORAGE_H__ +// BanjoDecomp: core2/code_C9E70.h +#ifndef BANJO_KAZOOIE_CODE_C9E70_H +#define BANJO_KAZOOIE_CODE_C9E70_H + +#ifndef __CORE2_C9E70_H__ +#define __CORE2_C9E70_H__ #include #include "structs.h" @@ -59,8 +63,8 @@ struct FF_StorageStruct { /* 08 */ s16 currentTileId; /* 0A */ u8 currFfMode; /* 0B */ u8 ffQuestionType; - /* 0C */ u8 questionTypeTableIndex; - /* 0D */ u8 questionAssetIndex; + /* 0C */ u8 questionTypeTableIndex; // Question Type Index + /* 0D */ u8 questionAssetIndex; // Question Asset Id /* 0E */ s8 unkE; /* 0F */ s8 unkF; @@ -90,3 +94,5 @@ struct FF_StorageStruct { /* 48 */ struct FF_StorageStruct_48 *unk48; }; // 0x4C #endif + +#endif // BANJO_KAZOOIE_CODE_C9E70_H diff --git a/src/core2/savedata.c b/src/core2/savedata.c index 39b9ec705..f35e6d712 100644 --- a/src/core2/savedata.c +++ b/src/core2/savedata.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_B5040.c #include #include "core1/core1.h" #include "functions.h" diff --git a/src/core2/scorequeue/drawui_air.c b/src/core2/scorequeue/airscore.c similarity index 99% rename from src/core2/scorequeue/drawui_air.c rename to src/core2/scorequeue/airscore.c index b45bde3c4..9c37b1e4c 100644 --- a/src/core2/scorequeue/drawui_air.c +++ b/src/core2/scorequeue/airscore.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/fx/airscore.c #include #include "core1/core1.h" #include "functions.h" diff --git a/src/core2/scorequeue/drawui_stub.c b/src/core2/scorequeue/common1score.c similarity index 91% rename from src/core2/scorequeue/drawui_stub.c rename to src/core2/scorequeue/common1score.c index bdee37f9a..677f4b307 100644 --- a/src/core2/scorequeue/drawui_stub.c +++ b/src/core2/scorequeue/common1score.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/fx/common1score.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/scorequeue/drawui_sprites.c b/src/core2/scorequeue/common2score.c similarity index 97% rename from src/core2/scorequeue/drawui_sprites.c rename to src/core2/scorequeue/common2score.c index ba439e554..53d02db77 100644 --- a/src/core2/scorequeue/drawui_sprites.c +++ b/src/core2/scorequeue/common2score.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/fx/common2score.c #include #include "core1/core1.h" #include "functions.h" @@ -225,7 +226,7 @@ void fxcommon2score_update(s32 arg0, struct8s * arg1){ phi_f16 = 0.333f; } if(arg0 < 6){ - if(item_getCount(arg0) < 30){ + if(item_getCount(arg0) < VER_SELECT(30, 25, 0, 0)){ arg1->unk28 |= 8; } else{ @@ -234,11 +235,11 @@ void fxcommon2score_update(s32 arg0, struct8s * arg1){ } if((arg1->unk28 & 4) == 0){ tmpf = arg1->unk2C; - arg1->unk60 = time_getDelta() * (arg1->unk34 * arg1->unk30) * 60.0f * phi_f16 + arg1->unk60; + arg1->unk60 = time_getDelta() * (arg1->unk34 * arg1->unk30) * VER_SELECT(60.0f, 50.0f, 0, 0) * phi_f16 + arg1->unk60; if(arg1->unk2C <= arg1->unk60){ if(arg1->unk28 & 1){ arg1->unk34 *= -1.0f; - arg1->unk60 -= two* arg1->unk30 * time_getDelta() * 60.0f; + arg1->unk60 -= two* arg1->unk30 * time_getDelta() * VER_SELECT(60.0f, 50.0f, 0, 0); } else{ arg1->unk60 -= arg1->unk2C; @@ -252,7 +253,7 @@ void fxcommon2score_update(s32 arg0, struct8s * arg1){ if(arg1->unk60 < 0.0){ if(arg1->unk28 & 1){ arg1->unk34 *= -1.0f; - arg1->unk60 += two * arg1->unk30 * time_getDelta() * 60.0f; + arg1->unk60 += two * arg1->unk30 * time_getDelta() * VER_SELECT(60.0f, 50.0f, 0, 0); } else{ arg1->unk60 += arg1->unk2C; @@ -281,7 +282,7 @@ void fxcommon2score_draw(enum item_e item_id, struct8s *arg1, Gfx **gfx, Mtx **m } } if(item_id < 6){ - sp38 = ((sp38)? 1: 0) + sp38/60; + sp38 = ((sp38)? 1: 0) + sp38/FRAMERATE; }//L802FDBA8 if(item_id == ITEM_1B_VILE_VILE_SCORE && 9 < sp38){ sp34 = -16.0f; diff --git a/src/core2/scorequeue/drawui_models.c b/src/core2/scorequeue/common3score.c similarity index 96% rename from src/core2/scorequeue/drawui_models.c rename to src/core2/scorequeue/common3score.c index b2232f835..a4bd65fb8 100644 --- a/src/core2/scorequeue/drawui_models.c +++ b/src/core2/scorequeue/common3score.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/fx/common3score.c #include #include "core1/core1.h" #include "functions.h" @@ -7,8 +8,8 @@ #include "port/Interpolation/FrameInterpolation.h" -extern f32 vtxList_getGlobalNorm(BKVertexList *); -extern void func_80253208(Gfx **gdl, s32 x, s32 y, s32 w, s32 h, void *color_buffer); + +extern void depthbuffer_clearRegion(Gfx **gdl, s32 x, s32 y, s32 w, s32 h, void *color_buffer); extern f32 func_802FB0E4(struct8s*); @@ -213,7 +214,7 @@ void fxcommon3score_draw(enum item_e item_id, void *arg1, Gfx **gfx, Mtx **mtx, if(a1->unk6C == 0.0f){ a1->unk6C = 1.1*(vtxList_getGlobalNorm(modelbin_getVtxList(a1->model)) * a1->unk3C); } - func_80253208(gfx, draw_x - a1->unk6C, sp40 - a1->unk6C, 2*a1->unk6C, 2*a1->unk6C, gFramebuffers[getActiveFramebuffer()]); + depthbuffer_clearRegion(gfx, a1->unk30 - a1->unk6C, sp40 - a1->unk6C, 2*a1->unk6C, 2*a1->unk6C, gFramebuffers[getActiveFramebuffer()]); if(a1->anim_ctrl != NULL){ anctrl_drawSetup(a1->anim_ctrl, sp5C, 1); } diff --git a/src/core2/scorequeue/dispatch.c b/src/core2/scorequeue/dispatch.c index fc9d41a8d..83d83a796 100644 --- a/src/core2/scorequeue/dispatch.c +++ b/src/core2/scorequeue/dispatch.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_74090.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/scorequeue/drawui_health.c b/src/core2/scorequeue/healthscore.c similarity index 99% rename from src/core2/scorequeue/drawui_health.c rename to src/core2/scorequeue/healthscore.c index 3673b3feb..5796e717e 100644 --- a/src/core2/scorequeue/drawui_health.c +++ b/src/core2/scorequeue/healthscore.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/fx/healthscore.c #include #include "core1/core1.h" #include "functions.h" diff --git a/src/core2/scorequeue/drawui_honeycarrier.c b/src/core2/scorequeue/honeycarrierscore.c similarity index 99% rename from src/core2/scorequeue/drawui_honeycarrier.c rename to src/core2/scorequeue/honeycarrierscore.c index 8ce9e90d4..e68b39820 100644 --- a/src/core2/scorequeue/drawui_honeycarrier.c +++ b/src/core2/scorequeue/honeycarrierscore.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/fx/honeycarrierscore.c #include #include "core1/core1.h" #include "functions.h" diff --git a/src/core2/scorequeue/drawui_jinjo.c b/src/core2/scorequeue/jinjoscore.c similarity index 99% rename from src/core2/scorequeue/drawui_jinjo.c rename to src/core2/scorequeue/jinjoscore.c index 3a613a4f6..f2c8486b6 100644 --- a/src/core2/scorequeue/drawui_jinjo.c +++ b/src/core2/scorequeue/jinjoscore.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/fx/jinjoscore.c #include #include "core1/core1.h" #include "functions.h" diff --git a/src/core2/scorequeue/drawui_lives.c b/src/core2/scorequeue/lifescore.c similarity index 99% rename from src/core2/scorequeue/drawui_lives.c rename to src/core2/scorequeue/lifescore.c index b59a2139f..0dbf6df22 100644 --- a/src/core2/scorequeue/drawui_lives.c +++ b/src/core2/scorequeue/lifescore.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/fx/lifescore.c #include #include "core1/core1.h" #include "functions.h" diff --git a/src/core2/scorequeue/manager.c b/src/core2/scorequeue/manager.c index 6b6dfd362..2e62963f9 100644 --- a/src/core2/scorequeue/manager.c +++ b/src/core2/scorequeue/manager.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_73640.c #include #include "functions.h" #include "variables.h" @@ -190,13 +191,13 @@ void itemPrint_update(void) { } -void itemPrint_draw(Gfx **gdl, Mtx ** mptr, Vtx **vptr){ +void itemPrint_draw(Gfx **gfx, Mtx **mtx, Vtx **vtx) { s32 i; if(D_803810B0 && level_get() != LEVEL_D_CUTSCENE){ for(i = 0; i < 0x2C; i++){ if(!func_802E4A08() || i < 6){ if(func_802FB0D4(D_803692F8[i].unk14)){ - D_803692F8[i].unk8(i, D_803692F8[i].unk14, gdl, mptr, vptr); + D_803692F8[i].unk8(i, D_803692F8[i].unk14, gfx, mtx, vtx); } } } diff --git a/src/core2/scorequeue/queue_collectibles.c b/src/core2/scorequeue/queue_collectibles.c index 3089b0774..8c3f38467 100644 --- a/src/core2/scorequeue/queue_collectibles.c +++ b/src/core2/scorequeue/queue_collectibles.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_74910.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/scorequeue/queue_honeycombs.c b/src/core2/scorequeue/queue_honeycombs.c index a4387833c..731c31de5 100644 --- a/src/core2/scorequeue/queue_honeycombs.c +++ b/src/core2/scorequeue/queue_honeycombs.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_74420.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/scorequeue/queue_lives.c b/src/core2/scorequeue/queue_lives.c index f208e68bc..6422a6de6 100644 --- a/src/core2/scorequeue/queue_lives.c +++ b/src/core2/scorequeue/queue_lives.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_75E90.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/scorequeue/queue_major_items.c b/src/core2/scorequeue/queue_major_items.c index 1d9ebc511..8a8ac6010 100644 --- a/src/core2/scorequeue/queue_major_items.c +++ b/src/core2/scorequeue/queue_major_items.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_74ED0.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/scorequeue/queue_notes.c b/src/core2/scorequeue/queue_notes.c index d16a25e5d..c6237e4e0 100644 --- a/src/core2/scorequeue/queue_notes.c +++ b/src/core2/scorequeue/queue_notes.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_74290.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/scorequeue/queue_timers.c b/src/core2/scorequeue/queue_timers.c index 00ed40b63..af1211b4a 100644 --- a/src/core2/scorequeue/queue_timers.c +++ b/src/core2/scorequeue/queue_timers.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_75930.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/scorequeue/queue_totals.c b/src/core2/scorequeue/queue_totals.c index 74f538ea2..7ee54a8c9 100644 --- a/src/core2/scorequeue/queue_totals.c +++ b/src/core2/scorequeue/queue_totals.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_75480.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/sfx/filedata.c b/src/core2/sfx/filedata.c index b338eb09a..61ad4c82f 100644 --- a/src/core2/sfx/filedata.c +++ b/src/core2/sfx/filedata.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_72060.c #include #include "core1/core1.h" #include "functions.h" diff --git a/src/core2/sfx/init.c b/src/core2/sfx/init.c index 65b251fa2..c59dc5f8a 100644 --- a/src/core2/sfx/init.c +++ b/src/core2/sfx/init.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_70C30.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/sfx/instruments.c b/src/core2/sfx/instruments.c index 4566c01bd..410004a40 100644 --- a/src/core2/sfx/instruments.c +++ b/src/core2/sfx/instruments.c @@ -1,12 +1,10 @@ +// BanjoDecomp: core2/code_AE290.c #include #include "functions.h" #include "variables.h" #include extern ALBank *music_get_sound_bank(void); -extern OSIoMesg *func_802405D0(void); -extern OSMesgQueue *func_802405C4(void); -extern ALHeap *func_802405B8(void); extern void func_80243070(void *arg0); extern u8 *soundfont1ctl_ROM_START; @@ -40,7 +38,7 @@ void sfxInstruments_init(void){ D_803835F0.unk4 = 0x100; D_803835F0.unk10 = 0x40; D_803835F0.unk8 = 0x18; - D_803835F0.unkC = func_802405B8(); + D_803835F0.unkC = audioManager_getALHeapInfo(); func_80243070(&D_803835F0); sfx_sound_bank = bnk; } diff --git a/src/core2/sfx/pitched.c b/src/core2/sfx/pitched.c index c70bb9b87..613667518 100644 --- a/src/core2/sfx/pitched.c +++ b/src/core2/sfx/pitched.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_599E0.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/sfx/playstate.c b/src/core2/sfx/playstate.c index a3d5020d8..bd8e25259 100644 --- a/src/core2/sfx/playstate.c +++ b/src/core2/sfx/playstate.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_71820.c #include "core1/core1.h" #include "functions.h" #include "variables.h" @@ -22,7 +23,7 @@ void func_802F87B0(struct6s *this){ return; player_getPosition(plyrPos); - viewport_getLookbk_vector(camNorm); + viewport_getLookVector(camNorm); viewport_getRotation_vec3f(camRot); ptr = bk_vector_pushBackNew(&this->unk1C); f20 = randf2(50.0f, 1200.0f); diff --git a/src/core2/sfx/randompitch.c b/src/core2/sfx/randompitch.c index 2ed9a5317..333e5423a 100644 --- a/src/core2/sfx/randompitch.c +++ b/src/core2/sfx/randompitch.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_72B10.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/sfx/sequenceindex.c b/src/core2/sfx/sequenceindex.c index 7f4298e94..b888aff1c 100644 --- a/src/core2/sfx/sequenceindex.c +++ b/src/core2/sfx/sequenceindex.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_857B0.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/sfx/soundsource.c b/src/core2/sfx/soundsource.c index 088874b78..06f8c5e02 100644 --- a/src/core2/sfx/soundsource.c +++ b/src/core2/sfx/soundsource.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/ch/soundsource.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/sfx/source.c b/src/core2/sfx/source.c index 071215159..3cd50ef42 100644 --- a/src/core2/sfx/source.c +++ b/src/core2/sfx/source.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_85800.c #include #include "core1/core1.h" #include "functions.h" @@ -221,7 +222,7 @@ s32 func_8030CDE4(SfxSource *arg0){ f32 pad; viewport_getPosition_vec3f(sp44); - viewport_getLookbk_vector(sp38); + viewport_getLookVector(sp38); sp2C[0] = arg0->position[0] - sp44[0]; sp2C[1] = arg0->position[1] - sp44[1]; sp2C[2] = arg0->position[2] - sp44[2]; @@ -860,8 +861,12 @@ void sfxsource_play(enum sfx_e uid, s32 sampleRate){ func_8030D6C4(uid, 1.0f, sampleRate, 0, 2); } -void gcsfx_playAtSampleRate(enum sfx_e uid){ - sfxsource_play(uid, 0x7ff8); +void gcsfx_playAtSampleRate(enum sfx_e uid, s32 sampleRate){ + sfxsource_play(uid, sampleRate); +} + +void gcsfx_play(enum sfx_e uid){ + gcsfx_playAtSampleRate(uid, 0x7FF8); } void func_8030E560(enum sfx_e uid, s32 arg1){ diff --git a/src/core2/sfx/streamctrl.c b/src/core2/sfx/streamctrl.c index af3324508..0e323c9f4 100644 --- a/src/core2/sfx/streamctrl.c +++ b/src/core2/sfx/streamctrl.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_70F20.c #include #include "core1/core1.h" #include "functions.h" @@ -20,7 +21,7 @@ void func_802F7EB0(struct3s *this){ return; player_getPosition(plyrPos); - viewport_getLookbk_vector(camNorm); + viewport_getLookVector(camNorm); viewport_getRotation_vec3f(camRot); sp50 = bk_vector_pushBackNew(&this->unk20); tmpf = randf2(50.0f, 1100.0f); diff --git a/src/core2/sfx/trackmanager.c b/src/core2/sfx/trackmanager.c index 155ddf472..e65939774 100644 --- a/src/core2/sfx/trackmanager.c +++ b/src/core2/sfx/trackmanager.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_9B650.c #include #include "core1/core1.h" #include "functions.h" diff --git a/src/core2/sfx/volume.c b/src/core2/sfx/volume.c index 6fa3d6690..f775cf9c8 100644 --- a/src/core2/sfx/volume.c +++ b/src/core2/sfx/volume.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_C8760.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/snacker_ctl.c b/src/core2/snackerctl.c similarity index 95% rename from src/core2/snacker_ctl.c rename to src/core2/snackerctl.c index 1f8b5bdb7..e016ff6bc 100644 --- a/src/core2/snacker_ctl.c +++ b/src/core2/snackerctl.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/snackerctl.c #include "core2/snackerctl.h" #include @@ -11,7 +12,7 @@ #define SNACKER_BB_DIALOG_0 VER_SELECT(0xe26, 0xa68, 0xa68, 0xa68) #define SNACKER_BB_DIALOG_1 VER_SELECT(0xe33, 0xa75, 0xa75, 0xa75) -void ncFirstPersonCamera_getZoomedInRotation(f32 *); +void ncba1p_getZoomedInRotation(f32 *); extern u8 D_8037DCCA; extern u8 D_8037DCCB; @@ -32,7 +33,7 @@ void snackerctl_reset(void){ static s32 __snackerctl_player_within_distance(f32 x, f32 z, f32 dist){ f32 player_position[3]; - _player_getPosition(player_position); + playerPosition_get(player_position); return ml_vec3f_point_within_horizontal_distance(player_position, x, z, dist); } @@ -40,7 +41,7 @@ static SnackerCtlState __snackerctl_update_ttc(void){ SnackerCtlState nextState = 0; f32 player_position[3]; - _player_getPosition(player_position); + playerPosition_get(player_position); if(player_isSwimming() || volatileFlag_get(VOLATILE_FLAG_C1_IN_FINAL_CHARACTER_PARADE)){ //(swimming || ???) if(player_position[1] < 600.0f && !__snackerctl_player_within_distance(2478.0f, 4586.0f, 1750.0f) //within 1750 of sandcastle center @@ -101,7 +102,7 @@ static SnackerCtlState _snackerctl_update_bottles_bonus(void){ chBottleBonusPuzzleIndex = 1; }//L8028A764 else if(jiggyscore_isCollected(0x10)){ - ncFirstPersonCamera_getZoomedInRotation(sp30); + ncba1p_getZoomedInRotation(sp30); if( (((D_8036361C[0] <= sp30[0])? (sp30[0] - D_8036361C[0]) : -(sp30[0] - D_8036361C[0])) < 4.0f) && (((D_8036361C[1] <= sp30[1])? (sp30[1] - D_8036361C[1]) : -(sp30[1] - D_8036361C[1])) < 20.0f) ){ diff --git a/src/core2/spawn_queue.c b/src/core2/spawnqueue.c similarity index 69% rename from src/core2/spawn_queue.c rename to src/core2/spawnqueue.c index d20633915..2ae41bf15 100644 --- a/src/core2/spawn_queue.c +++ b/src/core2/spawnqueue.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/spawnqueue.c #include #include "core1/core1.h" #include "functions.h" @@ -18,11 +19,11 @@ Actor *func_802D75B4(s32 *, s32, ActorInfo*, u32); Actor *func_802D7610(s32 *, s32, ActorInfo*, u32); Actor *chBottlesBonus_new(s32 *, s32, ActorInfo*, u32); -extern ActorInfo D_80365E58; //banjo.without_right_hand -extern ActorInfo D_80365EAC; //banjo.playing_gameboy -extern ActorInfo D_80365F00; //banjo.cooking -extern ActorInfo D_80365F60; -extern ActorInfo D_80365F84; //turbotrainers +extern ActorInfo gameSelect_banjoSleeping; //banjo.without_right_hand +extern ActorInfo gameSelect_banjoGameboy; //banjo.playing_gameboy +extern ActorInfo gameSelect_banjoCooking; //banjo.cooking +extern ActorInfo fxWadingBootsTouchSparkle; +extern ActorInfo fxTurboTrainersTouchSparkle; //turbotrainers extern ActorInfo D_80365FB0; //shrapnel extern ActorInfo chBubble; extern ActorInfo chBigbutt; //bigbutt @@ -37,8 +38,8 @@ extern ActorInfo D_803663D0; extern ActorInfo D_803663F4; extern ActorInfo chExtraLife; //extralife extern ActorInfo sumusicNote; //music_note -extern ActorInfo D_80366C80; //chhoneycarrier -extern ActorInfo D_80366CA4; //chhoney +extern ActorInfo chEmptyHoneycomb; //chhoneycarrier +extern ActorInfo chHoneycomb; //chhoney extern ActorInfo chTrainers; extern ActorInfo D_80366EF0; //large_shadow extern ActorInfo chShockJump; //chshockjump @@ -46,7 +47,7 @@ extern ActorInfo chFlightPad; //flight_pad extern ActorInfo chSnippet; //snippet extern ActorInfo chBlackSnippet; //black_snippet extern ActorInfo chMutieSnippet; //mutie_snippet -extern ActorInfo D_80367130; //buzzbomb +extern ActorInfo chBuzzbomb; //buzzbomb extern ActorInfo D_80367160; extern ActorInfo D_80367184; extern ActorInfo chJinjoBlue; //jingo_blue @@ -55,109 +56,109 @@ extern ActorInfo chJinjoYellow; //jingo_yellow extern ActorInfo chJinjoPink; //jingo_pink extern ActorInfo chJinjoOrange; //jingo_orange extern ActorInfo chBeehive; //chbeehive -extern ActorInfo D_80367310; //chswarm +extern ActorInfo chBeeSwarm; //chswarm extern ActorInfo D_80367390; //chwaterfallfx extern ActorInfo chShrapnelDescription; //scrapnel extern ActorInfo chGloop; //gloop -extern ActorInfo D_803674E0; //mumbo -extern ActorInfo D_80367530; //mumbo_token_sign.5 -extern ActorInfo D_80367554; //mumbo_toke_sign.10 -extern ActorInfo D_80367578; //mumbo_toke_sign.15 -extern ActorInfo D_8036759C; //mumbo_toke_sign.20 -extern ActorInfo D_803675C0; //mumbo_toke_sign.25 +extern ActorInfo chMumbo; //mumbo +extern ActorInfo chMumboSign5; //mumbo_token_sign.5 +extern ActorInfo chMumboSign10; //mumbo_toke_sign.10 +extern ActorInfo chMumboSign15; //mumbo_toke_sign.15 +extern ActorInfo chMumboSign20; //mumbo_toke_sign.20 +extern ActorInfo chMumboSign25; //mumbo_toke_sign.25 extern ActorInfo D_803675F0; extern ActorInfo D_80367760; extern ActorInfo D_80367784; -extern ActorInfo D_803677A8; //ice_key -extern ActorInfo D_803677CC; //mumbo_transform_pad -extern ActorInfo D_803677F0; -extern ActorInfo D_80367814; //SnS_egg -extern ActorInfo D_80367838; //level_entry_disk -extern ActorInfo D_8036785C; //witch_switch.mm; -extern ActorInfo D_80367880; //witch_switch.mmm -extern ActorInfo D_803678A4; //witch_switch.ttc -extern ActorInfo D_803678C8; //witch_switch.rbb -extern ActorInfo D_803678EC; //witch_switch.ccw -extern ActorInfo D_80367910; //witch_switch.fp -extern ActorInfo D_80367934; //witch_switch.cc -extern ActorInfo D_80367958; //witch_switch.bgs -extern ActorInfo D_8036797C; //witch_switch.gv -extern ActorInfo D_80367A20; //wading boots +extern ActorInfo chIceKey; //ice_key +extern ActorInfo chMumboSwitch; //mumbo_transform_pad +extern ActorInfo chFFTeleportPad; +extern ActorInfo chSnsEgg; //SnS_egg +extern ActorInfo gWorldExitPad; //level_entry_disk +extern ActorInfo chMMWitchSwitch; //witch_switch.mm; +extern ActorInfo chMMMWitchSwitch; //witch_switch.mmm +extern ActorInfo chTTCWitchSwitch; //witch_switch.ttc +extern ActorInfo chRBBWitchSwitch; //witch_switch.rbb +extern ActorInfo chCCWWitchSwitch; //witch_switch.ccw +extern ActorInfo chFPWitchSwitch; //witch_switch.fp +extern ActorInfo chCCWitchSwitch; //witch_switch.cc +extern ActorInfo chBGSWitchSwitch; //witch_switch.bgs +extern ActorInfo chGVWitchSwitch; //witch_switch.gv +extern ActorInfo chWadingBoots; //wading boots extern ActorInfo chBadShad; //chbadshad extern ActorInfo gDummyPlayerAnchorInfo; //dummy player anchor (port) extern ActorInfo D_80367AB0; extern ActorInfo D_80367AD4; extern ActorInfo D_80367AF8; extern ActorInfo D_80367B20; //chclimbbase -extern ActorInfo D_80367B80; //orange -extern ActorInfo D_80367BA4; //gold_bullion -extern ActorInfo D_80367BC8; -extern ActorInfo D_80367BEC; -extern ActorInfo D_80367C10; -extern ActorInfo D_80367C60; -extern ActorInfo D_80367C90; //spent_redfeather -extern ActorInfo D_80367CB4; //spent_goldfeather -extern ActorInfo D_80367D00; //egg -extern ActorInfo D_80367D24; //redfeather -extern ActorInfo D_80367D48; //goldfeather +extern ActorInfo chOrangeCollectible; //orange +extern ActorInfo chGoldBullion; //gold_bullion +extern ActorInfo chBluePresentCollectible; +extern ActorInfo chGreenPresentCollectible; +extern ActorInfo chRedPresentCollectible; +extern ActorInfo chPiranhaWaterParticles; +extern ActorInfo fxSpentRedFeather; //spent_redfeather +extern ActorInfo fxSpentGoldFeather; //spent_goldfeather +extern ActorInfo chBlueEgg; //egg +extern ActorInfo chRedFeather; //redfeather +extern ActorInfo chGoldFeather; //goldfeather extern ActorInfo gChMole; //bottles -extern ActorInfo D_80367E20; //chmolehill +extern ActorInfo chMolehill; //chmolehill extern ActorInfo D_80367E70; extern ActorInfo D_80367F30; -extern ActorInfo D_8036804C;//GAME_OVER -extern ActorInfo D_8036807C;//THE_END -extern ActorInfo D_803680AC;//player_KAZOOIE +extern ActorInfo gcGameOverSign;//GAME_OVER +extern ActorInfo gcTheEndSign;//THE_END +extern ActorInfo gcBanjoKazooieSign;//player_KAZOOIE extern ActorInfo chOverlayCopyrightDescription;//copyright_info -extern ActorInfo D_80368124;//PRESS_START -extern ActorInfo D_80368174;//NO_CONTROLLER) +extern ActorInfo chOverlayPressStart;//PRESS_START +extern ActorInfo chOverlayNoController;//NO_CONTROLLER) extern ActorInfo chBottlesBonusDescription; //jiggy_picture -extern ActorInfo D_8036833C; +extern ActorInfo chMumbosHandWithPicture; extern ActorInfo D_8036838C; -extern ActorInfo D_80368418; //banjos_hand_BB -extern ActorInfo D_80368450; //fire_sparkle -extern ActorInfo D_80368474; -extern ActorInfo D_80368498; -extern ActorInfo D_803684BC; //roysten -extern ActorInfo D_803684E0; //cuckoo_clock +extern ActorInfo chBottlesBonusCursor; //banjos_hand_BB +extern ActorInfo chFireSparkle; //fire_sparkle +extern ActorInfo chBanjoCurtains; +extern ActorInfo chBanjoHouseDoor; +extern ActorInfo chFishbowl; //roysten +extern ActorInfo chCuckooClock; //cuckoo_clock extern ActorInfo D_80368504; extern ActorInfo D_80368528; extern ActorInfo D_8036854C; extern ActorInfo D_80368570; -extern ActorInfo D_803685A0; //mumbotoken +extern ActorInfo chMumboToken; //mumbotoken extern ActorInfo chSnowman; //sirslush extern ActorInfo chSnowball; //snowball extern ActorInfo chSnowmanHat; //sir_slush_hat extern ActorInfo D_80372810; extern ActorInfo D_80372840; //grillchompa extern ActorInfo chClucker; //clucker -extern ActorInfo D_803728A0; //scarab +extern ActorInfo chScarabBeetle; //scarab extern ActorInfo chMinigame; //boombox -extern ActorInfo D_80372970; //leaf_particle -extern ActorInfo D_80372994; -extern ActorInfo D_803729B8; //rain -extern ActorInfo D_803729DC; -extern ActorInfo D_80372A00; //snow -extern ActorInfo D_80372A24; +extern ActorInfo leafEmitterCCWAutumn; //leaf_particle +extern ActorInfo leafEmitterCCWHub; +extern ActorInfo rainEmitterCCWSpring; //rain +extern ActorInfo rainEmitterCCWHub; +extern ActorInfo snowEmitterCCWWinter; //snow +extern ActorInfo snowEmitterCCWHub; extern ActorInfo D_80372A48; extern ActorInfo D_80372A6C; extern ActorInfo gChFireFxInfo; //fire extern ActorInfo gChDripsInfo;//water_drops extern ActorInfo chIcecubeA; extern ActorInfo chIcecubeB;//ice_cube -extern ActorInfo D_80372C18; //teehee +extern ActorInfo chTeeHee; //teehee extern ActorInfo chFlotsam; //floatsam extern ActorInfo D_80372D78; //limbo extern ActorInfo D_80372DF8; //grublin_hood extern ActorInfo chMumMum; //mummum -extern ActorInfo D_80372EE0; +extern ActorInfo chChumpFish; extern ActorInfo chTermite; //ticker extern ActorInfo D_80372FC0; extern ActorInfo D_80372FE4; extern ActorInfo gChBat; //nibbly extern ActorInfo chWhipcrack; -extern ActorInfo D_80373134; -extern ActorInfo D_80373158; -extern ActorInfo D_803731B0; +extern ActorInfo chBetaVent1; +extern ActorInfo chBetaVent2; +extern ActorInfo lairBottlesDialog; extern ActorInfo D_803732E0; extern ActorInfo D_80373DC0; @@ -239,9 +240,9 @@ void spawnQueue_reset(void){ spawnableActorList_add(&D_803675F0, actor_new, ACTOR_FLAG_UNKNOWN_6); spawnableActorList_add(&chBigbutt, actor_new, ACTOR_FLAG_UNKNOWN_0 | ACTOR_FLAG_UNKNOWN_1 | ACTOR_FLAG_UNKNOWN_8 | ACTOR_FLAG_UNKNOWN_16 | ACTOR_FLAG_UNKNOWN_25); spawnableActorList_add(&chSmallBull, actor_new, ACTOR_FLAG_UNKNOWN_0 | ACTOR_FLAG_UNKNOWN_1 | ACTOR_FLAG_UNKNOWN_8); - spawnableActorList_add(&D_803674E0, actor_new, ACTOR_FLAG_UNKNOWN_1 | ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_8); + spawnableActorList_add(&chMumbo, actor_new, ACTOR_FLAG_UNKNOWN_1 | ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_8); spawnableActorList_add(&chBeehive, actor_new, ACTOR_FLAG_UNKNOWN_3 | ACTOR_FLAG_UNKNOWN_8 | ACTOR_FLAG_UNKNOWN_25); - spawnableActorList_add(&D_80367310, actor_new, ACTOR_FLAG_UNKNOWN_0 | ACTOR_FLAG_UNKNOWN_17); + spawnableActorList_add(&chBeeSwarm, actor_new, ACTOR_FLAG_UNKNOWN_0 | ACTOR_FLAG_UNKNOWN_17); spawnableActorList_add(&D_80367390, actor_new, ACTOR_FLAG_UNKNOWN_2 | ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_19); spawnableActorList_add(&chJinjoYellow, actor_new, ACTOR_FLAG_UNKNOWN_6 | ACTOR_FLAG_UNKNOWN_8); spawnableActorList_add(&chJinjoOrange, actor_new, ACTOR_FLAG_UNKNOWN_6 | ACTOR_FLAG_UNKNOWN_8); @@ -250,12 +251,12 @@ void spawnQueue_reset(void){ spawnableActorList_add(&chJinjoGreen, actor_new, ACTOR_FLAG_UNKNOWN_6 | ACTOR_FLAG_UNKNOWN_8); spawnableActorList_add(&chJiggy, actor_new, ACTOR_FLAG_UNKNOWN_6 | ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_21); spawnableActorList_add(&chJigsawDance, actor_new, ACTOR_FLAG_UNKNOWN_2); - spawnableActorList_add(&D_80367C60, actor_new, ACTOR_FLAG_UNKNOWN_2); - spawnableActorList_add(&D_80367A20, actor_new, ACTOR_FLAG_NONE); - spawnableActorList_add(&D_80366C80, actor_new, ACTOR_FLAG_UNKNOWN_6 | ACTOR_FLAG_UNKNOWN_21); //chhoneycarrier - spawnableActorList_add(&D_80366CA4, actor_new, ACTOR_FLAG_UNKNOWN_6 | ACTOR_FLAG_UNKNOWN_21); //chhoney + spawnableActorList_add(&chPiranhaWaterParticles, actor_new, ACTOR_FLAG_UNKNOWN_2); + spawnableActorList_add(&chWadingBoots, actor_new, ACTOR_FLAG_NONE); + spawnableActorList_add(&chEmptyHoneycomb, actor_new, ACTOR_FLAG_UNKNOWN_6 | ACTOR_FLAG_UNKNOWN_21); //chhoneycarrier + spawnableActorList_add(&chHoneycomb, actor_new, ACTOR_FLAG_UNKNOWN_6 | ACTOR_FLAG_UNKNOWN_21); //chhoney spawnableActorList_add(&sumusicNote, actor_new, ACTOR_FLAG_UNKNOWN_21); //music_note - spawnableActorList_add(&D_80367D00, actor_new, ACTOR_FLAG_UNKNOWN_21); //egg + spawnableActorList_add(&chBlueEgg, actor_new, ACTOR_FLAG_UNKNOWN_21); //egg spawnableActorList_add(&D_80366340, func_802C8A54, ACTOR_FLAG_UNKNOWN_2); spawnableActorList_add(&D_80366364, func_802C8AA8, ACTOR_FLAG_UNKNOWN_2); spawnableActorList_add(&D_80366388, func_802C8AF8, ACTOR_FLAG_UNKNOWN_2); @@ -266,103 +267,102 @@ void spawnQueue_reset(void){ spawnableActorList_add(&D_80367AD4, func_802D75B4, ACTOR_FLAG_UNKNOWN_2); spawnableActorList_add(&D_80367AF8, func_802D7610, ACTOR_FLAG_UNKNOWN_2); spawnableActorList_add(&chTrainers, actor_new, ACTOR_FLAG_NONE); - spawnableActorList_add(&D_80365F60, actor_new, ACTOR_FLAG_UNKNOWN_2); - spawnableActorList_add(&D_80365F84, actor_new, ACTOR_FLAG_UNKNOWN_2); //turbotrainers + spawnableActorList_add(&fxWadingBootsTouchSparkle, actor_new, ACTOR_FLAG_UNKNOWN_2); + spawnableActorList_add(&fxTurboTrainersTouchSparkle, actor_new, ACTOR_FLAG_UNKNOWN_2); //turbotrainers spawnableActorList_add(&D_80367184, actor_new, ACTOR_FLAG_NONE); spawnableActorList_add(&chExtraLife, actor_new, ACTOR_FLAG_UNKNOWN_21); //extralife spawnableActorList_add(&D_80365FB0, actor_new, ACTOR_FLAG_UNKNOWN_2); //shrapnel spawnableActorList_add(&chBadShad, actor_new, ACTOR_FLAG_UNKNOWN_2); //chbadshad - spawnableActorList_add(&gDummyPlayerAnchorInfo, actor_new, ACTOR_FLAG_UNKNOWN_2); //dummy player anchor - spawnableActorList_add(&D_803685A0, actor_new, ACTOR_FLAG_UNKNOWN_6); //mumbotoken + spawnableActorList_add(&chMumboToken, actor_new, ACTOR_FLAG_UNKNOWN_6); //mumbotoken spawnableActorList_add(&D_80367F30, actor_new, ACTOR_FLAG_UNKNOWN_10); spawnableActorList_add(&chBubble, actor_new, ACTOR_FLAG_UNKNOWN_2); spawnableActorList_add(&chGloop, actor_new, ACTOR_FLAG_UNKNOWN_1 | ACTOR_FLAG_UNKNOWN_3 | ACTOR_FLAG_UNKNOWN_7); //gloop spawnableActorList_add(&chShockJump, actor_new, ACTOR_FLAG_NONE); //chshockjump spawnableActorList_add(&chFlightPad, actor_new, ACTOR_FLAG_NONE); //flight_pad - spawnableActorList_add(&D_80367D24, actor_new, ACTOR_FLAG_UNKNOWN_21); //redfeather - spawnableActorList_add(&D_80367D48, actor_new, ACTOR_FLAG_UNKNOWN_21); //goldfeather - spawnableActorList_add(&D_80367C90, actor_new, ACTOR_FLAG_UNKNOWN_2); //spent_redfeather - spawnableActorList_add(&D_80367CB4, actor_new, ACTOR_FLAG_UNKNOWN_2); //spent_goldfeather + spawnableActorList_add(&chRedFeather, actor_new, ACTOR_FLAG_UNKNOWN_21); //redfeather + spawnableActorList_add(&chGoldFeather, actor_new, ACTOR_FLAG_UNKNOWN_21); //goldfeather + spawnableActorList_add(&fxSpentRedFeather, actor_new, ACTOR_FLAG_UNKNOWN_2); //spent_redfeather + spawnableActorList_add(&fxSpentGoldFeather, actor_new, ACTOR_FLAG_UNKNOWN_2); //spent_goldfeather spawnableActorList_add(&gChMole, actor_new, ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_8); //bottles - spawnableActorList_add(&D_80367E20, actor_new, ACTOR_FLAG_UNKNOWN_2 | ACTOR_FLAG_UNKNOWN_6); //chmolehill + spawnableActorList_add(&chMolehill, actor_new, ACTOR_FLAG_UNKNOWN_2 | ACTOR_FLAG_UNKNOWN_6); //chmolehill spawnableActorList_add(&D_80373DC0, actor_new, ACTOR_FLAG_UNKNOWN_19); spawnableActorList_add(&D_80367E70, actor_new, ACTOR_FLAG_NONE); spawnableActorList_add(&gChSnacker, actor_new, ACTOR_FLAG_UNKNOWN_2 | ACTOR_FLAG_UNKNOWN_16); //snacker spawnableActorList_add(&D_80366EF0, actor_new, ACTOR_FLAG_UNKNOWN_2 | ACTOR_FLAG_UNKNOWN_17); //large_shadow spawnableActorList_add(&D_80367B20, actor_new, ACTOR_FLAG_UNKNOWN_7); //chclimbbase - spawnableActorList_add(&D_80367BA4, actor_new, ACTOR_FLAG_UNKNOWN_6); //gold_bullion - spawnableActorList_add(&D_80367B80, actor_new, ACTOR_FLAG_UNKNOWN_1); //orange - spawnableActorList_add(&D_80372970, actor_new, ACTOR_FLAG_UNKNOWN_7); //leaf_particle - spawnableActorList_add(&D_80372994, actor_new, ACTOR_FLAG_UNKNOWN_7); - spawnableActorList_add(&D_803729B8, actor_new, ACTOR_FLAG_UNKNOWN_7); //rain - spawnableActorList_add(&D_803729DC, actor_new, ACTOR_FLAG_UNKNOWN_7); - spawnableActorList_add(&D_80372A00, actor_new, ACTOR_FLAG_UNKNOWN_7); //snow - spawnableActorList_add(&D_80372A24, actor_new, ACTOR_FLAG_UNKNOWN_7); + spawnableActorList_add(&chGoldBullion, actor_new, ACTOR_FLAG_UNKNOWN_6); //gold_bullion + spawnableActorList_add(&chOrangeCollectible, actor_new, ACTOR_FLAG_UNKNOWN_1); //orange + spawnableActorList_add(&leafEmitterCCWAutumn, actor_new, ACTOR_FLAG_UNKNOWN_7); //leaf_particle + spawnableActorList_add(&leafEmitterCCWHub, actor_new, ACTOR_FLAG_UNKNOWN_7); + spawnableActorList_add(&rainEmitterCCWSpring, actor_new, ACTOR_FLAG_UNKNOWN_7); //rain + spawnableActorList_add(&rainEmitterCCWHub, actor_new, ACTOR_FLAG_UNKNOWN_7); + spawnableActorList_add(&snowEmitterCCWWinter, actor_new, ACTOR_FLAG_UNKNOWN_7); //snow + spawnableActorList_add(&snowEmitterCCWHub, actor_new, ACTOR_FLAG_UNKNOWN_7); spawnableActorList_add(&D_80372A48, actor_new, ACTOR_FLAG_UNKNOWN_0 | ACTOR_FLAG_UNKNOWN_7); spawnableActorList_add(&D_80372A6C, actor_new, ACTOR_FLAG_UNKNOWN_0 | ACTOR_FLAG_UNKNOWN_7); spawnableActorList_add(&chMinigame, actor_new, ACTOR_FLAG_UNKNOWN_7); //boombox - spawnableActorList_add(&D_803677A8, actor_new, ACTOR_FLAG_UNKNOWN_9 | ACTOR_FLAG_UNKNOWN_10 | ACTOR_FLAG_UNKNOWN_15); //ice_key - spawnableActorList_add(&D_80367814, actor_new, ACTOR_FLAG_UNKNOWN_9 | ACTOR_FLAG_UNKNOWN_10 | ACTOR_FLAG_UNKNOWN_15); //SnS_egg + spawnableActorList_add(&chIceKey, actor_new, ACTOR_FLAG_UNKNOWN_9 | ACTOR_FLAG_UNKNOWN_10 | ACTOR_FLAG_UNKNOWN_15); //ice_key + spawnableActorList_add(&chSnsEgg, actor_new, ACTOR_FLAG_UNKNOWN_9 | ACTOR_FLAG_UNKNOWN_10 | ACTOR_FLAG_UNKNOWN_15); //SnS_egg spawnableActorList_add(&gChFireFxInfo, actor_new, ACTOR_FLAG_NONE); //fire - spawnableActorList_add(&D_80367838, actor_new, ACTOR_FLAG_UNKNOWN_9 | ACTOR_FLAG_UNKNOWN_10 | ACTOR_FLAG_UNKNOWN_15); //level_entry_disk + spawnableActorList_add(&gWorldExitPad, actor_new, ACTOR_FLAG_UNKNOWN_9 | ACTOR_FLAG_UNKNOWN_10 | ACTOR_FLAG_UNKNOWN_15); //level_entry_disk spawnableActorList_add(&D_80367760, actor_new, ACTOR_FLAG_UNKNOWN_12); spawnableActorList_add(&D_80367784, actor_new, ACTOR_FLAG_UNKNOWN_12); - spawnableActorList_add(&D_80365E58, actor_new, ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_10 | ACTOR_FLAG_UNKNOWN_17); //banjo.without_right_hand - spawnableActorList_add(&D_80365EAC, actor_new, ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_10 | ACTOR_FLAG_UNKNOWN_17); //banjo.playing_gameboy - spawnableActorList_add(&D_80365F00, actor_new, ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_10 | ACTOR_FLAG_UNKNOWN_17); //banjo.cooking - spawnableActorList_add(&D_803677CC, actor_new, ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_9 | ACTOR_FLAG_UNKNOWN_10 | ACTOR_FLAG_UNKNOWN_15);//mumbo_transform_pad - spawnableActorList_add(&D_803677F0, actor_new, ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_9 | ACTOR_FLAG_UNKNOWN_10 | ACTOR_FLAG_UNKNOWN_15); - spawnableActorList_add(&D_803731B0, actor_new, ACTOR_FLAG_NONE); + spawnableActorList_add(&gameSelect_banjoSleeping, actor_new, ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_10 | ACTOR_FLAG_UNKNOWN_17); //banjo.without_right_hand + spawnableActorList_add(&gameSelect_banjoGameboy, actor_new, ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_10 | ACTOR_FLAG_UNKNOWN_17); //banjo.playing_gameboy + spawnableActorList_add(&gameSelect_banjoCooking, actor_new, ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_10 | ACTOR_FLAG_UNKNOWN_17); //banjo.cooking + spawnableActorList_add(&chMumboSwitch, actor_new, ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_9 | ACTOR_FLAG_UNKNOWN_10 | ACTOR_FLAG_UNKNOWN_15);//mumbo_transform_pad + spawnableActorList_add(&chFFTeleportPad, actor_new, ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_9 | ACTOR_FLAG_UNKNOWN_10 | ACTOR_FLAG_UNKNOWN_15); + spawnableActorList_add(&lairBottlesDialog, actor_new, ACTOR_FLAG_NONE); spawnableActorList_add(&chSnowball, actor_new, ACTOR_FLAG_UNKNOWN_2 | ACTOR_FLAG_UNKNOWN_6 | ACTOR_FLAG_UNKNOWN_20);//snowball spawnableActorList_add(&chSnowmanHat, actor_new, ACTOR_FLAG_UNKNOWN_2);//sir_slush_hat spawnableActorList_add(&gChDripsInfo, actor_new, ACTOR_FLAG_UNKNOWN_10);//water_drops spawnableActorList_add(&chIcecubeB, actor_new, ACTOR_FLAG_UNKNOWN_0 | ACTOR_FLAG_UNKNOWN_6 | ACTOR_FLAG_UNKNOWN_8 | ACTOR_FLAG_UNKNOWN_17 | ACTOR_FLAG_UNKNOWN_25);//ice_cube - spawnableActorList_add(&D_8036804C, actor_new, ACTOR_FLAG_UNKNOWN_2 | ACTOR_FLAG_UNKNOWN_9 | ACTOR_FLAG_UNKNOWN_10 | ACTOR_FLAG_UNKNOWN_15 | ACTOR_FLAG_UNKNOWN_20 | ACTOR_FLAG_UNKNOWN_22);//GAME_OVER - spawnableActorList_add(&D_8036807C, actor_new, ACTOR_FLAG_UNKNOWN_2 | ACTOR_FLAG_UNKNOWN_9 | ACTOR_FLAG_UNKNOWN_10 | ACTOR_FLAG_UNKNOWN_15 | ACTOR_FLAG_UNKNOWN_20 | ACTOR_FLAG_UNKNOWN_22);//THE_END - spawnableActorList_add(&D_803680AC, actor_new, ACTOR_FLAG_UNKNOWN_2 | ACTOR_FLAG_UNKNOWN_9 | ACTOR_FLAG_UNKNOWN_10 | ACTOR_FLAG_UNKNOWN_15 | ACTOR_FLAG_UNKNOWN_20 | ACTOR_FLAG_UNKNOWN_22);//player_KAZOOIE + spawnableActorList_add(&gcGameOverSign, actor_new, ACTOR_FLAG_UNKNOWN_2 | ACTOR_FLAG_UNKNOWN_9 | ACTOR_FLAG_UNKNOWN_10 | ACTOR_FLAG_UNKNOWN_15 | ACTOR_FLAG_UNKNOWN_20 | ACTOR_FLAG_UNKNOWN_22);//GAME_OVER + spawnableActorList_add(&gcTheEndSign, actor_new, ACTOR_FLAG_UNKNOWN_2 | ACTOR_FLAG_UNKNOWN_9 | ACTOR_FLAG_UNKNOWN_10 | ACTOR_FLAG_UNKNOWN_15 | ACTOR_FLAG_UNKNOWN_20 | ACTOR_FLAG_UNKNOWN_22);//THE_END + spawnableActorList_add(&gcBanjoKazooieSign, actor_new, ACTOR_FLAG_UNKNOWN_2 | ACTOR_FLAG_UNKNOWN_9 | ACTOR_FLAG_UNKNOWN_10 | ACTOR_FLAG_UNKNOWN_15 | ACTOR_FLAG_UNKNOWN_20 | ACTOR_FLAG_UNKNOWN_22);//player_KAZOOIE spawnableActorList_add(&chOverlayCopyrightDescription, actor_new, ACTOR_FLAG_UNKNOWN_2 | ACTOR_FLAG_UNKNOWN_9 | ACTOR_FLAG_UNKNOWN_10 | ACTOR_FLAG_UNKNOWN_15 | ACTOR_FLAG_UNKNOWN_20 | ACTOR_FLAG_UNKNOWN_22);//copyright_info - spawnableActorList_add(&D_80368124, actor_new, ACTOR_FLAG_UNKNOWN_2 | ACTOR_FLAG_UNKNOWN_9 | ACTOR_FLAG_UNKNOWN_10 | ACTOR_FLAG_UNKNOWN_15 | ACTOR_FLAG_UNKNOWN_20 | ACTOR_FLAG_UNKNOWN_22);//PRESS_START + spawnableActorList_add(&chOverlayPressStart, actor_new, ACTOR_FLAG_UNKNOWN_2 | ACTOR_FLAG_UNKNOWN_9 | ACTOR_FLAG_UNKNOWN_10 | ACTOR_FLAG_UNKNOWN_15 | ACTOR_FLAG_UNKNOWN_20 | ACTOR_FLAG_UNKNOWN_22);//PRESS_START spawnableActorList_add(&chBottlesBonusDescription, chBottlesBonus_new, ACTOR_FLAG_UNKNOWN_2 | ACTOR_FLAG_UNKNOWN_9 | ACTOR_FLAG_UNKNOWN_10 | ACTOR_FLAG_UNKNOWN_12 | ACTOR_FLAG_UNKNOWN_15 | ACTOR_FLAG_UNKNOWN_20 | ACTOR_FLAG_UNKNOWN_22);//jiggy_picture - spawnableActorList_add(&D_8036833C, actor_new, ACTOR_FLAG_UNKNOWN_2 | ACTOR_FLAG_UNKNOWN_9 | ACTOR_FLAG_UNKNOWN_10 | ACTOR_FLAG_UNKNOWN_15 | ACTOR_FLAG_UNKNOWN_20 | ACTOR_FLAG_UNKNOWN_22); + spawnableActorList_add(&chMumbosHandWithPicture, actor_new, ACTOR_FLAG_UNKNOWN_2 | ACTOR_FLAG_UNKNOWN_9 | ACTOR_FLAG_UNKNOWN_10 | ACTOR_FLAG_UNKNOWN_15 | ACTOR_FLAG_UNKNOWN_20 | ACTOR_FLAG_UNKNOWN_22); spawnableActorList_add(&D_8036838C, actor_new, ACTOR_FLAG_UNKNOWN_2 | ACTOR_FLAG_UNKNOWN_9 | ACTOR_FLAG_UNKNOWN_10 | ACTOR_FLAG_UNKNOWN_12 | ACTOR_FLAG_UNKNOWN_15 | ACTOR_FLAG_UNKNOWN_20 | ACTOR_FLAG_UNKNOWN_22); - spawnableActorList_add(&D_80368418, actor_new, ACTOR_FLAG_UNKNOWN_2 | ACTOR_FLAG_UNKNOWN_6 | ACTOR_FLAG_UNKNOWN_9 | ACTOR_FLAG_UNKNOWN_10 | ACTOR_FLAG_UNKNOWN_15 | ACTOR_FLAG_UNKNOWN_20 | ACTOR_FLAG_UNKNOWN_22);//banjos_hand_BB - spawnableActorList_add(&D_80368174, actor_new, ACTOR_FLAG_UNKNOWN_2 | ACTOR_FLAG_UNKNOWN_9 | ACTOR_FLAG_UNKNOWN_10 | ACTOR_FLAG_UNKNOWN_15 | ACTOR_FLAG_UNKNOWN_20 | ACTOR_FLAG_UNKNOWN_22);//NO_CONTROLLER); - spawnableActorList_add(&D_80367530, actor_new, ACTOR_FLAG_NONE);//mumbo_token_sign.5 - spawnableActorList_add(&D_80367554, actor_new, ACTOR_FLAG_NONE);//mumbo_toke_sign.10 - spawnableActorList_add(&D_80367578, actor_new, ACTOR_FLAG_NONE);//mumbo_toke_sign.15 - spawnableActorList_add(&D_8036759C, actor_new, ACTOR_FLAG_NONE);//mumbo_toke_sign.20 - spawnableActorList_add(&D_803675C0, actor_new, ACTOR_FLAG_NONE);//mumbo_toke_sign.25 - spawnableActorList_add(&D_8036785C, actor_new, ACTOR_FLAG_NONE);//witch_switch.mm; - spawnableActorList_add(&D_80367880, actor_new, ACTOR_FLAG_NONE);//witch_switch.mmm - spawnableActorList_add(&D_803678A4, actor_new, ACTOR_FLAG_NONE);//witch_switch.ttc - spawnableActorList_add(&D_803678C8, actor_new, ACTOR_FLAG_NONE);//witch_switch.rbb - spawnableActorList_add(&D_803678EC, actor_new, ACTOR_FLAG_NONE);//witch_switch.ccw - spawnableActorList_add(&D_80367910, actor_new, ACTOR_FLAG_NONE);//witch_switch.fp - spawnableActorList_add(&D_80367934, actor_new, ACTOR_FLAG_NONE);//witch_switch.cc - spawnableActorList_add(&D_80367958, actor_new, ACTOR_FLAG_NONE);//witch_switch.bgs - spawnableActorList_add(&D_8036797C, actor_new, ACTOR_FLAG_UNKNOWN_10);//witch_switch.gv - spawnableActorList_add(&D_80368450, actor_new, ACTOR_FLAG_UNKNOWN_17);//fire_sparkle - spawnableActorList_add(&D_803684BC, actor_new, ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_8);//roysten - spawnableActorList_add(&D_803684E0, actor_new, ACTOR_FLAG_NONE);//cuckoo_clock + spawnableActorList_add(&chBottlesBonusCursor, actor_new, ACTOR_FLAG_UNKNOWN_2 | ACTOR_FLAG_UNKNOWN_6 | ACTOR_FLAG_UNKNOWN_9 | ACTOR_FLAG_UNKNOWN_10 | ACTOR_FLAG_UNKNOWN_15 | ACTOR_FLAG_UNKNOWN_20 | ACTOR_FLAG_UNKNOWN_22);//banjos_hand_BB + spawnableActorList_add(&chOverlayNoController, actor_new, ACTOR_FLAG_UNKNOWN_2 | ACTOR_FLAG_UNKNOWN_9 | ACTOR_FLAG_UNKNOWN_10 | ACTOR_FLAG_UNKNOWN_15 | ACTOR_FLAG_UNKNOWN_20 | ACTOR_FLAG_UNKNOWN_22);//NO_CONTROLLER); + spawnableActorList_add(&chMumboSign5, actor_new, ACTOR_FLAG_NONE);//mumbo_token_sign.5 + spawnableActorList_add(&chMumboSign10, actor_new, ACTOR_FLAG_NONE);//mumbo_toke_sign.10 + spawnableActorList_add(&chMumboSign15, actor_new, ACTOR_FLAG_NONE);//mumbo_toke_sign.15 + spawnableActorList_add(&chMumboSign20, actor_new, ACTOR_FLAG_NONE);//mumbo_toke_sign.20 + spawnableActorList_add(&chMumboSign25, actor_new, ACTOR_FLAG_NONE);//mumbo_toke_sign.25 + spawnableActorList_add(&chMMWitchSwitch, actor_new, ACTOR_FLAG_NONE);//witch_switch.mm; + spawnableActorList_add(&chMMMWitchSwitch, actor_new, ACTOR_FLAG_NONE);//witch_switch.mmm + spawnableActorList_add(&chTTCWitchSwitch, actor_new, ACTOR_FLAG_NONE);//witch_switch.ttc + spawnableActorList_add(&chRBBWitchSwitch, actor_new, ACTOR_FLAG_NONE);//witch_switch.rbb + spawnableActorList_add(&chCCWWitchSwitch, actor_new, ACTOR_FLAG_NONE);//witch_switch.ccw + spawnableActorList_add(&chFPWitchSwitch, actor_new, ACTOR_FLAG_NONE);//witch_switch.fp + spawnableActorList_add(&chCCWitchSwitch, actor_new, ACTOR_FLAG_NONE);//witch_switch.cc + spawnableActorList_add(&chBGSWitchSwitch, actor_new, ACTOR_FLAG_NONE);//witch_switch.bgs + spawnableActorList_add(&chGVWitchSwitch, actor_new, ACTOR_FLAG_UNKNOWN_10);//witch_switch.gv + spawnableActorList_add(&chFireSparkle, actor_new, ACTOR_FLAG_UNKNOWN_17);//fire_sparkle + spawnableActorList_add(&chFishbowl, actor_new, ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_8);//roysten + spawnableActorList_add(&chCuckooClock, actor_new, ACTOR_FLAG_NONE);//cuckoo_clock spawnableActorList_add(&D_80368504, actor_new, ACTOR_FLAG_NONE); spawnableActorList_add(&D_80368528, actor_new, ACTOR_FLAG_NONE); spawnableActorList_add(&D_8036854C, actor_new, ACTOR_FLAG_NONE); spawnableActorList_add(&D_80368570, actor_new, ACTOR_FLAG_NONE); - spawnableActorList_add(&D_80368474, actor_new, ACTOR_FLAG_UNKNOWN_3 | ACTOR_FLAG_UNKNOWN_6 | ACTOR_FLAG_UNKNOWN_7); - spawnableActorList_add(&D_80368498, actor_new, ACTOR_FLAG_NONE); + spawnableActorList_add(&chBanjoCurtains, actor_new, ACTOR_FLAG_UNKNOWN_3 | ACTOR_FLAG_UNKNOWN_6 | ACTOR_FLAG_UNKNOWN_7); + spawnableActorList_add(&chBanjoHouseDoor, actor_new, ACTOR_FLAG_NONE); spawnableActorList_add(&D_803732E0, actor_new, ACTOR_FLAG_NONE); spawnableActorList_add(&D_80372810, actor_new, ACTOR_FLAG_UNKNOWN_3 | ACTOR_FLAG_UNKNOWN_5 | ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_11 | ACTOR_FLAG_UNKNOWN_23); spawnableActorList_add(&chWhipcrack, actor_new, ACTOR_FLAG_UNKNOWN_3 | ACTOR_FLAG_UNKNOWN_5 | ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_11 | ACTOR_FLAG_UNKNOWN_23 | ACTOR_FLAG_UNKNOWN_25); - spawnableActorList_add(&D_80373134, actor_new, ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_11); - spawnableActorList_add(&D_80373158, actor_new, ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_11); - spawnableActorList_add(&D_80372EE0, actor_new, ACTOR_FLAG_UNKNOWN_0 | ACTOR_FLAG_UNKNOWN_6 | ACTOR_FLAG_UNKNOWN_8 | ACTOR_FLAG_UNKNOWN_25); + spawnableActorList_add(&chBetaVent1, actor_new, ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_11); + spawnableActorList_add(&chBetaVent2, actor_new, ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_11); + spawnableActorList_add(&chChumpFish, actor_new, ACTOR_FLAG_UNKNOWN_0 | ACTOR_FLAG_UNKNOWN_6 | ACTOR_FLAG_UNKNOWN_8 | ACTOR_FLAG_UNKNOWN_25); spawnableActorList_addIfMapVisited(&chTermite, actor_new, ACTOR_FLAG_UNKNOWN_0 | ACTOR_FLAG_UNKNOWN_8 | ACTOR_FLAG_UNKNOWN_16 | ACTOR_FLAG_UNKNOWN_25, MAP_2_MM_MUMBOS_MOUNTAIN); //ticker spawnableActorList_addIfMapVisited(&chFlotsam, actor_new, ACTOR_FLAG_UNKNOWN_0 | ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_8 | ACTOR_FLAG_UNKNOWN_11 | ACTOR_FLAG_UNKNOWN_16 | ACTOR_FLAG_UNKNOWN_25, MAP_31_RBB_RUSTY_BUCKET_BAY); //floatsam - spawnableActorList_addIfMapVisited(&D_80372C18, actor_new, ACTOR_FLAG_UNKNOWN_0 | ACTOR_FLAG_UNKNOWN_3 | ACTOR_FLAG_UNKNOWN_5 | ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_8 | ACTOR_FLAG_UNKNOWN_12 | ACTOR_FLAG_UNKNOWN_17, MAP_1B_MMM_MAD_MONSTER_MANSION); //teehee + spawnableActorList_addIfMapVisited(&chTeeHee, actor_new, ACTOR_FLAG_UNKNOWN_0 | ACTOR_FLAG_UNKNOWN_3 | ACTOR_FLAG_UNKNOWN_5 | ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_8 | ACTOR_FLAG_UNKNOWN_12 | ACTOR_FLAG_UNKNOWN_17, MAP_1B_MMM_MAD_MONSTER_MANSION); //teehee spawnableActorList_addIfMapVisited(&D_80372FC0, actor_new, ACTOR_FLAG_UNKNOWN_0 | ACTOR_FLAG_UNKNOWN_16 | ACTOR_FLAG_UNKNOWN_25, MAP_1B_MMM_MAD_MONSTER_MANSION); spawnableActorList_addIfMapVisited(&D_80372FE4, actor_new, ACTOR_FLAG_UNKNOWN_0 | ACTOR_FLAG_UNKNOWN_10 | ACTOR_FLAG_UNKNOWN_16 | ACTOR_FLAG_UNKNOWN_25, MAP_1B_MMM_MAD_MONSTER_MANSION); spawnableActorList_addIfMapVisited(&gChBat, actor_new, ACTOR_FLAG_UNKNOWN_0 | ACTOR_FLAG_UNKNOWN_5 | ACTOR_FLAG_UNKNOWN_21 |ACTOR_FLAG_UNKNOWN_25, MAP_1B_MMM_MAD_MONSTER_MANSION); //nibbly - spawnableActorList_addIfMapVisited(&D_80367130, actor_new, ACTOR_FLAG_UNKNOWN_0 | ACTOR_FLAG_UNKNOWN_3 | ACTOR_FLAG_UNKNOWN_5 | ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_8 | ACTOR_FLAG_UNKNOWN_11 | ACTOR_FLAG_UNKNOWN_25, MAP_D_BGS_BUBBLEGLOOP_SWAMP); //buzzbomb + spawnableActorList_addIfMapVisited(&chBuzzbomb, actor_new, ACTOR_FLAG_UNKNOWN_0 | ACTOR_FLAG_UNKNOWN_3 | ACTOR_FLAG_UNKNOWN_5 | ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_8 | ACTOR_FLAG_UNKNOWN_11 | ACTOR_FLAG_UNKNOWN_25, MAP_D_BGS_BUBBLEGLOOP_SWAMP); //buzzbomb spawnableActorList_addIfMapVisited(&chIcecubeA, actor_new, ACTOR_FLAG_UNKNOWN_0 | ACTOR_FLAG_UNKNOWN_6 | ACTOR_FLAG_UNKNOWN_8 | ACTOR_FLAG_UNKNOWN_17 | ACTOR_FLAG_UNKNOWN_25, MAP_27_FP_FREEZEEZY_PEAK); spawnableActorList_addIfMapVisited(&chShrapnelDescription, actor_new, ACTOR_FLAG_UNKNOWN_0 | ACTOR_FLAG_UNKNOWN_8 | ACTOR_FLAG_UNKNOWN_25, MAP_7_TTC_TREASURE_TROVE_COVE); //scrapnel spawnableActorList_addIfMapVisited(&D_80372D78, actor_new, ACTOR_FLAG_UNKNOWN_0 | ACTOR_FLAG_UNKNOWN_5 | ACTOR_FLAG_UNKNOWN_8 | ACTOR_FLAG_UNKNOWN_16 | ACTOR_FLAG_UNKNOWN_24 | ACTOR_FLAG_UNKNOWN_25, MAP_1B_MMM_MAD_MONSTER_MANSION); //limbo @@ -373,7 +373,7 @@ void spawnQueue_reset(void){ spawnableActorList_addIfMapVisited(&chBlackSnippet, actor_new, ACTOR_FLAG_UNKNOWN_5 | ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_24 | ACTOR_FLAG_UNKNOWN_25, MAP_7_TTC_TREASURE_TROVE_COVE); //black_snippet spawnableActorList_addIfMapVisited(&chMutieSnippet, actor_new, ACTOR_FLAG_UNKNOWN_0 | ACTOR_FLAG_UNKNOWN_5 | ACTOR_FLAG_UNKNOWN_12 | ACTOR_FLAG_UNKNOWN_24 | ACTOR_FLAG_UNKNOWN_25, MAP_7_TTC_TREASURE_TROVE_COVE); //mutie_snippet spawnableActorList_addIfMapVisited(&chClucker, actor_new, ACTOR_FLAG_UNKNOWN_5 | ACTOR_FLAG_UNKNOWN_11 | ACTOR_FLAG_UNKNOWN_23 |ACTOR_FLAG_UNKNOWN_25, MAP_40_CCW_HUB); //clucker - spawnableActorList_addIfMapVisited(&D_803728A0, actor_new, ACTOR_FLAG_UNKNOWN_0 | ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_8 | ACTOR_FLAG_UNKNOWN_11 | ACTOR_FLAG_UNKNOWN_25, MAP_12_GV_GOBIS_VALLEY); //scarab + spawnableActorList_addIfMapVisited(&chScarabBeetle, actor_new, ACTOR_FLAG_UNKNOWN_0 | ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_8 | ACTOR_FLAG_UNKNOWN_11 | ACTOR_FLAG_UNKNOWN_25, MAP_12_GV_GOBIS_VALLEY); //scarab spawnableActorList_addIfMapVisited(&chSnowman, actor_new, ACTOR_FLAG_UNKNOWN_5 | ACTOR_FLAG_UNKNOWN_6 | ACTOR_FLAG_UNKNOWN_10 | ACTOR_FLAG_UNKNOWN_25, MAP_27_FP_FREEZEEZY_PEAK); //sirslush switch(loaded_asm_file){ default: @@ -406,16 +406,16 @@ void spawnQueue_reset(void){ MM_func_803888B0(); break; case OVERLAY_7_SWAMP: - BGS_func_8038F1E0(); + bgs_updateSpawnableActors(); break; case OVERLAY_8_SHIP: RBB_func_80386C48(); break; case OVERLAY_9_SNOW: FP_func_80391324(); - spawnableActorList_add(&D_80367BC8, actor_new, ACTOR_FLAG_UNKNOWN_3); - spawnableActorList_add(&D_80367BEC, actor_new, ACTOR_FLAG_UNKNOWN_3); - spawnableActorList_add(&D_80367C10, actor_new, ACTOR_FLAG_UNKNOWN_3); + spawnableActorList_add(&chBluePresentCollectible, actor_new, ACTOR_FLAG_UNKNOWN_3); + spawnableActorList_add(&chGreenPresentCollectible, actor_new, ACTOR_FLAG_UNKNOWN_3); + spawnableActorList_add(&chRedPresentCollectible, actor_new, ACTOR_FLAG_UNKNOWN_3); break; case OVERLAY_A_TREE: CCW_func_8038DB6C(); @@ -434,7 +434,7 @@ void spawnQueue_reset(void){ if (loaded_asm_file != OVERLAY_4_DESERT) { GV_func_8038F154(); } if (loaded_asm_file != OVERLAY_5_BEACH) { code26D0_resetSpawnableActorsForTTC(); } if (loaded_asm_file != OVERLAY_6_JUNGLE) { MM_func_803888B0(); } - if (loaded_asm_file != OVERLAY_7_SWAMP) { BGS_func_8038F1E0(); } + if (loaded_asm_file != OVERLAY_7_SWAMP) { bgs_updateSpawnableActors(); } if (loaded_asm_file != OVERLAY_8_SHIP) { RBB_func_80386C48(); } if (loaded_asm_file != OVERLAY_9_SNOW) { FP_func_80391324(); } if (loaded_asm_file != OVERLAY_A_TREE) { CCW_func_8038DB6C(); } @@ -462,7 +462,7 @@ void spawnQueue_free(void){ void spawnQueue_func_802C39D4(void){ func_803268B4(); if(!levelSpecificFlags_validateCRC2()){ - eeprom_writeBlocks(0, 0, (void *)(uintptr_t)0x80749530, EEPROM_MAXBLOCKS); + eeprom_writeBlocks(0, 0, (void *)(uintptr_t) PHYS_TO_K0(0x00749530), EEPROM_MAXBLOCKS); } } @@ -502,12 +502,12 @@ void spawnQueue_flush(void){ func_803283D4(); } -void spawnQueue_unlock(void){ - spawnQueueLock = 0; +void spawnQueue_unlock(void) { + spawnQueueLock = FALSE; } -void spawnQueue_lock(void){ - spawnQueueLock = 1; +void spawnQueue_lock(void) { + spawnQueueLock = TRUE; } void __spawnQueue_add_0(void (* arg0)(void)){ diff --git a/src/core2/spline_bezier.c b/src/core2/spline_bezier.c index 60b98db21..bdc4a40d1 100644 --- a/src/core2/spline_bezier.c +++ b/src/core2/spline_bezier.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_C31A0.c #include "functions.h" #include "variables.h" #include diff --git a/src/core2/spline_pathfollow.c b/src/core2/spline_pathfollow.c index f9a7dc596..3d416e8d8 100644 --- a/src/core2/spline_pathfollow.c +++ b/src/core2/spline_pathfollow.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_B9770.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/sprite/render.c b/src/core2/sprite/render.c index 7424da231..688853f8c 100644 --- a/src/core2/sprite/render.c +++ b/src/core2/sprite/render.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_BD100.c #include "core1/core1.h" #include "functions.h" #include "variables.h" @@ -55,7 +56,7 @@ void func_80344138(BKSpriteDisplayData *self, s32 frame, s32 mirrored, f32 posit FrameInterpolation_RecordOpenChild("sprite_viewport", (uintptr_t)self); viewport_getPosition_vec3f(sp6C); - viewport_getLookbk_vector(sp60); + viewport_getLookVector(sp60); sp50[0] = position[0] - sp6C[0]; sp50[1] = position[1] - sp6C[1]; sp50[2] = position[2] - sp6C[2]; @@ -129,7 +130,7 @@ void func_80344424(BKSpriteDisplayData *arg0, s32 frame, bool mirrored, f32 posi FrameInterpolation_RecordOpenChild("sprite_viewport_rot", (uintptr_t)arg0); viewport_getPosition_vec3f(sp6C); - viewport_getLookbk_vector(sp60); + viewport_getLookVector(sp60); sp50[0] = position[0] - sp6C[0]; sp50[1] = position[1] - sp6C[1]; sp50[2] = position[2] - sp6C[2]; @@ -204,7 +205,7 @@ void func_80344720(BKSpriteDisplayData *arg0, s32 frame, bool mirrored, f32 posi // the caller rather than billboarded against the camera. FrameInterpolation_RecordOpenChild("sprite_3d", (uintptr_t)arg0); viewport_getPosition_vec3f(sp5C); - viewport_getLookbk_vector(sp50); + viewport_getLookVector(sp50); sp40[0] = position[0] - sp5C[0]; sp40[1] = position[1] - sp5C[1]; sp40[2] = position[2] - sp5C[2]; diff --git a/src/core2/sprite/rendertex.c b/src/core2/sprite/rendertex.c index 7933db4f3..29e33f5bf 100644 --- a/src/core2/sprite/rendertex.c +++ b/src/core2/sprite/rendertex.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_C0E60.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/sprite/screenoverlay.c b/src/core2/sprite/screenoverlay.c index 81e63673d..a0110f11d 100644 --- a/src/core2/sprite/screenoverlay.c +++ b/src/core2/sprite/screenoverlay.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_AEDA0.c #include "core1/core1.h" #include "functions.h" #include "variables.h" diff --git a/src/core2/sprite/texblock.c b/src/core2/sprite/texblock.c index 877da6005..b1f56c843 100644 --- a/src/core2/sprite/texblock.c +++ b/src/core2/sprite/texblock.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_B8020.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/state_timer.c b/src/core2/statetimer.c similarity index 97% rename from src/core2/state_timer.c rename to src/core2/statetimer.c index cc4132e0e..43ec68385 100644 --- a/src/core2/state_timer.c +++ b/src/core2/statetimer.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/statetimer.c #include "core2/statetimer.h" #include "bk_time.h" diff --git a/src/core2/texture_dataaccess.c b/src/core2/texture_dataaccess.c index 164e942ed..918f00c50 100644 --- a/src/core2/texture_dataaccess.c +++ b/src/core2/texture_dataaccess.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_63690.c #include #include "functions.h" #include "variables.h" @@ -51,12 +52,12 @@ s32 textureInfo_getPaletteSize(BKTextureInfo *this){ } // texture_getOffset -s32 func_802EA6DC(BKTextureInfo *this){ +s32 textureInfo_getOffset(BKTextureInfo *this){ return this->offset; } //texture_getSize -s32 func_802EA6E4(BKTextureInfo *this){ +s32 textureInfo_getTextureSize(BKTextureInfo *this){ s32 palette_size = textureInfo_getPaletteSize(this); s32 pixel_size = textureInfo_getBitDepth(this); @@ -64,6 +65,6 @@ s32 func_802EA6E4(BKTextureInfo *this){ } //textureList_getTexture -BKTextureInfo *func_802EA748(BKTextureList *arg0, s32 indx){ +BKTextureInfo *textureList_getTextureInfo(BKTextureList *arg0, s32 indx){ return (BKTextureInfo *)(arg0 +1) + indx; } diff --git a/src/core2/time.c b/src/core2/time.c index fa7e9f224..120493fa5 100644 --- a/src/core2/time.c +++ b/src/core2/time.c @@ -1,6 +1,7 @@ #include "bk_time.h" #include "core1/vimgr.h" +#include "version.h" #ifndef MIN # define MIN(a,b) (((a)<(b))?(a):(b)) @@ -26,7 +27,7 @@ void time_reset(void){ void time_setDeltaReal_sec(f32 d_seconds){ if(d_seconds != 0.0f){ - s_dTimeReal_sec = MIN(d_seconds, 0.05); + s_dTimeReal_sec = MIN(d_seconds, VER_SELECT(0.05, 0.06, 0.05, 0.05)); } else{ s_dTimeReal_sec = 0.01f; @@ -35,7 +36,7 @@ void time_setDeltaReal_sec(f32 d_seconds){ void time_setDeltaReal_frames(s32 d_frames){ s_dTimeReal_frames = MAX(MIN(0xf, d_frames) , 1); - time_setDeltaReal_sec(s_dTimeReal_frames*(1/60.0)); + time_setDeltaReal_sec(s_dTimeReal_frames*(1.0/FRAMERATE)); } s32 time_getDeltaReal_frames(void){ @@ -47,11 +48,11 @@ f32 time_getDelta(void){ } f32 time_func_8033DDB8(void){ - return viMgr_func_8024BD94()*(1/60.0); + return viMgr_func_8024BD94()*(1.0/FRAMERATE); } f32 time_getDelta_frames(void){ - return time_getDelta()*30.0; + return time_getDelta()*(FRAMERATE/2.0); } void time_setMultiplier(f32 multiplier){ diff --git a/src/core2/time_framedelta.c b/src/core2/time_framedelta.c index d9ac652ca..525731e34 100644 --- a/src/core2/time_framedelta.c +++ b/src/core2/time_framedelta.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_B6C60.c #include #include "functions.h" #include "variables.h" @@ -28,22 +29,7 @@ f32 func_8033DC20(void){ u64 now = SDL_GetPerformanceCounter(); u64 freq = SDL_GetPerformanceFrequency(); f32 out; - - if (last_ticks == 0) { - last_ticks = now; - out = 1.0f / 30.0f; // first frame: assume 1/30 (N64 rate) - } else { - out = (f32)(now - last_ticks) / (f32)freq; - last_ticks = now; - } - - // Cap at 50ms (matching time_setDeltaReal_sec cap) - if (out > 0.05f) out = 0.05f; - if (out <= 0.0f) out = 1.0f / 60.0f; - - // Keep D_80384470 updated for anything that reads it - D_80384470 = (s32)(out * 60.0f + 0.5f); - if (D_80384470 < 1) D_80384470 = 1; - + D_80384470 = viMgr_func_8024BD94(); + out = (1.0 / FRAMERATE)*D_80384470; return out; } diff --git a/src/core2/timed_funcqueue.c b/src/core2/timedfuncqueue.c similarity index 99% rename from src/core2/timed_funcqueue.c rename to src/core2/timedfuncqueue.c index 6fb994e18..7bb527941 100644 --- a/src/core2/timed_funcqueue.c +++ b/src/core2/timedfuncqueue.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/timedfuncqueue.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/vector.c b/src/core2/vla.c similarity index 99% rename from src/core2/vector.c rename to src/core2/vla.c index ddb6dc37b..5fc9ff726 100644 --- a/src/core2/vector.c +++ b/src/core2/vla.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/vla.c #include #include "functions.h" #include "core2/vla.h" diff --git a/src/core2/vtx/alphablend.c b/src/core2/vtx/alphablend.c index 32ee43d7e..bed705f72 100644 --- a/src/core2/vtx/alphablend.c +++ b/src/core2/vtx/alphablend.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_C76D0.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/vtx/colorapply.c b/src/core2/vtx/colorapply.c index 81ab464a1..deaa3182d 100644 --- a/src/core2/vtx/colorapply.c +++ b/src/core2/vtx/colorapply.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_C4F40.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/vtx/colorintensity.c b/src/core2/vtx/colorintensity.c index a27db662d..c6582ad65 100644 --- a/src/core2/vtx/colorintensity.c +++ b/src/core2/vtx/colorintensity.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_C8230.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/vtx/colorset.c b/src/core2/vtx/colorset.c index c881d926f..0675a34dd 100644 --- a/src/core2/vtx/colorset.c +++ b/src/core2/vtx/colorset.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_C5AF0.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/vtx/convert.c b/src/core2/vtx/convert.c index 9d530a9c3..bfe05a056 100644 --- a/src/core2/vtx/convert.c +++ b/src/core2/vtx/convert.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_C61C0.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/vtx/lighting.c b/src/core2/vtx/gclights.c similarity index 98% rename from src/core2/vtx/lighting.c rename to src/core2/vtx/gclights.c index ccf12fa17..4ec7b3eb3 100644 --- a/src/core2/vtx/lighting.c +++ b/src/core2/vtx/gclights.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/gclights.c #include "functions.h" #include "variables.h" #include @@ -165,7 +166,7 @@ static void __lighting_setPosition(s32 index , f32 *position) { TUPLE_COPY(v0->position, position) } -static void __lighting_setUnk18AndUnk1C(s32 index , f32 *unk18_and_unk1c) { +static void __lighting_setFadeRadii(s32 index , f32 *unk18_and_unk1c) { Lighting *v0 = bk_vector_at(sLightingbk_vectorList.bk_vector_ptr, index-1); v0->fade_radius_min_unscaled = unk18_and_unk1c[0]; v0->fade_radius_max_unscaled = unk18_and_unk1c[1]; @@ -190,7 +191,7 @@ void lightingVectorList_fromFile(File *file_ptr) { ) { lighting_ptr = __lighting_create(); __lighting_setPosition(lighting_ptr, position); - __lighting_setUnk18AndUnk1C(lighting_ptr, unk18_and_unk1c); + __lighting_setFadeRadii(lighting_ptr, unk18_and_unk1c); __lighting_setRgb(lighting_ptr, rgb); } } diff --git a/src/core2/vtx/list.c b/src/core2/vtx/list.c index eac054e13..59eb775d5 100644 --- a/src/core2/vtx/list.c +++ b/src/core2/vtx/list.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_654C0.c #include "core1/core1.h" #include "functions.h" #include "variables.h" @@ -41,7 +42,7 @@ void vtxList_getBounds_f32(BKVertexList *vtxList, f32 min[3], f32 max[3]){ max[2] = (f32) vtxList->maxCoord[2]; } -void vtxList_getBoundsMlMtxTransformed(BKVertexList *self, f32 min[3], f32 max[3]) { +void vtxList_getBoundsTransformed(BKVertexList *self, f32 min[3], f32 max[3]) { Vtx *start_vtx; Vtx *end_vtx; Vtx *i_vtx; @@ -75,7 +76,7 @@ void vtxList_getBoundsMlMtxTransformed(BKVertexList *self, f32 min[3], f32 max[3 } } -void func_802EC680(BKVertexList *self, s32 arg1, f32 arg2[3], f32 arg3[3]) { +void vtxList_func_802EC680(BKVertexList *self, s32 arg1, f32 arg2[3], f32 arg3[3]) { Vtx *start_vtx; Vtx *end_vtx; Vtx *i_vtx; @@ -227,7 +228,7 @@ void vtxList_func_802ECBD4(BKVertexList *dst, BKVertexList *src, f32 position[3] s32 pad40; viewport_getPosition_vec3f(vp_position); - viewport_getLookbk_vector(vp_look); + viewport_getLookVector(vp_look); mlMtxIdent(); func_80252CC4(position, rotation, 1.0f, NULL); mlMtx_apply_vec3f(vp_position, vp_position); diff --git a/src/core2/vtx/listutils.c b/src/core2/vtx/listutils.c index f484b58bd..5c028c7dc 100644 --- a/src/core2/vtx/listutils.c +++ b/src/core2/vtx/listutils.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_5FD90.c #include #include "functions.h" #include "variables.h" @@ -204,8 +205,8 @@ bool func_802E74A0(f32 arg0[3], f32 arg1, f32 arg2[3], f32 arg3[3]) { f32 sp24[3]; f32 sp20; - if (arg1 <= ml_func_802560D0(arg2, arg3, arg0)) { - return false; + if (arg1 <= ml_vec3f_distance_to_point(arg2, arg3, arg0)) { + return FALSE; } sp24[0] = (arg2[0] + arg3[0]) / 2; sp24[1] = (arg2[1] + arg3[1]) / 2; @@ -217,6 +218,7 @@ bool func_802E74A0(f32 arg0[3], f32 arg1, f32 arg2[3], f32 arg3[3]) { return true; } +// Unused bool func_802E7588(f32 arg0[3], f32 arg1, f32 arg2[3], f32 arg3) { return (ml_vec3f_distance(arg0, arg2) < (arg1 + arg3)); } diff --git a/src/core2/vtx/meshcount.c b/src/core2/vtx/meshcount.c index 3d553ebd1..393fd29e0 100644 --- a/src/core2/vtx/meshcount.c +++ b/src/core2/vtx/meshcount.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_62FD0.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/vtx/normalset.c b/src/core2/vtx/normalset.c index 786ce7efb..e31a5efd0 100644 --- a/src/core2/vtx/normalset.c +++ b/src/core2/vtx/normalset.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_C5F00.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/vtx/positionset.c b/src/core2/vtx/positionset.c index 49b2cb594..0c560f4f0 100644 --- a/src/core2/vtx/positionset.c +++ b/src/core2/vtx/positionset.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_C8490.c #include #include "functions.h" #include "variables.h" @@ -16,7 +17,7 @@ void func_8034F434(Struct76s *arg0, s32 arg1) { arg0->alpha = 0; arg0->unk2 = randi2(200, 255); arg0->unk4 = (s32) (arg0->unk4 + 1); - arg0->unk14 = arg0->unk10 = randf2(0.08f, 0.12f); + arg0->unk14 = arg0->unk10 = randf2(VER_SELECT(0.08f, 0.12f, 0.0f, 0.0f), VER_SELECT(0.12f, 0.18f, 0.0f, 0.0f)); if ((arg0->unk4 == 1) && func_8034C4CC()) { gcsfx_playWithPitch(SFX_B5_THUNDERBOLT, randf2(0.9f, 1.1f), randi2(10000, 20000)); } @@ -56,13 +57,13 @@ void func_8034F5B0(Struct76s *arg0, BKModel *arg1, s32 arg2){ func_8034F434(arg0, 1); } if (arg0->unkC == 1) { - if (arg0->unk10 <= 0.04) { - arg0->alpha = (arg0->unk10 / 0.04) * arg0->unk2; + if (arg0->unk10 <= VER_SELECT(0.04, 0.06, 0.0, 0.0)) { + arg0->alpha = (arg0->unk10 / VER_SELECT(0.04, 0.06, 0.0, 0.0)) * arg0->unk2; } else { - if (arg0->unk10 < (arg0->unk14 - 0.04)) { + if (arg0->unk10 < (arg0->unk14 - VER_SELECT(0.04, 0.06, 0.0, 0.0))) { arg0->alpha = arg0->unk2; } else { - arg0->alpha = ((arg0->unk14 - arg0->unk10) / 0.04) * arg0->unk2; + arg0->alpha = ((arg0->unk14 - arg0->unk10) / VER_SELECT(0.04, 0.06, 0.0, 0.0)) * arg0->unk2; } } if (ml_timer_update(&arg0->unk10, sp24)) { diff --git a/src/core2/vtx/renderstart.c b/src/core2/vtx/renderstart.c index b48c8919e..f20ff1171 100644 --- a/src/core2/vtx/renderstart.c +++ b/src/core2/vtx/renderstart.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_C62B0.c #include #include "functions.h" #include "variables.h" @@ -246,7 +247,7 @@ void func_8034E120(Struct6Ds *arg0, f32 arg1, f32 arg2, f32 arg3,s32 arg4){ } void func_8034E174(Struct6Ds *arg0){ - func_8034E1A4(arg0, 0x3ec, 0.7f, 0.9f); + func_8034E1A4(arg0, SFX_3EC_CCW_DOOR_OPENING, 0.7f, 0.9f); } void func_8034E1A4(Struct6Ds *arg0, enum sfx_e sfx_id, f32 arg2, f32 arg3){ diff --git a/src/core2/vtx/scale.c b/src/core2/vtx/scale.c index f0111ce62..f72955fea 100644 --- a/src/core2/vtx/scale.c +++ b/src/core2/vtx/scale.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_C7CC0.c #include #include "functions.h" #include "variables.h" diff --git a/src/core2/vtx/transform.c b/src/core2/vtx/transform.c index 48f8cb443..f737f7104 100644 --- a/src/core2/vtx/transform.c +++ b/src/core2/vtx/transform.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_C5440.c #include #include "functions.h" #include "port/ShipUtils.h" // BK_LOG_*, port_shapeControllerInput diff --git a/src/core2/vtx/uvset.c b/src/core2/vtx/uvset.c index 57a578bec..dc4e191e3 100644 --- a/src/core2/vtx/uvset.c +++ b/src/core2/vtx/uvset.c @@ -1,3 +1,4 @@ +// BanjoDecomp: core2/code_C5CC0.c #include #include "functions.h" #include "variables.h" diff --git a/src/cutscenes/bss_pad.c b/src/cutscenes/bss_pad.c deleted file mode 100644 index 598952dc5..000000000 --- a/src/cutscenes/bss_pad.c +++ /dev/null @@ -1,2 +0,0 @@ -// BanjoDecomp: bss_pad.c -char pad_cutscenes_8038E9E0[0x10]; diff --git a/src/cutscenes/checksums.c b/src/cutscenes/checksums.c new file mode 100644 index 000000000..6514c7fd6 --- /dev/null +++ b/src/cutscenes/checksums.c @@ -0,0 +1,7 @@ +// BanjoDecomp: cutscenes/checksums.c +#include +#include "checksums.h" + +// !! THIS FILE MUST BE LINKED FIRST FOR THIS OVERLAY !! + +/* bss */ struct overlay_checksums_s gChecksumsCutscenes; diff --git a/src/cutscenes/cutscene_trigger.c b/src/cutscenes/cutscene_trigger.c index 9c9ba8858..253557059 100644 --- a/src/cutscenes/cutscene_trigger.c +++ b/src/cutscenes/cutscene_trigger.c @@ -1,4 +1,4 @@ -// BanjoDecomp: (core2 origin - unknown exact file) +// BanjoDecomp: core2/ch/code_468E0.c #include #include "core1/core1.h" #include "functions.h" diff --git a/src/cutscenes/actor_spawninit.c b/src/cutscenes/cutscenesspawnqueue.c similarity index 99% rename from src/cutscenes/actor_spawninit.c rename to src/cutscenes/cutscenesspawnqueue.c index ab09fe0e4..d3a35cd79 100644 --- a/src/cutscenes/actor_spawninit.c +++ b/src/cutscenes/cutscenesspawnqueue.c @@ -1,4 +1,4 @@ -// BanjoDecomp: code_60F0.c +// BanjoDecomp: cutscenes/cutscenesspawnqueue.c #include #include "functions.h" #include "variables.h" diff --git a/src/cutscenes/fx/glow_sparkle.c b/src/cutscenes/glow_sparkle.c similarity index 100% rename from src/cutscenes/fx/glow_sparkle.c rename to src/cutscenes/glow_sparkle.c diff --git a/src/cutscenes/fx/smoke.c b/src/cutscenes/smoke.c similarity index 100% rename from src/cutscenes/fx/smoke.c rename to src/cutscenes/smoke.c diff --git a/src/cutscenes/fx/sparkle.c b/src/cutscenes/sparkle.c similarity index 100% rename from src/cutscenes/fx/sparkle.c rename to src/cutscenes/sparkle.c diff --git a/src/cutscenes/character_parade.c b/src/cutscenes/theendsign.c similarity index 79% rename from src/cutscenes/character_parade.c rename to src/cutscenes/theendsign.c index 8948202fb..3b1665620 100644 --- a/src/cutscenes/character_parade.c +++ b/src/cutscenes/theendsign.c @@ -1,17 +1,18 @@ -// BanjoDecomp: (core2 origin - unknown exact file) +// BanjoDecomp: core2/gc/theendsign.c #include #include "functions.h" #include "variables.h" Actor *func_802DC320(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx); -void func_802DC67C(Actor *this); +void gcTheEndSign_update(Actor *this); /* .data */ f32 D_80368070[3] = {0.0f, 0.0f, 0.0f}; -ActorInfo D_8036807C = { - 0x17C, 0x19C, 0x56C, - 0x1, NULL, - func_802DC67C, actor_update_func_80326224, func_802DC320, + +ActorInfo gcTheEndSign = { + MARKER_17C_MODEL_THE_END_SIGN, ACTOR_19C_MODEL_THE_END_SIGN, ASSET_56C_MODEL_THE_END_SIGN, + 0x1, NULL, + gcTheEndSign_update, actor_update_func_80326224, func_802DC320, 0, 0, 0.0f, 0 }; @@ -24,7 +25,7 @@ void func_802DC650(Actor * this){ func_8025A7DC(COMUSIC_AC_GOOD_ENDING); } -void func_802DC67C(Actor *this){ +void gcTheEndSign_update(Actor *this){ if(!this->initialized){ this->initialized = true; diff --git a/src/emptyLvl/checksums.c b/src/emptyLvl/checksums.c new file mode 100644 index 000000000..3475b09b2 --- /dev/null +++ b/src/emptyLvl/checksums.c @@ -0,0 +1,7 @@ +// BanjoDecomp: emptyLvl/checksums.c +#include +#include "checksums.h" + +// !! THIS FILE MUST BE LINKED FIRST FOR THIS OVERLAY !! + +/* bss */ struct overlay_checksums_s gChecksumsEmptyLvl; diff --git a/src/overlay_stub/empty_level.c b/src/emptyLvl/empty_level.c similarity index 75% rename from src/overlay_stub/empty_level.c rename to src/emptyLvl/empty_level.c index dbc493fde..532935b68 100644 --- a/src/overlay_stub/empty_level.c +++ b/src/emptyLvl/empty_level.c @@ -1,5 +1,5 @@ // BanjoDecomp: emptyLvl/code_0.c unsigned char emptyLvl = 0; -unsigned char emptyLvlBss[0x20]; +unsigned char emptyLvlBss[0x10]; void emptyLvl_func_803863F0(void){} diff --git a/src/FINALE/ch/chbossjinjo.c b/src/fight/chbossjinjo.c similarity index 99% rename from src/FINALE/ch/chbossjinjo.c rename to src/fight/chbossjinjo.c index 2d43be5ca..3fb61196b 100644 --- a/src/FINALE/ch/chbossjinjo.c +++ b/src/fight/chbossjinjo.c @@ -3,7 +3,7 @@ #include "core1/core1.h" #include "functions.h" #include "variables.h" -#include "../fight.h" +#include "fight.h" #include "core2/particle.h" extern void func_80324CFC(f32, enum comusic_e, s32); diff --git a/src/FINALE/ch/chbossjinjobase.c b/src/fight/chbossjinjobase.c similarity index 99% rename from src/FINALE/ch/chbossjinjobase.c rename to src/fight/chbossjinjobase.c index efb45d3b4..1cc5265b1 100644 --- a/src/FINALE/ch/chbossjinjobase.c +++ b/src/fight/chbossjinjobase.c @@ -1,5 +1,5 @@ // BanjoDecomp: fight/chbossjinjobase.c -#include "../fight.h" +#include "fight.h" #include "functions.h" #include "variables.h" #include diff --git a/src/FINALE/ch/chbossshadow.c b/src/fight/chbossshadow.c similarity index 97% rename from src/FINALE/ch/chbossshadow.c rename to src/fight/chbossshadow.c index 153ac9ed8..48bda115e 100644 --- a/src/FINALE/ch/chbossshadow.c +++ b/src/fight/chbossshadow.c @@ -2,7 +2,7 @@ #include #include "functions.h" #include "variables.h" -#include "../fight.h" +#include "fight.h" ActorInfo chBossShadow = { MARKER_288_GRUNTY_SHADOW, ACTOR_3AF_GRUNTY_SHADOW, ASSET_3BF_MODEL_PLAYER_SHADOW, 1, NULL, chBossShadow_update, actor_update_func_80326224, chBossShadow_draw, 0, 0, 0.0f, 0 }; diff --git a/src/fight/checksums.c b/src/fight/checksums.c new file mode 100644 index 000000000..3bc3a4bea --- /dev/null +++ b/src/fight/checksums.c @@ -0,0 +1,7 @@ +// BanjoDecomp: fight/checksums.c +#include +#include "checksums.h" + +// !! THIS FILE MUST BE LINKED FIRST FOR THIS OVERLAY !! + +/* bss */ struct overlay_checksums_s gChecksumsFight; diff --git a/src/FINALE/ch/chfinalboss.c b/src/fight/chfinalboss.c similarity index 97% rename from src/FINALE/ch/chfinalboss.c rename to src/fight/chfinalboss.c index 90e3d733d..a228d23c5 100644 --- a/src/FINALE/ch/chfinalboss.c +++ b/src/fight/chfinalboss.c @@ -1,5 +1,5 @@ // BanjoDecomp: fight/chfinalboss.c -#include "../fight.h" +#include "fight.h" #include "functions.h" #include "variables.h" #include @@ -168,9 +168,9 @@ Actor *chfinalboss_draw(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx) { Actor *this = marker_getActor(marker); ActorLocal_FinalBoss *local = (ActorLocal_FinalBoss *)&this->local; - func_8033A45C(3, local->unkD); - func_8033A45C(4, local->unkE); - func_8033A45C(5, local->unkC); + modelRender_setAppendageVisibility(3, local->unkD); + modelRender_setAppendageVisibility(4, local->unkE); + modelRender_setAppendageVisibility(5, local->unkC); if (local->phase == FINALBOSS_PHASE_1_BROOMSTICK) { modelRender_func_8033A25C(false); @@ -315,7 +315,7 @@ void chfinalboss_func_80386B54(f32 *arg0, f32 arg1) { } } -bool chfinalboss_func_80386BEC(Actor *this, f32 arg1) { +bool chfinalboss_turnTowardPlayer(Actor *this, f32 arg1) { this->yaw_ideal = (f32) subaddie_getYawToPlayer(this); subaddie_turnToYaw(this, arg1); if ((this->yaw_ideal < (this->yaw + arg1)) && ((this->yaw - arg1) < this->yaw_ideal)) { @@ -354,7 +354,7 @@ void chfinalboss_func_80386CF8(Actor *actor) { sp4C[0] = sp28[0] + sp34[0]; sp4C[1] = sp28[1] + sp34[1]; sp4C[2] = sp28[2] + sp34[2]; - func_8025727C(sp28[0], sp28[1], sp28[2], sp4C[0], sp4C[1], sp4C[2], &sp40[0], &sp40[1]); + ml_horizontal_and_vertical_angles(sp28[0], sp28[1], sp28[2], sp4C[0], sp4C[1], sp4C[2], &sp40[0], &sp40[1]); sp40[0] = 360.0f - sp40[0]; sp40[2] = 0.0f; ncStaticCamera_setPositionAndRotation(sp4C, sp40); @@ -427,7 +427,7 @@ void chfinalboss_func_80387074(s32 arg0) { FightSync_OnSpellSpawned(1); } -void chfinalboss_func_80387110(ActorMarker *marker, f32 arg1[3], f32 arg2, s32 arg3) { +void chfinalboss_throwObject(ActorMarker *marker, f32 arg1[3], f32 arg2, s32 arg3) { Actor *temp_v0; ActorLocal_FinalBoss *local; f32 sp2C[3]; @@ -468,14 +468,14 @@ void chfinalboss_func_80387110(ActorMarker *marker, f32 arg1[3], f32 arg2, s32 a } } -void chfinalboss_func_803872F8(Actor *arg0) { +void chfinalboss_throwFinalSpell(Actor *arg0) { f32 vec[3]; vec3fArray_get_vec3f(arg0->marker->unk44, 0xA, vec); - chfinalboss_func_80387110(arg0->marker, vec, 3.0f, 1); + chfinalboss_throwObject(arg0->marker, vec, 3.0f, 1); } -s32 chfinalboss_func_80387340(Actor *this, f32 arg1) { +s32 chfinalboss_throwFireball(Actor *this, f32 arg1) { f32 sp24[3]; if (actor_animationIsAt(this, 0.50f) != 0) { @@ -486,7 +486,7 @@ s32 chfinalboss_func_80387340(Actor *this, f32 arg1) { sp24[1] = this->position_y; sp24[2] = this->position_z; } - chfinalboss_func_80387110(this->marker, sp24, arg1, 0); + chfinalboss_throwObject(this->marker, sp24, arg1, 0); return 1; } return 0; @@ -948,7 +948,7 @@ void chfinalboss_phase1_update(ActorMarker *marker) { chfinalboss_func_80386600(this->marker, 0); chfinalboss_spawnBroomstickGlowParticles(this); chfinalboss_func_80387ACC(this, 60.0f * sp54); - if (chfinalboss_func_80386BEC(this, 240.0f * sp54)) { + if (chfinalboss_turnTowardPlayer(this, 240.0f * sp54)) { chfinalboss_phase1_setState(this, 5); chfinalboss_func_80386654(1.0f, fight_D_80391380, fight_D_80391390); } @@ -1046,9 +1046,9 @@ void chfinalboss_phase1_update(ActorMarker *marker) { break; case 10: chfinalboss_func_80387ACC(this, 60.0f * sp54); - chfinalboss_func_80386BEC(this, 30.0f); + chfinalboss_turnTowardPlayer(this, 30.0f); chfinalboss_func_8038871C(this, 460.0f, 400.0f * sp54); - chfinalboss_func_80387340(this, 1.0f); + chfinalboss_throwFireball(this, 1.0f); if (actor_animationIsAt(this, 0.9999f)) { chfinalboss_phase1_setState(this, 2); chfinalboss_func_803880A0(this, 2000.0f); @@ -1056,14 +1056,14 @@ void chfinalboss_phase1_update(ActorMarker *marker) { break; case 11: chfinalboss_func_80387ACC(this, 60.0f * sp54); - chfinalboss_func_80386BEC(this, 30.0f); + chfinalboss_turnTowardPlayer(this, 30.0f); if (local->unk9) { chfinalboss_func_8038871C(this, 460.0f, 400.0f * sp54); } break; case 12: chfinalboss_func_80387ACC(this, 60.0f * sp54); - chfinalboss_func_80386BEC(this, 30.0f); + chfinalboss_turnTowardPlayer(this, 30.0f); chfinalboss_func_8038871C(this, 460.0f, 400.0f * sp54); chfinalboss_func_803873DC(this, 600.0f, 2000.0f); if (actor_animationIsAt(this, 0.9999f)) { @@ -1074,7 +1074,7 @@ void chfinalboss_phase1_update(ActorMarker *marker) { break; case 13: chfinalboss_func_80387ACC(this, 60.0f * sp54); - chfinalboss_func_80386BEC(this, 30.0f); + chfinalboss_turnTowardPlayer(this, 30.0f); if (actor_animationIsAt(this, 0.9999f)) { if (local->hits >= 4) { chfinalboss_phase1_setState(this, 0xB); @@ -1147,13 +1147,13 @@ void chfinalboss_phase2_update(ActorMarker *marker) { break; case 15: - if (chfinalboss_func_80386BEC(this, 9.0f)) { + if (chfinalboss_turnTowardPlayer(this, 9.0f)) { chfinalboss_phase2_setState(this, 0x10); } break; case 16: - chfinalboss_func_80386BEC(this, 3.0f); - chfinalboss_func_80387340(this, 1.3f); + chfinalboss_turnTowardPlayer(this, 3.0f); + chfinalboss_throwFireball(this, 1.3f); if (actor_animationIsAt(this, 0.9999f)) { chfinalboss_phase2_setState(this, 0x12); local->unk3++; @@ -1167,19 +1167,19 @@ void chfinalboss_phase2_update(ActorMarker *marker) { } break; case 17: - chfinalboss_func_80386BEC(this, 3.0f); + chfinalboss_turnTowardPlayer(this, 3.0f); chfinalboss_func_803873DC(this, 1200.0f, 2400.0f); if (actor_animationIsAt(this, 0.9999f)) { chfinalboss_setPhase(this->marker, FINALBOSS_PHASE_3_FLIGHT); } break; case 18: - chfinalboss_func_80386BEC(this, 3.0f); + chfinalboss_turnTowardPlayer(this, 3.0f); if (this->lifetime_value > 0.0) { this->lifetime_value = this->lifetime_value - sp4C; break; } - if (chfinalboss_func_80386BEC(this, 3.0f)) { + if (chfinalboss_turnTowardPlayer(this, 3.0f)) { chfinalboss_phase2_setState(this, 0x10); } break; @@ -1355,13 +1355,13 @@ void chfinalboss_phase3_update(ActorMarker *marker) { } break; case 23: - if (chfinalboss_func_80386BEC(this, 9.0f) && (baiFrame_getState() != 3)) { + if (chfinalboss_turnTowardPlayer(this, 9.0f) && (baiFrame_getState() != 3)) { chfinalboss_phase3_setState(this, 0x18); } break; case 24: - chfinalboss_func_80386BEC(this, 3.0f); - if (chfinalboss_func_80387340(this, 1.3f)) { + chfinalboss_turnTowardPlayer(this, 3.0f); + if (chfinalboss_throwFireball(this, 1.3f)) { local->unk3++; } if (actor_animationIsAt(this, 0.9999f)) { @@ -1604,15 +1604,15 @@ void chfinalboss_phase4_update(ActorMarker *marker) { break; case 29: - if ((chfinalboss_func_80386BEC(this, 9.0f)) && (baiFrame_getState() != 3) && (sFinalBossJinjoStatueActivated == 0)) { + if ((chfinalboss_turnTowardPlayer(this, 9.0f)) && (baiFrame_getState() != 3) && (sFinalBossJinjoStatueActivated == 0)) { chfinalboss_phase4_setState(this, 0x1E); } break; case 30: - chfinalboss_func_80386BEC(this, 3.0f); + chfinalboss_turnTowardPlayer(this, 3.0f); if (sFinalBossJinjoStatueActivated == 0) { - chfinalboss_func_80387340(this, 1.0f); + chfinalboss_throwFireball(this, 1.0f); if (actor_animationIsAt(this, 0.9999f)) { local->unk3++; chfinalboss_phase4_setState(this, 0x1F); @@ -1624,12 +1624,12 @@ void chfinalboss_phase4_update(ActorMarker *marker) { break; case 31: - chfinalboss_func_80386BEC(this, 3.0f); + chfinalboss_turnTowardPlayer(this, 3.0f); if (this->lifetime_value > 0.0) { this->lifetime_value -= sp74; break; } - if (chfinalboss_func_80386BEC(this, 3.0f)) { + if (chfinalboss_turnTowardPlayer(this, 3.0f)) { chfinalboss_phase4_setState(this, 0x1E); } break; @@ -1641,7 +1641,7 @@ void chfinalboss_phase4_update(ActorMarker *marker) { break; case 33: - chfinalboss_func_80386BEC(this, 3.0f); + chfinalboss_turnTowardPlayer(this, 3.0f); sp5C[0] = this->position[0] + (this->velocity[0] * sp74); sp5C[1] = this->position[1] + (this->velocity[1] * sp74); sp5C[2] = this->position[2] + (this->velocity[2] * sp74); @@ -1839,22 +1839,22 @@ void chfinalboss_phase5_update(ActorMarker *marker) { } switch (this->state) { case 35: - chfinalboss_func_80386BEC(this, 3.0f); + chfinalboss_turnTowardPlayer(this, 3.0f); break; case 36: - if (chfinalboss_func_80386BEC(this, 9.0f) && (baiFrame_getState() != 3)) { + if (chfinalboss_turnTowardPlayer(this, 9.0f) && (baiFrame_getState() != 3)) { chfinalboss_phase5_setState(this, 0x25); } break; case 37: - chfinalboss_func_80386BEC(this, 3.0f); + chfinalboss_turnTowardPlayer(this, 3.0f); if (baiFrame_getState() == 3) { chfinalboss_phase5_setState(this, 0x24); break; } - if (chfinalboss_func_80387340(this, 1.0f)) { + if (chfinalboss_throwFireball(this, 1.0f)) { local->unk3++; } if ((actor_animationIsAt(this, 0.9999f)) && (local->unk3 >= 5)) { @@ -1863,7 +1863,7 @@ void chfinalboss_phase5_update(ActorMarker *marker) { break; case 38: - chfinalboss_func_80386BEC(this, 3.0f); + chfinalboss_turnTowardPlayer(this, 3.0f); chfinalboss_func_803873DC(this, 700.0f, 2400.0f); if (actor_animationIsAt(this, 0.9999f)) { chfinalboss_phase5_setState(this, 0x27); @@ -1875,7 +1875,7 @@ void chfinalboss_phase5_update(ActorMarker *marker) { if (local->unk8) { chfinalboss_func_80386C68(this, 4.5f); } else { - chfinalboss_func_80386BEC(this, 3.0f); + chfinalboss_turnTowardPlayer(this, 3.0f); } if (this->lifetime_value > 0.0) { this->lifetime_value -= dt; @@ -1948,7 +1948,7 @@ void chfinalboss_phase5_update(ActorMarker *marker) { FUNC_8030E624(SFX_130_GRUNTY_ECHOING_CRY, 1.0f, 32000); } if (actor_animationIsAt(this, 0.85f)) { - chfinalboss_func_803872F8(this); + chfinalboss_throwFinalSpell(this); } if (actor_animationIsAt(this, 0.9f)) { ncStaticCamera_exit(); diff --git a/src/FINALE/chgreenblast.c b/src/fight/chgreenblast.c similarity index 100% rename from src/FINALE/chgreenblast.c rename to src/fight/chgreenblast.c diff --git a/src/FINALE/ch/chjinjonator.c b/src/fight/chjinjonator.c similarity index 99% rename from src/FINALE/ch/chjinjonator.c rename to src/fight/chjinjonator.c index 470f72003..4566ed1b9 100644 --- a/src/FINALE/ch/chjinjonator.c +++ b/src/fight/chjinjonator.c @@ -2,7 +2,7 @@ #include #include "functions.h" #include "variables.h" -#include "../fight.h" +#include "fight.h" extern void func_80324CFC(f32, s32, s32); extern void func_802F9E44(s32, f32, f32, f32, f32); diff --git a/src/FINALE/ch/chjinjonatorbase.c b/src/fight/chjinjonatorbase.c similarity index 99% rename from src/FINALE/ch/chjinjonatorbase.c rename to src/fight/chjinjonatorbase.c index 19b68b56c..591f74524 100644 --- a/src/FINALE/ch/chjinjonatorbase.c +++ b/src/fight/chjinjonatorbase.c @@ -2,7 +2,7 @@ #include #include "functions.h" #include "variables.h" -#include "../fight.h" +#include "fight.h" #include "port/Network/Anchor/FightSync.h" diff --git a/src/FINALE/chspellbarrier.c b/src/fight/chspellbarrier.c similarity index 100% rename from src/FINALE/chspellbarrier.c rename to src/fight/chspellbarrier.c diff --git a/src/FINALE/chspellfireball.c b/src/fight/chspellfireball.c similarity index 100% rename from src/FINALE/chspellfireball.c rename to src/fight/chspellfireball.c diff --git a/src/FINALE/chstonejinjo.c b/src/fight/chstonejinjo.c similarity index 100% rename from src/FINALE/chstonejinjo.c rename to src/fight/chstonejinjo.c diff --git a/src/FINALE/fight.c b/src/fight/fight.c similarity index 99% rename from src/FINALE/fight.c rename to src/fight/fight.c index c068e4ef9..c22543b63 100644 --- a/src/FINALE/fight.c +++ b/src/fight/fight.c @@ -6,8 +6,6 @@ #include "fight.h" #include "actor.h" -u8 sFightPadding[0x10]; - void fight_addSpawnableActors(void) { spawnableActorList_add(&chSpellFireball, actor_new, ACTOR_FLAG_UNKNOWN_2 | ACTOR_FLAG_UNKNOWN_6 | ACTOR_FLAG_UNKNOWN_10 | ACTOR_FLAG_UNKNOWN_15 | ACTOR_FLAG_UNKNOWN_20); diff --git a/src/FINALE/fight.h b/src/fight/fight.h similarity index 97% rename from src/FINALE/fight.h rename to src/fight/fight.h index 63a1e6794..7f960766a 100644 --- a/src/FINALE/fight.h +++ b/src/fight/fight.h @@ -127,7 +127,7 @@ extern void chfinalboss_createGreenGlowParticle(f32 position[3], s32 color[3]); extern void chfinalboss_createSingleSpriteParticle(f32 position[3], enum asset_e sprite_id); extern void chfinalboss_spawnBroomstickGlowParticles(Actor *this); extern void chfinalboss_func_80386B54(f32 *arg0, f32 arg1); -extern bool chfinalboss_func_80386BEC(Actor *this, f32 arg1); +extern bool chfinalboss_turnTowardPlayer(Actor *this, f32 arg1); extern bool chfinalboss_func_80386C68(Actor *this, f32 arg1); extern void chfinalboss_func_80386CF8(Actor *actor); extern void __chfinalboss_dropHealth(ActorMarker *arg0); @@ -137,9 +137,9 @@ extern void chfinalboss_func_80386EC0(s32 arg0); extern void chfinalboss_func_80386F5C(ActorMarker * arg0, f32 arg1[3], f32 arg2, f32 arg3); extern void chfinalboss_func_80386FD8(s32 arg0); extern void chfinalboss_func_80387074(s32 arg0); -extern void chfinalboss_func_80387110(ActorMarker *marker, f32 arg1[3], f32 arg2, s32 arg3); -extern void chfinalboss_func_803872F8(Actor *arg0); -extern s32 chfinalboss_func_80387340(Actor *this, f32 arg1); +extern void chfinalboss_throwObject(ActorMarker *marker, f32 arg1[3], f32 arg2, s32 arg3); +extern void chfinalboss_throwFinalSpell(Actor *arg0); +extern s32 chfinalboss_throwFireball(Actor *this, f32 arg1); extern void chfinalboss_func_803873DC(Actor *actor, f32 arg1, f32 arg2); extern bool chfinalboss_flyTo(Actor *this, f32 arg1[3], f32 v_max, f32 arg3, f32 arg4, f32 arg5, f32 arg6); extern void chfinalboss_func_8038770C(Actor *actor); diff --git a/src/LAIR/ch/brentilda.c b/src/lair/ch/brentilda.c similarity index 99% rename from src/LAIR/ch/brentilda.c rename to src/lair/ch/brentilda.c index 57e78e5c4..7506b988f 100644 --- a/src/LAIR/ch/brentilda.c +++ b/src/lair/ch/brentilda.c @@ -178,7 +178,7 @@ void chBrentilda_update(Actor *this) { } if( (phi_f2 < 300.0) && (player_movementGroup() == BSGROUP_0_NONE) - && func_8028F20C() + && player_isStableWithExtraSteps() && !gcdialog_hasCurrentTextId()) { if (!fileProgressFlag_get(FILEPROG_96_MET_BRENTILDA)) { gcdialog_showDialog(ASSET_10A1_DIALOG_BRENTILDA_MEET, 0xA, this->position, this->marker, func_8038BADC, NULL); diff --git a/src/LAIR/ch/cauldron.c b/src/lair/ch/cauldron.c similarity index 98% rename from src/LAIR/ch/cauldron.c rename to src/lair/ch/cauldron.c index 18ff35ec1..e2e24e790 100644 --- a/src/LAIR/ch/cauldron.c +++ b/src/lair/ch/cauldron.c @@ -166,7 +166,7 @@ void func_8038AB90(Actor *this, s32 arg1, s32 arg2, enum sfx_e sfx_id, f32 sfx_t if (arg2 == 2) { coMusicPlayer_playMusicWeak(COMUSIC_3F_MAGIC_CARPET_RISING, 32000); func_80324D2C(2.6f, COMUSIC_3F_MAGIC_CARPET_RISING); - gcsfx_playAtSampleRate(SFX_7C_CHEBOOF); + gcsfx_play(SFX_7C_CHEBOOF); } } } @@ -351,7 +351,7 @@ void chWarpCauldron_update(Actor *this) { case 5: //L8038B48C func_8038A96C(this, 3); if (actor_animationIsAt(this, 0.01f)) { - gcsfx_playAtSampleRate(SFX_7C_CHEBOOF); + gcsfx_play(SFX_7C_CHEBOOF); } if (actor_animationIsAt(this, 0.63f)) { volatileFlag_set(VOLATILE_FLAG_1E, 0); @@ -435,8 +435,8 @@ Actor *chWarpCauldron_draw(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx) this = marker_getActor(marker); if(this->modelCacheIndex == ACTOR_23B_WARP_CAULDRON) { - func_8033A45C(3, BOOL(this->unk38_0)); - func_8033A45C(4, this->unk38_0 ? false : true); + modelRender_setAppendageVisibility(3, BOOL(this->unk38_0)); + modelRender_setAppendageVisibility(4, this->unk38_0 ? false : true); } this = actor_draw(marker, gfx, mtx, vtx); if (marker->unk14_21 && this->unk38_0 && (getGameMode() != GAME_MODE_4_PAUSED)) { diff --git a/src/LAIR/ch/cheato.c b/src/lair/ch/cheato.c similarity index 96% rename from src/LAIR/ch/cheato.c rename to src/lair/ch/cheato.c index bff79a50a..0b5388c37 100644 --- a/src/LAIR/ch/cheato.c +++ b/src/lair/ch/cheato.c @@ -1,4 +1,4 @@ -// BanjoDecomp: code_9C40.c +// BanjoDecomp: lair/ch/cheato.c #include #include "functions.h" #include "variables.h" @@ -17,8 +17,8 @@ ActorInfo D_803948B8 = { 0x16F, 0x1D7, 0x54F, 0x1, D_80394860, func_803902B8, ac /* .code */ Actor *func_80390030(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx){ - func_8033A45C(3, 1); - func_8033A45C(4, 1); + modelRender_setAppendageVisibility(3, 1); + modelRender_setAppendageVisibility(4, 1); return actor_draw(marker, gfx, mtx, vtx); } @@ -94,7 +94,7 @@ void func_803902B8(Actor *this) { this->has_met_before = volatileFlag_get(VOLATILE_FLAG_1F_IN_CHARACTER_PARADE); this->initialized = true; } - _player_getPosition(sp5C); + playerPosition_get(sp5C); sp58 = ml_vec3f_within_distance(this->position, sp5C, 1750.0f) && !this->has_met_before; if (sp58 && !this->unk38_0) { func_8032BB88(this, 0, 0x1F4); diff --git a/src/LAIR/ch/minigame_ffprize.c b/src/lair/ch/furnacefunprizes.c similarity index 97% rename from src/LAIR/ch/minigame_ffprize.c rename to src/lair/ch/furnacefunprizes.c index dde3d4b26..66a69b41e 100644 --- a/src/LAIR/ch/minigame_ffprize.c +++ b/src/lair/ch/furnacefunprizes.c @@ -1,4 +1,4 @@ -// BanjoDecomp: code_BBD0.c +// BanjoDecomp: lair/ch/furnacefunprizes.c #include #include "functions.h" #include "variables.h" @@ -43,8 +43,8 @@ ActorInfo D_80394C94 = { MARKER_29A_FF_PRIZE, ACTOR_3C8_FF_PRIZE_TOOTY, ASSET_35 /* .code */ Actor *func_80391FC0(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx){ - func_8033A45C(4, 1); - func_8033A45C(5, 1); + modelRender_setAppendageVisibility(4, 1); + modelRender_setAppendageVisibility(5, 1); return actor_draw(marker, gfx, mtx, vtx); } diff --git a/src/LAIR/ch/gruntling.c b/src/lair/ch/gruntling.c similarity index 99% rename from src/LAIR/ch/gruntling.c rename to src/lair/ch/gruntling.c index 353e13e31..ce3125ac1 100644 --- a/src/LAIR/ch/gruntling.c +++ b/src/lair/ch/gruntling.c @@ -1,4 +1,4 @@ -// BanjoDecomp: code_A4A0.c +// BanjoDecomp: lair/ch/gruntling.c #include #include "functions.h" #include "variables.h" diff --git a/src/LAIR/ch/grunty_final.c b/src/lair/ch/lairgruntilda.c similarity index 95% rename from src/LAIR/ch/grunty_final.c rename to src/lair/ch/lairgruntilda.c index 4aad4aaa2..f635457c9 100644 --- a/src/LAIR/ch/grunty_final.c +++ b/src/lair/ch/lairgruntilda.c @@ -1,4 +1,4 @@ -// BanjoDecomp: code_C1C0.c +// BanjoDecomp: lair/ch/lairgruntilda.c #include #include "functions.h" #include "variables.h" @@ -21,9 +21,9 @@ ActorInfo D_80394CF0 = { 0x29B, 0x3C5, 0x53D, 0x1, D_80394CC0, func_80392700, fu /* .code */ Actor *func_803925B0(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx){ - func_8033A45C(3, 0); - func_8033A45C(4, 0); - func_8033A45C(5, 0); + modelRender_setAppendageVisibility(3, 0); + modelRender_setAppendageVisibility(4, 0); + modelRender_setAppendageVisibility(5, 0); return actor_draw(marker, gfx, mtx, vtx); } diff --git a/src/LAIR/ch/item_pillows.c b/src/lair/ch/refillpillow.c similarity index 94% rename from src/LAIR/ch/item_pillows.c rename to src/lair/ch/refillpillow.c index df541c8e5..e9b9f5d35 100644 --- a/src/LAIR/ch/item_pillows.c +++ b/src/lair/ch/refillpillow.c @@ -1,4 +1,4 @@ -// BanjoDecomp: code_A170.c +// BanjoDecomp: lair/ch/refillpillow.c #include #include "functions.h" #include "variables.h" @@ -26,8 +26,8 @@ ActorInfo D_80394958 = { 0x172, 0x1DA, 0x549, 0x1, D_80394900, func_803906A0, ac /* .code */ Actor *func_80390560(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx){ - func_8033A45C(3, marker->collidable); - func_8033A45C(4, marker->collidable); + modelRender_setAppendageVisibility(3, marker->collidable); + modelRender_setAppendageVisibility(4, marker->collidable); return actor_draw(marker, gfx, mtx, vtx); } diff --git a/src/lair/checksums.c b/src/lair/checksums.c new file mode 100644 index 000000000..dd033ff12 --- /dev/null +++ b/src/lair/checksums.c @@ -0,0 +1,7 @@ +// BanjoDecomp: lair/checksums.c +#include +#include "checksums.h" + +// !! THIS FILE MUST BE LINKED FIRST FOR THIS OVERLAY !! + +/* bss */ struct overlay_checksums_s gChecksumsLair; diff --git a/src/LAIR/ch/fall_damagedetect.c b/src/lair/fall_damagedetect.c similarity index 100% rename from src/LAIR/ch/fall_damagedetect.c rename to src/lair/fall_damagedetect.c diff --git a/src/LAIR/ch/ff_lava_fireball.c b/src/lair/ff_lava_fireball.c similarity index 100% rename from src/LAIR/ch/ff_lava_fireball.c rename to src/lair/ff_lava_fireball.c diff --git a/src/LAIR/ch/ff_lava_fireball_actor.c b/src/lair/ff_lava_fireball_actor.c similarity index 100% rename from src/LAIR/ch/ff_lava_fireball_actor.c rename to src/lair/ff_lava_fireball_actor.c diff --git a/src/LAIR/ff_manager.c b/src/lair/ff_manager.c similarity index 97% rename from src/LAIR/ff_manager.c rename to src/lair/ff_manager.c index 4f93e4c56..4b1fee6ff 100644 --- a/src/LAIR/ff_manager.c +++ b/src/lair/ff_manager.c @@ -5,9 +5,8 @@ #include "model.h" #include "core2/gc/zoombox.h" -#include "core2/quiz_storage.h" #include "core2/nc/camera.h" - +#include "core2/quiz/storage.h" #define ARRLEN(x) ((s32)(sizeof(x) / sizeof(x[0]))) @@ -947,17 +946,17 @@ void ff_setState(enum FF_Action next_state) { if (((s32) ffStorage->currentBoardTile->tileType >= 7) && (quizQuestionAskedBitfield_get(func_8038D60C(ffStorage->currentTileId)) == 0)) { item_adjustByDiffWithHud(ITEM_27_JOKER_CARD, ffStorage->currentBoardTile->tileType - 6); quizQuestionAskedBitfield_set(func_8038D60C(ffStorage->currentTileId), true); - volatileFlag_setAndTriggerDialog_4(VOLATILE_FLAG_A8_FF_GOT_JOKER); + progressDialog_setAndTriggerDialog_4(VOLATILE_FLAG_A8_FF_GOT_JOKER); } if (ffStorage->currentTileId != 0x1EF) { gcsfx_playWithPitch(SFX_126_AUDIENCE_BOOING, 1.0f, 0x7FF8); if (ffStorage->currentBoardTile->tileType == FFTT_5_GRUNTY) { - volatileFlag_setAndTriggerDialog_4(VOLATILE_FLAG_A2_FF_GRUNTY_ANSWER_RIGHT); + progressDialog_setAndTriggerDialog_4(VOLATILE_FLAG_A2_FF_GRUNTY_ANSWER_RIGHT); } if (volatileFlag_get(VOLATILE_FLAG_A0_FF_FIRST_ANSWER_RIGHT)) { - volatileFlag_setAndTriggerDialog_4(VOLATILE_FLAG_A1_FF_NEXT_ANSWER_RIGHT); + progressDialog_setAndTriggerDialog_4(VOLATILE_FLAG_A1_FF_NEXT_ANSWER_RIGHT); } - volatileFlag_setAndTriggerDialog_4(VOLATILE_FLAG_A0_FF_FIRST_ANSWER_RIGHT); + progressDialog_setAndTriggerDialog_4(VOLATILE_FLAG_A0_FF_FIRST_ANSWER_RIGHT); } } else { if (ffStorage->currentBoardTile->tileType == FFTT_6_SKULL) { @@ -984,9 +983,9 @@ void ff_setState(enum FF_Action next_state) { lair_func_8038C640(ffStorage->currentTileId, ffStorage->currentBoardTile); } if (volatileFlag_get(VOLATILE_FLAG_A3_FF_FIRST_ANSWER_WRONG)) { - volatileFlag_setAndTriggerDialog_4(VOLATILE_FLAG_A4_FF_NEXT_ANSWER_WRONG); + progressDialog_setAndTriggerDialog_4(VOLATILE_FLAG_A4_FF_NEXT_ANSWER_WRONG); } - volatileFlag_setAndTriggerDialog_4(VOLATILE_FLAG_A3_FF_FIRST_ANSWER_WRONG); + progressDialog_setAndTriggerDialog_4(VOLATILE_FLAG_A3_FF_FIRST_ANSWER_WRONG); } break; @@ -1138,7 +1137,7 @@ void lair_func_8038E0B0(void) { s32 sp48[6]; //buttons s32 temp_v0; s32 sp3C[2]; //joystick - s32 sp38; + s32 ff_tile_type; s32 sp28; if( (gsworld_getMap() == MAP_8E_GL_FURNACE_FUN) @@ -1160,11 +1159,12 @@ void lair_func_8038E0B0(void) { ffStorage->currentTileId = temp_v0; ffStorage->currentBoardTile = ff_getCurrentBoardTile(ffStorage->currentTileId); } - sp38 = MIN((ffStorage->currentTileId != 0) ? ffStorage->currentBoardTile->tileType : -1, FFTT_7_JOKER); - if ((ffStorage->currentTileId != 0) && (ffStorage->currentBoardTile->unk9 == 0) && func_8028F20C()) { + // If you see FFTT_8_JOKER in the table, use FFTT_7_JOKER instead + ff_tile_type = MIN((ffStorage->currentTileId != 0) ? ffStorage->currentBoardTile->tileType : -1, FFTT_7_JOKER); + if ((ffStorage->currentTileId != 0) && (ffStorage->currentBoardTile->unk9 == 0) && player_isStableWithExtraSteps()) { ffStorage->currentBoardTile->unk9 = 2; if (ffStorage->unk11) { - switch(sp38){ + switch(ff_tile_type){ case FFTT_6_SKULL://L8038E26C comusic_playTrack(COMUSIC_7B_STEP_ON_SKULL_TILE); break; @@ -1220,23 +1220,23 @@ void lair_func_8038E0B0(void) { } code_73640_printItemCount(0x14); code_73640_printItemCount(0x16); - if (sp38 != FFTT_0_NIL) { - sp28 = sp38 - 1 + FILEPROG_55_FF_BK_SQUARE_INSTRUCTIONS; - if (!fileProgressFlag_get(sp28) && gcdialog_showDialog(sp38 + 0x101E, 0, NULL, NULL, NULL, NULL)) { + if (ff_tile_type != FFTT_0_NIL) { + sp28 = ff_tile_type - 1 + FILEPROG_55_FF_BK_SQUARE_INSTRUCTIONS; + if (!fileProgressFlag_get(sp28) && gcdialog_showDialog(ff_tile_type + 0x101E, 0, NULL, NULL, NULL, NULL)) { fileProgressFlag_set(sp28, true); } s32 ffLifeThreshold = 1; CALL_EVENT(OnFurnaceFunDialog, &ffLifeThreshold); - if ((sp38 == FFTT_6_SKULL) && (item_getCount(ITEM_16_LIFE) == ffLifeThreshold)) { - volatileFlag_setAndTriggerDialog_4(VOLATILE_FLAG_AB_LAST_LIFE_ON_SKULL); + if ((ff_tile_type == FFTT_6_SKULL) && (item_getCount(ITEM_16_LIFE) == ffLifeThreshold)) { + progressDialog_setAndTriggerDialog_4(VOLATILE_FLAG_AB_LAST_LIFE_ON_SKULL); } else if (item_getCount(ITEM_14_HEALTH) == 1) { - volatileFlag_setAndTriggerDialog_4(VOLATILE_FLAG_AA_FF_LOW_HEALTH); + progressDialog_setAndTriggerDialog_4(VOLATILE_FLAG_AA_FF_LOW_HEALTH); } if ((ffStorage->currentBoardTile->unk9 == 2) && (player_movementGroup() == BSGROUP_0_NONE)) { if (func_8028EFEC() && (sp48[FACE_BUTTON(BUTTON_A)] == 1)) { func_803114D0(); player_getRotation(ffStorage->playerRotation); - ffStorage->ffQuestionType = ff_getQuestionType(sp38); + ffStorage->ffQuestionType = ff_getQuestionType(ff_tile_type); ff_prepareNextQuestion(ffStorage->ffQuestionType); ff_setState(3); return; @@ -1246,7 +1246,7 @@ void lair_func_8038E0B0(void) { lair_func_8038C640(ffStorage->currentTileId, ffStorage->currentBoardTile); item_dec(ITEM_27_JOKER_CARD); func_8030E6D4(SFX_3EA_BANJO_GUH_HUH); - volatileFlag_setAndTriggerDialog_4(VOLATILE_FLAG_A9_FF_USED_JOKER); + progressDialog_setAndTriggerDialog_4(VOLATILE_FLAG_A9_FF_USED_JOKER); if (ffStorage->currentTileId == 0x1EF) { ff_setState(8); } diff --git a/src/LAIR/jigsawpicture.c b/src/lair/jigsawpicture.c similarity index 97% rename from src/LAIR/jigsawpicture.c rename to src/lair/jigsawpicture.c index 02b65c090..416ada145 100644 --- a/src/LAIR/jigsawpicture.c +++ b/src/lair/jigsawpicture.c @@ -2,6 +2,7 @@ #include #include "functions.h" #include "variables.h" +#include "jigsawpicture.h" #include "port/Romhack/RomhackConfig.h" #include "port/Network/Anchor/JigsawPedestal.h" extern void player_walkToPosition(f32[3], f32, void(*)(ActorMarker *), ActorMarker *); @@ -116,7 +117,7 @@ void onJigsawPodiumCollide(ActorMarker *marker, ActorMarker *other_marker){ } bool isBanjoOnPodium(ActorMarker *marker) { - return func_8028F20C() && func_8028FB48(0x08000000) && marker->isBanjoOnTop; + return player_isStableWithExtraSteps() && func_8028FB48(0x08000000) && marker->isBanjoOnTop; } s32 isPicturePiecePlaced(Actor *this, s32 arg1){ @@ -496,14 +497,15 @@ void updateJigsawPictureActor(Actor *this) { controller_copyFaceButtons(0, sp7C); controller_copySideButtons(0, sp6C); func_8038EDBC(this); - if (this->state != 1 && !port_jigsawPedestal_isSelf(this->actorTypeSpecificField)) { - jigsawPicture_setState(this, 1); + if (this->state != JIGSAW_PICTURE_LEAVE_PODIUM && !port_jigsawPedestal_isSelf(this->actorTypeSpecificField)) { + jigsawPicture_setState(this, JIGSAW_PICTURE_LEAVE_PODIUM); return; } - switch(this->state){ - case 1://L8038FCD0 - if (!this->has_met_before && (!func_8028F20C() || !func_8028FB48(0x08000000))) { - this->has_met_before = true; + + switch (this->state) { + case JIGSAW_PICTURE_LEAVE_PODIUM: + if (!this->has_met_before && (!player_isStableWithExtraSteps() || !func_8028FB48(0x08000000))) { + this->has_met_before = TRUE; } if (subaddie_playerIsWithinSphereAndActive(this, 300)) { if ((this->actorTypeSpecificField == 0xA) && !fileProgressFlag_get(FILEPROG_F6_SEEN_DOOR_OF_GRUNTY_PUZZLE_PODIUM)) { diff --git a/src/lair/jigsawpicture.h b/src/lair/jigsawpicture.h new file mode 100644 index 000000000..9e940ac34 --- /dev/null +++ b/src/lair/jigsawpicture.h @@ -0,0 +1,11 @@ +// BanjoDecomp: lair/jigsawpicture.h +typedef enum { + JIGSAW_PICTURE_LEAVE_PODIUM = 1, + JIGSAW_PICTURE_ENTER_PODIUM = 2, + JIGSAW_PICTURE_INSTRUCTIONS = 3, + JIGSAW_PICTURE_WAITING = 4, + JIGSAW_PICTURE_ADD_PIECE = 5, + JIGSAW_PICTURE_ADD_ALL = 6, + JIGSAW_PICTURE_COMPLETE = 7, + JIGSAW_PICTURE_REMOVE_PIECE = 8 +} JigsawPictureState; diff --git a/src/LAIR/actor_spawninit.c b/src/lair/lairspawnqueue.c similarity index 84% rename from src/LAIR/actor_spawninit.c rename to src/lair/lairspawnqueue.c index 2be3d8338..e749655eb 100644 --- a/src/LAIR/actor_spawninit.c +++ b/src/lair/lairspawnqueue.c @@ -1,4 +1,4 @@ -// BanjoDecomp: code_0.c +// BanjoDecomp: lair/lairspawnqueue.c #include #include "functions.h" #include "variables.h" @@ -10,13 +10,13 @@ extern void func_8028F918(s32); extern void func_802D2FB0(Actor *, s32, s32, s32, f32, s32, s32, s32); extern void func_802D3CE8(Actor *); -extern void func_802D3D54(Actor *); +extern void chMMMBreakableWooden_update(Actor *); extern void func_802D3D74(Actor *this); extern void func_802D4830(Actor *, s32, f32); extern void func_80324CFC(f32, enum comusic_e, s32); extern int actor_animationIsAt(Actor *, f32); extern void subaddie_set_state_with_direction(Actor *, s32, f32, s32); -extern void func_8033A45C(s32, s32); +extern void modelRender_setAppendageVisibility(s32, s32); extern ActorArray *suBaddieActorArray; @@ -116,53 +116,335 @@ ActorAnimationInfo D_80392CB0[] = { {0x271, 3.0f}, {0x271, 1e+08f} }; -ActorInfo lair_D_80392D90 = { 0x270, 0x2D8, 0x3B2, 0x1, NULL, func_802D3D54, actor_update_func_80326224, actor_drawFullDepth, 0, 0, 0.0f, 0}; -ActorInfo D_80392DB4 = { 0x110, 0x214, 0x4AB, 0x1, D_80392CB0, func_803896D4, actor_update_func_80326224, actor_draw, 0, 0, 0.0f, 0}; -ActorInfo D_80392DD8 = { 0x113, 0x217, 0x4A9, 0x1, D_80392CB0, func_803896F4, actor_update_func_80326224, actor_draw, 0, 0, 0.0f, 0}; -ActorInfo D_80392DFC = { 0x115, 0x219, 0x4AA, 0x1, D_80392CB0, func_80389714, actor_update_func_80326224, actor_draw, 0, 0, 0.0f, 0}; -ActorInfo D_80392E20 = { 0x11B, 0x221, 0x4B5, 0x1, D_80392CB0, func_80389734, actor_update_func_80326224, actor_draw, 0, 0, 0.0f, 0}; -ActorInfo D_80392E44 = { 0x11C, 0x222, 0x4B2, 0x1, D_80392CB0, func_8038975C, actor_update_func_80326224, actor_draw, 0, 0, 0.0f, 0}; -ActorInfo D_80392E68 = { 0x11D, 0x223, 0x4B0, 0x1, D_80392CB0, func_80389784, actor_update_func_80326224, actor_draw, 0, 0, 0.0f, 0}; -ActorInfo D_80392E8C = { 0x232, 0x23C, 0x4B8, 0x1, D_80392CB0, func_803897AC, actor_update_func_80326224, actor_draw, 0, 0, 0.0f, 0}; -ActorInfo D_80392EB0 = { 0x23F, 0x246, 0x534, 0x1, D_80392CB0, func_80386D20, actor_update_func_80326224, actor_draw, 0, 0, 0.0f, 0}; -ActorInfo D_80392ED4 = { 0x241, 0x248, 0x540, 0x1, D_80392CB0, func_80386780, actor_update_func_80326224, actor_draw, 0, 0, 0.0f, 0}; -ActorInfo D_80392EF8 = { MARKER_109_BREAKABLE_BRICK_WALL, ACTOR_20D_BREAKABLE_BRICK_WALL, ASSET_4A1_MODEL_BREAKABLE_BRICK_WALL, 0x1, D_80392CB0, lair_func_80386550, actor_update_func_80326224, actor_draw, 0, 0, 0.0f, 0x85}; -ActorInfo D_80392F1C = { 0x264, 0x2E5, 0x550, 0x19, D_80392CB0, func_80388524, actor_update_func_80326224, actor_draw, 0, 0, 0.0f, 0}; -ActorInfo D_80392F40 = { MARKER_224_BREAKABLE_FLOOR_COBWEB, ACTOR_230_BREAKABLE_FLOOR_COBWEB, ASSET_4BF_MODEL_FLOOR_COBWEB, 0xB, D_80392CB0, chFloorCobweb_update, actor_update_func_80326224, actor_draw, 0, 0, 0.0f, 0x88}; -ActorInfo D_80392F64 = { MARKER_225_BREAKABLE_WALL_COBWEB, ACTOR_231_BREAKABLE_WALL_COBWEB, ASSET_4D5_MODEL_WALL_COBWEB, 0xE, D_80392CB0, chWallCobweb_update, actor_update_func_80326224, actor_draw, 0, 0, 0.0f, 0x88}; -ActorInfo D_80392F88 = { 0x111, 0x215, 0x4A4, 0x1, NULL, func_80388FC8, actor_update_func_80326224, actor_drawFullDepth, 0, 0, 0.0f, 0}; -ActorInfo D_80392FAC = { 0x112, 0x216, 0x4A5, 0x1, NULL, func_80388FC8, actor_update_func_80326224, actor_drawFullDepth, 0, 0, 0.0f, 0}; -ActorInfo D_80392FD0 = { 0x114, 0x218, 0x4A6, 0x1, NULL, lair_func_80389204, actor_update_func_80326224, actor_drawFullDepth, 0, 0, 0.0f, 0}; -ActorInfo D_80392FF4 = { 0x10D, 0x211, 0x4A3, 0x1, NULL, func_80388524, actor_update_func_80326224, actor_drawFullDepth, 0, 0, 0.0f, 0}; -ActorInfo D_80393018 = { 0x22C, 0x23A, 0x4D9, 0x1, NULL, func_803882B0, actor_update_func_80326224, actor_drawFullDepth, 0, 0, 0.0f, 0}; -ActorInfo D_8039303C = { 0x164, 0x259, 0x507, 0x1, NULL, func_803880BC, actor_update_func_80326224, actor_drawFullDepth, 0, 0, 0.0f, 0}; -ActorInfo D_80393060 = { 0x165, 0x25A, 0x508, 0x1, NULL, func_8038824C, actor_update_func_80326224, actor_drawFullDepth, 0, 0, 0.0f, 0}; -ActorInfo D_80393084 = { MARKER_240_LAIR_SWITCH_FLIGHT_PAD, 0x247, 0x48A, 0x1, NULL, func_80386D78, actor_update_func_80326224, actor_drawFullDepth, 0, 0, 0.0f, 0}; -ActorInfo D_803930A8 = { 0x242, 0x249, 0x2DD, 0x1, NULL, func_803867A8, actor_update_func_80326224, actor_drawFullDepth, 0, 0, 0.0f, 0}; -ActorInfo D_803930CC = { 0x11F, 0x225, 0x4B3, 0x1, NULL, func_8038A064, actor_update_func_80326224, actor_drawFullDepth, 0, 0, 0.0f, 0}; -ActorInfo D_803930F0 = { 0x10A, 0x20E, 0x4A2, 0x1, NULL, func_80388524, actor_update_func_80326224, actor_drawFullDepth, 0, 0, 0.0f, 0}; -ActorInfo D_80393114 = { 0x11A, 0x220, 0x4B7, 0x1, NULL, func_80389FF4, actor_update_func_80326224, actor_drawFullDepth, 0, 0, 0.0f, 0x91}; -ActorInfo D_80393138 = { 0x11E, 0x224, 0x4AF, 0x1, NULL, func_8038A014, actor_update_func_80326224, actor_drawFullDepth, 0, 0, 0.0f, 0x83}; -ActorInfo D_8039315C = { 0x227, 0x234, 0x4D6, 0x1, NULL, func_80388524, actor_update_func_80326224, actor_drawFullDepth, 0, 0, 0.0f, 0x93}; -ActorInfo D_80393180 = { 0x228, 0x235, 0x4D7, 0x1, NULL, func_80388524, actor_update_func_80326224, actor_drawFullDepth, 0, 0, 0.0f, 0x8B}; -ActorInfo D_803931A4 = { 0x229, 0x236, 0x4D8, 0x1, NULL, func_80388524, actor_update_func_80326224, actor_drawFullDepth, 0, 0, 0.0f, 0x8B}; -ActorInfo D_803931C8 = { MARKER_121_GLASS_EYE, ACTOR_227_GLASS_EYE, ASSET_4BD_MODEL_GLASS_EYE, 0x1, NULL, func_8038A034, actor_update_func_80326224, actor_draw, 0, 0, 0.0f, 0x89}; -ActorInfo D_803931EC = { 0x116, 0x21A, 0x4AC, 0x1, NULL, func_803893B8, actor_update_func_80326224, actor_drawFullDepth, 0, 0, 0.0f, 0x82}; -ActorInfo D_80393210 = { 0x117, 0x21B, 0x4AD, 0x1, NULL, lair_func_803894B0, actor_update_func_80326224, actor_drawFullDepth, 0, 0, 0.0f, 0x82}; -ActorInfo D_80393234 = { 0x10B, 0x20F, 0x4B4, 0x1, NULL, func_80388524, actor_update_func_80326224, actor_drawFullDepth, 0, 0, 0.0f, 0x90}; -ActorInfo D_80393258 = { 0x10C, 0x210, 0x4AE, 0x1, NULL, func_80388524, actor_update_func_80326224, actor_drawFullDepth, 0, 0, 0.0f, 0x84}; -ActorInfo D_8039327C = { 0x10E, 0x212, 0x4A7, 0x1, NULL, func_80388524, actor_update_func_80326224, actor_drawFullDepth, 0, 0, 0.0f, 0x7F}; -ActorInfo D_803932A0 = { 0x120, 0x226, 0x4BC, 0x1, NULL, func_80388524, actor_update_func_80326224, actor_drawFullDepth, 0, 0, 0.0f, 0x87}; -ActorInfo D_803932C4 = { 0x122, ACTOR_228_MMM_ENTRANCE_DOOR, 0x4BE, 0x1, NULL, func_80388524, actor_update_func_80326224, actor_drawFullDepth, 0, 0, 0.0f, 0x8C}; -ActorInfo D_803932E8 = { 0x10F, 0x213, 0x4A8, 0x1, NULL, func_803875F0, actor_update_func_80326224, actor_drawFullDepth, 0, 0, 0.0f, 0x80}; -ActorInfo D_8039330C = { 0x118, 0x21E, 0x4B1, 0x1, NULL, lair_func_8038A084, actor_update_func_80326224, actor_drawFullDepth, 0, 0, 0.0f, 0x8F}; -ActorInfo D_80393330 = { 0x119, 0x21F, 0x4B6, 0x1, NULL, func_8038A0A4, actor_update_func_80326224, actor_drawFullDepth, 0, 0, 0.0f, 0x92}; -ActorInfo D_80393354 = { 0x266, 0x2E3, 0x563, 0x1, NULL, func_803870DC, actor_update_func_80326224, lair_func_80387560, 0, 0, 0.0f, 0}; -ActorInfo D_80393378 = { 0x17D, 0x1E1, 0x517, 0x1, NULL, func_80389D08, actor_update_func_80326224, func_80389E10, 0, 0, 0.0f, 0x8D}; -ActorInfo D_8039339C = { 0x234, 0x23E, 0x4E1, 0x12, D_80392CB0, func_8038982C, actor_update_func_80326224, actor_drawFullDepth, 0, 0, 0.0f, 0}; -ActorInfo D_803933C0 = { 0x163, 0x258, 0x511, 0x12, D_80392CB0, func_80389898, actor_update_func_80326224, func_8038664C, 0, 0, 0.0f, 0x8E}; -ActorInfo D_803933E4 = { 0x160, 0x255, 0x509, 0x15, D_80392CB0, func_80389934, actor_update_func_80326224, actor_draw, 0, 0, 0.0f, 0}; -ActorInfo D_80393408 = { 0x102, 0x203, 0x491, 0x1, D_80392CB0, func_80387730, actor_update_func_80326224, func_80387DA8, 0, 0, 0.0f, 0}; +ActorInfo lair_D_80392D90 = { + MARKER_270_TWO_ICE_POLES_NEAR_CHEATO_3, ACTOR_2D8_TWO_ICE_POLES_NEAR_CHEATO_3, ASSET_3B2_MODEL_TWO_ICE_POLES_NEAR_CHEATO_3, + 0x1, NULL, + chMMMBreakableWooden_update, actor_update_func_80326224, actor_drawFullDepth, + 0, 0, 0.0f, 0 +}; + +ActorInfo D_80392DB4 = { + MARKER_110_RAISE_GRATE_TO_BGS_PUZZLE_SWITCH, ACTOR_214_RAISE_GRATE_TO_BGS_PUZZLE_SWITCH, ASSET_4AB_MODEL_RAISE_GRATE_TO_BGS_PUZZLE_SWITCH, + 0x1, D_80392CB0, + func_803896D4, actor_update_func_80326224, actor_draw, + 0, 0, 0.0f, 0 +}; + +ActorInfo D_80392DD8 = { + MARKER_113_RAISE_PIPE_TO_CC_ENTRANCE_SWITCH, ACTOR_217_RAISE_PIPE_TO_CC_ENTRANCE_SWITCH, ASSET_4A9_MODEL_RAISE_PIPE_TO_CC_ENTRANCE_SWITCH, + 0x1, D_80392CB0, + func_803896F4, actor_update_func_80326224, actor_draw, + 0, 0, 0.0f, 0 +}; + +ActorInfo D_80392DFC = { + MARKER_115_RAISE_PIPE_TO_BRENTILDA_SWITCH, ACTOR_219_RAISE_PIPE_TO_BRENTILDA_SWITCH, ASSET_4AA_MODEL_RAISE_PIPE_TO_BRENTILDA_SWITCH, + 0x1, D_80392CB0, + func_80389714, actor_update_func_80326224, actor_draw, + 0, 0, 0.0f, 0 +}; + +ActorInfo D_80392E20 = { + MARKER_11B_WATER_LEVEL_SWITCH_1, ACTOR_221_LEVEL_1_WATER_SWITCH, ASSET_4B5_MODEL_LEVEL_1_WATER_SWITCH, + 0x1, D_80392CB0, + func_80389734, actor_update_func_80326224, actor_draw, + 0, 0, 0.0f, 0 +}; + +ActorInfo D_80392E44 = { + MARKER_11C_WATER_LEVEL_SWITCH_2, ACTOR_222_LEVEL_2_WATER_SWITCH, ASSET_4B2_MODEL_LEVEL_2_WATER_SWITCH, + 0x1, D_80392CB0, + func_8038975C, actor_update_func_80326224, actor_draw, + 0, 0, 0.0f, 0 +}; + +ActorInfo D_80392E68 = { + MARKER_11D_WATER_LEVEL_SWITCH_3, ACTOR_223_LEVEL_3_WATER_SWITCH, ASSET_4B0_MODEL_LEVEL_3_WATER_SWITCH, + 0x1, D_80392CB0, + func_80389784, actor_update_func_80326224, actor_draw, + 0, 0, 0.0f, 0 +}; + +ActorInfo D_80392E8C = { + MARKER_232_CCW_PUZZLE_SWITCH, ACTOR_23C_CCW_PUZZLE_SWITCH, ASSET_4B8_MODEL_CCW_PUZZLE_SWITCH, + 0x1, D_80392CB0, + func_803897AC, actor_update_func_80326224, actor_draw, + 0, 0, 0.0f, 0 +}; + +ActorInfo D_80392EB0 = { + MARKER_23F_LAIR_FLIGHT_PAD_SWITCH, ACTOR_246_FLIGHT_PAD_SWITCH, ASSET_534_MODEL_FLIGHT_PAD_SWITCH, + 0x1, D_80392CB0, + func_80386D20, actor_update_func_80326224, actor_draw, + 0, 0, 0.0f, 0 +}; + +ActorInfo D_80392ED4 = { + MARKER_241_SHOCK_JUMP_PAD_SWITCH, ACTOR_248_SHOCK_JUMP_PAD_SWITCH, ASSET_540_MODEL_SHOCK_JUMP_PAD_SWITCH, + 0x1, D_80392CB0, + func_80386780, actor_update_func_80326224, actor_draw, + 0, 0, 0.0f, 0 +}; + +ActorInfo D_80392EF8 = { + MARKER_109_BREAKABLE_BRICK_WALL, ACTOR_20D_BREAKABLE_BRICK_WALL, ASSET_4A1_MODEL_BREAKABLE_BRICK_WALL, + 0x1, D_80392CB0, + lair_func_80386550, actor_update_func_80326224, actor_draw, + 0, 0, 0.0f, 0x85 +}; + +ActorInfo D_80392F1C = { + MARKER_264_LARGE_DOOR_TO_FINAL_BATTLE, ACTOR_2E5_LARGE_DOOR_TO_FINAL_BATTLE, ASSET_550_MODEL_LARGE_DOOR_TO_FINAL_BATTLE, + 0x19, D_80392CB0, + func_80388524, actor_update_func_80326224, actor_draw, + 0, 0, 0.0f, 0 +}; + +ActorInfo D_80392F40 = { + MARKER_224_BREAKABLE_FLOOR_COBWEB, ACTOR_230_BREAKABLE_FLOOR_COBWEB, ASSET_4BF_MODEL_FLOOR_COBWEB, + 0xB, D_80392CB0, + chFloorCobweb_update, actor_update_func_80326224, actor_draw, + 0, 0, 0.0f, 0x88 +}; + +ActorInfo D_80392F64 = { + MARKER_225_BREAKABLE_WALL_COBWEB, ACTOR_231_BREAKABLE_WALL_COBWEB, ASSET_4D5_MODEL_WALL_COBWEB, + 0xE, D_80392CB0, + chWallCobweb_update, actor_update_func_80326224, actor_draw, + 0, 0, 0.0f, 0x88 +}; + +ActorInfo D_80392F88 = { + MARKER_111_GL_CC_ENTRANCE_LONG_PIPE_GREEN, ACTOR_215_GL_CC_ENTRANCE_LONG_PIPE_GREEN, ASSET_4A4_MODEL_GL_CC_ENTRANCE_LONG_PIPE_GREEN, + 0x1, NULL, + func_80388FC8, actor_update_func_80326224, actor_drawFullDepth, + 0, 0, 0.0f, 0 +}; + +ActorInfo D_80392FAC = { + MARKER_112_GL_CC_ENTRANCE_LONG_PIPE_BLUE, ACTOR_216_GL_CC_ENTRANCE_LONG_PIPE_BLUE, ASSET_4A5_MODEL_GL_CC_ENTRANCE_LONG_PIPE_BLUE, + 0x1, NULL, + func_80388FC8, actor_update_func_80326224, actor_drawFullDepth, + 0, 0, 0.0f, 0 +}; + +ActorInfo D_80392FD0 = { + MARKER_114_GL_CC_ENTRANCE_SHORT_PIPE, ACTOR_218_GL_CC_ENTRANCE_SHORT_PIPE, ASSET_4A6_MODEL_GL_CC_ENTRANCE_SHORT_PIPE, + 0x1, NULL, + lair_func_80389204, actor_update_func_80326224, actor_drawFullDepth, + 0, 0, 0.0f, 0 +}; + +ActorInfo D_80392FF4 = { + MARKER_10D_TTC_ENTRANCE_CHEST_LID, ACTOR_211_TTC_ENTRANCE_CHEST_LID, ASSET_4A3_MODEL_GL_TTC_ENTRANCE_CHEST_LID, + 0x1, NULL, + func_80388524, actor_update_func_80326224, actor_drawFullDepth, + 0, 0, 0.0f, 0 +}; + +ActorInfo D_80393018 = { + MARKER_22C_GL_ADVENT_CALENDAR_HATCH_DOOR, ACTOR_23A_GL_ADVENT_CALENDAR_HATCH_DOOR, ASSET_4D9_MODEL_GL_ADVENT_CALENDAR_HATCH_DOOR, + 0x1, NULL, + func_803882B0, actor_update_func_80326224, actor_drawFullDepth, + 0, 0, 0.0f, 0 +}; + +ActorInfo D_8039303C = { + MARKER_164_GL_GRUNTY_FLOOR_PICTURE_EYE_1, ACTOR_259_GL_GRUNTY_FLOOR_PICTURE_EYE_1, ASSET_507_MODEL_GL_GRUNTY_FLOOR_PICTURE_EYE_1, + 0x1, NULL, + func_803880BC, actor_update_func_80326224, actor_drawFullDepth, + 0, 0, 0.0f, 0 +}; + +ActorInfo D_80393060 = { + MARKER_165_GL_GRUNTY_FLOOR_PICTURE_EYE_2, ACTOR_25A_GL_GRUNTY_FLOOR_PICTURE_EYE_2, ASSET_508_MODEL_GL_GRUNTY_FLOOR_PICTURE_EYE_2, + 0x1, NULL, + func_8038824C, actor_update_func_80326224, actor_drawFullDepth, + 0, 0, 0.0f, 0 +}; + +ActorInfo D_80393084 = { + MARKER_240_LAIR_SWITCH_FLIGHT_PAD, ACTOR_247_LAIR_SWITCH_FLIGHT_PAD, ASSET_48A_MODEL_FLIGHT_PAD, + 0x1, NULL, + func_80386D78, actor_update_func_80326224, actor_drawFullDepth, + 0, 0, 0.0f, 0 +}; + +ActorInfo D_803930A8 = { + MARKER_242_LAIR_SWITCH_SHOCK_JUMP_PAD, ACTOR_249_LAIR_SWITCH_SHOCK_JUMP_PAD, ASSET_2DD_MODEL_SHOCK_JUMP_PAD, + 0x1, NULL, + func_803867A8, actor_update_func_80326224, actor_drawFullDepth, + 0, 0, 0.0f, 0 +}; + +ActorInfo D_803930CC = { + MARKER_11F_RAREWARE_BOX, ACTOR_225_RAREWARE_BOX, ASSET_4B3_MODEL_RAREWARE_BOX, + 0x1, NULL, + func_8038A064, actor_update_func_80326224, actor_drawFullDepth, + 0, 0, 0.0f, 0 +}; + +ActorInfo D_803930F0 = { + MARKER_10A_MM_ENTRANCE_DOOR, ACTOR_20E_MM_ENTRANCE_DOOR, ASSET_4A2_MODEL_GL_MM_DOOR_ENTRANCE, + 0x1, NULL, + func_80388524, actor_update_func_80326224, actor_drawFullDepth, + 0, 0, 0.0f, 0 +}; + +ActorInfo D_80393114 = { + MARKER_11A_GRATE_TO_RBB_PUZZLE, ACTOR_220_GRATE_TO_RBB_PUZZLE, ASSET_4B7_MODEL_GRATE_TO_RBB_PUZZLE, + 0x1, NULL, + func_80389FF4, actor_update_func_80326224, actor_drawFullDepth, + 0, 0, 0.0f, 0x91 +}; + +ActorInfo D_80393138 = { + MARKER_11E_ICE_BALL_TO_CHEATO, ACTOR_224_ICE_BALL_TO_CHEATO, ASSET_4AF_MODEL_ICE_BALL_TO_CHEATO, + 0x1, NULL, + func_8038A014, actor_update_func_80326224, actor_drawFullDepth, + 0, 0, 0.0f, 0x83 +}; + +ActorInfo D_8039315C = { + MARKER_227_CCW_ENTRANCE_DOOR, ACTOR_234_CCW_ENTRANCE_DOOR, ASSET_4D6_MODEL_GL_CCW_DOOR_ENTRANCE, + 0x1, NULL, + func_80388524, actor_update_func_80326224, actor_drawFullDepth, + 0, 0, 0.0f, 0x93 +}; + +ActorInfo D_80393180 = { + MARKER_228_FP_ENTRANCE_DOOR_LEFT, ACTOR_235_FP_ENTRANCE_DOOR_LEFT, ASSET_4D7_MODEL_GL_FP_DOOR_ENTRANCE_LEFT, + 0x1, NULL, + func_80388524, actor_update_func_80326224, actor_drawFullDepth, + 0, 0, 0.0f, 0x8B +}; + +ActorInfo D_803931A4 = { + MARKER_229_FP_ENTRANCE_DOOR_RIGHT, ACTOR_236_FP_ENTRANCE_DOOR_RIGHT, ASSET_4D8_MODEL_GL_FP_DOOR_ENTRANCE_LEFT, + 0x1, NULL, + func_80388524, actor_update_func_80326224, actor_drawFullDepth, + 0, 0, 0.0f, 0x8B +}; + +ActorInfo D_803931C8 = { + MARKER_121_GLASS_EYE, ACTOR_227_GLASS_EYE, ASSET_4BD_MODEL_GLASS_EYE, + 0x1, NULL, + func_8038A034, actor_update_func_80326224, actor_draw, + 0, 0, 0.0f, 0x89 +}; + +ActorInfo D_803931EC = { + MARKER_116_IRON_BARS_UNDER_GRUNTY_STATUE, ACTOR_21A_IRON_BARS_UNDER_GRUNTY_STATUE, ASSET_4AC_MODEL_IRON_BARS_UNDER_GRUNTY_STATUE, + 0x1, NULL, + func_803893B8, actor_update_func_80326224, actor_drawFullDepth, + 0, 0, 0.0f, 0x82 +}; + +ActorInfo D_80393210 = { + MARKER_117_GRUNTY_STATUE_BREAKABLE_HAT_TOP, ACTOR_21B_GRUNTY_STATUE_BREAKABLE_HAT_TOP, ASSET_4AD_MODEL_GRUNTY_STATUE_BREAKABLE_HAT_TOP, + 0x1, NULL, + lair_func_803894B0, actor_update_func_80326224, actor_drawFullDepth, + 0, 0, 0.0f, 0x82 +}; + +ActorInfo D_80393234 = { + MARKER_10B_RBB_ENTRANCE_DOOR, ACTOR_20F_RBB_ENTRANCE_DOOR, ASSET_4B4_MODEL_GL_RBB_DOOR_ENTRANCE, + 0x1, NULL, + func_80388524, actor_update_func_80326224, actor_drawFullDepth, + 0, 0, 0.0f, 0x90 +}; + +ActorInfo D_80393258 = { + MARKER_10C_BGS_ENTRANCE_DOOR, ACTOR_210_BGS_ENTRANCE_DOOR, ASSET_4AE_MODEL_GL_BGS_DOOR_ENTRANCE, + 0x1, NULL, + func_80388524, actor_update_func_80326224, actor_drawFullDepth, + 0, 0, 0.0f, 0x84 +}; + +ActorInfo D_8039327C = { + MARKER_10E_CC_ENTRANCE_DOOR, ACTOR_212_CC_ENTRANCE_BARS, ASSET_4A7_MODEL_GL_CC_IRON_BARS_ENTRANCE, + 0x1, NULL, + func_80388524, actor_update_func_80326224, actor_drawFullDepth, + 0, 0, 0.0f, 0x7F +}; + +ActorInfo D_803932A0 = { + MARKER_120_GV_ENTRANCE, ACTOR_226_GV_ENTRANCE, ASSET_4BC_MODEL_GL_GV_DOOR_ENTRANCE, + 0x1, NULL, + func_80388524, actor_update_func_80326224, actor_drawFullDepth, + 0, 0, 0.0f, 0x87 +}; + +ActorInfo D_803932C4 = { + MARKER_122_MMM_ENTRANCE_DOOR, ACTOR_228_MMM_ENTRANCE_DOOR, ASSET_4BE_MODEL_GL_MMM_DOOR_ENTRANCE, + 0x1, NULL, + func_80388524, actor_update_func_80326224, actor_drawFullDepth, + 0, 0, 0.0f, 0x8C +}; + +ActorInfo D_803932E8 = { + MARKER_10F_GL_BGS_PUZZLE_GRATE, ACTOR_213_GL_BGS_PUZZLE_GRATE, ASSET_4A8_MODEL_GL_BGS_PUZZLE_GRATE, + 0x1, NULL, + func_803875F0, actor_update_func_80326224, actor_drawFullDepth, + 0, 0, 0.0f, 0x80 +}; + +ActorInfo D_8039330C = { + MARKER_118_GRATE_TO_LEVEL_3_WATER_SWITCH, ACTOR_21E_GRATE_TO_LEVEL_3_WATER_SWITCH, ASSET_4B1_MODEL_GRATE_TO_LEVEL_3_WATER_SWITCH, + 0x1, NULL, + lair_func_8038A084, actor_update_func_80326224, actor_drawFullDepth, + 0, 0, 0.0f, 0x8F +}; + +ActorInfo D_80393330 = { + MARKER_119_GRATE_BETWEEN_MMM_AND_RBB_PUZZLES, ACTOR_21F_GRATE_BETWEEN_MMM_AND_RBB_PUZZLES, ASSET_4B6_MODEL_GRATE_BETWEEN_MMM_AND_RBB_PUZZLES, + 0x1, NULL, + func_8038A0A4, actor_update_func_80326224, actor_drawFullDepth, + 0, 0, 0.0f, 0x92 +}; + +ActorInfo D_80393354 = { + MARKER_266_LEVEL_ENTRY_SIGNS, ACTOR_2E3_LEVEL_ENTRY_SIGNS, ASSET_563_MODEL_LEVEL_ENTRY_SIGNS, + 0x1, NULL, + func_803870DC, actor_update_func_80326224, lair_func_80387560, + 0, 0, 0.0f, 0 +}; + +ActorInfo D_80393378 = { + MARKER_17D_IRON_GATE_NO_LOCK, ACTOR_1E1_IRON_GATE_NO_LOCK, ASSET_517_MODEL_IRON_GATE_NO_LOCK, + 0x1, NULL, + func_80389D08, actor_update_func_80326224, func_80389E10, + 0, 0, 0.0f, 0x8D +}; + +ActorInfo D_8039339C = { + MARKER_234_GL_WOODEN_COFFIN_NO_LID, ACTOR_23E_GL_WOODEN_COFFIN_NO_LID, ASSET_4E1_MODEL_GL_WOODEN_COFFIN_NO_LID, + 0x12, D_80392CB0, + func_8038982C, actor_update_func_80326224, actor_drawFullDepth, + 0, 0, 0.0f, 0 +}; + +ActorInfo D_803933C0 = { + MARKER_163_CRYPT_COFFIN_LID, ACTOR_258_CRYPT_COFFIN_LID, ASSET_511_MODEL_CRYPT_COFFIN_LID, + 0x12, D_80392CB0, + func_80389898, actor_update_func_80326224, func_8038664C, + 0, 0, 0.0f, 0x8E +}; + +ActorInfo D_803933E4 = { + MARKER_160_GL_SARCOPHAGUS, ACTOR_255_GL_SARCOPHAGUS, ASSET_509_MODEL_GL_SARCOPHAGUS, + 0x15, D_80392CB0, + func_80389934, actor_update_func_80326224, actor_draw, + 0, 0, 0.0f, 0 +}; + +ActorInfo D_80393408 = { + MARKER_102_NOTE_DOOR, ACTOR_203_NOTE_DOOR, ASSET_491_MODEL_NOTE_DOOR, + 0x1, D_80392CB0, + func_80387730, actor_update_func_80326224, func_80387DA8, + 0, 0, 0.0f, 0 +}; + ParticleScaleAndLifetimeRanges D_8039342C = { {0.31f, 0.37f}, {0.17f, 0.22f}, @@ -346,8 +628,8 @@ Actor *func_8038664C(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx) actor = marker_getActor(marker); val = actor->unk10_12; - func_8033A45C(3, val == 1 ? 1 : 0); - func_8033A45C(4, val == 0 ? 1 : 0); + modelRender_setAppendageVisibility(3, val == 1 ? 1 : 0); + modelRender_setAppendageVisibility(4, val == 0 ? 1 : 0); return actor_draw(marker, gfx, mtx, vtx); } @@ -487,7 +769,7 @@ void func_80386D20(Actor *this) void func_80386D40(void) { - func_802D68F0(0xC); + code_4C020_setHourglassTimer(0xC); item_set(ITEM_6_HOURGLASS, true); mapSpecificFlags_set(1, true); } @@ -635,7 +917,7 @@ Actor *lair_func_80387560(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx) u32 i; for (i = 0; i != 10; i++) - func_8033A45C(i + 1, actor->actorTypeSpecificField + 1 == i + 2); + modelRender_setAppendageVisibility(i + 1, actor->actorTypeSpecificField + 1 == i + 2); return actor_drawFullDepth(marker, gfx, mtx, vtx); } @@ -799,7 +1081,7 @@ void func_80387730(Actor *this) { } } } else if ((this->actorTypeSpecificField >= 2) && (ml_vec3f_distance(spAC, this->position) < 290.0f)) { - volatileFlag_setAndTriggerDialog_0(VOLATILE_FLAG_B0_NOT_ENOUGH_NOTES); + progressDialog_setAndTriggerDialog_0(VOLATILE_FLAG_B0_NOT_ENOUGH_NOTES); } } } @@ -861,7 +1143,7 @@ Actor *func_80387DA8(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx) * e.g. for the 50 note door, hides 180, 260, etc. */ for (i = 0; i != NUM_NOTE_DOORS; i++) - func_8033A45C(i + 1, actor->noteDoorIdx + 1 == i + 2); + modelRender_setAppendageVisibility(i + 1, actor->noteDoorIdx + 1 == i + 2); /** * Draw the note door @@ -1069,7 +1351,7 @@ static enum file_progress_e __leveldoor_persistentFlag(s32 actorId) { case ACTOR_228_MMM_ENTRANCE_DOOR: return FILEPROG_37_MMM_OPEN; case ACTOR_20F_RBB_ENTRANCE_DOOR: return FILEPROG_38_RBB_OPEN; case ACTOR_234_CCW_ENTRANCE_DOOR: return FILEPROG_39_CCW_OPEN; - case ACTOR_2E5_DOOR_OF_GRUNTY: return FILEPROG_E2_DOOR_OF_GRUNTY_OPEN; + case ACTOR_2E5_LARGE_DOOR_TO_FINAL_BATTLE: return FILEPROG_E2_DOOR_OF_GRUNTY_OPEN; default: return 0; } } @@ -1085,7 +1367,7 @@ void port_leveldoor_remoteOpen(s32 progressFlag) { case 0x2E: sRemoteOpenDoorActor = ACTOR_228_MMM_ENTRANCE_DOOR; break; case 0x2F: sRemoteOpenDoorActor = ACTOR_20F_RBB_ENTRANCE_DOOR; break; case 0x30: sRemoteOpenDoorActor = ACTOR_234_CCW_ENTRANCE_DOOR; break; - case 0xE2: sRemoteOpenDoorActor = ACTOR_2E5_DOOR_OF_GRUNTY; break; + case 0xE2: sRemoteOpenDoorActor = ACTOR_2E5_LARGE_DOOR_TO_FINAL_BATTLE; break; default: break; } } @@ -1095,7 +1377,7 @@ void func_80388450(Actor *actor1, Actor *actor2) f32 vec1[3]; f32 vec2[3]; void *actor3 = nodeprop_findByActorIdAndActorPosition(0x22A, actor1); - s32 val = nodeprop_getYaw(actor3); + s32 val = nodeProp_getYaw(actor3); actor2->yaw = val; actor1->yaw = val; @@ -1141,7 +1423,7 @@ void func_80388524(Actor *this) { if (!this->initialized) { if (!sp34) { switch(this->modelCacheIndex){ - case ACTOR_2E5_DOOR_OF_GRUNTY://L80388630 + case ACTOR_2E5_LARGE_DOOR_TO_FINAL_BATTLE://L80388630 if (!fileProgressFlag_get(FILEPROG_E2_DOOR_OF_GRUNTY_OPEN) && jigsawPicture_isJigsawPictureComplete(0xA)) { fileProgressFlag_set(FILEPROG_E2_DOOR_OF_GRUNTY_OPEN, true); } @@ -1207,7 +1489,7 @@ void func_80388524(Actor *this) { if (!this->volatile_initialized) { this->volatile_initialized = true; switch(this->modelCacheIndex){ - case ACTOR_2E5_DOOR_OF_GRUNTY: //L80388880 + case ACTOR_2E5_LARGE_DOOR_TO_FINAL_BATTLE: //L80388880 if (fileProgressFlag_get(FILEPROG_E2_DOOR_OF_GRUNTY_OPEN) && (this->state == 0x19)) { subaddie_set_state_with_direction(this, 0x1B, 0.999f, 1); } @@ -1484,7 +1766,7 @@ void func_80388FC8(Actor *this) if (this->modelCacheIndex == 0x215) { func_802D48B8(this); - gcsfx_playAtSampleRate(SFX_7F_HEAVYDOOR_SLAM); + gcsfx_play(SFX_7F_HEAVYDOOR_SLAM); } this->lifetime_value = 1.f; @@ -1550,7 +1832,7 @@ void lair_func_80389204(Actor *this) this->position_y = this->unk1C[1]; func_802D48B8(this); - gcsfx_playAtSampleRate(SFX_7F_HEAVYDOOR_SLAM); + gcsfx_play(SFX_7F_HEAVYDOOR_SLAM); this->lifetime_value = 1.f; } @@ -1929,7 +2211,7 @@ void func_80389FA8(Actor *this, enum file_progress_e flag) { if (!this->initialized) { - func_802D3D54(this); + chMMMBreakableWooden_update(this); if (fileProgressFlag_get(flag)) marker_despawn(this->marker); diff --git a/src/LAIR/ch/tooty_parade.c b/src/lair/tooty_parade.c similarity index 100% rename from src/LAIR/ch/tooty_parade.c rename to src/lair/tooty_parade.c diff --git a/src/port/Controller/ControlSchemes.cpp b/src/port/Controller/ControlSchemes.cpp index 05c55e9e1..dbe2a2ecf 100644 --- a/src/port/Controller/ControlSchemes.cpp +++ b/src/port/Controller/ControlSchemes.cpp @@ -215,7 +215,7 @@ extern "C" void port_shapeControllerInput(void* contPad) { } const bool modern = CVarGetInteger(CVAR_SETTING("Controls.Scheme"), CONTROL_SCHEME_RETRO) == CONTROL_SCHEME_MODERN; - const bool crouched = (bs_getState() == BS_CROUCH); + const bool crouched = (bs_getState() == BS_7_CROUCH); const bool eggPooping = (bs_getState() == BS_A_EGG_ASS); int32_t rx = pad->right_stick_x; diff --git a/src/port/Controller/ModernCamera.cpp b/src/port/Controller/ModernCamera.cpp index e350082c5..431700f90 100644 --- a/src/port/Controller/ModernCamera.cpp +++ b/src/port/Controller/ModernCamera.cpp @@ -32,7 +32,7 @@ int bainput_should_look_first_person_camera(void); void controller_getRightStick(int controller_index, float dst[2]); } -#include "enums.h" // BS_CROUCH +#include "enums.h" // BS_7_CROUCH #include "port/ShipUtils.h" namespace { @@ -84,7 +84,7 @@ bool ManualCameraControl() { } // namespace extern "C" int port_modernCamera_handleYaw(void) { - bool schemeOk = ModernSchemeActive() && bs_getState() != BS_CROUCH && !IsDemoMode(); + bool schemeOk = ModernSchemeActive() && bs_getState() != BS_7_CROUCH && !IsDemoMode(); if (!schemeOk) { if (sModern.active) { OrbitCamera_Exit(&sModern); @@ -142,14 +142,14 @@ extern "C" int port_camera_suppressVanillaZoom(void) { if (scheme == CONTROL_SCHEME_MODERN) { return 1; } - if (scheme == CONTROL_SCHEME_POCKET && bs_getState() == BS_CROUCH) { + if (scheme == CONTROL_SCHEME_POCKET && bs_getState() == BS_7_CROUCH) { return 1; } return 0; } extern "C" void port_modernCamera_handleZoom(void) { - if (!ModernSchemeActive() || bs_getState() == BS_CROUCH || IsDemoMode()) { + if (!ModernSchemeActive() || bs_getState() == BS_7_CROUCH || IsDemoMode()) { return; } diff --git a/src/port/Engine.cpp b/src/port/Engine.cpp index 24ad983fd..5365a55e7 100644 --- a/src/port/Engine.cpp +++ b/src/port/Engine.cpp @@ -75,7 +75,7 @@ bool prevAltAssets = false; // Audio synthesis entry point (decomp n_synthesizer.c) Acmd* n_alAudioFrame(Acmd* cmdList, s32* cmdLen, s16* outBuf, s32 outLen); // DMA cache cleanup (decomp audio_manager.c) -void func_802403F0(void); +void audioManager_func_802403F0(void); void func_80250650(void); // Game mode helper bool func_802E4A08(void); @@ -1144,7 +1144,7 @@ void GameEngine::HandleAudioThread() { // Lock only the engine work; the volume scale and backend submit touch // worker-local / backend state, not the synth. port_lockAudio(); - func_802403F0(); + audioManager_func_802403F0(); n_alAudioFrame(cmdList, &cmdLen, audioBuffer, AlFrameSize); func_80250650(); port_unlockAudio(); diff --git a/src/port/Enhancements/Backports/EggAim.cpp b/src/port/Enhancements/Backports/EggAim.cpp index 32437f86c..d2967c892 100644 --- a/src/port/Enhancements/Backports/EggAim.cpp +++ b/src/port/Enhancements/Backports/EggAim.cpp @@ -222,7 +222,7 @@ void RegisterEggAimSpawn_Init() { } auto* ev = reinterpret_cast(event); float rotation[3]; - ncFirstPersonCamera_getZoomedInRotation(rotation); + ncba1p_getZoomedInRotation(rotation); *ev->pitch = -rotation[0]; *ev->spawnHeight = 100.0f; *ev->minVerticalVelocity = -99999.0f; @@ -245,7 +245,7 @@ void RegisterEggAim_Init() { return; } - if (ncFirstPersonCamera_getState() == FIRSTPERSON_STATE_2_IDLE) { + if (ncba1p_getState() == FIRSTPERSON_STATE_2_IDLE) { if (sOverlayShown < kOverlayFadeDuration) { sOverlayShown++; } diff --git a/src/port/Enhancements/Cheats/Cheats.cpp b/src/port/Enhancements/Cheats/Cheats.cpp index 3855dd874..a9b21b2a8 100644 --- a/src/port/Enhancements/Cheats/Cheats.cpp +++ b/src/port/Enhancements/Cheats/Cheats.cpp @@ -231,7 +231,7 @@ void RegisterCycleTransform_Init() { if (currentTransform == TRANSFORM_7_WISHWASHY && !isWishyWashyUnlocked()) { currentTransform = TRANSFORM_1_BANJO; // skip Wishy Washy -> wrap to Banjo } - func_8028FB88((enum transformation_e)currentTransform); + player_transform((enum transformation_e)currentTransform); } // D-pad Down: Cycle backward through transformations else if (bakey_pressed(BUTTON_D_DOWN)) { @@ -242,7 +242,7 @@ void RegisterCycleTransform_Init() { if (currentTransform == TRANSFORM_7_WISHWASHY && !isWishyWashyUnlocked()) { currentTransform = TRANSFORM_6_BEE; // skip Wishy Washy -> step to Bee } - func_8028FB88((enum transformation_e)currentTransform); + player_transform((enum transformation_e)currentTransform); } }); } diff --git a/src/port/Localization/Localization.cpp b/src/port/Localization/Localization.cpp index b10f58ae3..0e0fde746 100644 --- a/src/port/Localization/Localization.cpp +++ b/src/port/Localization/Localization.cpp @@ -31,8 +31,8 @@ int code94620_func_8031B5B0(void); // current dialog-language index (0 int func_8031877C(void* zoombox); // clear a zoombox's strings before re-setting // Print font internals -extern void* D_80380AB8[]; // BKSprite*[5]: font alphamask assets (slot 2 = JP font) -extern void* print_sFonts[]; // FontLetter*[4]: decoded glyph tables per slot +extern void* print_sFontSpriteAssets[]; // BKSprite*[5]: font alphamask assets (slot 2 = JP font) +extern void* print_sFonts[]; // FontLetter*[4]: decoded glyph tables per slot void* print_getLettersFromFont(void* alphaMask, void* textureSprite); int print_getCurrentMapBoldFontTexture(void); void print_setBoldFontTexture(int textureId); @@ -58,34 +58,34 @@ void FreeJpFontSlot() { bk_free(print_sFonts[2]); print_sFonts[2] = nullptr; } - if (D_80380AB8[2] != nullptr) { - assetcache_release(D_80380AB8[2]); - D_80380AB8[2] = nullptr; + if (print_sFontSpriteAssets[2] != nullptr) { + assetcache_release(print_sFontSpriteAssets[2]); + print_sFontSpriteAssets[2] = nullptr; } } void LoadJpFontSlot() { // Bail early if print_init hasn't run to load this slot yet - if (D_80380AB8[0] == nullptr) { + if (print_sFontSpriteAssets[0] == nullptr) { return; } FreeJpFontSlot(); // drop any stale font first (e.g. a different pack) void* tex = assetcache_get(print_getCurrentMapBoldFontTexture()); - D_80380AB8[2] = assetcache_get(kJpDialogFontAssetId); - print_sFonts[2] = print_getLettersFromFont(D_80380AB8[2], tex); + print_sFontSpriteAssets[2] = assetcache_get(kJpDialogFontAssetId); + print_sFonts[2] = print_getLettersFromFont(print_sFontSpriteAssets[2], tex); assetcache_release(tex); } // Re-decode the base dialog font (slot 0) from its current asset. void ReloadDialogFontSlot() { - if (D_80380AB8[0] == nullptr) { + if (print_sFontSpriteAssets[0] == nullptr) { return; // print_init hasn't run yet } void* tex = assetcache_get(print_getCurrentMapBoldFontTexture()); - assetcache_release(D_80380AB8[0]); - D_80380AB8[0] = assetcache_get(kDialogFontAssetId); + assetcache_release(print_sFontSpriteAssets[0]); + print_sFontSpriteAssets[0] = assetcache_get(kDialogFontAssetId); bk_free(print_sFonts[0]); - print_sFonts[0] = print_getLettersFromFont(D_80380AB8[0], tex); + print_sFonts[0] = print_getLettersFromFont(print_sFontSpriteAssets[0], tex); assetcache_release(tex); // A pack may ship an extended dialog font; refresh the reachable glyph count to match. port_refreshDialogFontGlyphCount(); @@ -555,7 +555,7 @@ static void RegisterLocalizedText() { if (ResourceMgr_IsJapanese()) { sJpFontFreeDelay = 0; // cancel a pending free; ensure slot 2 is current LoadJpFontSlot(); - } else if (D_80380AB8[2] != nullptr) { + } else if (print_sFontSpriteAssets[2] != nullptr) { sJpFontFreeDelay = kJpFontFreeDelayFrames; } bool fontOverridden = ResourceMgr_IsAssetRepointed(kDialogFontAssetId) != 0; @@ -579,7 +579,7 @@ static void RegisterLocalizedText() { // frame instead of letting the draw dereference a NULL slot. REGISTER_LISTENER(ResolveBoldFontSlot, EVENT_PRIORITY_NORMAL, [](IEvent* event) { auto* ev = (ResolveBoldFontSlot*)event; - if (D_80380AB8[*ev->slot] == nullptr) { + if (print_sFontSpriteAssets[*ev->slot] == nullptr) { *ev->slot = 0; *ev->letterId = 0; } diff --git a/src/port/Network/Anchor/DummyPlayer.cpp b/src/port/Network/Anchor/DummyPlayer.cpp index 1bcfa3626..930d41a5c 100644 --- a/src/port/Network/Anchor/DummyPlayer.cpp +++ b/src/port/Network/Anchor/DummyPlayer.cpp @@ -60,27 +60,27 @@ void DummyPlayer::dummy_func_8029DBF0(void) { case ASSET_34D_MODEL_BANJOKAZOOIE_LOW_POLY: // L8029DC24 case ASSET_34E_MODEL_BANJOKAZOOIE_HIGH_POLY: // L8029DC24 temp_s0 = (s32)ml_interpolate_f(dummy_modelEyeBlendUpper, 1.0f, 8.0f); - func_8033A45C(0x1B, temp_s0); - func_8033A45C(0x1D, temp_s0); - func_8033A45C(0x1F, temp_s0); - func_8033A45C(0x21, temp_s0); + modelRender_setAppendageVisibility(0x1B, temp_s0); + modelRender_setAppendageVisibility(0x1D, temp_s0); + modelRender_setAppendageVisibility(0x1F, temp_s0); + modelRender_setAppendageVisibility(0x21, temp_s0); temp_s0 = (s32)ml_interpolate_f(dummy_modelEyeBlendLower, 1.0f, 8.0f); - func_8033A45C(0x1A, temp_s0); - func_8033A45C(0x1C, temp_s0); - func_8033A45C(0x1E, temp_s0); - func_8033A45C(0x20, temp_s0); + modelRender_setAppendageVisibility(0x1A, temp_s0); + modelRender_setAppendageVisibility(0x1C, temp_s0); + modelRender_setAppendageVisibility(0x1E, temp_s0); + modelRender_setAppendageVisibility(0x20, temp_s0); break; case ASSET_34F_MODEL_BANJO_TERMITE: // L8029DCCC case ASSET_359_MODEL_BANJO_WALRUS: // L8029DCCC case ASSET_36F_MODEL_BANJO_PUMPKIN: // L8029DCCC case ASSET_374_MODEL_BANJO_CROC: // L8029DCCC - func_8033A45C(0x1B, (s32)ml_interpolate_f(dummy_modelEyeBlendUpper, 1.0f, 6.0f)); - func_8033A45C(0x1A, (s32)ml_interpolate_f(dummy_modelEyeBlendLower, 1.0f, 6.0f)); + modelRender_setAppendageVisibility(0x1B, (s32)ml_interpolate_f(dummy_modelEyeBlendUpper, 1.0f, 6.0f)); + modelRender_setAppendageVisibility(0x1A, (s32)ml_interpolate_f(dummy_modelEyeBlendLower, 1.0f, 6.0f)); break; case ASSET_356_MODEL_BANJO_WISHYWASHY: // L8029DD2C - func_8033A45C(1, (s32)ml_interpolate_f(dummy_modelEyeBlendLower, 1.0f, 4.0f)); + modelRender_setAppendageVisibility(1, (s32)ml_interpolate_f(dummy_modelEyeBlendLower, 1.0f, 4.0f)); break; } } @@ -96,53 +96,53 @@ void DummyPlayer::dummy_setEyeState(bool squint, bool wink, bool isHat) { dummy_D_8037D234 = isHat; } -void DummyPlayer::func_8029DD6C(void) { +void DummyPlayer::modelAppendages_loadAppendage(void) { s32 temp_s0; // [port] must hold values > 1 for geo selector branches modelRender_func_8033A1FC(); switch (dummy_getModelId()) { case ASSET_34D_MODEL_BANJOKAZOOIE_LOW_POLY: case ASSET_34E_MODEL_BANJOKAZOOIE_HIGH_POLY: - func_8033A45C(1, dummy_kazooieVisible); - func_8033A45C(9, dummy_kazooieVisible); - func_8033A45C(0xC, dummy_kazooieVisible); - func_8033A45C(0xF, dummy_kazooieVisible); - func_8033A45C(2, dummy_modelWink); - func_8033A45C(0xA, dummy_modelWink); - func_8033A45C(0xD, dummy_modelWink); - func_8033A45C(0x10, dummy_modelWink); - func_8033A45C(8, dummy_modelSquint); - func_8033A45C(0xB, dummy_modelSquint); - func_8033A45C(0xE, dummy_modelSquint); - func_8033A45C(0x11, dummy_modelSquint); + modelRender_setAppendageVisibility(1, dummy_kazooieVisible); + modelRender_setAppendageVisibility(9, dummy_kazooieVisible); + modelRender_setAppendageVisibility(0xC, dummy_kazooieVisible); + modelRender_setAppendageVisibility(0xF, dummy_kazooieVisible); + modelRender_setAppendageVisibility(2, dummy_modelWink); + modelRender_setAppendageVisibility(0xA, dummy_modelWink); + modelRender_setAppendageVisibility(0xD, dummy_modelWink); + modelRender_setAppendageVisibility(0x10, dummy_modelWink); + modelRender_setAppendageVisibility(8, dummy_modelSquint); + modelRender_setAppendageVisibility(0xB, dummy_modelSquint); + modelRender_setAppendageVisibility(0xE, dummy_modelSquint); + modelRender_setAppendageVisibility(0x11, dummy_modelSquint); temp_s0 = dummy_modelMouth1 + 1; - func_8033A45C(0x12, temp_s0); - func_8033A45C(0x14, temp_s0); - func_8033A45C(0x16, temp_s0); - func_8033A45C(0x18, temp_s0); - func_8033A45C(0x13, temp_s0); - func_8033A45C(0x15, temp_s0); - func_8033A45C(0x17, temp_s0); - func_8033A45C(0x19, temp_s0); + modelRender_setAppendageVisibility(0x12, temp_s0); + modelRender_setAppendageVisibility(0x14, temp_s0); + modelRender_setAppendageVisibility(0x16, temp_s0); + modelRender_setAppendageVisibility(0x18, temp_s0); + modelRender_setAppendageVisibility(0x13, temp_s0); + modelRender_setAppendageVisibility(0x15, temp_s0); + modelRender_setAppendageVisibility(0x17, temp_s0); + modelRender_setAppendageVisibility(0x19, temp_s0); temp_s0 = dummy_modelMouth2 + 1; - func_8033A45C(0x22, temp_s0); - func_8033A45C(0x24, temp_s0); - func_8033A45C(0x26, temp_s0); - func_8033A45C(0x28, temp_s0); - func_8033A45C(0x23, temp_s0); - func_8033A45C(0x25, temp_s0); - func_8033A45C(0x27, temp_s0); - func_8033A45C(0x29, temp_s0); + modelRender_setAppendageVisibility(0x22, temp_s0); + modelRender_setAppendageVisibility(0x24, temp_s0); + modelRender_setAppendageVisibility(0x26, temp_s0); + modelRender_setAppendageVisibility(0x28, temp_s0); + modelRender_setAppendageVisibility(0x23, temp_s0); + modelRender_setAppendageVisibility(0x25, temp_s0); + modelRender_setAppendageVisibility(0x27, temp_s0); + modelRender_setAppendageVisibility(0x29, temp_s0); break; case ASSET_359_MODEL_BANJO_WALRUS: - func_8033A45C(3, dummy_D_8037D23A); + modelRender_setAppendageVisibility(3, dummy_D_8037D23A); break; case ASSET_374_MODEL_BANJO_CROC: temp_s0 = dummy_modelMouth1 + 1; - func_8033A45C(4, temp_s0); - func_8033A45C(5, temp_s0); - func_8033A45C(6, temp_s0); - func_8033A45C(7, temp_s0); + modelRender_setAppendageVisibility(4, temp_s0); + modelRender_setAppendageVisibility(5, temp_s0); + modelRender_setAppendageVisibility(6, temp_s0); + modelRender_setAppendageVisibility(7, temp_s0); break; } dummy_func_8029DBF0(); @@ -193,7 +193,7 @@ void DummyPlayer::Draw(Gfx** gfx, Mtx** mtx, Vtx** vtx) { sActiveDummyBottlesBonus = dummyBottlesBonus; anctrl_drawSetup(dummyAnimCtrl, dummyPosition, 1); sActiveDummyBottlesBonus = 0; - func_8029DD6C(); + modelAppendages_loadAppendage(); modelRender_setEnvColor(env_color[0], env_color[1], env_color[2], dummyEnvAlpha); modelRender_func_8033A280(2.0f); // modelRender_preDraw((GenFunction_1)_dummy_preDraw, 0); diff --git a/src/port/Network/Anchor/DummyPlayer.h b/src/port/Network/Anchor/DummyPlayer.h index 5341ac590..860e11f52 100644 --- a/src/port/Network/Anchor/DummyPlayer.h +++ b/src/port/Network/Anchor/DummyPlayer.h @@ -55,7 +55,7 @@ class DummyPlayer { void dummy_update(void); void dummy_updateModel(void); // void func_80254008(void); - void func_8029DD6C(void); + void modelAppendages_loadAppendage(void); // void modelRender_func_8033A280(f32); // anim void dummyAnim_init(void); diff --git a/src/port/Network/Anchor/FightSync.c b/src/port/Network/Anchor/FightSync.c index f4cd9107a..d53fd8551 100644 --- a/src/port/Network/Anchor/FightSync.c +++ b/src/port/Network/Anchor/FightSync.c @@ -5,7 +5,7 @@ #include "functions.h" #include "variables.h" #include "prop.h" -#include "FINALE/fight.h" +#include "fight/fight.h" // chfinalboss.c globals. D_803927xx = spell-spawn scratch vectors. extern f32 D_80392758[3]; @@ -430,7 +430,7 @@ void FightSync_ApplyEvent(s32 ev, s32 a, s32 b, const f32 v0[3], const f32 v1[3] src[0] = boss->position[0]; src[1] = boss->position[1]; src[2] = boss->position[2]; - chfinalboss_func_80387110(boss->marker, src, leadTime, 0); + chfinalboss_throwObject(boss->marker, src, leadTime, 0); } break; } diff --git a/src/port/Network/Anchor/HookHandlers.cpp b/src/port/Network/Anchor/HookHandlers.cpp index bd451730d..b665cc3e2 100644 --- a/src/port/Network/Anchor/HookHandlers.cpp +++ b/src/port/Network/Anchor/HookHandlers.cpp @@ -12,7 +12,9 @@ extern "C" { #include "variables.h" -s32 chvile_netGetAnimMode(Actor* actor); +float OTRGetDimensionFromLeftEdge(float v); +float OTRGetDimensionFromRightEdge(float v); +s32 chMrVile_netGetAnimMode(Actor* actor); void port_jiggySpawn_remove(int32_t jiggyId); int32_t port_mapFlag_wasSetRemotely(int32_t index); } @@ -44,7 +46,7 @@ static void Anchor_UpdateVileSync() { Actor* vile = actorArray_findClosestActorFromActorId(origin, ACTOR_13A_MR_VILE, -1, &dist); if (vile != nullptr) { Anchor::GetInstance()->SendPacket_VileUpdate(vile->position, vile->pitch, vile->yaw, vile->roll, - (u8)chvile_netGetAnimMode(vile)); + (u8)chMrVile_netGetAnimMode(vile)); } static u32 sSnapshotTimer = 0; @@ -305,7 +307,7 @@ void Anchor::RegisterHooks() { COND_VB_SHOULD(VB_LEVELDOOR_REMOTE_OPEN_DONE, EVENT_PRIORITY_NORMAL, isConnected, { s32 doorActorId = va_arg(args, s32); s32 doorState = va_arg(args, s32); - if (doorActorId == ACTOR_2E5_DOOR_OF_GRUNTY) { + if (doorActorId == ACTOR_2E5_LARGE_DOOR_TO_FINAL_BATTLE) { *should = (doorState == 0x1B); } }); diff --git a/src/port/Network/Anchor/Packets/PlayerUpdate.cpp b/src/port/Network/Anchor/Packets/PlayerUpdate.cpp index 496b9f95e..d42f8e5e6 100644 --- a/src/port/Network/Anchor/Packets/PlayerUpdate.cpp +++ b/src/port/Network/Anchor/Packets/PlayerUpdate.cpp @@ -7,7 +7,7 @@ #include "macros.h" #include "variables.h" -extern "C" ActorMarker* bacarry_get_marker(void); +extern "C" ActorMarker* bacarry_getMarker(void); #include "port/Patches/Patches.h" @@ -173,18 +173,18 @@ void Anchor::SendPacket_PlayerUpdate(bool full, uint32_t targetClientId) { anctrl_getSubRange(baanim_getAnimCtrlPtr(), &sub_start, &sub_end); payload["subrange_end"] = sub_end; } - payload["kazooieVisible"] = func_8029DFBC(); // Kazooie visibility (Kazooie popped out) - payload["modelSquint"] = func_8029DFA4(); // squint - payload["modelWink"] = func_8029DFB0(); // wink - payload["modelMouth1"] = func_8029DFE0(); // mouth - payload["modelMouth2"] = func_8029DFEC(); // mouth 2 - payload["modelEyeBlendUpper"] = func_8029DFC8(); // eye blend upper - payload["modelEyeBlendLower"] = func_8029DFD4(); // eye blend lower + payload["kazooieVisible"] = modelAppendages_showKazooiesUpperHalf(); // Kazooie visibility (Kazooie popped out) + payload["modelSquint"] = modelAppendages_showKazooiesAss(); // Kazooie's ass visibility + payload["modelWink"] = modelAppendages_showKazooiesFeetAndShoes(); // Kazooie's feet & shoes visibility + payload["modelMouth1"] = modelAppendages_hideTurboTrainers(); // turbo trainers hidden + payload["modelMouth2"] = modelAppendages_hideWadingBoots(); // wading boots hidden + payload["modelEyeBlendUpper"] = modelAppendages_showBanjosLeftEye(); // Banjo's left eye blend + payload["modelEyeBlendLower"] = modelAppendages_showBanjosRightEye(); // Banjo's right eye blend payload["bottlesBonus"] = baanim_getActiveBottlesBonusMask(); { // Carried-collectible marker id (0 = none); skipped once thrown (unk138_21 = in flight). s32 carryId = 0; - ActorMarker* carryMarker = bacarry_get_marker(); + ActorMarker* carryMarker = bacarry_getMarker(); if (carryMarker != nullptr) { Actor* carried = marker_getActor(carryMarker); if (carried != nullptr && !carried->unk138_21) { diff --git a/src/port/Network/Anchor/Packets/VileUpdate.cpp b/src/port/Network/Anchor/Packets/VileUpdate.cpp index 21110c7d6..642375c9b 100644 --- a/src/port/Network/Anchor/Packets/VileUpdate.cpp +++ b/src/port/Network/Anchor/Packets/VileUpdate.cpp @@ -13,7 +13,7 @@ * in the chamber at the player-update cadence. Remote clients skip Mr. Vile's AI and * apply this instead. * - * animMode is the BGS_func_8038BBA0 mode (101 idle / 102 walk / 103 munch / 104 burp). + * animMode is the chMrVile_setAction mode (101 idle / 102 walk / 103 munch / 104 burp). * * Note: sent every frame while the minigame runs, so keep this payload lean. */ diff --git a/src/port/Network/Anchor/VileSync.c b/src/port/Network/Anchor/VileSync.c index 3a5bc3c5a..096f768b9 100644 --- a/src/port/Network/Anchor/VileSync.c +++ b/src/port/Network/Anchor/VileSync.c @@ -9,7 +9,8 @@ // Implemented in src/BGS (see [port] Anchor sync entry points there). extern void chyumblie_netApplyState(Actor* actor, s32 state, s32 piece_type); extern s32 chyumblie_netGetState(Actor* actor, s32* piece_type); -extern void chvile_netApplyUpdate(Actor* actor, const f32 position[3], f32 pitch, f32 yaw, f32 roll, u8 anim_mode); +extern void chMrVile_netApplyUpdate(Actor* actor, const f32 position[3], f32 pitch, f32 yaw, f32 roll, u8 anim_mode); +extern s32 chMrVile_netGetAnimMode(Actor* actor); extern bool chvilegame_netGather(Actor* actor, VileGameSnapshot* dst); extern void chvilegame_netApply(Actor* actor, const VileGameSnapshot* src); extern bool chvilegame_netConsumeRemote(Actor* actor, f32 position[3], s32* out_piece_type, s32* out_correct_type); @@ -97,7 +98,7 @@ bool VileSync_HandleEatRequest(int32_t holeId, uint32_t eaterClientId, int32_t* return false; } pos[0] = holePos[0]; - pos[1] = 0.0f; // piece positions are stored with y = 0 (see chvilegame_new_piece) + pos[1] = 0.0f; // piece positions are stored with y = 0 (see chMrVileMinigame_newPiece) pos[2] = holePos[1]; // A successful consume broadcasts the eaten hole state itself (the state change // fires OnVileHoleStateChange on this authority client); the piece type / correctness @@ -116,7 +117,7 @@ void VileSync_ApplyVileUpdate(const float position[3], float pitch, float yaw, f Actor* vile = VileSync_FindActor(ACTOR_13A_MR_VILE); if (vile != NULL) { - chvile_netApplyUpdate(vile, position, pitch, yaw, roll, animMode); + chMrVile_netApplyUpdate(vile, position, pitch, yaw, roll, animMode); } } diff --git a/src/port/Network/Anchor/VileSync.h b/src/port/Network/Anchor/VileSync.h index 68c21e9fb..c6e6a83b0 100644 --- a/src/port/Network/Anchor/VileSync.h +++ b/src/port/Network/Anchor/VileSync.h @@ -69,7 +69,7 @@ bool VileSync_HandleEatRequest(int32_t holeId, uint32_t eaterClientId, int32_t* // plus the wrong-type reaction) once the authority confirms the eat succeeded. void VileSync_PlayLocalEatFeedback(int32_t pieceType, int32_t correctType); -// Apply a streamed Mr. Vile transform + anim mode (BGS_func_8038BBA0 modes 101-104). +// Apply a streamed Mr. Vile transform + anim mode (chMrVile_setAction modes 101-104). void VileSync_ApplyVileUpdate(const float position[3], float pitch, float yaw, float roll, uint8_t animMode); // Fill dst from the live minigame controller. Returns false if there is nothing to diff --git a/src/port/Patches/FramebufferPatches.cpp b/src/port/Patches/FramebufferPatches.cpp index 9ae95dfa9..5f9fb533c 100644 --- a/src/port/Patches/FramebufferPatches.cpp +++ b/src/port/Patches/FramebufferPatches.cpp @@ -179,16 +179,16 @@ static void patchModelDL(BKModelBin* model_bin, uintptr_t seg_start, uintptr_t s // Aux picture FB readback (Bottles Bonus / SNS pictures) -extern s16* D_80382450; // aux picture CPU buffer (picturebuffer.c) -extern s32 sAuxGpuFbId; // aux picture GPU FB id (picturebuffer.c) +extern s16* sPictureBoxColorBuffer; // aux picture CPU buffer (auxbuffer.c) +extern s32 sAuxGpuFbId; // aux picture GPU FB id (picturebuffer.c) s32 port_getAuxGpuFbId(void) { return sAuxGpuFbId; } void port_readAuxFbToCpu(Gfx** gfx) { - if (sAuxGpuFbId >= 0 && D_80382450 != NULL) { - gDPReadFB((*gfx)++, sAuxGpuFbId, (u16*)D_80382450, 0, 0, IMAGE_WIDTH, IMAGE_HEIGHT, 1); + if (sAuxGpuFbId >= 0 && sPictureBoxColorBuffer != NULL) { + gDPReadFB((*gfx)++, sAuxGpuFbId, (u16*)sPictureBoxColorBuffer, 0, 0, IMAGE_WIDTH, IMAGE_HEIGHT, 1); __gSPInvalidateTexCache((*gfx)++, 0); } } diff --git a/src/port/Patches/MirrorPatches.cpp b/src/port/Patches/MirrorPatches.cpp index e1b7f1ce6..eb8264a25 100644 --- a/src/port/Patches/MirrorPatches.cpp +++ b/src/port/Patches/MirrorPatches.cpp @@ -25,12 +25,12 @@ static ActorDrawFunc sOrig_actor_draw = nullptr; extern "C" { // ActorInfo externs for text-bearing models (must be inside extern "C" for correct linkage) -extern ActorInfo D_80393354; // level entry signs (model 0x563) -extern ActorInfo D_80367530; // 5 mumbo token sign (0x301) -extern ActorInfo D_80367554; // 10 mumbo token sign (0x302) -extern ActorInfo D_80367578; // 15 mumbo token sign (0x303) -extern ActorInfo D_8036759C; // 20 mumbo token sign (0x304) -extern ActorInfo D_803675C0; // 25 mumbo token sign (0x305) +extern ActorInfo D_80393354; // level entry signs (model 0x563) +extern ActorInfo chMumboSign5; // 5 mumbo token sign (0x301) +extern ActorInfo chMumboSign10; // 10 mumbo token sign (0x302) +extern ActorInfo chMumboSign15; // 15 mumbo token sign (0x303) +extern ActorInfo chMumboSign20; // 20 mumbo token sign (0x304) +extern ActorInfo chMumboSign25; // 25 mumbo token sign (0x305) // Custom draw functions used by text-bearing actors (not in functions.h) extern Actor* lair_func_80387560(ActorMarker*, Gfx**, Mtx**, Vtx**); @@ -142,11 +142,11 @@ void port_mirror_patchTextActors(void) { // Mumbo token signs (5 variants: 5, 10, 15, 20, 25 tokens) sOrig_actor_draw = (ActorDrawFunc)actor_draw; - D_80367530.draw_func = mirror_excluded_actor_draw; - D_80367554.draw_func = mirror_excluded_actor_draw; - D_80367578.draw_func = mirror_excluded_actor_draw; - D_8036759C.draw_func = mirror_excluded_actor_draw; - D_803675C0.draw_func = mirror_excluded_actor_draw; + chMumboSign5.draw_func = mirror_excluded_actor_draw; + chMumboSign10.draw_func = mirror_excluded_actor_draw; + chMumboSign15.draw_func = mirror_excluded_actor_draw; + chMumboSign20.draw_func = mirror_excluded_actor_draw; + chMumboSign25.draw_func = mirror_excluded_actor_draw; } } // extern "C" diff --git a/src/port/Patches/SpritePatches.cpp b/src/port/Patches/SpritePatches.cpp index 88a0f6333..9f5df2199 100644 --- a/src/port/Patches/SpritePatches.cpp +++ b/src/port/Patches/SpritePatches.cpp @@ -25,8 +25,8 @@ enum level_e level_get(void); s32 gcpausemenu_levelToMenuPage(enum level_e level); extern s32 gFramebufferWidth; -extern BKSprite* D_80380AB8[]; // font alphamask sprites ([0] = dialog font) -extern s32 print_sDialogFontGlyphCount; // reachable glyph count: byte range 0x21 .. 0x21+count-1 +extern BKSprite* print_sFontSpriteAssets[]; // font alphamask sprites ([0] = dialog font) +extern s32 print_sDialogFontGlyphCount; // reachable glyph count: byte range 0x21 .. 0x21+count-1 #define SPRITE_DISPLAY_CACHE_SIZE 256 @@ -46,8 +46,8 @@ void port_spriteDisplayCache_clear(void) { // sets this once from the base font, but a language pack can swap in an extended dialog font // (more glyphs than the base 62) at runtime. void port_refreshDialogFontGlyphCount(void) { - if (D_80380AB8[0] != NULL) { - print_sDialogFontGlyphCount = sprite_getFramePtr(D_80380AB8[0], 0)->chunkCnt; + if (print_sFontSpriteAssets[0] != NULL) { + print_sDialogFontGlyphCount = sprite_getFramePtr(print_sFontSpriteAssets[0], 0)->chunkCnt; } } diff --git a/src/port/Rando/CustomObject/CustomObject.cpp b/src/port/Rando/CustomObject/CustomObject.cpp index dd007f8a7..4196ed129 100644 --- a/src/port/Rando/CustomObject/CustomObject.cpp +++ b/src/port/Rando/CustomObject/CustomObject.cpp @@ -43,17 +43,17 @@ extern ActorInfo chJinjoYellow; extern ActorInfo chJinjoPink; extern ActorInfo chJinjoOrange; extern ActorInfo chJiggy; -extern ActorInfo D_80366C80; -extern ActorInfo D_803685A0; +extern ActorInfo chEmptyHoneycomb; +extern ActorInfo chMumboToken; extern ActorInfo sumusicNote; -extern ActorInfo D_80366CA4; -extern ActorInfo D_80367D00; -extern ActorInfo D_80367D24; -extern ActorInfo D_80367D48; +extern ActorInfo chHoneycomb; +extern ActorInfo chBlueEgg; +extern ActorInfo chRedFeather; +extern ActorInfo chGoldFeather; -extern ActorInfo D_80367814; -extern ActorInfo D_803677A8; +extern ActorInfo chSnsEgg; +extern ActorInfo chIceKey; } typedef struct { @@ -68,21 +68,21 @@ bool shouldRemoveEX = false; // clang-format off std::map> actorInfoMap = { - { ACTOR_2D_MUMBO_TOKEN, { D_803685A0, ACTOR_FLAG_UNKNOWN_6 } }, + { ACTOR_2D_MUMBO_TOKEN, { chMumboToken, ACTOR_FLAG_UNKNOWN_6 } }, { ACTOR_46_JIGGY, { chJiggy, ACTOR_FLAG_UNKNOWN_6 | ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_21 } }, - { ACTOR_47_EMPTY_HONEYCOMB, { D_80366C80, ACTOR_FLAG_UNKNOWN_6 | ACTOR_FLAG_UNKNOWN_21 } }, + { ACTOR_47_EMPTY_HONEYCOMB, { chEmptyHoneycomb, ACTOR_FLAG_UNKNOWN_6 | ACTOR_FLAG_UNKNOWN_21 } }, { ACTOR_51_MUSIC_NOTE, { sumusicNote, ACTOR_FLAG_UNKNOWN_21 } }, { ACTOR_5E_JINJO_YELLOW, { chJinjoYellow, ACTOR_FLAG_UNKNOWN_6 | ACTOR_FLAG_UNKNOWN_8 } }, { ACTOR_5F_JINJO_ORANGE, { chJinjoOrange, ACTOR_FLAG_UNKNOWN_6 | ACTOR_FLAG_UNKNOWN_8 } }, { ACTOR_60_JINJO_BLUE, { chJinjoBlue, ACTOR_FLAG_UNKNOWN_6 | ACTOR_FLAG_UNKNOWN_8 } }, { ACTOR_61_JINJO_PINK, { chJinjoPink, ACTOR_FLAG_UNKNOWN_6 | ACTOR_FLAG_UNKNOWN_8 } }, { ACTOR_62_JINJO_GREEN, { chJinjoGreen, ACTOR_FLAG_UNKNOWN_6 | ACTOR_FLAG_UNKNOWN_8 } }, - { ACTOR_50_HONEYCOMB, { D_80366CA4, ACTOR_FLAG_UNKNOWN_6 | ACTOR_FLAG_UNKNOWN_21 } }, - { ACTOR_52_BLUE_EGG, { D_80367D00, ACTOR_FLAG_UNKNOWN_21 } }, - { ACTOR_129_RED_FEATHER, { D_80367D24, ACTOR_FLAG_UNKNOWN_21 } }, - { ACTOR_370_GOLD_FEATHER, { D_80367D48, ACTOR_FLAG_UNKNOWN_21 } }, - { ACTOR_25E_SNS_EGG, { D_80367814, ACTOR_FLAG_UNKNOWN_9 | ACTOR_FLAG_UNKNOWN_10 | ACTOR_FLAG_UNKNOWN_15 } }, - { ACTOR_25D_ICE_KEY, { D_803677A8, ACTOR_FLAG_UNKNOWN_9 | ACTOR_FLAG_UNKNOWN_10 | ACTOR_FLAG_UNKNOWN_15 } }, + { ACTOR_50_HONEYCOMB, { chHoneycomb, ACTOR_FLAG_UNKNOWN_6 | ACTOR_FLAG_UNKNOWN_21 } }, + { ACTOR_52_BLUE_EGG, { chBlueEgg, ACTOR_FLAG_UNKNOWN_21 } }, + { ACTOR_129_RED_FEATHER, { chRedFeather, ACTOR_FLAG_UNKNOWN_21 } }, + { ACTOR_370_GOLD_FEATHER, { chGoldFeather, ACTOR_FLAG_UNKNOWN_21 } }, + { ACTOR_25E_SNS_EGG, { chSnsEgg, ACTOR_FLAG_UNKNOWN_9 | ACTOR_FLAG_UNKNOWN_10 | ACTOR_FLAG_UNKNOWN_15 } }, + { ACTOR_25D_ICE_KEY, { chIceKey, ACTOR_FLAG_UNKNOWN_9 | ACTOR_FLAG_UNKNOWN_10 | ACTOR_FLAG_UNKNOWN_15 } }, }; // clang-format on diff --git a/src/port/UI/DeveloperTools/GameplayTools.cpp b/src/port/UI/DeveloperTools/GameplayTools.cpp index 0c40e009d..cb5e69abd 100644 --- a/src/port/UI/DeveloperTools/GameplayTools.cpp +++ b/src/port/UI/DeveloperTools/GameplayTools.cpp @@ -127,17 +127,17 @@ std::vector mapSpecificFlagList = { { TTC_SPECIFIC_FLAG_5_CLAM_FIRST_MEET_TEXT_SHOWN, "TTC_SPECIFIC_FLAG_5_CLAM_FIRST_MEET_TEXT_SHOWN", LEVEL_2_TREASURE_TROVE_COVE }, { TTC_SPECIFIC_FLAG_7_NIPPER_FIRST_MEET_TEXT_SHOWN, "TTC_SPECIFIC_FLAG_7_NIPPER_FIRST_MEET_TEXT_SHOWN", LEVEL_2_TREASURE_TROVE_COVE }, { BGS_SPECIFIC_FLAG_1, "BGS_SPECIFIC_FLAG_1", LEVEL_4_BUBBLEGLOOP_SWAMP }, - { BGS_SPECIFIC_FLAG_WALKWAY_JIGGY_RESET, "BGS_SPECIFIC_FLAG_WALKWAY_JIGGY_RESET", LEVEL_4_BUBBLEGLOOP_SWAMP }, - { BGS_SPECIFIC_FLAG_WALKWAY_JIGGY_TIMER_RUNNING, "BGS_SPECIFIC_FLAG_WALKWAY_JIGGY_TIMER_RUNNING", LEVEL_4_BUBBLEGLOOP_SWAMP }, - { BGS_SPECIFIC_FLAG_WALKWAY_JIGGY, "BGS_SPECIFIC_FLAG_WALKWAY_JIGGY", LEVEL_4_BUBBLEGLOOP_SWAMP }, - { BGS_SPECIFIC_FLAG_WALKWAY_JIGGY_SWITCH_PRESSED, "BGS_SPECIFIC_FLAG_WALKWAY_JIGGY_SWITCH_PRESSED", LEVEL_4_BUBBLEGLOOP_SWAMP }, + { BGS_SPECIFIC_FLAG_2_WALKWAY_JIGGY_RESET, "BGS_SPECIFIC_FLAG_2_WALKWAY_JIGGY_RESET", LEVEL_4_BUBBLEGLOOP_SWAMP }, + { BGS_SPECIFIC_FLAG_3_WALKWAY_JIGGY_TIMER_RUNNING, "BGS_SPECIFIC_FLAG_3_WALKWAY_JIGGY_TIMER_RUNNING", LEVEL_4_BUBBLEGLOOP_SWAMP }, + { BGS_SPECIFIC_FLAG_4_WALKWAY_JIGGY, "BGS_SPECIFIC_FLAG_4_WALKWAY_JIGGY", LEVEL_4_BUBBLEGLOOP_SWAMP }, + { BGS_SPECIFIC_FLAG_5_WALKWAY_JIGGY_SWITCH_PRESSED, "BGS_SPECIFIC_FLAG_5_WALKWAY_JIGGY_SWITCH_PRESSED", LEVEL_4_BUBBLEGLOOP_SWAMP }, { BGS_SPECIFIC_FLAG_7, "BGS_SPECIFIC_FLAG_7", LEVEL_4_BUBBLEGLOOP_SWAMP }, { BGS_SPECIFIC_FLAG_8, "BGS_SPECIFIC_FLAG_8", LEVEL_4_BUBBLEGLOOP_SWAMP }, - { BGS_SPECIFIC_FLAG_MAZE_JIGGY_SWITCH_PRESSED, "BGS_SPECIFIC_FLAG_MAZE_JIGGY_SWITCH_PRESSED", LEVEL_4_BUBBLEGLOOP_SWAMP }, + { BGS_SPECIFIC_FLAG_9_MAZE_JIGGY_SWITCH_PRESSED, "BGS_SPECIFIC_FLAG_9_MAZE_JIGGY_SWITCH_PRESSED", LEVEL_4_BUBBLEGLOOP_SWAMP }, { BGS_SPECIFIC_FLAG_A, "BGS_SPECIFIC_FLAG_A", LEVEL_4_BUBBLEGLOOP_SWAMP }, - { BGS_SPECIFIC_FLAG_MAZE_JIGGY_RESET, "BGS_SPECIFIC_FLAG_MAZE_JIGGY_RESET", LEVEL_4_BUBBLEGLOOP_SWAMP }, - { BGS_SPECIFIC_FLAG_MAZE_JIGGY_TIMER_RUNNING, "BGS_SPECIFIC_FLAG_MAZE_JIGGY_TIMER_RUNNING", LEVEL_4_BUBBLEGLOOP_SWAMP }, - { BGS_SPECIFIC_FLAG_MAZE_JIGGY, "BGS_SPECIFIC_FLAG_MAZE_JIGGY", LEVEL_4_BUBBLEGLOOP_SWAMP }, + { BGS_SPECIFIC_FLAG_B_MAZE_JIGGY_RESET, "BGS_SPECIFIC_FLAG_B_MAZE_JIGGY_RESET", LEVEL_4_BUBBLEGLOOP_SWAMP }, + { BGS_SPECIFIC_FLAG_C_MAZE_JIGGY_TIMER_RUNNING, "BGS_SPECIFIC_FLAG_C_MAZE_JIGGY_TIMER_RUNNING", LEVEL_4_BUBBLEGLOOP_SWAMP }, + { BGS_SPECIFIC_FLAG_D_MAZE_JIGGY, "BGS_SPECIFIC_FLAG_D_MAZE_JIGGY", LEVEL_4_BUBBLEGLOOP_SWAMP }, { FP_SPECIFIC_FLAG_0_XMAS_TREE_LIGHTS_ON, "FP_SPECIFIC_FLAG_0_XMAS_TREE_LIGHTS_ON", LEVEL_5_FREEZEEZY_PEAK }, { FP_SPECIFIC_FLAG_1_UNKNOWN, "FP_SPECIFIC_FLAG_1_UNKNOWN", LEVEL_5_FREEZEEZY_PEAK }, { FP_SPECIFIC_FLAG_2_XMAS_TREE_SWITCH, "FP_SPECIFIC_FLAG_2_XMAS_TREE_SWITCH", LEVEL_5_FREEZEEZY_PEAK }, diff --git a/src/port/UI/DeveloperTools/SaveEditor.cpp b/src/port/UI/DeveloperTools/SaveEditor.cpp index 259b79c30..0207a1fbb 100644 --- a/src/port/UI/DeveloperTools/SaveEditor.cpp +++ b/src/port/UI/DeveloperTools/SaveEditor.cpp @@ -25,7 +25,7 @@ #define HONEYCOMB_ID_MULTIPLIER(levelId) (1 + (2 * (levelId - 1))) extern "C" { -int ability_isUnlocked(enum ability_e uid); +bool ability_isUnlocked(enum ability_e uid); void jiggyscore_setCollected(s32 indx, s32 val); void honeycombscore_set(enum honeycomb_e indx, bool val); void mumboscore_set(enum mumbotoken_e indx, bool val); diff --git a/src/unused/datalookup.c b/src/unused/datalookup.c index 6da37f5f2..c3033cebc 100644 --- a/src/unused/datalookup.c +++ b/src/unused/datalookup.c @@ -1,4 +1,4 @@ -// BanjoDecomp: (unknown decomp origin - data lookup) +// BanjoDecomp: core2/code_5FD80.c #include #include "functions.h" #include "variables.h" diff --git a/src/unused/debug_assert.c b/src/unused/debug_assert.c index 4a0de56a5..4bba81053 100644 --- a/src/unused/debug_assert.c +++ b/src/unused/debug_assert.c @@ -1,4 +1,4 @@ -// BanjoDecomp: core2/ultra/debug/assert.c +// BanjoDecomp: core2/ultra/debug/assert.c (kept in unused/, not built on PC) #include #include "functions.h" #include "variables.h" diff --git a/src/unused/debug_boxdraw.c b/src/unused/debug_boxdraw.c index c49e57865..8dec67ea0 100644 --- a/src/unused/debug_boxdraw.c +++ b/src/unused/debug_boxdraw.c @@ -1,4 +1,4 @@ -// BanjoDecomp: (unknown decomp origin - unused debug drawing) +// BanjoDecomp: core1/stub_3A70.c #include #include "core1/core1.h" #include "functions.h" diff --git a/src/unused/unused_block.c b/src/unused/unused_block.c index 9f2f5b6a0..a71bdf874 100644 --- a/src/unused/unused_block.c +++ b/src/unused/unused_block.c @@ -1,4 +1,4 @@ -// BanjoDecomp: (unknown decomp origin - unused block) +// BanjoDecomp: core2/code_B7F40.c #include #include "functions.h" #include "variables.h" From 65b2c271fcfd3e09878eef1f70e9af035ab30b7d Mon Sep 17 00:00:00 2001 From: Jeod <47716344+JeodC@users.noreply.github.com> Date: Sat, 25 Jul 2026 13:46:54 -0400 Subject: [PATCH 018/131] Hotfix for camera orbit core (#259) * Hotfix for camera orbit core * Fix a bug where rotating modern cam while climbing caused it to get stuck --- src/port/Controller/ModernCamera.cpp | 41 +++++++++++++++++-- .../Enhancements/Camera/OrbitCameraCore.cpp | 12 ++++-- 2 files changed, 46 insertions(+), 7 deletions(-) diff --git a/src/port/Controller/ModernCamera.cpp b/src/port/Controller/ModernCamera.cpp index 431700f90..dbe1f3302 100644 --- a/src/port/Controller/ModernCamera.cpp +++ b/src/port/Controller/ModernCamera.cpp @@ -3,6 +3,8 @@ // The right stick orbits the camera in yaw around the player (no pitch). It runs // on the shared orbit core; this file is just the modern-scheme policy. +#include + #include #include "port/UI/cvar_prefixes.h" @@ -24,6 +26,9 @@ int balookat_getState(void); // nonzero while the look-around camera is activ int player_movementGroup(void); // enum bsgroup_e int ncDynamicCamera_getState(void); +int func_8029147C(void); // current ba camera mode +void func_80291488(int mode); // set the ba camera mode +void func_802914CC(int state); // force a dynamic camera state (mode 1) int bainput_should_rotate_camera_left(void); int bainput_should_rotate_camera_right(void); @@ -41,6 +46,9 @@ bool ModernSchemeActive() { return CVarGetInteger(CVAR_SETTING("Controls.Scheme"), CONTROL_SCHEME_RETRO) == CONTROL_SCHEME_MODERN; } +constexpr int kClimbCamState = 0x10; +constexpr int kSwivelCamMode = 8; +constexpr int kFollowCamMode = 2; constexpr float kYawDeadzone = 0.2f; constexpr float kYawEnter = 0.3f; constexpr float kYawSpeed = 160.0f; @@ -81,13 +89,34 @@ bool ManualCameraControl() { bainput_should_look_first_person_camera(); } +bool Climbing() { + return player_movementGroup() == BSGROUP_5_CLIMB; +} + +// Give the mode back +void ReleaseSwivelMode() { + if (func_8029147C() != kSwivelCamMode) { + return; + } + if (Climbing()) { + func_802914CC(kClimbCamState); + } else { + func_80291488(kFollowCamMode); + } +} + +void ExitOrbit() { + OrbitCamera_Exit(&sModern); + ReleaseSwivelMode(); +} + } // namespace extern "C" int port_modernCamera_handleYaw(void) { bool schemeOk = ModernSchemeActive() && bs_getState() != BS_7_CROUCH && !IsDemoMode(); if (!schemeOk) { if (sModern.active) { - OrbitCamera_Exit(&sModern); + ExitOrbit(); } return 0; } @@ -102,17 +131,23 @@ extern "C" int port_modernCamera_handleYaw(void) { return 0; } if (ManualCameraControl()) { - OrbitCamera_Exit(&sModern); + ExitOrbit(); return 0; } + if (!Climbing()) { + ReleaseSwivelMode(); + } return 1; } float x; float y; ReadStickNorm(x, y); - if (x > kYawEnter || x < -kYawEnter) { + if (std::fabs(x) > kYawEnter) { OrbitCamera_Enter(&sModern); + if (state == kClimbCamState) { + func_80291488(kSwivelCamMode); + } return 1; } return 0; diff --git a/src/port/Enhancements/Camera/OrbitCameraCore.cpp b/src/port/Enhancements/Camera/OrbitCameraCore.cpp index cbfc4ff7c..6efe6520d 100644 --- a/src/port/Enhancements/Camera/OrbitCameraCore.cpp +++ b/src/port/Enhancements/Camera/OrbitCameraCore.cpp @@ -11,6 +11,7 @@ int ncDynamicCamera_getState(void); void ncDynamicCamera_setState(int state); void func_802C02D4(float center[3]); // camera focus/orbit center +void func_802C0150(int mode); // select the focus target void func_80256E24(float dst[3], float pitch, float yaw, float x, float y, float z); // spherical -> offset int func_8025801C(float vec[3], float* yaw); // vector -> yaw (degrees) void func_802BC434(float rotOut[3], float fromPos[3], float targetPos[3]); // look-at rotation @@ -30,8 +31,9 @@ namespace { constexpr float kDistanceRate = 8.0f; constexpr float kReturnRateFactor = 0.2f; // collision offset relaxes this much slower than it deepens -constexpr float kVertRate = 0.8f; // height + aim Y follow rate; low to filter floor-height churn -constexpr float kRotRate = 12.0f; // look-at damping, mirroring the vanilla follow camera +constexpr float kHeightRate = 2.0f; +constexpr float kAimHeightRate = 8.0f; +constexpr float kRotRate = 12.0f; // look-at damping, mirroring the vanilla follow camera float clampf(float v, float lo, float hi) { return v < lo ? lo : (v > hi ? hi : v); @@ -40,6 +42,8 @@ float clampf(float v, float lo, float hi) { } // namespace extern "C" void OrbitCamera_Capture(OrbitCamera* c) { + func_802C0150(2); + float camPos[3]; float center[3]; ncDynamicCamera_getPosition(camPos); @@ -120,7 +124,7 @@ extern "C" void OrbitCamera_Update(OrbitCamera* c, float yawDelta, float pitchDe pos[1] = center[1] + offset[1]; // pitch carries the vertical offset } else { // Flat orbit: height low-passes the vanilla target, filtering plank/step floor churn. - c->height += (func_802BD51C() - c->height) * clampf(kVertRate * dt, 0.0f, 1.0f); + c->height += (func_802BD51C() - c->height) * clampf(kHeightRate * dt, 0.0f, 1.0f); pos[1] = c->height; } ncDynamicCamera_setPosition(pos); @@ -166,7 +170,7 @@ extern "C" void OrbitCamera_Update(OrbitCamera* c, float yawDelta, float pitchDe c->aimCenterY = center[1]; c->aimValid = 1; } else { - c->aimCenterY += (center[1] - c->aimCenterY) * clampf(kVertRate * dt, 0.0f, 1.0f); + c->aimCenterY += (center[1] - c->aimCenterY) * clampf(kAimHeightRate * dt, 0.0f, 1.0f); } float aimCenter[3] = { center[0], c->aimCenterY, center[2] }; From 32bb29d704aa193c17d412d446938132eac72cce Mon Sep 17 00:00:00 2001 From: Jeod <47716344+JeodC@users.noreply.github.com> Date: Sat, 25 Jul 2026 13:51:24 -0400 Subject: [PATCH 019/131] Add permadeath enhancement (#254) --- src/core2/bs/player_spawn.c | 2 + src/core2/gameSelect.c | 7 +++ src/port/Enhancements/Events/Hooks/Events.h | 1 + .../Events/Hooks/List/GameEvent.h | 2 + .../Enhancements/Events/PortEnhancements.cpp | 2 + .../Enhancements/Gameplay/DamageScale.cpp | 13 ----- src/port/Enhancements/Gameplay/Difficulty.cpp | 53 +++++++++++++++++++ src/port/Save/SaveManager.cpp | 22 ++++++-- src/port/UI/LighthouseMenuEnhancements.cpp | 10 ++++ 9 files changed, 96 insertions(+), 16 deletions(-) delete mode 100644 src/port/Enhancements/Gameplay/DamageScale.cpp create mode 100644 src/port/Enhancements/Gameplay/Difficulty.cpp diff --git a/src/core2/bs/player_spawn.c b/src/core2/bs/player_spawn.c index 3a6087257..c7f386739 100644 --- a/src/core2/bs/player_spawn.c +++ b/src/core2/bs/player_spawn.c @@ -297,6 +297,8 @@ void func_8029B62C(void){ func_802E4048(gVoidOutReturnLocation[0], gVoidOutReturnLocation[1], 1); return; } + // [port] Permadeath difficulty empties the reserve and erases the save here. + CALL_EVENT(OnPlayerDeath); if(item_empty(ITEM_16_LIFE)){ if(!fileProgressFlag_get(FILEPROG_BD_ENTER_LAIR_CUTSCENE) || fileProgressFlag_get(FILEPROG_A6_FURNACE_FUN_COMPLETE)){ func_8025A430(-1, 0x7D0, 3); diff --git a/src/core2/gameSelect.c b/src/core2/gameSelect.c index c1faffbc6..3254c057f 100644 --- a/src/core2/gameSelect.c +++ b/src/core2/gameSelect.c @@ -285,6 +285,8 @@ void setGameInformationZoombox(s32 gamenum){ void eraseGame(s32 arg0){ gameFile_clear(arg0); + // [port] The clear only zeroes the slot in RAM; also delete the file. + CALL_EVENT(OnGameFileErase, arg0); setGameInformationZoombox(arg0); } @@ -669,6 +671,11 @@ void gameSelect_saveAndExit(void){ s32 sp1C = level_get(); s32 t6 = gsworld_getMap() == MAP_83_CS_GAME_OVER_MACHINE_ROOM; s32 a1 = (0 < sp1C && sp1C < 0xd); + // [port] Permadeath erases the save on death; the game over path routes back through + // here, and saving would write the still-live game state over the erased slot. + if(!EventSystem_Should(VB_SAVE_AND_EXIT, true)){ + return; + } if( a1 || t6) { if(D_80365E00 != -1 && !func_802E4A08() && gsworld_getMap() != MAP_91_FILE_SELECT){ diff --git a/src/port/Enhancements/Events/Hooks/Events.h b/src/port/Enhancements/Events/Hooks/Events.h index 5def299b7..cead7e13f 100644 --- a/src/port/Enhancements/Events/Hooks/Events.h +++ b/src/port/Enhancements/Events/Hooks/Events.h @@ -21,6 +21,7 @@ typedef enum VBehaviorID { VB_PLAY_INTRO_CUTSCENE, VB_DISABLE_SNACKER, VB_VOID_OUT_GAME_OVER, + VB_SAVE_AND_EXIT, VB_CCW_GNAWTY_SPRING_ROCK, VB_CCW_FLOWER_REPLANT, VB_TERMITE_MOUND_SLOPES, diff --git a/src/port/Enhancements/Events/Hooks/List/GameEvent.h b/src/port/Enhancements/Events/Hooks/List/GameEvent.h index 47f66605c..65faafe70 100644 --- a/src/port/Enhancements/Events/Hooks/List/GameEvent.h +++ b/src/port/Enhancements/Events/Hooks/List/GameEvent.h @@ -3,6 +3,8 @@ #include DEFINE_EVENT(OnActorDestroy, Actor* actor;) +DEFINE_EVENT(OnPlayerDeath) +DEFINE_EVENT(OnGameFileErase, int32_t gamenum;) DEFINE_EVENT(OnGameSave, int32_t fileNum;) DEFINE_EVENT(OnGameLoad, int32_t fileNum;) DEFINE_EVENT(OnGameErase, int32_t gameNum;) diff --git a/src/port/Enhancements/Events/PortEnhancements.cpp b/src/port/Enhancements/Events/PortEnhancements.cpp index dbca6c499..fd9739a89 100644 --- a/src/port/Enhancements/Events/PortEnhancements.cpp +++ b/src/port/Enhancements/Events/PortEnhancements.cpp @@ -78,6 +78,8 @@ void PortEnhancements_Register() { REGISTER_EVENT(OnAbilityLearned); REGISTER_EVENT(OnJiggySpawned); REGISTER_EVENT(OnTimedJiggyExpired); + REGISTER_EVENT(OnPlayerDeath); + REGISTER_EVENT(OnGameFileErase); REGISTER_EVENT(OnGameLoad); REGISTER_EVENT(OnGameSave); REGISTER_EVENT(OnGameErase); diff --git a/src/port/Enhancements/Gameplay/DamageScale.cpp b/src/port/Enhancements/Gameplay/DamageScale.cpp deleted file mode 100644 index 7893a0f2f..000000000 --- a/src/port/Enhancements/Gameplay/DamageScale.cpp +++ /dev/null @@ -1,13 +0,0 @@ -#include -#include "port/UI/cvar_prefixes.h" - -extern "C" int port_scalePlayerDamage(int damage) { - if (damage <= 0) { - return damage; - } - int mode = CVarGetInteger(CVAR_ENHANCEMENT("Gameplay.Difficulty"), 1); - if (mode >= 4) { - return 9999; - } - return damage * (mode < 1 ? 1 : mode); -} \ No newline at end of file diff --git a/src/port/Enhancements/Gameplay/Difficulty.cpp b/src/port/Enhancements/Gameplay/Difficulty.cpp new file mode 100644 index 000000000..fdf918b3e --- /dev/null +++ b/src/port/Enhancements/Gameplay/Difficulty.cpp @@ -0,0 +1,53 @@ +#include +#include "port/UI/cvar_prefixes.h" +#include "port/Enhancements/Events/Hooks/Events.h" +#include "port/ShipInit.hpp" +#include "port/Romhack/RomhackConfig.h" + +extern "C" { +#include "enums.h" +#include "functions.h" +} + +static bool sSaveErased = false; + +extern "C" int port_scalePlayerDamage(int damage) { + if (damage <= 0) { + return damage; + } + int mode = CVarGetInteger(CVAR_ENHANCEMENT("Gameplay.Difficulty"), 1); + if (mode >= 4) { + return 9999; + } + return damage * (mode < 1 ? 1 : mode); +} + +void RegisterDifficulty_Init() { + // Permadeath, ignore lives and game over with file erase + COND_HOOK(OnPlayerDeath, EVENT_PRIORITY_NORMAL, CVarGetInteger(CVAR_ENHANCEMENT("Gameplay.Permadeath"), 0), + [](IEvent* event) { + if (port_isRomhack()) { + return; + } + item_adjustByDiffWithoutHud(ITEM_16_LIFE, -item_getCount(ITEM_16_LIFE)); + + s32 gamenum = gameSelect_getGameNumber(); + if (gamenum == -1) { + return; + } + + gameFile_clear(gamenum); + gameFile_8033CFD4(gamenum); + sSaveErased = true; + }); + + COND_HOOK(OnGameLoad, EVENT_PRIORITY_NORMAL, true, [](IEvent* event) { sSaveErased = false; }); + + COND_VB_SHOULD(VB_SAVE_AND_EXIT, EVENT_PRIORITY_NORMAL, true, { + if (sSaveErased) { + *should = false; + } + }); +} + +static RegisterShipInitFunc initFunc(RegisterDifficulty_Init, { CVAR_ENHANCEMENT("Gameplay.Permadeath") }); diff --git a/src/port/Save/SaveManager.cpp b/src/port/Save/SaveManager.cpp index ffc65d916..fda108d9f 100644 --- a/src/port/Save/SaveManager.cpp +++ b/src/port/Save/SaveManager.cpp @@ -748,13 +748,24 @@ void SaveManager_Init() { REGISTER_LISTENER(OnSaveFileSave, EVENT_PRIORITY_NORMAL, [](IEvent* event) { OnSaveFileSave* ev = (OnSaveFileSave*)event; + std::string fileName = createFileName(ev->fileNum); + std::string filePath = SaveManager_GetSavePath(fileName); + + if (((SaveData*)ev->saveBuffer)->magic == 0) { + std::error_code ec; + fs::remove(filePath, ec); + if (ec) { + SPDLOG_ERROR("SaveManager: failed to remove erased save file \"{}\": {}", filePath, ec.message()); + } + SaveGlobalData(); + event->Cancelled = true; + return; + } + ordered_json saveFile = Convert_SaveDataToJSON((SaveData*)ev->saveBuffer, ev->fileNum); if (!saveFile.empty()) { std::string collapsedString = CollapsedJSONArray(saveFile); - std::string fileName = createFileName(ev->fileNum); - std::string filePath = SaveManager_GetSavePath(fileName); - std::ofstream outputFile(filePath); if (outputFile.is_open()) { outputFile << collapsedString; @@ -801,6 +812,11 @@ void SaveManager_Init() { event->Cancelled = true; }); + REGISTER_LISTENER(OnGameFileErase, EVENT_PRIORITY_NORMAL, [](IEvent* event) { + OnGameFileErase* ev = (OnGameFileErase*)event; + gameFile_8033CFD4(ev->gamenum); + }); + REGISTER_LISTENER(OnGameLoad, EVENT_PRIORITY_NORMAL, [](IEvent* event) { OnGameLoad* ev = (OnGameLoad*)event; gSelectedFileNum = ev->fileNum; diff --git a/src/port/UI/LighthouseMenuEnhancements.cpp b/src/port/UI/LighthouseMenuEnhancements.cpp index bd5ba9667..fa47e3106 100644 --- a/src/port/UI/LighthouseMenuEnhancements.cpp +++ b/src/port/UI/LighthouseMenuEnhancements.cpp @@ -381,6 +381,16 @@ void LighthouseMenu::AddMenuEnhancements() { }) .DefaultIndex(1)); + AddWidget(path, "Permadeath", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("Gameplay.Permadeath")) + .RaceDisable(false) + .PreFunc([](WidgetInfo& info) { + if (mLighthouseMenu->disabledMap.at(DISABLE_FOR_ROMHACK).active) { + info.activeDisables.push_back(DISABLE_FOR_ROMHACK); + } + }) + .Options(CheckboxOptions().Tooltip("Your save file is deleted on death. Lives are ignored.")); + AddWidget(path, "Skip Spiral Mountain Tutorial", WIDGET_CVAR_CHECKBOX) .CVar(CVAR_ENHANCEMENT("Gameplay.SkipSMTutorial")) .RaceDisable(false) From e607895a879cbba5406d6b2edc6e1d7a77e13f1e Mon Sep 17 00:00:00 2001 From: Jeod <47716344+JeodC@users.noreply.github.com> Date: Sat, 25 Jul 2026 15:22:24 -0400 Subject: [PATCH 020/131] Romhack code integration (#258) * Switch soundfontctl extraction to own factory * Reorder GEO section * Bump Torch and LUS * Add ported romhack code for Jiggies of Time, Nostalgia 64, and Cutthroat Coast * Fix missing jiggy puzzle sizes and flags * CTC: Blank note door digits * Add Cheato's Challenges port * Sort disabled romhacks alphabetically * Add Bubbling Bog Brewery code port * Disable select enhancements in romhacks * Add partial support for Gruntch and Santa's Village * Post-rebase fixups --- Torch | 2 +- assets/yaml/jp/rev0/soundfont.yaml | 4 +- assets/yaml/pal/rev0/soundfont.yaml | 4 +- assets/yaml/us/rev0/soundfont.yaml | 4 +- assets/yaml/us/rev1/soundfont.yaml | 4 +- include/core2/timedfunc.h | 2 + libultraship | 2 +- src/FP/ch/boggy3.c | 4 +- src/FP/ch/xmastreeice.c | 5 + src/MM/ch/hut.c | 2 +- src/core1/pfsmanager.c | 1 + src/core2/actor_array.c | 3 + src/core2/ba/hazards.c | 5 +- src/core2/ba/marker.c | 5 +- src/core2/bs/player_spawn.c | 7 +- src/core2/gameSelect.c | 10 +- src/core2/gameloop.c | 4 + src/core2/gc/pauseMenu.c | 51 ++- src/core2/gc/sky.c | 6 +- src/core2/gc/transition.c | 6 +- src/core2/jiggyscore.c | 6 + src/core2/map/gsworld.c | 4 +- src/core2/map/warp_dispatch.c | 13 +- src/core2/model/modelRender.c | 3 + src/core2/mumbo.c | 12 +- src/core2/spawnqueue.c | 9 +- src/lair/ch/brentilda.c | 3 +- src/lair/jigsawpicture.c | 20 +- src/lair/lairspawnqueue.c | 5 +- .../Backports/TooieJiggyDance.cpp | 11 +- src/port/Enhancements/Events/Hooks/Events.h | 24 ++ .../Events/Hooks/List/EngineEvent.h | 1 + .../Enhancements/Events/PortEnhancements.cpp | 1 + src/port/Extractor/GameExtractor.cpp | 29 +- src/port/Network/Anchor/Packets/HutSmash.cpp | 6 +- src/port/Patches/GraphicsPatches.cpp | 14 +- src/port/Patches/Patches.h | 8 +- src/port/Resource/Importers/ModelFactory.cpp | 36 +- src/port/Romhack/RomhackConfig.cpp | 79 +++- src/port/Romhack/RomhackConfig.h | 13 +- src/port/Romhack/RomhackQuirks.cpp | 56 --- src/port/Romhack/RomhackRegistration.cpp | 60 +++ src/port/Romhack/RomhackTable.h | 64 ++- src/port/Romhack/Shared/HackShared.cpp | 126 ++++++ src/port/Romhack/Shared/HackShared.h | 9 + src/port/Romhack/Shared/ProximityDialogs.cpp | 81 ++++ src/port/Romhack/Shared/ProximityDialogs.h | 40 ++ src/port/Romhack/Shared/Storybook.cpp | 134 ++++++ src/port/Romhack/Shared/Storybook.h | 12 + src/port/Romhack/Specific/BubblingBog.cpp | 22 + src/port/Romhack/Specific/CutThroatCoast.cpp | 284 +++++++++++++ src/port/Romhack/Specific/JiggiesOfTime.cpp | 31 ++ src/port/Romhack/Specific/NewHorizons.cpp | 25 ++ src/port/Romhack/Specific/Nostalgia64.cpp | 90 ++++ src/port/Romhack/Specific/TheGruntch.cpp | 383 ++++++++++++++++++ src/port/UI/LighthouseMenuEnhancements.cpp | 40 ++ src/port/UI/LighthouseModMenuWindow.cpp | 35 +- 57 files changed, 1729 insertions(+), 191 deletions(-) delete mode 100644 src/port/Romhack/RomhackQuirks.cpp create mode 100644 src/port/Romhack/RomhackRegistration.cpp create mode 100644 src/port/Romhack/Shared/HackShared.cpp create mode 100644 src/port/Romhack/Shared/HackShared.h create mode 100644 src/port/Romhack/Shared/ProximityDialogs.cpp create mode 100644 src/port/Romhack/Shared/ProximityDialogs.h create mode 100644 src/port/Romhack/Shared/Storybook.cpp create mode 100644 src/port/Romhack/Shared/Storybook.h create mode 100644 src/port/Romhack/Specific/BubblingBog.cpp create mode 100644 src/port/Romhack/Specific/CutThroatCoast.cpp create mode 100644 src/port/Romhack/Specific/JiggiesOfTime.cpp create mode 100644 src/port/Romhack/Specific/NewHorizons.cpp create mode 100644 src/port/Romhack/Specific/Nostalgia64.cpp create mode 100644 src/port/Romhack/Specific/TheGruntch.cpp diff --git a/Torch b/Torch index 75956acb7..205bd3e8b 160000 --- a/Torch +++ b/Torch @@ -1 +1 @@ -Subproject commit 75956acb7c2210427d3ac4cc7213421f6e1c490c +Subproject commit 205bd3e8be07df1544d7938ae8f5827f5d90b77f diff --git a/assets/yaml/jp/rev0/soundfont.yaml b/assets/yaml/jp/rev0/soundfont.yaml index e0d1e89b1..ee925d2ef 100644 --- a/assets/yaml/jp/rev0/soundfont.yaml +++ b/assets/yaml/jp/rev0/soundfont.yaml @@ -4,7 +4,7 @@ - '#include "structs.h"' soundfont1ctl: - type: BLOB + type: BK64:SOUNDFONT_CTL offset: 0xDA80A0 size: 0x10DF0 symbol: soundfont1ctl @@ -17,7 +17,7 @@ soundfont1tbl: symbol: soundfont1tbl soundfont2ctl: - type: BLOB + type: BK64:SOUNDFONT_CTL offset: 0xEC7890 size: 0x9FB0 symbol: soundfont2ctl diff --git a/assets/yaml/pal/rev0/soundfont.yaml b/assets/yaml/pal/rev0/soundfont.yaml index a1176d24a..b549551f0 100644 --- a/assets/yaml/pal/rev0/soundfont.yaml +++ b/assets/yaml/pal/rev0/soundfont.yaml @@ -4,7 +4,7 @@ - '#include "structs.h"' soundfont1ctl: - type: BLOB + type: BK64:SOUNDFONT_CTL offset: 0xDA8DF0 size: 0x10DF0 symbol: soundfont1ctl @@ -17,7 +17,7 @@ soundfont1tbl: symbol: soundfont1tbl soundfont2ctl: - type: BLOB + type: BK64:SOUNDFONT_CTL offset: 0xEC85E0 size: 0x9FB0 symbol: soundfont2ctl diff --git a/assets/yaml/us/rev0/soundfont.yaml b/assets/yaml/us/rev0/soundfont.yaml index d6220ade8..7378d4f5d 100644 --- a/assets/yaml/us/rev0/soundfont.yaml +++ b/assets/yaml/us/rev0/soundfont.yaml @@ -4,7 +4,7 @@ - '#include "structs.h"' soundfont1ctl: - type: BLOB + type: BK64:SOUNDFONT_CTL offset: 0xD846C0 size: 0x10DF0 symbol: soundfont1ctl @@ -17,7 +17,7 @@ soundfont1tbl: symbol: soundfont1tbl soundfont2ctl: - type: BLOB + type: BK64:SOUNDFONT_CTL offset: 0xEA3EB0 size: 0x9FB0 symbol: soundfont2ctl diff --git a/assets/yaml/us/rev1/soundfont.yaml b/assets/yaml/us/rev1/soundfont.yaml index 138c28ffd..bb9ae6b69 100644 --- a/assets/yaml/us/rev1/soundfont.yaml +++ b/assets/yaml/us/rev1/soundfont.yaml @@ -4,7 +4,7 @@ - '#include "structs.h"' soundfont1ctl: - type: BLOB + type: BK64:SOUNDFONT_CTL offset: 0xD87CA0 size: 0x10DF0 symbol: soundfont1ctl @@ -17,7 +17,7 @@ soundfont1tbl: symbol: soundfont1tbl soundfont2ctl: - type: BLOB + type: BK64:SOUNDFONT_CTL offset: 0xEA7490 size: 0x9FB0 symbol: soundfont2ctl diff --git a/include/core2/timedfunc.h b/include/core2/timedfunc.h index 2892d462e..1c3007b4f 100644 --- a/include/core2/timedfunc.h +++ b/include/core2/timedfunc.h @@ -4,7 +4,9 @@ #include "generic.h" +#ifndef __cplusplus #define reinterpret_cast(type, var) (*((type *)&var)) +#endif void timedFunc_set_0(f32 time, GenFunction_0 funcPtr); diff --git a/libultraship b/libultraship index 2c63e7ede..8a67fa4b9 160000 --- a/libultraship +++ b/libultraship @@ -1 +1 @@ -Subproject commit 2c63e7edef577cd2a3726ce24dfedd7f088f12ae +Subproject commit 8a67fa4b9c6d8302cba4aeecd02411d16d28d818 diff --git a/src/FP/ch/boggy3.c b/src/FP/ch/boggy3.c index b36a7b1c3..6e0e66200 100644 --- a/src/FP/ch/boggy3.c +++ b/src/FP/ch/boggy3.c @@ -53,7 +53,9 @@ void func_80390388(Actor *this){ levelSpecificFlags_set(LEVEL_FLAG_12_FP_UNKNOWN, true); levelSpecificFlags_set(LEVEL_FLAG_13_FP_UNKNOWN, true); } - if(jiggyscore_isCollected(JIGGY_2C_FP_BOGGY_3) || jiggyscore_isSpawned(JIGGY_2C_FP_BOGGY_3)){ + if(EventSystem_Should(VB_BOGGY_HOME_VISIBLE, + jiggyscore_isCollected(JIGGY_2C_FP_BOGGY_3) || jiggyscore_isSpawned(JIGGY_2C_FP_BOGGY_3), + this)){ this->unk38_31 = false; this->marker->propPtr->unk8_3 = true; } diff --git a/src/FP/ch/xmastreeice.c b/src/FP/ch/xmastreeice.c index dc73e9674..aa3cc1e63 100644 --- a/src/FP/ch/xmastreeice.c +++ b/src/FP/ch/xmastreeice.c @@ -94,6 +94,11 @@ void chXmasTreeIce_initiateShatter(Actor *this){ void chXmasTreeIce_update(Actor *this) { ActorLocal_XmasTreeIce *local = (ActorLocal_XmasTreeIce *)&this->local; + + if (!EventSystem_Should(VB_XMAS_TREE_ICE_UPDATE, true, this)) { + return; + } + this->marker->propPtr->unk8_3 = true; actor_collisionOff(this); diff --git a/src/MM/ch/hut.c b/src/MM/ch/hut.c index 36c96b86e..f4925d563 100644 --- a/src/MM/ch/hut.c +++ b/src/MM/ch/hut.c @@ -131,7 +131,7 @@ void chhut_update(Actor *this) { __spawnQueue_add_1((GenFunction_1) __chhut_spawnExplosion, (uintptr_t)this->marker); bundle_setYaw(this->yaw); - smashIndex = port_hutSmash_countForCurrentMap(); + smashIndex = port_hutSmash_countForCurrentLevel(); if (smashIndex < 5) { __spawnQueue_add_4((GenFunction_4) spawnQueue_bundle_f32, mm_hut_bundles[smashIndex], *(s32 * )(&diff_pos[0]), *(s32 * )(&diff_pos[1]), *(s32 * )(&diff_pos[2])); } diff --git a/src/core1/pfsmanager.c b/src/core1/pfsmanager.c index 1d06ee4cc..b91107670 100644 --- a/src/core1/pfsmanager.c +++ b/src/core1/pfsmanager.c @@ -295,6 +295,7 @@ void pfsManager_update(void) { } } + CALL_EVENT(OnControllerUpdate); osSetThreadPri(0, 0x14); } diff --git a/src/core2/actor_array.c b/src/core2/actor_array.c index 4c58c688b..100a6ede3 100644 --- a/src/core2/actor_array.c +++ b/src/core2/actor_array.c @@ -3,6 +3,7 @@ #include "core1/core1.h" #include "functions.h" #include "variables.h" +#include "port/Patches/Patches.h" #include "actor.h" #include "prop.h" @@ -800,6 +801,8 @@ void func_803272D0(f32 arg0[3], f32 arg1, s32 arg2, int (*arg3)(Actor *)){ } Actor *actor_new(s32 position[3], s32 yaw, ActorInfo* actorInfo, u32 flags){ + // [port] Romhacks rewrite spawn args per actor id before the real work + romhack_RewriteActorSpawn(actorInfo, &flags); ActorAnimationInfo * sp54; s32 i; f32 sp44[3]; diff --git a/src/core2/ba/hazards.c b/src/core2/ba/hazards.c index 402aab5ac..8b70a882a 100644 --- a/src/core2/ba/hazards.c +++ b/src/core2/ba/hazards.c @@ -187,7 +187,10 @@ bool isPlayerInHazard(void){ case MAP_6E_GL_GV_LOBBY: case MAP_72_GL_BGS_LOBBY: case MAP_8E_GL_FURNACE_FUN://L8029D6FC - return func_80294610(0xE000) && player_isStable(); + // [port] Default is the vanilla hazard-collision-flag check; a romhack + // whose hazard-flagged collision was stripped on export can force it. + return EventSystem_Should(VB_GROUND_HAZARD_ACTIVE, func_80294610(0xE000) != 0, gsworld_getMap()) && + player_isStable(); case MAP_31_RBB_RUSTY_BUCKET_BAY: player_getPosition(sp2C); diff --git a/src/core2/ba/marker.c b/src/core2/ba/marker.c index eb5197d37..d6431fd47 100644 --- a/src/core2/ba/marker.c +++ b/src/core2/ba/marker.c @@ -582,7 +582,7 @@ void __baMarker_resolveCollision(Prop *other_prop){ if (jiggy_id == JIGGY_20_BGS_ELEVATED_WALKWAY || jiggy_id == JIGGY_25_BGS_MAZE) { func_802D6924(); } - if (jiggyscore_total() < 3) { + if (jiggyscore_total() < 3 && EventSystem_Should(VB_JIGGY_COLLECT_TUTORIAL, true)) { __baMarker_8028B848(); } @@ -601,7 +601,8 @@ void __baMarker_resolveCollision(Prop *other_prop){ if (__baMarker_8028BC20(marker)) return; sp98 = func_802CA1C4(marker_getActor(marker)); - if (sp98 != HONEYCOMB_12_MMM_FLOORBOARD || player_getTransformation() == TRANSFORM_3_PUMPKIN) + if (sp98 != HONEYCOMB_12_MMM_FLOORBOARD || player_getTransformation() == TRANSFORM_3_PUMPKIN + || !EventSystem_Should(VB_HONEYCOMB_PUMPKIN_REQUIREMENT, true)) { honeycombscore_set(sp98, 1); CALL_EVENT(OnCollectibleCollected, ANCHOR_COLLECTIBLE_HONEYCOMB, sp98); diff --git a/src/core2/bs/player_spawn.c b/src/core2/bs/player_spawn.c index c7f386739..50c667bcc 100644 --- a/src/core2/bs/player_spawn.c +++ b/src/core2/bs/player_spawn.c @@ -314,7 +314,12 @@ void func_8029B62C(void){ } } else{ - func_802E4048(gVoidOutReturnLocation[0], gVoidOutReturnLocation[1], 1); + // [port] Romhack gate: listeners can replace the void-out respawn with a + // full map transition. + if (EventSystem_Should(VB_VOID_OUT_RESPAWN_TRANSITION, true, gVoidOutReturnLocation[0], + gVoidOutReturnLocation[1])) { + func_802E4048(gVoidOutReturnLocation[0], gVoidOutReturnLocation[1], 1); + } } } diff --git a/src/core2/gameSelect.c b/src/core2/gameSelect.c index 3254c057f..019afc1e4 100644 --- a/src/core2/gameSelect.c +++ b/src/core2/gameSelect.c @@ -452,14 +452,14 @@ void gameSelect_update(Actor *this){ chBottlesBonus_resetCompleted(); gameFile_load(gSelectedGameNum); port_syncBottlesBonusIndex(); - if(!gameFile_isNotEmpty(sp84)){ + if(EventSystem_Should(VB_GAMESELECT_START_NEW_GAME, !gameFile_isNotEmpty(sp84), sp84)){ s32 skipIntro = 0; CALL_EVENT(OnNewGame, &skipIntro); if (skipIntro) { timedFunc_set_2(0.0f, (GenFunction_2)warp_lairEnterLairFromSMLevel, 0, 0); timedFunc_set_1(0.0f, (GenFunction_1)gsworld_setEnableUpdate, 1); } else { - // [port] BB romhacks can override the new-game boot map + // [port] Romhacks can override the new-game boot map s32 newGameMap = port_getRomhackNewGameMap(); if (newGameMap < 0) { newGameMap = MAP_85_CS_SPIRAL_MOUNTAIN_3; @@ -475,7 +475,11 @@ void gameSelect_update(Actor *this){ sp44 = 0.0f; if(this->state == 4 && (sp84 == CH_GAME_SELECT_SAVEFILE_0_BED || sp84 == CH_GAME_SELECT_SAVEFILE_1_GAMING_CHAIR)) sp44 = 0.25f; - if(chmole_learnedAllSpiralMountainAbilities() && fileProgressFlag_get(FILEPROG_BD_ENTER_LAIR_CUTSCENE)){ + // [port] Romhacks can replace the resume transition outright + if(port_getRomhackResumeWarpFunc() != NULL){ + timedFunc_set_2(sp44, (GenFunction_2)port_getRomhackResumeWarpFunc(), 0, 0); + } + else if(chmole_learnedAllSpiralMountainAbilities() && fileProgressFlag_get(FILEPROG_BD_ENTER_LAIR_CUTSCENE)){ timedFunc_set_2(sp44, (GenFunction_2)warp_lairEnterLairFromSMLevel, 0, 0); } else{//L802C5188 diff --git a/src/core2/gameloop.c b/src/core2/gameloop.c index fb92b7c44..05e7c61ac 100644 --- a/src/core2/gameloop.c +++ b/src/core2/gameloop.c @@ -371,6 +371,8 @@ void transitionToMap(enum map_e map, s32 exit, s32 transition){ } void func_802E40A8(s32 map, s32 exit){ + // [port] Romhack gate: listeners may rewrite the requested destination. + EventSystem_Should(VB_MAP_CHANGE_REQUEST, true, &map, &exit); D_8037E8E0.unk18 = 1; D_8037E8E0.map = map; D_8037E8E0.exit = exit; @@ -381,6 +383,8 @@ void func_802E40C4( s32 arg0){ } void func_802E40D0(s32 map, s32 exit){ + // [port] Romhack gate: listeners may rewrite the requested destination. + EventSystem_Should(VB_MAP_CHANGE_REQUEST, true, &map, &exit); D_8037E8E0.unk18 = 0; D_8037E8E0.map = map; D_8037E8E0.exit = exit; diff --git a/src/core2/gc/pauseMenu.c b/src/core2/gc/pauseMenu.c index 20c2063d4..53aec1773 100644 --- a/src/core2/gc/pauseMenu.c +++ b/src/core2/gc/pauseMenu.c @@ -428,6 +428,11 @@ void gcpausemenu_printTotals(void) { } s32 gcpausemenu_levelToMenuPage(enum level_e level) { + // [port] Romhack gate: listeners can pin every level to one menu page. + s32 override_page = 0; + if (!EventSystem_Should(VB_PAUSEMENU_LEVEL_TO_PAGE, true, level, &override_page)) { + return override_page; + } switch (level) { case LEVEL_1_MUMBOS_MOUNTAIN: case LEVEL_2_TREASURE_TROVE_COVE: @@ -531,7 +536,10 @@ void gcPauseMenu_setState(enum gcpausemenu_state_e next_state) { gcpausemenu_zoomboxes_initTotalsMenu(); if (D_80383010.selection == gcpausemenu_levelToMenuPage(level_get())) { - print_setBoldFontTexture(0x6e7); + // [port] Romhack gate: listeners can swap the highlight bold-font texture. + s32 boldFontId = 0x6e7; + EventSystem_Should(VB_PAUSEMENU_BOLD_FONT_TEXTURE, true, &boldFontId); + print_setBoldFontTexture(boldFontId); } if (D_80383010.selection) { @@ -547,13 +555,17 @@ void gcPauseMenu_setState(enum gcpausemenu_state_e next_state) { if (hideCollLvl < 0) { hideCollLvl = LEVEL_6_LAIR; } if (hideJigLvl < 0) { hideJigLvl = LEVEL_B_SPIRAL_MOUNTAIN; } for (i = 0; i < 4; i++) { + s32 rowVisible; if (selLvl == hideCollLvl) { - gczoombox_highlight(D_80383010.zoombox[i], (!(i == 0) && !(i == 2))); + rowVisible = (!(i == 0) && !(i == 2)); } else if (selLvl == hideJigLvl) { - gczoombox_highlight(D_80383010.zoombox[i], (!(i == 0) && !(i == 1))); + rowVisible = (!(i == 0) && !(i == 1)); } else { - gczoombox_highlight(D_80383010.zoombox[i], 1); + rowVisible = 1; } + // [port] Romhack gate: level-merging hacks can hide extra rows per page. + rowVisible = EventSystem_Should(VB_PAUSEMENU_ROW_VISIBLE, rowVisible, selLvl, i); + gczoombox_highlight(D_80383010.zoombox[i], rowVisible); } break; @@ -610,7 +622,10 @@ void gcPauseMenu_setState(enum gcpausemenu_state_e next_state) { D_80383010.selection = D_80383010.page; if (D_80383010.selection && D_80383010.selection == gcpausemenu_levelToMenuPage(level_get())) { - print_setBoldFontTexture(0x6e7); + // [port] Romhack gate: listeners can swap the highlight bold-font texture. + s32 boldFontId = 0x6e7; + EventSystem_Should(VB_PAUSEMENU_BOLD_FONT_TEXTURE, true, &boldFontId); + print_setBoldFontTexture(boldFontId); } if (D_80383010.selection) { @@ -626,13 +641,17 @@ void gcPauseMenu_setState(enum gcpausemenu_state_e next_state) { if (hideCollLvl < 0) { hideCollLvl = LEVEL_6_LAIR; } if (hideJigLvl < 0) { hideJigLvl = LEVEL_B_SPIRAL_MOUNTAIN; } for (i = 0; i < 4; i++) { + s32 rowVisible; if (selLvl == hideCollLvl) { - gczoombox_highlight(D_80383010.zoombox[i], !((i == 0) || (i == 2))); + rowVisible = !((i == 0) || (i == 2)); } else if (selLvl == hideJigLvl) { - gczoombox_highlight(D_80383010.zoombox[i], (!(i == 0) && !(i == 1))); + rowVisible = (!(i == 0) && !(i == 1)); } else { - gczoombox_highlight(D_80383010.zoombox[i], 1); + rowVisible = 1; } + // [port] Romhack gate: level-merging hacks can hide extra rows per page. + rowVisible = EventSystem_Should(VB_PAUSEMENU_ROW_VISIBLE, rowVisible, selLvl, i); + gczoombox_highlight(D_80383010.zoombox[i], rowVisible); if (gczoombox_is_highlighted(D_80383010.zoombox[i])) { gczoombox_maximize(D_80383010.zoombox[i]); @@ -868,7 +887,11 @@ void gcpausemenu_printTotalsHeader(s32 page_id) { if (port_pauseBannerUpdate(page_id)) { return; } - print_bold_overlapping(v0->x, D_80383010.unk8, -1.05f, name ? (u8*)name : v0->string); + // [port] A custom romhack name inherits the vanilla name's hand-tuned x; let a + // listener recenter it for its own width. + s32 nameX = v0->x; + EventSystem_Should(VB_PAUSEMENU_LEVEL_NAME_X, true, &nameX, page_id, (const char*)v0->string, name); + print_bold_overlapping(nameX, D_80383010.unk8, -1.05f, name ? (u8*)name : v0->string); } void gcpausemenu_80312FD0(s32 arg0) { @@ -898,6 +921,10 @@ s32 gcpausemenu_getMaxPage(void) { } void gcpausemenu_setNextPage(s32 increment) { + // [port] Romhack gate: listeners can pin the page and skip paging entirely. + if (!EventSystem_Should(VB_PAUSEMENU_SET_NEXT_PAGE, true, &D_80383010.page)) { + return; + } D_80383010.page = D_80383010.selection; do { D_80383010.page += increment; @@ -1469,8 +1496,10 @@ void gcpausemenu_draw(Gfx **gfx, Mtx **mtx, Vtx **vtx) { } } - gcpausemenu_drawSprite(gfx, mtx, vtx, D_80383010.joystick_sprite, D_80383010.joystick_frame, 30.0f, 196.0f, 1, (s32) D_80383010.left_joystick_alpha); - gcpausemenu_drawSprite(gfx, mtx, vtx, D_80383010.joystick_sprite, D_80383010.joystick_frame, (f32)(gFramebufferWidth - 0x1E), 196.0f, 0, (s32) D_80383010.right_joystick_alpha); + if (EventSystem_Should(VB_PAUSEMENU_DRAW_JOYSTICKS, true, NULL)) { + gcpausemenu_drawSprite(gfx, mtx, vtx, D_80383010.joystick_sprite, D_80383010.joystick_frame, 30.0f, 196.0f, 1, (s32) D_80383010.left_joystick_alpha); + gcpausemenu_drawSprite(gfx, mtx, vtx, D_80383010.joystick_sprite, D_80383010.joystick_frame, (f32)(gFramebufferWidth - 0x1E), 196.0f, 0, (s32) D_80383010.right_joystick_alpha); + } // [port] Original decomp used raw u32 bit extraction: ((*((u32*)&D_80383010.state) << N) >> 0x1f) // This depends on big-endian byte order (byte 3 of the u32 is the bitfield byte on MIPS). // On little-endian, byte 0 of the u32 is 'state', so the shifts extract wrong bits. diff --git a/src/core2/gc/sky.c b/src/core2/gc/sky.c index 8c728bfd3..fe157f99e 100644 --- a/src/core2/gc/sky.c +++ b/src/core2/gc/sky.c @@ -65,7 +65,7 @@ static MapSkyInfo sSkyOverride; MapSkyInfo * sky_getMapSkyInfo(enum map_e map_id){ int models[3]; float scales[3], rotations[3]; - if (port_getRomhackSkyboxFull(map_getLevel(map_id), models, scales, rotations)) { + if (port_getRomhackSkyboxFull(map_id, models, scales, rotations)) { sSkyOverride.map = map_id; for (int i = 0; i < 3; i++) { sSkyOverride.sky_list[i].model_id = (s16)models[i]; @@ -94,7 +94,9 @@ void sky_draw(Gfx **gfx, Mtx **mtx, Vtx **vtx) { viewport_setNearAndFar(5.0f, 15000.0f); if (gcSky.model_bins[0]) { - drawRectangle2D(gfx, 0, 0, (f32) gFramebufferWidth, (f32) gFramebufferHeight, 0, 0, 0); + if (EventSystem_Should(VB_SKY_DRAW_BACKDROP_RECT, true)) { + drawRectangle2D(gfx, 0, 0, (f32) gFramebufferWidth, (f32) gFramebufferHeight, 0, 0, 0); + } viewport_setRenderViewportAndPerspectiveMatrix(gfx, mtx); viewport_getPosition_vec3f(position); for (i = 0; i < 3; i++) { diff --git a/src/core2/gc/transition.c b/src/core2/gc/transition.c index 05d7588ea..08f0ca3ba 100644 --- a/src/core2/gc/transition.c +++ b/src/core2/gc/transition.c @@ -383,8 +383,12 @@ void gctransition_draw(Gfx **gfx, Mtx **mtx, Vtx **vtx) { void gctransition_8030BD4C(void){ MapTransitionInfo *tmp_10s; TransitionInfo *tmp_a1; + s32 in_index; tmp_10s = _gctranstion_get_map_transition_info(gsworld_getMap()); - tmp_a1 = _gctranstion_8030B400(tmp_10s->in_index); + in_index = tmp_10s->in_index; + // [port] Romhack gate: listeners may override the incoming transition style. + EventSystem_Should(VB_MAP_TRANSITION_IN_INDEX, true, gsworld_getMap(), &in_index); + tmp_a1 = _gctranstion_8030B400(in_index); _gctranstion_changeState(tmp_a1->state, tmp_a1); } diff --git a/src/core2/jiggyscore.c b/src/core2/jiggyscore.c index a24f92fb8..6d7d9c46f 100644 --- a/src/core2/jiggyscore.c +++ b/src/core2/jiggyscore.c @@ -84,6 +84,12 @@ s32 jiggyscore_leveltotal(s32 lvl) { s32 start; s32 end; s32 cnt; + s32 override_total = 0; + + // [port] Romhack gate: listeners can supply the whole per-level tally. + if (!EventSystem_Should(VB_JIGGYSCORE_LEVEL_TOTAL, true, lvl, &override_total)) { + return override_total; + } if (lvl <= 0 || lvl == 0xB || lvl >= 0xB) return 0; diff --git a/src/core2/map/gsworld.c b/src/core2/map/gsworld.c index ab377fdad..8426ecdcf 100644 --- a/src/core2/map/gsworld.c +++ b/src/core2/map/gsworld.c @@ -385,7 +385,9 @@ s32 gsworld_update(void) { func_8031B790(); func_8034C9D4(); propModelList_flush(1); - sky_update(); + if (EventSystem_Should(VB_SKY_UPDATE, true)) { + sky_update(); + } partEmitMgr_update(); func_8034F918(); func_80350250(); diff --git a/src/core2/map/warp_dispatch.c b/src/core2/map/warp_dispatch.c index e2fbc601e..839b4a8b1 100644 --- a/src/core2/map/warp_dispatch.c +++ b/src/core2/map/warp_dispatch.c @@ -559,14 +559,17 @@ void func_80334448(NodeProp *arg0, ActorMarker *arg1) { case 3: // warp (L80334480) global_timer_time = globalTimer_getTime(); if ((codeA5BC0_getNodePropUnkC(arg0) + 1) != global_timer_time) { - // [port] BB romhacks remap warp destinations via BKCF config + // [port] Romhacks remap warp destinations via BKCF config warpIdx = codeA5BC0_getNodePropActorId(arg0); warpDest = port_getRomhackWarpDest(warpIdx); CALL_EVENT(OnWarpDispatch, warpIdx, warpDest); - if (warpDest >= 0) { - func_8031CC8C(arg0, warpDest); - } else { - sWarpFunctions[warpIdx](arg0, arg1); + // [port] Romhacks can hold a warp shut behind progress + if (EventSystem_Should(VB_WARP_DISPATCH, true, warpIdx)) { + if (warpDest >= 0) { + func_8031CC8C(arg0, warpDest); + } else { + sWarpFunctions[warpIdx](arg0, arg1); + } } } codeA5BC0_setNodePropUnkC(arg0, global_timer_time); diff --git a/src/core2/model/modelRender.c b/src/core2/model/modelRender.c index fde1ef513..dfd193f1f 100644 --- a/src/core2/model/modelRender.c +++ b/src/core2/model/modelRender.c @@ -1328,6 +1328,9 @@ BKModelBin *modelRender_draw(Gfx **gfx, Mtx **mtx, f32 position[3], f32 rotation // [port] Mirror mode: restore culling inversion if (_mirror_excluded) gSPSetExtraGeometryMode((*gfx)++, G_EX_INVERT_CULLING); gSPPopMatrix((*gfx)++, G_MTX_MODELVIEW); + // [port] Romhack model DLs can leave a palette (TLUT) mode enabled and leak it + // into the next model's draw; reset it after every model for romhacks. + port_modelRenderResetTLUT(gfx); if(modelRenderCallback.post_draw != NULL){ modelRenderCallback.post_draw(modelRenderCallback.post_draw_arg); diff --git a/src/core2/mumbo.c b/src/core2/mumbo.c index 2eb4c9d11..ceb5bf2c6 100644 --- a/src/core2/mumbo.c +++ b/src/core2/mumbo.c @@ -335,7 +335,7 @@ void chMumbo_update(Actor *this) { func_8028F94C(2, this->position); if ( sp44 && gsworld_getMap() != MAP_7A_GL_CRYPT && !fileProgressFlag_get(FILEPROG_BA_HAS_SEEN_TREX_TEXT) - && randf() < 0.01 + && romhack_mumboRandomEventsAllowed() && randf() < 0.01 && sp48 ) { gcdialog_showDialog(VER_SELECT(ASSET_DAE_DIALOG_MUMBO_TREX_START, 0xA2C, 0, 0), 6, NULL, this->marker, __chMumbo_textCallback, NULL); @@ -347,7 +347,7 @@ void chMumbo_update(Actor *this) { && gsworld_getMap() != MAP_7A_GL_CRYPT && !this->unk138_23 && (sp40 = fileProgressFlag_getN(FILEPROG_BB_MUMBO_MISTAKE_INDEX, 2), sp40 < 3) - && randf() < 0.05 + && romhack_mumboRandomEventsAllowed() && randf() < 0.05 && sp48 ){ this->unk138_23 = true; @@ -395,11 +395,11 @@ void chMumbo_update(Actor *this) { if ( this->has_met_before || (this->unk10_12 == 0 && (player_getTransformation() != TRANSFORM_1_BANJO) - && (player_getTransformation() != TRANSFORM_7_WISHWASHY)) + && (player_getTransformation() != romhack_mumboWishwashyId())) ) { - player_transform(TRANSFORM_1_BANJO); - } else if (player_transform(D_8037DDF0)) { - if (D_8037DDF0 != TRANSFORM_7_WISHWASHY) { + romhack_mumboTransform(TRANSFORM_1_BANJO); + } else if (romhack_mumboTransform(D_8037DDF0)) { + if (D_8037DDF0 != romhack_mumboWishwashyId()) { if (fileProgressFlag_getAndSet(__bkProgId_from_transformationId(D_8037DDF0), true)) { this->velocity[0] = 1.0f; } diff --git a/src/core2/spawnqueue.c b/src/core2/spawnqueue.c index 2ae41bf15..75607c657 100644 --- a/src/core2/spawnqueue.c +++ b/src/core2/spawnqueue.c @@ -422,7 +422,7 @@ void spawnQueue_reset(void){ break; } - // BB romhacks globalize all overlays so any actor can spawn on any map. + // Romhacks globalize all overlays so any actor can spawn on any map. // Register actors from every overlay that wasn't already handled above. if (port_isRomhack()) { if (loaded_asm_file != OVERLAY_D_WITCH) { lair_func_8038A0C4(); } @@ -436,7 +436,12 @@ void spawnQueue_reset(void){ if (loaded_asm_file != OVERLAY_6_JUNGLE) { MM_func_803888B0(); } if (loaded_asm_file != OVERLAY_7_SWAMP) { bgs_updateSpawnableActors(); } if (loaded_asm_file != OVERLAY_8_SHIP) { RBB_func_80386C48(); } - if (loaded_asm_file != OVERLAY_9_SNOW) { FP_func_80391324(); } + if (loaded_asm_file != OVERLAY_9_SNOW) { + FP_func_80391324(); + spawnableActorList_add(&chBluePresentCollectible, actor_new, ACTOR_FLAG_UNKNOWN_3); + spawnableActorList_add(&chGreenPresentCollectible, actor_new, ACTOR_FLAG_UNKNOWN_3); + spawnableActorList_add(&chRedPresentCollectible, actor_new, ACTOR_FLAG_UNKNOWN_3); + } if (loaded_asm_file != OVERLAY_A_TREE) { CCW_func_8038DB6C(); } } diff --git a/src/lair/ch/brentilda.c b/src/lair/ch/brentilda.c index 7506b988f..e33438ea7 100644 --- a/src/lair/ch/brentilda.c +++ b/src/lair/ch/brentilda.c @@ -40,7 +40,8 @@ void func_8038BADC(ActorMarker *marker, enum asset_e text_id, s32 arg2) { Actor *this; this = marker_getActor(marker); - if (text_id == ((ActorLocal_lair_5640 *)&this->local)->unk0 + 2) { + if (text_id == ((ActorLocal_lair_5640 *)&this->local)->unk0 + 2 + && EventSystem_Should(VB_BRENTILDA_HEAL_DIALOG, true)) { if (!fileProgressFlag_get(this->actorTypeSpecificField - 1 + FILEPROG_E9_HEALED_BY_BRENTILDA_1)) { if (item_getCount(ITEM_14_HEALTH) < item_getCount(ITEM_15_HEALTH_TOTAL)) { gcdialog_showDialog(ASSET_10A2_DIALOG_BRENTILDA_HEAL, 0xF, this->position, this->marker, func_8038BADC, healDuoToFull); diff --git a/src/lair/jigsawpicture.c b/src/lair/jigsawpicture.c index 416ada145..a58b77c37 100644 --- a/src/lair/jigsawpicture.c +++ b/src/lair/jigsawpicture.c @@ -59,9 +59,19 @@ s32 _puzzleCost(s32 index) { return (override >= 0) ? override : D_803947F8[index].cost; } +s32 _puzzleSize(s32 index) { + s32 override = port_getRomhackJiggyPuzzleSize(index); + return (override >= 0) ? override : D_803947F8[index].size_bits; +} + +s32 _puzzleFlag(s32 index) { + s32 override = port_getRomhackJiggyPuzzleFlag(index); + return (override >= 0) ? override : D_803947F8[index].progress_flag; +} + bool jigsawPicture_isJigsawPictureComplete(s32 arg0) { s32 cost = _puzzleCost(arg0 - 1); - return fileProgressFlag_getN(D_803947F8[arg0 -1].progress_flag, D_803947F8[arg0 -1].size_bits) == cost; + return fileProgressFlag_getN(_puzzleFlag(arg0 - 1), _puzzleSize(arg0 - 1)) == cost; } s32 getPictureCost(Actor *this){ @@ -337,7 +347,7 @@ void jigsawPicture_setState(Actor *this, s32 next_state){ addOrRemovePieceFromDisplay(this, temp_s1, 0); local->unk4--; local->unk0 &= ~(1 << temp_s1); - fileProgressFlag_setN(D_803947F8[this->actorTypeSpecificField - 1].progress_flag, local->unk4, D_803947F8[this->actorTypeSpecificField - 1].size_bits); + fileProgressFlag_setN(_puzzleFlag(this->actorTypeSpecificField - 1), local->unk4, _puzzleSize(this->actorTypeSpecificField - 1)); item_adjustByDiffWithoutHud(ITEM_26_JIGGY_TOTAL, 1); } break; @@ -350,7 +360,7 @@ void jigsawPicture_setState(Actor *this, s32 next_state){ temp_s1 = getPicturePiecePosition(this); addOrRemovePieceFromDisplay(this, temp_s1, 1); local->unk0 |= (1 << temp_s1); - fileProgressFlag_setN(D_803947F8[this->actorTypeSpecificField - 1].progress_flag, local->unk4, D_803947F8[this->actorTypeSpecificField - 1].size_bits); + fileProgressFlag_setN(_puzzleFlag(this->actorTypeSpecificField - 1), local->unk4, _puzzleSize(this->actorTypeSpecificField - 1)); item_adjustByDiffWithoutHud(ITEM_26_JIGGY_TOTAL, -1); unlockAdditionalActions(this); } @@ -373,7 +383,7 @@ void jigsawPicture_setState(Actor *this, s32 next_state){ local->unk0 |= (1 << temp_s1); item_adjustByDiffWithoutHud(ITEM_26_JIGGY_TOTAL, -1); } - fileProgressFlag_setN(D_803947F8[this->actorTypeSpecificField - 1].progress_flag, local->unk4, D_803947F8[this->actorTypeSpecificField - 1].size_bits); + fileProgressFlag_setN(_puzzleFlag(this->actorTypeSpecificField - 1), local->unk4, _puzzleSize(this->actorTypeSpecificField - 1)); unlockAdditionalActions(this); } break; @@ -437,7 +447,7 @@ void updateJigsawPictureActor(Actor *this) { if (!this->volatile_initialized) { // temp_v0 = &D_803947F8[this->actorTypeSpecificField - 1]; - sp64 = fileProgressFlag_getN(D_803947F8[this->actorTypeSpecificField - 1].progress_flag, D_803947F8[this->actorTypeSpecificField - 1].size_bits); + sp64 = fileProgressFlag_getN(_puzzleFlag(this->actorTypeSpecificField - 1), _puzzleSize(this->actorTypeSpecificField - 1)); local->unk0 = 0; local->unk4 = 0; local->unk8 = (isBanjoOnPodium(this->marker)) ? 0xff : 1; diff --git a/src/lair/lairspawnqueue.c b/src/lair/lairspawnqueue.c index e749655eb..5a6b77511 100644 --- a/src/lair/lairspawnqueue.c +++ b/src/lair/lairspawnqueue.c @@ -1142,8 +1142,11 @@ Actor *func_80387DA8(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx) * Hides all note door graphics that don't match this note door's index * e.g. for the 50 note door, hides 180, 260, etc. */ + // [port] Romhack gate: a listener may blank this door's baked number (the digits + // are a fixed mesh, so an overridden threshold would show the wrong one). + bool showNumber = EventSystem_Should(VB_NOTEDOOR_DRAW_NUMBER, true, actor->noteDoorIdx); for (i = 0; i != NUM_NOTE_DOORS; i++) - modelRender_setAppendageVisibility(i + 1, actor->noteDoorIdx + 1 == i + 2); + modelRender_setAppendageVisibility(i + 1, showNumber && (actor->noteDoorIdx + 1 == i + 2)); /** * Draw the note door diff --git a/src/port/Enhancements/Backports/TooieJiggyDance.cpp b/src/port/Enhancements/Backports/TooieJiggyDance.cpp index 64a9b1ecb..6a1539c6d 100644 --- a/src/port/Enhancements/Backports/TooieJiggyDance.cpp +++ b/src/port/Enhancements/Backports/TooieJiggyDance.cpp @@ -263,10 +263,14 @@ void updateOrbit() { } // namespace +// Romhacks that bundle wedarobi's jiggy dance should have it on by default. +// The hack may depend on the retained player motion that the animation provides. +static bool sJiggyDanceForced = false; + void RegisterJiggyCollect_Init() { clearOrbit(); const bool skip = CVarGetInteger(CVAR_SKIP_JIGGY_DANCE, 0); - const bool tooie = CVarGetInteger(CVAR_TOOIE_JIGGY_DANCE, 0); + const bool tooie = CVarGetInteger(CVAR_TOOIE_JIGGY_DANCE, 0) || sJiggyDanceForced; const bool playOrbit = tooie && !skip; COND_VB_SHOULD(VB_PLAY_JIGGY_DANCE, EVENT_PRIORITY_NORMAL, skip || tooie, { *should = false; }); @@ -276,5 +280,10 @@ void RegisterJiggyCollect_Init() { COND_HOOK(OnMapLoad, EVENT_PRIORITY_NORMAL, playOrbit, [](IEvent*) { forgetOrbit(); }); } +void TooieJiggyDance_ForceEnable() { + sJiggyDanceForced = true; + RegisterJiggyCollect_Init(); +} + static RegisterShipInitFunc initJiggyCollect(RegisterJiggyCollect_Init, { CVAR_TOOIE_JIGGY_DANCE, CVAR_SKIP_JIGGY_DANCE }); diff --git a/src/port/Enhancements/Events/Hooks/Events.h b/src/port/Enhancements/Events/Hooks/Events.h index cead7e13f..938f46a36 100644 --- a/src/port/Enhancements/Events/Hooks/Events.h +++ b/src/port/Enhancements/Events/Hooks/Events.h @@ -62,6 +62,30 @@ typedef enum VBehaviorID { VB_CC_RINGS_SNAP_WATER, // Lair door remote-open "already handled" test (Anchor). Args: (s32 doorActorId, s32 doorState). VB_LEVELDOOR_REMOTE_OPEN_DONE, + // Romhack port gates. Cancel to override the vanilla behavior; + // args carry the site-specific data. + VB_JIGGYSCORE_LEVEL_TOTAL, + VB_PAUSEMENU_LEVEL_TO_PAGE, + VB_PAUSEMENU_SET_NEXT_PAGE, + VB_MAP_CHANGE_REQUEST, + VB_VOID_OUT_RESPAWN_TRANSITION, + VB_MAP_TRANSITION_IN_INDEX, + VB_CCW_SEASON_SWITCH_PRESSED_INIT, + VB_PAUSEMENU_DRAW_JOYSTICKS, + VB_PAUSEMENU_BOLD_FONT_TEXTURE, + VB_PAUSEMENU_LEVEL_NAME_X, + VB_PAUSEMENU_ROW_VISIBLE, + VB_NOTEDOOR_DRAW_NUMBER, + VB_JIGGY_COLLECT_TUTORIAL, + VB_HONEYCOMB_PUMPKIN_REQUIREMENT, + VB_SKY_UPDATE, + VB_SKY_DRAW_BACKDROP_RECT, + VB_BRENTILDA_HEAL_DIALOG, + VB_GROUND_HAZARD_ACTIVE, + VB_GAMESELECT_START_NEW_GAME, + VB_WARP_DISPATCH, + VB_XMAS_TREE_ICE_UPDATE, + VB_BOGGY_HOME_VISIBLE, } VBehaviorID; typedef enum DoorCameraId { diff --git a/src/port/Enhancements/Events/Hooks/List/EngineEvent.h b/src/port/Enhancements/Events/Hooks/List/EngineEvent.h index b01226a3b..885f199f5 100644 --- a/src/port/Enhancements/Events/Hooks/List/EngineEvent.h +++ b/src/port/Enhancements/Events/Hooks/List/EngineEvent.h @@ -14,6 +14,7 @@ extern "C" { DEFINE_EVENT(GameFrameUpdate); DEFINE_EVENT(FrameDrawEnd); +DEFINE_EVENT(OnControllerUpdate); DEFINE_EVENT(OnMapLoad, GameMap prevMap; GameMap nextMap; s32 exit;); diff --git a/src/port/Enhancements/Events/PortEnhancements.cpp b/src/port/Enhancements/Events/PortEnhancements.cpp index fd9739a89..523a255cc 100644 --- a/src/port/Enhancements/Events/PortEnhancements.cpp +++ b/src/port/Enhancements/Events/PortEnhancements.cpp @@ -19,6 +19,7 @@ void PortEnhancements_Register() { // Register engine events REGISTER_EVENT(GameFrameUpdate); REGISTER_EVENT(FrameDrawEnd); + REGISTER_EVENT(OnControllerUpdate); REGISTER_EVENT(VanillaBehavior); REGISTER_EVENT(OnMapLoad); REGISTER_EVENT(OnDialogLoaded); diff --git a/src/port/Extractor/GameExtractor.cpp b/src/port/Extractor/GameExtractor.cpp index cb82abfb3..75d09b80e 100644 --- a/src/port/Extractor/GameExtractor.cpp +++ b/src/port/Extractor/GameExtractor.cpp @@ -27,6 +27,7 @@ #ifndef __SWITCH__ #include "Companion.h" #include "factories/bk64/ConfigFactory.h" +#include "port/Romhack/RomhackTable.h" #if !defined(__IOS__) && !defined(__ANDROID__) && !defined(__SWITCH__) #include "portable-file-dialogs.h" @@ -339,9 +340,31 @@ bool GameExtractor::GenerateOTR(std::atomic& assetCount, std::atomicmGameData)) { - SPDLOG_WARN("[GameExtractor] Custom MIPS code detected in ROM; prompting user before extraction."); + // Detect custom code: an injected MIPS blob or a rebuilt code overlay. + BK64::CustomCodeKind ccKind = BK64::CustomCodeKind::NONE; + char ccSha1[41] = {}; + const bool hasBlob = BK64::GetCustomCodeBlobInfo(this->mGameData, ccKind, ccSha1); + const bool rebuiltOverlay = BK64::ClassifyRomhack(this->mGameData) == BK64::RomhackKind::CustomBuild; + bool promptCustomCode = rebuiltOverlay; + if (!promptCustomCode && hasBlob) { + if (const auto* entry = Lighthouse::LookupRomhackEntry(ccSha1)) { + // Known blob: the table's verdict beats the location heuristic — an + // isPorted=false row means analysis found real un-ported code even + // inside a globalization-kind blob (e.g. Nostalgia 64). + promptCustomCode = !entry->isPorted; + if (!promptCustomCode) { + SPDLOG_INFO("[GameExtractor] Custom code blob {} is ported ({}); no warning needed.", ccSha1, + entry->identifier); + } + } else { + // Unknown blob: only injected blobs warrant the prompt; the stock + // globalization framework is covered by the statically linked build. + promptCustomCode = (ccKind == BK64::CustomCodeKind::BB_INJECTED); + } + } + if (promptCustomCode) { + SPDLOG_WARN("[GameExtractor] Romhack ships custom code ({}); prompting user before extraction.", + rebuiltOverlay ? "rebuilt code overlay, non-BB build" : "injected MIPS code blob"); sCustomCodePromptResult = -1; sCustomCodePromptActive = true; sCustomCodePromptRequested = true; diff --git a/src/port/Network/Anchor/Packets/HutSmash.cpp b/src/port/Network/Anchor/Packets/HutSmash.cpp index 25b475646..4ba1718b7 100644 --- a/src/port/Network/Anchor/Packets/HutSmash.cpp +++ b/src/port/Network/Anchor/Packets/HutSmash.cpp @@ -23,11 +23,11 @@ extern "C" int32_t port_hutSmash_get(int32_t x, int32_t y, int32_t z) { return it != sHuts.end() ? it->second : -1; } -extern "C" int32_t port_hutSmash_countForCurrentMap(void) { - int32_t map = (int32_t)gsworld_getMap(); +extern "C" int32_t port_hutSmash_countForCurrentLevel(void) { + int32_t level = (int32_t)map_getLevel(gsworld_getMap()); int32_t count = 0; for (const auto& [key, loot] : sHuts) { - if (key[0] == map) { + if ((int32_t)map_getLevel((enum map_e)key[0]) == level) { count++; } } diff --git a/src/port/Patches/GraphicsPatches.cpp b/src/port/Patches/GraphicsPatches.cpp index 7fbc86365..37b4aff39 100644 --- a/src/port/Patches/GraphicsPatches.cpp +++ b/src/port/Patches/GraphicsPatches.cpp @@ -17,13 +17,25 @@ static int sDrawDistanceCubeWidth(int mul) { static int sDrawDistanceLevel = 0; static int sDisableLOD = 0; -#include "functions.h" extern "C" { +#include #include "enums.h" +#include "functions.h" +#include "libultraship/libultra/gbi.h" +#include "port/Romhack/RomhackConfig.h" extern s32 gFramebufferWidth; extern s32 gFramebufferHeight; +// Romhack model display lists can leave a palette (TLUT) mode enabled and leak it +// into the next model's draw. +void port_modelRenderResetTLUT(Gfx** gfx) { + if (!port_isRomhack()) { + return; + } + gDPSetTextureLUT((*gfx)++, G_TT_NONE); +} + // Widescreen HUD edge anchoring (centered-ortho HUD geometry). float port_hudOrthoShift(float refX) { float halfW = (f32)gFramebufferWidth * 0.5f; diff --git a/src/port/Patches/Patches.h b/src/port/Patches/Patches.h index 5dafa405a..1e52205db 100644 --- a/src/port/Patches/Patches.h +++ b/src/port/Patches/Patches.h @@ -76,6 +76,7 @@ float port_drawDistanceMul(void); void port_applyModelDrawDistanceCull(int* fadeFlag, float* cullMult, float* cullDist); int port_spriteSizeCulled(float depth, float size, float baseThreshold, int disableFlag); float port_hudOrthoShift(float refX); +void port_modelRenderResetTLUT(Gfx** gfx); // Mirror (MirrorPatches.cpp) @@ -104,6 +105,11 @@ void port_unlockAudio(void); void port_audioIntMaskEnter(void); void port_audioIntMaskExit(void); +// Romhacks + +void* port_getRomhackResumeWarpFunc(void); +void romhack_RewriteActorSpawn(void* actorInfo, u32* flags); + // Attract-demo audio hold void port_beginDemoAudioHold(void); @@ -172,7 +178,7 @@ int32_t port_puzzleCount_get(int32_t counterId); void port_hutSmash_record(int32_t x, int32_t y, int32_t z, int32_t loot); int32_t port_hutSmash_get(int32_t x, int32_t y, int32_t z); -int32_t port_hutSmash_countForCurrentMap(void); +int32_t port_hutSmash_countForCurrentLevel(void); void port_jiggyCrane_broadcast(int32_t stage); void port_jiggyCrane_remoteApply(int32_t stage); diff --git a/src/port/Resource/Importers/ModelFactory.cpp b/src/port/Resource/Importers/ModelFactory.cpp index ce586d8a1..9dfbbe0e6 100644 --- a/src/port/Resource/Importers/ModelFactory.cpp +++ b/src/port/Resource/Importers/ModelFactory.cpp @@ -384,29 +384,22 @@ ResourceFactoryBinaryModelV0::ReadResource(std::shared_ptr file, // // Layout (each section padded to 8-byte alignment): // [ 0 ] BKModelBin header (zero-init, geo_type set) - // [ GL ] GeoLayout command tree → geo_list_offset - // [ T ] BKTextureList + BKTextureInfo[] + pixel data → texture_list_offset - // [ A ] BKAnimationList + BKAnimation[] → animation_list_offset - // [ B ] BKCollisionList + ColGeo[] + ColTri[] → collision_list_offset - // [ 14 ] BKModelUnk14List + entries → unk14 - // [ 20 ] BKCameraAreaList + entries → unk20 - // [ E ] effect count (s16) + effects → mesh_list_offset - // [ 28 ] BKAnimVerticesList + entries → unk28 - // [ AT ] AnimTexture[4] → animated_texture_list_offset - // [ V ] BKVertexList header + Vtx[] → vtx_list_offset - // [ G ] BKGfxList header + Gfx[] → gfx_list_offset + // [ T ] BKTextureList + BKTextureInfo[] + pixel data -> texture_list_offset + // [ GL ] GeoLayout command tree -> geo_list_offset + // [ A ] BKAnimationList + BKAnimation[] -> animation_list_offset + // [ B ] BKCollisionList + ColGeo[] + ColTri[] -> collision_list_offset + // [ 14 ] BKModelUnk14List + entries -> unk14 + // [ 20 ] BKCameraAreaList + entries -> unk20 + // [ E ] effect count (s16) + effects -> mesh_list_offset + // [ 28 ] BKAnimVerticesList + entries -> unk28 + // [ AT ] AnimTexture[4] -> animated_texture_list_offset + // [ V ] BKVertexList header + Vtx[] -> vtx_list_offset + // [ G ] BKGfxList header + Gfx[] -> gfx_list_offset auto out = std::vector(sizeof(BKModelBin), 0); auto hdr = [&]() -> BKModelBin* { return reinterpret_cast(out.data()); }; hdr()->geo_type = static_cast(geoType); - // GeoLayout section - if (geoBlob && !geoBlob->Data.empty()) { - PadTo8(out); - hdr()->geo_list_offset = static_cast(out.size()); - AppendBytes(out, geoBlob->Data.data(), geoBlob->Data.size()); - } - // Texture section if (texCount > 0) { PadTo8(out); @@ -442,6 +435,13 @@ ResourceFactoryBinaryModelV0::ReadResource(std::shared_ptr file, } } + // GeoLayout section + if (geoBlob && !geoBlob->Data.empty()) { + PadTo8(out); + hdr()->geo_list_offset = static_cast(out.size()); + AppendBytes(out, geoBlob->Data.data(), geoBlob->Data.size()); + } + // Animation section if (hasAnim) { PadTo8(out); diff --git a/src/port/Romhack/RomhackConfig.cpp b/src/port/Romhack/RomhackConfig.cpp index 092d875b3..ddcbee98d 100644 --- a/src/port/Romhack/RomhackConfig.cpp +++ b/src/port/Romhack/RomhackConfig.cpp @@ -62,6 +62,8 @@ static int sHideJiggiesLevel = -1; static int sHideCollectiblesLevel = -1; static int sNoteDoors[12] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }; static int sJiggyCosts[11] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }; +static int sJiggySizes[11] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }; +static int sJiggyFlags[11] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }; static char* sLevelNames[13] = {}; static std::unordered_map sWarpDests; static std::string sRomName; @@ -70,6 +72,7 @@ static std::string sRomName; // loaded romhack has no detectable injected MIPS code. static std::string sCustomCodeHashHex; static uint32_t sCustomCodeRamBase = 0; +static int sCustomCodeKind = -1; // ROM SHA1 — populated by the ROM_HASH section. Always emitted by Torch for // any romhack; serves as the fallback identifier when no custom-code blob is @@ -351,12 +354,16 @@ static void LoadGameConfig() { break; case 8: // JIGGY_PUZZLES - for (uint16_t e = 0; e < entryCount && pos + 2 <= size; e++) { + for (uint16_t e = 0; e < entryCount && pos + 6 <= size; e++) { int idx = data[pos]; int cost = data[pos + 1]; - pos += 2; + int sizeBits = data[pos + 2]; + int flag = readLE16(data + pos + 4); + pos += 6; if (idx >= 0 && idx < 11) { sJiggyCosts[idx] = cost; + sJiggySizes[idx] = sizeBits; + sJiggyFlags[idx] = flag; } } break; @@ -390,7 +397,7 @@ static void LoadGameConfig() { } break; - case 11: // CUSTOM_CODE — single entry: u32 ramBase + u8 hash[20] + case 11: // CUSTOM_CODE if (entryCount >= 1 && pos + 24 <= size) { sCustomCodeRamBase = readLE32(data + pos); char hex[41]; @@ -398,17 +405,6 @@ static void LoadGameConfig() { std::snprintf(hex + i * 2, 3, "%02x", data[pos + 4 + i]); } sCustomCodeHashHex.assign(hex, 40); - if (Lighthouse::LookupRomhackIdentifier(sCustomCodeHashHex.c_str()) == nullptr) { - // Hash isn't in RomhackTable.h yet — Lighthouse can detect - // this hack ships custom code but doesn't know which one. - // Log the SHA1 so a hand-port author can pick it up. - SPDLOG_WARN("[GameConfig] Custom-code SHA1 {} is not identified! This romhack's " - "scripted behavior will be absent until a hand-port is added " - "(ramBase=0x{:08X}).", - sCustomCodeHashHex, sCustomCodeRamBase); - } - // Known identifiers are surfaced in the summary log line below. - pos += 24; // Skip any additional entries (forward-compat). for (uint16_t e = 1; e < entryCount && pos + 24 <= size; e++) { @@ -420,6 +416,13 @@ static void LoadGameConfig() { } break; + case 13: // CUSTOM_CODE_INFO + if (entryCount >= 1 && pos + 4 <= size) { + sCustomCodeKind = readLE16(data + pos); + } + pos += entryCount * 4; + break; + case 12: // ROM_HASH — single entry: u8 hash[20] if (entryCount >= 1 && pos + 20 <= size) { char hex[41]; @@ -448,11 +451,27 @@ static void LoadGameConfig() { // Data-only romhack — BB patches only, no injected MIPS to identify. // Fall back to the o2r-derived name for visibility. SPDLOG_INFO("[GameConfig] Loaded romhack: {}", sRomName.empty() ? "" : sRomName); - } else if (const char* id = Lighthouse::LookupRomhackIdentifier(sCustomCodeHashHex.c_str())) { - SPDLOG_INFO("[GameConfig] Loaded romhack: {}", id); + } else if (const auto* entry = Lighthouse::LookupRomhackEntry(sCustomCodeHashHex.c_str())) { + SPDLOG_INFO("[GameConfig] Loaded romhack: {}", entry->identifier); + // No warning when the custom code is just the BB globalized-overlay + // framework or is already ported. Only injected, not-yet-ported code merits one. + // isPorted=false means analysis confirmed real un-ported custom code, + // regardless of how the blob is shipped (Nostalgia 64's lives inside a + // globalization-kind blob). + if (!entry->isPorted) { + SPDLOG_WARN("[GameConfig] {} ships injected custom code that is not ported yet; " + "scripted behavior driven by it will be absent.", + entry->identifier); + } + } else if (sCustomCodeKind == 1 /* BB_GLOBALIZATION */) { + const char* romId = sRomHashHex.empty() ? nullptr : Lighthouse::LookupRomhackIdentifier(sRomHashHex.c_str()); + SPDLOG_INFO("[GameConfig] Loaded romhack: {}", + romId ? romId : (sRomName.empty() ? "" : sRomName.c_str())); } else { - // Custom code present but the SHA1 is not in RomhackTable.h. The - // separate warn earlier in this function already surfaced the hash. + // Custom code present but the SHA1 is not in RomhackTable.h. + SPDLOG_WARN("[GameConfig] Custom-code SHA1 {} is not identified! This romhack's scripted " + "behavior will be absent until a port is added (ramBase=0x{:08X}).", + sCustomCodeHashHex, sCustomCodeRamBase); SPDLOG_INFO("[GameConfig] Loaded romhack: unidentified custom-code"); } } @@ -488,6 +507,14 @@ extern "C" const char* port_getRomhackName(void) { return sRomName.empty() ? "" : sRomName.c_str(); } +extern "C" int port_getRomhackCustomCodeKind(void) { + LoadGameConfig(); + if (!sIsRomhack || sCustomCodeHashHex.empty() || sCustomCodeKind < 0) { + return 0; // none + } + return sCustomCodeKind; +} + extern "C" bool port_getRomhackCustomCodeHash(char out_hex[41]) { LoadGameConfig(); if (sCustomCodeHashHex.empty()) { @@ -713,6 +740,22 @@ extern "C" int port_getRomhackJiggyPuzzleCost(int puzzle_index) { return -1; } +extern "C" int port_getRomhackJiggyPuzzleSize(int puzzle_index) { + ROMHACK_GUARD_INT; + if (puzzle_index >= 0 && puzzle_index < 11) { + return sJiggySizes[puzzle_index]; + } + return -1; +} + +extern "C" int port_getRomhackJiggyPuzzleFlag(int puzzle_index) { + ROMHACK_GUARD_INT; + if (puzzle_index >= 0 && puzzle_index < 11) { + return sJiggyFlags[puzzle_index]; + } + return -1; +} + extern "C" const char* port_getRomhackLevelName(int level_index) { ROMHACK_GUARD_NULL; if (level_index >= 0 && level_index < 13) { diff --git a/src/port/Romhack/RomhackConfig.h b/src/port/Romhack/RomhackConfig.h index 4d704ecb7..dc614ebf8 100644 --- a/src/port/Romhack/RomhackConfig.h +++ b/src/port/Romhack/RomhackConfig.h @@ -4,10 +4,7 @@ extern "C" { #endif -// BB romhack game config — loaded from aGameConfig blob in the o2r. -// Returns -1 (or 0/NULL) for vanilla default when no override exists. -// All functions are fast after first call: vanilla ROMs hit one branch. - +// Config building bool port_isRomhack(void); const char* port_getRomhackName(void); @@ -41,12 +38,20 @@ int port_getRomhackHoneycombsPerWorld(void); int port_getRomhackExtraHcStart(void); int port_getRomhackNoteDoor(int door_index); int port_getRomhackJiggyPuzzleCost(int puzzle_index); +int port_getRomhackJiggyPuzzleSize(int puzzle_index); +int port_getRomhackJiggyPuzzleFlag(int puzzle_index); const char* port_getRomhackLevelName(int level_index); int port_getRomhackWarpDest(int warp_index); bool port_getRomhackCustomCodeHash(char out_hex[41]); +int port_getRomhackCustomCodeKind(void); bool port_getRomhackRomHash(char out_hex[41]); const char* port_getRomhackIdentifier(void); +// Hack specific functions +int romhack_mumboTransform(int transformId); +int romhack_mumboWishwashyId(void); +int romhack_mumboRandomEventsAllowed(void); + #ifdef __cplusplus } #endif diff --git a/src/port/Romhack/RomhackQuirks.cpp b/src/port/Romhack/RomhackQuirks.cpp deleted file mode 100644 index efc46609f..000000000 --- a/src/port/Romhack/RomhackQuirks.cpp +++ /dev/null @@ -1,56 +0,0 @@ -// Per-romhack quirk handlers. Each block here is a port-side listener that -// adjusts engine behavior for a specific romhack identified via the -// RomhackTable.h SHA1 -> name mapping. Listeners run only when the loaded -// romhack matches the relevant identifier; vanilla and unrelated romhacks -// see no behavior change. -// -// To add a new quirk: -// 1. Make sure the romhack has an entry in RomhackTable.h. -// 2. Find the engine event the quirk should hook (or define a new one in -// src/port/Enhancements/Events/Hooks/List/). -// 3. Add a REGISTER_LISTENER block below, gated on -// port_getRomhackIdentifier() returning the matching name. -// 4. Wire the registration into RegisterRomhackQuirks_Init(). - -#include - -#include -#include "port/Enhancements/Events/PortEnhancements.h" -#include "port/Enhancements/Events/Hooks/Events.h" -#include "port/ShipInit.hpp" -#include "port/Romhack/RomhackConfig.h" - -namespace { - -bool IsRomhack(const char* identifier) { - const char* id = port_getRomhackIdentifier(); - return id != nullptr && std::strcmp(id, identifier) == 0; -} - -// --- Banjo-Dreamie -// -// Pre-BB romhack whose BB-patched warp constants live in the relocated overlay -// copy. Dreamie's boot loader doesn't actually load that copy on N64. -// -// On every OnWarpResolveDest fire, restore the dispatcher's vanilla default, -// ignoring whatever the BKCF claims. - -void RegisterDreamiePatches() { - REGISTER_LISTENER(OnWarpResolveDest, EVENT_PRIORITY_NORMAL, [](IEvent* event) { - if (!IsRomhack("Dreamie")) { - return; - } - auto* ev = reinterpret_cast(event); - if (ev->warpId == WARP_ID_SM_EXIT_BANJOS_HOUSE || ev->warpId == WARP_ID_LAIR_ENTER_MM_LOBBY_FROM_SM_LEVEL) { - *ev->dest = ev->defaultDest; - } - }); -} - -void RegisterRomhackQuirks_Init() { - RegisterDreamiePatches(); -} - -RegisterShipInitFunc initFunc(RegisterRomhackQuirks_Init); - -} // namespace diff --git a/src/port/Romhack/RomhackRegistration.cpp b/src/port/Romhack/RomhackRegistration.cpp new file mode 100644 index 000000000..98760acef --- /dev/null +++ b/src/port/Romhack/RomhackRegistration.cpp @@ -0,0 +1,60 @@ +// Registration hub for per-romhack ports. +// +// Each supported romhack lives in its own file under Romhack/Specific/ and +// exposes a RegisterPatches() that installs its listeners. Registration +// itself is gated on the loaded romhack's RomhackTable.h identifier. +// +// To add a new port: +// 1. Add an entry in RomhackTable.h by hash. +// 2. Add Romhack/Specific/.cpp exposing RegisterPatches(). +// 3. Add one PORT() line to the list below. The identifier must match the +// RomhackTable.h identifier and the RegisterPatches() name. + +#include + +#include "port/Romhack/RomhackConfig.h" +#include "port/ShipInit.hpp" + +#define ROMHACK_PORT_LIST(PORT) \ + PORT(JiggiesOfTime) \ + PORT(NewHorizons) \ + PORT(Nostalgia64) \ + PORT(CutThroatCoast) \ + PORT(BubblingBog) \ + PORT(Gruntch) + +#define ROMHACK_PORT_DECL(name) void Register##name##Patches(); +ROMHACK_PORT_LIST(ROMHACK_PORT_DECL) +#undef ROMHACK_PORT_DECL + +namespace { + +struct RomhackPort { + const char* identifier; + void (*install)(); +}; + +constexpr RomhackPort kRomhackPorts[] = { +#define ROMHACK_PORT_ENTRY(name) { #name, &Register##name##Patches }, + ROMHACK_PORT_LIST(ROMHACK_PORT_ENTRY) +#undef ROMHACK_PORT_ENTRY +}; + +void RegisterRomhackPatches_Init() { + const char* id = port_getRomhackIdentifier(); + if (id == nullptr) { + return; + } + for (const RomhackPort& port : kRomhackPorts) { + if (std::strcmp(id, port.identifier) == 0) { + port.install(); + return; + } + } +} + +RegisterShipInitFunc initFunc(RegisterRomhackPatches_Init, { "BOOT" }); + +} // namespace + +#undef ROMHACK_PORT_LIST diff --git a/src/port/Romhack/RomhackTable.h b/src/port/Romhack/RomhackTable.h index db90a0618..b613a636a 100644 --- a/src/port/Romhack/RomhackTable.h +++ b/src/port/Romhack/RomhackTable.h @@ -7,46 +7,74 @@ namespace Lighthouse { struct RomhackTableEntry { const char* sha1; const char* identifier; + bool isPorted; }; /* - This romhack table contains the sha1 hashes for custom code - blobs injected into romhacks. Torch inserts these hashes into - aGameConfig per romhack generated into an o2r. Having a table - of such hashes allows Lighthouse to eventually port custom code - that allows these romhacks to function properly, and gate custom - code paths behind matching hashes per o2r. + This romhack table contains the sha1 hashes for detected code changes + injected into romhacks. Torch inserts these hashes into aGameConfig + per romhack generated into an o2r. Having a table of such hashes allows + Lighthouse to eventually port the code modifications that allow these + romhacks to function properly, and gate such changes behind matching + hashes per o2r. + + Known romhacks hashed against the latest at patch.wedarobi.com + as of July 2026. */ static constexpr RomhackTableEntry kRomhackTable[] = { + // These hacks ship a separate code blob; the hash covers its decompressed + // payload. + // Cut-Throat Coast - { "13f4fa8a180fe5775a606486effbafeb58862d26", "CutThroatCoast" }, + { "13f4fa8a180fe5775a606486effbafeb58862d26", "CutThroatCoast", true }, - // How the Gruntch Stole Christmas — also shipped, byte-identical, in - // Santa's Village. Single hand-port covers both. - { "bed22dd8ef931228fbc94f006dfc718a4d4f6f8c", "Gruntch" }, + // The Gruntch, Santa's Village + { "bed22dd8ef931228fbc94f006dfc718a4d4f6f8c", "Gruntch", false }, - // Snow Glow Village — derivative of Gruntch's blob with diverged code. - { "23596c2858283b847e9e0ff44785e35110002fc7", "SnowGlowVillage" }, + // Snow Glow Village + { "23596c2858283b847e9e0ff44785e35110002fc7", "SnowGlowVillage", false }, // The Corrupted Jiggies - { "9e20be78496d66f2e5f7930022a0fee769753488", "CorruptedJiggies" }, + { "9e20be78496d66f2e5f7930022a0fee769753488", "CorruptedJiggies", false }, + + // Bubbling Bog Brewery Redone + { "af7c71b034b2d7af867cd0aec8751c49aca1f0bc", "BubblingBog", false }, + + // Cheatos Challenges + { "017bf33d80b22d7926a9839f09fd1c52f83d3b97", "CheatosChallenges", true }, + + // These hacks ship no blob of their own; they edit the globalized overlay + // in place, which aGameConfig has no schema for. Mostly actor table + // rebinds, though Nostalgia 64 also fills spare overlay space with its own + // functions and repoints update funcs at them. + + // Jiggies of Time + { "ad7ef5ba9051c6a360c1d60546d5ca8cf61f0d92", "JiggiesOfTime", true }, - // Banjo-Dreamie - { "3972b2a3aca230dde1cbf66ffa6f052327b7d3fa", "Dreamie" }, + // New Horizons + { "663dd77a9e3a1ed1f25399380665511a04b91a54", "NewHorizons", true }, - { nullptr, nullptr }, // terminator — keep last + // Nostalgia 64 + { "7a7a07c26d77530dc45caf8ab96e9056ea2877e1", "Nostalgia64", true }, + + { nullptr, nullptr, false }, // terminator }; -inline const char* LookupRomhackIdentifier(const char* sha1Hex) { +inline const RomhackTableEntry* LookupRomhackEntry(const char* sha1Hex) { if (sha1Hex == nullptr || sha1Hex[0] == '\0') { return nullptr; } for (const auto* entry = kRomhackTable; entry->sha1 != nullptr; entry++) { if (std::strcmp(entry->sha1, sha1Hex) == 0) { - return entry->identifier; + return entry; } } return nullptr; } +inline const char* LookupRomhackIdentifier(const char* sha1Hex) { + const RomhackTableEntry* entry = LookupRomhackEntry(sha1Hex); + return entry ? entry->identifier : nullptr; +} + } // namespace Lighthouse diff --git a/src/port/Romhack/Shared/HackShared.cpp b/src/port/Romhack/Shared/HackShared.cpp new file mode 100644 index 000000000..6f18d60ac --- /dev/null +++ b/src/port/Romhack/Shared/HackShared.cpp @@ -0,0 +1,126 @@ +#include +#include "port/UI/cvar_prefixes.h" +#include "port/Enhancements/Events/Hooks/Events.h" +#include "port/Romhack/RomhackConfig.h" +#include "port/ShipInit.hpp" +#include "HackShared.h" + +extern "C" { +#include "enums.h" +#include "functions.h" +#include "actor.h" + +extern ActorArray* suBaddieActorArray; + +extern s32 print_sCurrentFont; +extern s32 print_sMonospacedModeEnabled; +extern char print_sPreviousBoldLetter; +f32 print_calculateLetterXPos(u8 letter, f32* xPtr, f32* yPtr, f32 arg3); +} + +#define CVAR_NOTE_RETENTION CVAR_ENHANCEMENT("Gameplay.NoteRetention") + +namespace { + +void ApplyNoteSignHooks(); +f32 MeasureBoldNameWidth(const char* s); +void ApplyPauseNameCentering(); +void ApplyDialogSuppression(); + +int sNoteSignActorId = -1; +const int* sSuppressedDialogs = nullptr; +int sSuppressedDialogCount = 0; + +// Romhacks that have note signs and Bottles explainers don't need them when +// note saving is turned on. Suppress them. +void ApplyNoteSignHooks() { + const bool active = sNoteSignActorId >= 0 && CVarGetInteger(CVAR_NOTE_RETENTION, 0); + + COND_HOOK(OnActorSpawn, EVENT_PRIORITY_NORMAL, active, [](IEvent* event) { + auto* ev = reinterpret_cast(event); + if (ev->actorId == sNoteSignActorId) { + ev->result = nullptr; + event->Cancelled = true; + } + }); + + COND_HOOK(GameFrameUpdate, EVENT_PRIORITY_NORMAL, active, [](IEvent*) { + if (suBaddieActorArray == nullptr) { + return; + } + Actor* start = suBaddieActorArray->data; + Actor* end = start + suBaddieActorArray->cnt; + for (Actor* actor = start; actor < end; actor++) { + if (actor->marker == nullptr || actor->marker->id != MARKER_B7_TUTORIAL_BOTTLES || + actor->actorTypeSpecificField != 8) { + continue; + } + if (actor->partnerActor != nullptr) { + marker_despawn(actor->partnerActor); + } + marker_despawn(actor->marker); + } + }); +} + +// Center bold font in pause menu +f32 MeasureBoldNameWidth(const char* s) { + const s32 savedSlot = print_sCurrentFont; + const s32 savedMono = print_sMonospacedModeEnabled; + const char savedPrev = print_sPreviousBoldLetter; + print_sCurrentFont = 1; + print_sMonospacedModeEnabled = 0; + print_sPreviousBoldLetter = 0; + f32 x = 0.0f; + f32 y = 0.0f; + for (const char* p = s; *p != '\0'; ++p) { + print_calculateLetterXPos((u8)(unsigned char)*p, &x, &y, 1.05f); + } + print_sCurrentFont = savedSlot; + print_sMonospacedModeEnabled = savedMono; + print_sPreviousBoldLetter = savedPrev; + return x; +} + +void ApplyPauseNameCentering() { + COND_VB_SHOULD(VB_PAUSEMENU_LEVEL_NAME_X, EVENT_PRIORITY_NORMAL, port_getRomhackIdentifier() != nullptr, { + s32* x = va_arg(args, s32*); + va_arg(args, s32); + const char* vanillaName = va_arg(args, const char*); + const char* romhackName = va_arg(args, const char*); + if (romhackName != nullptr && vanillaName != nullptr) { + const f32 shift = (MeasureBoldNameWidth(vanillaName) - MeasureBoldNameWidth(romhackName)) * 0.5f; + *x += (s32)(shift >= 0.0f ? shift + 0.5f : shift - 0.5f); + } + (void)should; + }); +} + +// Suppress a caller-supplied set of dialogs +void ApplyDialogSuppression() { + COND_VB_SHOULD(VB_OVERRIDE_DIALOG_SHOW, EVENT_PRIORITY_NORMAL, sSuppressedDialogCount > 0, { + const s32 textId = va_arg(args, s32); + for (int i = 0; i < sSuppressedDialogCount; i++) { + if (sSuppressedDialogs[i] == textId) { + *should = true; + break; + } + } + }); +} + +RegisterShipInitFunc noteSignInitFunc(ApplyNoteSignHooks, { CVAR_NOTE_RETENTION }); +RegisterShipInitFunc pauseNameCenterInit(ApplyPauseNameCentering, { "BOOT" }); + +} // namespace + +void HackShared_EnableNoteSignSuppression(int signActorId) { + sNoteSignActorId = signActorId; + ApplyNoteSignHooks(); +} + +void HackShared_EnableDialogSuppression(const int* dialogIds, int count) { + sSuppressedDialogs = dialogIds; + sSuppressedDialogCount = count; + ApplyDialogSuppression(); +} diff --git a/src/port/Romhack/Shared/HackShared.h b/src/port/Romhack/Shared/HackShared.h new file mode 100644 index 000000000..f0da30635 --- /dev/null +++ b/src/port/Romhack/Shared/HackShared.h @@ -0,0 +1,9 @@ +#pragma once + +void HackShared_EnableNoteSignSuppression(int signActorId); +void HackShared_EnableDialogSuppression(const int* dialogIds, int count); + +template +inline void HackShared_EnableDialogSuppression(const int (&dialogIds)[N]) { + HackShared_EnableDialogSuppression(dialogIds, N); +} diff --git a/src/port/Romhack/Shared/ProximityDialogs.cpp b/src/port/Romhack/Shared/ProximityDialogs.cpp new file mode 100644 index 000000000..75c09762b --- /dev/null +++ b/src/port/Romhack/Shared/ProximityDialogs.cpp @@ -0,0 +1,81 @@ +#include +#include "port/Enhancements/Events/Hooks/Events.h" +#include "ProximityDialogs.h" + +extern "C" { +#include "enums.h" +#include "functions.h" +#include "core1/ml.h" + +extern f32 D_8037C5B0[3]; +} + +namespace { +u16 sDialogShown[2] = { 0, 0 }; +const ProximityDialogMap* sWorldMaps = nullptr; +s32 sWorldMapCount = 0; +} // namespace + +void ProximityDialogs_Run(const ProximityDialogMap* maps, int count) { + if (getGameMode() != GAME_MODE_3_NORMAL || gcdialog_hasCurrentTextId()) { + return; + } + + const ProximityDialogMap* entry = nullptr; + const s32 map = gsworld_getMap(); + for (s32 i = 0; i < count; i++) { + if (maps[i].map == map) { + entry = &maps[i]; + break; + } + } + if (entry == nullptr) { + return; + } + if (entry->gate != nullptr && !entry->gate()) { + return; + } + + for (s32 i = 0; i < entry->pageCount; i++) { + const ProximityDialogPage& page = entry->pages[i]; + const bool tokenIsGuard = page.doneBit == 0; + if (tokenIsGuard ? mumboscore_get((enum mumbotoken_e)page.token) + : (sDialogShown[page.word] & page.doneBit) != 0) { + continue; + } + if (page.skipIfJiggy > 0 && jiggyscore_isCollected((enum jiggy_e)page.skipIfJiggy)) { + continue; + } + if (page.needFlag > 0 && !fileProgressFlag_get((enum file_progress_e)page.needFlag)) { + continue; + } + if (page.needFlagClear > 0 && fileProgressFlag_get((enum file_progress_e)page.needFlagClear)) { + continue; + } + f32 anchor[3] = { page.anchor[0], page.anchor[1], page.anchor[2] }; + if (!(ml_vec3f_distance(anchor, D_8037C5B0) < page.radius)) { + return; + } + gcdialog_showDialog(page.textId, page.dialogFlags, (f32*)page.dialogPos, NULL, NULL, NULL); + sDialogShown[page.word] |= page.doneBit; + if (page.token >= 0) { + mumboscore_set((enum mumbotoken_e)page.token, true); + } + } +} + +void ProximityDialogs_Enable(const ProximityDialogMap* maps, int count) { + sWorldMaps = maps; + sWorldMapCount = count; + COND_HOOK(GameFrameUpdate, EVENT_PRIORITY_NORMAL, sWorldMapCount > 0, [](IEvent*) { + ProximityDialogs_Run(sWorldMaps, sWorldMapCount); + }); +} + +bool ProximityDialogs_IsShown(int word, unsigned bits) { + return (sDialogShown[word] & bits) != 0; +} + +void ProximityDialogs_ClearShown(int word, unsigned bits) { + sDialogShown[word] &= ~(u16)bits; +} diff --git a/src/port/Romhack/Shared/ProximityDialogs.h b/src/port/Romhack/Shared/ProximityDialogs.h new file mode 100644 index 000000000..96ed1a095 --- /dev/null +++ b/src/port/Romhack/Shared/ProximityDialogs.h @@ -0,0 +1,40 @@ +#pragma once + +struct ProximityDialogPage { + float anchor[3]; + float radius; + int textId; + int dialogFlags; + unsigned char word; // which sDialogShown word tracks this page + unsigned short doneBit; // bit within that word; 0 means "guarded by token instead" + int token; // mumbotoken to guard on / bank (-1 = none) + const float* dialogPos; + int skipIfJiggy; // skip if this jiggy is collected (>0) + int needFlag; // skip unless this FILEPROG flag is set (>0) + int needFlagClear; // skip if this FILEPROG flag is set (>0) +}; + +struct ProximityDialogMap { + int map; + const ProximityDialogPage* pages; + int pageCount; + // Optional per-map hook run before the page loop. Return false to skip this + // map's pages this frame; may also perform side effects. nullptr = always run. + bool (*gate)(); +}; + +// Run one frame of checks against a caller-owned table (used by the storybook). +void ProximityDialogs_Run(const ProximityDialogMap* maps, int count); + +// Register a GameFrameUpdate that runs the given world table every frame. +void ProximityDialogs_Enable(const ProximityDialogMap* maps, int count); + +// Deduce the count from a fixed table so callers pass just the table. +template +inline void ProximityDialogs_Enable(const ProximityDialogMap (&maps)[N]) { + ProximityDialogs_Enable(maps, N); +} + +// Shown-bit access for gate() callbacks that re-arm a page. +bool ProximityDialogs_IsShown(int word, unsigned bits); +void ProximityDialogs_ClearShown(int word, unsigned bits); diff --git a/src/port/Romhack/Shared/Storybook.cpp b/src/port/Romhack/Shared/Storybook.cpp new file mode 100644 index 000000000..d461cb546 --- /dev/null +++ b/src/port/Romhack/Shared/Storybook.cpp @@ -0,0 +1,134 @@ +#include +#include +#include "port/Enhancements/Events/Hooks/Events.h" +#include "Storybook.h" + +extern "C" { +#include "enums.h" +#include "functions.h" +#include "macros.h" +#include "actor.h" +#include "core1/ml.h" + +extern OSContPad pfsManagerContPadData[4]; +extern PfsManagerControllerData D_80281138[4]; +extern Struct_core1_10A00_1 D_80281250[4]; +extern f32 D_8037C5B0[3]; +extern f32 player_position[3]; +} + +namespace { + +bool IsStorybookMap(enum map_e map); +f32 StoryStickAxis(s32 raw); +void StorybookInputCapture(); +void StorybookPageUpdate(); +void ApplyStorybookIntroHooks(); + +// Engine tuning +constexpr f32 kPageStep = 2500.0f; +constexpr f32 kStickClamp = 80.0f; +constexpr f32 kPushThreshold = 0.5f; +constexpr f32 kCenterThreshold = 0.3f; +constexpr s32 kDebounceTicks = 50; + +// Per-hack data +const ProximityDialogMap* sPages = nullptr; +s32 sPageCount = 0; +s32 sResumeDest = 0; +s32 sSeenToken = -1; + +bool sStorybookEnabled = false; +s32 sStoryTick = 0; +s32 sStoryLastStep = -kDebounceTicks - 1; +s32 sStoryStickX = 0; +s32 sStoryStickY = 0; + +bool IsStorybookMap(enum map_e map) { + for (s32 i = 0; i < sPageCount; i++) { + if ((enum map_e)sPages[i].map == map) { + return true; + } + } + return false; +} + +f32 StoryStickAxis(s32 raw) { + f32 v = (f32)raw; + if (v > kStickClamp) { + v = kStickClamp; + } else if (v < -kStickClamp) { + v = -kStickClamp; + } + return v / kStickClamp; +} + +void StorybookInputCapture() { + if (!IsStorybookMap(gsworld_getMap())) { + return; + } + sStoryStickX = pfsManagerContPadData[0].stick_x; + sStoryStickY = pfsManagerContPadData[0].stick_y; + memset(&D_80281138[0], 0, sizeof(D_80281138[0])); + memset(&D_80281250[0], 0, sizeof(D_80281250[0])); + pfsManagerContPadData[0].stick_x = 0; + pfsManagerContPadData[0].stick_y = 0; + pfsManagerContPadData[0].button = 0; +} + +void StorybookPageUpdate() { + sStoryTick++; + if (!IsStorybookMap(gsworld_getMap())) { + return; + } + D_8037C5B0[1] = 0.0f; + D_8037C5B0[2] = 0.0f; + + if (!gcdialog_hasCurrentTextId()) { + const f32 x = StoryStickAxis(sStoryStickX); + const f32 y = StoryStickAxis(sStoryStickY); + if (y > -kCenterThreshold && y < kCenterThreshold && x > kPushThreshold && + sStoryLastStep + kDebounceTicks < sStoryTick) { + sStoryLastStep = sStoryTick; + D_8037C5B0[0] += kPageStep; + } + } + player_position[0] = D_8037C5B0[0]; +} + +void ApplyStorybookIntroHooks() { + // First storybook writes a mumbo token to indicate that it's been seen + COND_VB_SHOULD(VB_GAMESELECT_START_NEW_GAME, EVENT_PRIORITY_NORMAL, sStorybookEnabled, { + (void)args; // gamenum is passed but unused + const bool seen = sSeenToken >= 0 && mumboscore_get((enum mumbotoken_e)sSeenToken); + *should = !seen; + }); + + // Storybook mode freezes all input except the left stick's right movement + COND_HOOK(OnControllerUpdate, EVENT_PRIORITY_NORMAL, sStorybookEnabled, [](IEvent*) { StorybookInputCapture(); }); + + COND_HOOK(GameFrameUpdate, EVENT_PRIORITY_NORMAL, sStorybookEnabled, [](IEvent*) { + ProximityDialogs_Run(sPages, sPageCount); + StorybookPageUpdate(); + }); +} + +} // namespace + +extern "C" void Storybook_ResumeWarp(NodeProp* node, ActorMarker* marker) { + (void)marker; + func_8031CC8C(node, sResumeDest); +} + +extern "C" void* port_getRomhackResumeWarpFunc(void) { + return sStorybookEnabled ? (void*)&Storybook_ResumeWarp : nullptr; +} + +void Storybook_Enable(const StorybookConfig& cfg) { + sPages = cfg.pages; + sPageCount = cfg.pageCount; + sResumeDest = cfg.resumeDest; + sSeenToken = cfg.newGameSeenToken; + sStorybookEnabled = true; + ApplyStorybookIntroHooks(); +} diff --git a/src/port/Romhack/Shared/Storybook.h b/src/port/Romhack/Shared/Storybook.h new file mode 100644 index 000000000..554ec22d3 --- /dev/null +++ b/src/port/Romhack/Shared/Storybook.h @@ -0,0 +1,12 @@ +#pragma once + +#include "ProximityDialogs.h" + +struct StorybookConfig { + const ProximityDialogMap* pages; // book pages, one entry per book map + int pageCount; // number of book maps + int resumeDest; // MAP<<8 | ENTRY warp used when resuming a save + int newGameSeenToken; // mumbotoken the first book banks (-1 = none) +}; + +void Storybook_Enable(const StorybookConfig& cfg); diff --git a/src/port/Romhack/Specific/BubblingBog.cpp b/src/port/Romhack/Specific/BubblingBog.cpp new file mode 100644 index 000000000..fe1e4c682 --- /dev/null +++ b/src/port/Romhack/Specific/BubblingBog.cpp @@ -0,0 +1,22 @@ +#include +#include "port/Enhancements/Events/Hooks/Events.h" + +extern "C" { +#include "enums.h" +#include "functions.h" +} + +// The Tooie jiggy animation exists in this hack +void TooieJiggyDance_ForceEnable(); + +void RegisterBubblingBogPatches() { + TooieJiggyDance_ForceEnable(); + + // Bubbling Bog Brewery's swapy water is hazardous + REGISTER_VB_SHOULD(VB_GROUND_HAZARD_ACTIVE, EVENT_PRIORITY_NORMAL, { + s32 map = va_arg(args, s32); + if (map == MAP_D_BGS_BUBBLEGLOOP_SWAMP && func_80294554()) { + *should = true; + } + }); +} diff --git a/src/port/Romhack/Specific/CutThroatCoast.cpp b/src/port/Romhack/Specific/CutThroatCoast.cpp new file mode 100644 index 000000000..01223d183 --- /dev/null +++ b/src/port/Romhack/Specific/CutThroatCoast.cpp @@ -0,0 +1,284 @@ +#include +#include +#include +#include +#include "port/Enhancements/Events/Hooks/Events.h" +#include "port/Romhack/RomhackConfig.h" + +extern "C" { +#include "enums.h" +#include "functions.h" +#include "model.h" + +extern struct1Cs_1 D_8036C58C[0xD]; + +// Acorn replaced with collectible doubloon +extern ActorInfo D_8038F460; +void chCarriedAcorn_update(Actor* thisx); + +typedef struct { + u8 map_id; + u8 rgb[3]; + u8 alpha; +} CameraFogEntry; +extern CameraFogEntry D_80365D60[]; + +typedef struct { + u8 uid; + u8 state; + u8 next_state; + f32 duration; + s32 model_index; + s32 anim_index; + f32 scale; +} TransitionInfoEntry; +extern TransitionInfoEntry D_8036C150[0x16]; +} + +namespace { + +// Custom transition pair +constexpr s32 kPairMapA = MAP_2_MM_MUMBOS_MOUNTAIN; +constexpr s32 kPairMapB = MAP_31_RBB_RUSTY_BUCKET_BAY; +constexpr s32 kPairInIndex = 0xD; + +GameMap sPrevMap = (GameMap)0; +GameMap sCurMap = (GameMap)0; + +struct PauseRemap { + int src; + s16 level_id; + s16 x; +}; +constexpr PauseRemap kRemap[0xD] = { + { 0, 0, 80 }, { 1, 0, 64 }, { 3, 0, 37 }, { 4, 0, 27 }, { 5, 0, 52 }, { 6, 0, 35 }, { 7, 0, 72 }, + { 8, 0, 78 }, { 9, 0xA, 43 }, { 10, 0, 50 }, { 11, 0, 48 }, { 2, 0, 60 }, { 12, 0, 72 }, +}; + +void RebuildPauseMenuTable() { + u8* names[0xD]; + for (int i = 0; i < 0xD; i++) { + names[i] = D_8036C58C[i].string; + } + for (int page = 0; page < 0xD; page++) { + D_8036C58C[page].string = names[kRemap[page].src]; + D_8036C58C[page].level_id = kRemap[page].level_id; + D_8036C58C[page].x = kRemap[page].x; + } + D_8036C58C[8].string = (u8*)"CUT-THROAT COAST"; +} + +void ApplyDataPatches() { + D_80365D60[3] = { 0, { 0x34, 0x6E, 0xEF }, 0x5A }; + D_8036C150[3].state = 7; // TRANSITION_STATE_7_WHITE_IN + D_8036C150[3].next_state = 0; // TRANSITION_STATE_0_NONE + D_8036C150[3].duration = 0.7f; + D_8036C150[3].model_index = 0; + D_8036C150[3].anim_index = 0; + D_8036C150[12].duration = 0.4f; + D_8036C150[13].state = 3; // TRANSITION_STATE_3_BLACK_OUT + D_8036C150[13].next_state = 1; // TRANSITION_STATE_1_LOADING + D_8036C150[13].duration = 0.4f; + D_8036C150[13].model_index = 0; + D_8036C150[13].scale = 0.0f; +} + +// Lighthouse beam sweep +constexpr s32 kBeamFirstVtx = 423; +constexpr s32 kBeamLastVtx = 454; +constexpr f32 kBeamDegPerTick = 2.0f; + +struct BeamVert { + Vtx* v; + f32 dx, dz; +}; +BKModelBin* sBeamModelBin = nullptr; +std::vector sBeamVerts; +f32 sBeamAngle = 0.0f; +f32 sBeamPivotX, sBeamPivotZ; + +void UpdateLighthouseBeam() { + if (gsworld_getMap() != MAP_1B_MMM_MAD_MONSTER_MANSION) { + return; + } + BKModelBin* bin = mapModel_getModelBin(1); + if (bin == nullptr) { + sBeamModelBin = nullptr; + return; + } + if (bin != sBeamModelBin) { + sBeamModelBin = bin; + sBeamVerts.clear(); + BKVertexList* vl = modelbin_getVtxList(bin); + if (vl == nullptr) { + sBeamModelBin = nullptr; + return; + } + s32 cnt = vtxList_getVtxCount(vl); + if (cnt <= kBeamLastVtx) { + return; + } + for (s32 i = kBeamFirstVtx; i <= kBeamLastVtx; i++) { + sBeamVerts.push_back({ &vl->vertices[i], 0.0f, 0.0f }); + } + sBeamPivotX = 3563.0f; + sBeamPivotZ = 8751.0f; + for (auto& bv : sBeamVerts) { + bv.dx = bv.v->v.ob[0] - sBeamPivotX; + bv.dz = bv.v->v.ob[2] - sBeamPivotZ; + } + } + sBeamAngle = mlNormalizeAngle(sBeamAngle + kBeamDegPerTick); + f32 rad = sBeamAngle * (f32)(BAD_PI / 180.0); + f32 c = cosf(rad), s = sinf(rad); + for (auto& bv : sBeamVerts) { + bv.v->v.ob[0] = (s16)(sBeamPivotX + bv.dx * c - bv.dz * s); + bv.v->v.ob[2] = (s16)(sBeamPivotZ + bv.dx * s + bv.dz * c); + } +} + +} // namespace + +extern "C" void CutThroatCoast_DoubloonUpdate(Actor* thisx) { + thisx->yaw = mlNormalizeAngle(thisx->yaw + 12.0f); + chCarriedAcorn_update(thisx); +} + +void RegisterCutThroatCoastPatches() { + RebuildPauseMenuTable(); + ApplyDataPatches(); + D_8038F460.update_func = CutThroatCoast_DoubloonUpdate; + + // Sweep the lighthouse beam + REGISTER_LISTENER(GameFrameUpdate, EVENT_PRIORITY_NORMAL, [](IEvent* event) { + (void)event; + UpdateLighthouseBeam(); + }); + + // Track map changes for the custom MM <-> RBB transition below. + REGISTER_LISTENER(OnMapLoad, EVENT_PRIORITY_HIGH, [](IEvent* event) { + auto* ev = reinterpret_cast(event); + sPrevMap = ev->prevMap; + sCurMap = ev->nextMap; + }); + + // Pause menu pins below + REGISTER_VB_SHOULD(VB_JIGGYSCORE_LEVEL_TOTAL, EVENT_PRIORITY_NORMAL, { + s32 lvl = va_arg(args, s32); + s32* result = va_arg(args, s32*); + s32 cnt = 0; + if (lvl == 0xA) { + for (s32 i = 1; i < 0x65; i++) { + if (jiggyscore_isCollected((enum jiggy_e)i)) { + cnt++; + } + } + if (cnt > 0xA) { + cnt = 0xA; + } + } + *result = cnt; + *should = false; + }); + + REGISTER_VB_SHOULD(VB_PAUSEMENU_LEVEL_TO_PAGE, EVENT_PRIORITY_NORMAL, { + va_arg(args, s32); + s32* page = va_arg(args, s32*); + *page = 8; + *should = false; + }); + + REGISTER_VB_SHOULD(VB_PAUSEMENU_SET_NEXT_PAGE, EVENT_PRIORITY_NORMAL, { + s8* page = va_arg(args, s8*); + *page = 8; + *should = false; + }); + + REGISTER_VB_SHOULD(VB_PAUSEMENU_DRAW_JOYSTICKS, EVENT_PRIORITY_NORMAL, { + (void)args; + *should = false; + }); + + REGISTER_VB_SHOULD(VB_PAUSEMENU_BOLD_FONT_TEXTURE, EVENT_PRIORITY_NORMAL, { + s32* fontId = va_arg(args, s32*); + *fontId = 0x6E4; + (void)should; + }); + + // TODO: CTC has an extra data blob separate from the asset table + // where a custom gravestone and note door (100) are. Torch should not + // need to do per-romhack extraction, so these will need to either be skipped + // or rebuilt a different way. For now, blank the digits on the note door. + REGISTER_VB_SHOULD(VB_NOTEDOOR_DRAW_NUMBER, EVENT_PRIORITY_NORMAL, { + s32 noteDoorIdx = va_arg(args, s32); + if (noteDoorIdx >= 1 && port_getRomhackNoteDoor(noteDoorIdx - 1) >= 0) { + *should = false; + } + }); + + // Exiting via the exit pad should go back to the CTC lobby map + REGISTER_VB_SHOULD(VB_MAP_CHANGE_REQUEST, EVENT_PRIORITY_NORMAL, { + s32* map = va_arg(args, s32*); + s32* exit = va_arg(args, s32*); + if (*map == MAP_75_GL_MMM_LOBBY) { + *map = MAP_1_SM_SPIRAL_MOUNTAIN; + *exit = 2; + } + (void)should; + }); + + REGISTER_VB_SHOULD(VB_VOID_OUT_RESPAWN_TRANSITION, EVENT_PRIORITY_NORMAL, { + s32 map = va_arg(args, s32); + s32 exit = va_arg(args, s32); + transitionToMap((enum map_e)map, exit, 1); + *should = false; + }); + + REGISTER_VB_SHOULD(VB_MAP_TRANSITION_IN_INDEX, EVENT_PRIORITY_NORMAL, { + s32 map = va_arg(args, s32); + s32* inIndex = va_arg(args, s32*); + s32 other = (map == sCurMap) ? sPrevMap : sCurMap; + if ((map == kPairMapA && other == kPairMapB) || (map == kPairMapB && other == kPairMapA)) { + *inIndex = kPairInIndex; + } + (void)should; + }); + + // The repurposed season switches are hidden below the ground when hit + REGISTER_VB_SHOULD(VB_CCW_SEASON_SWITCH_PRESSED_INIT, EVENT_PRIORITY_NORMAL, { + Actor* switchActor = va_arg(args, Actor*); + switchActor->position[1] = -420.0f; + subaddie_set_state(switchActor, 4); + *should = false; + }); + + // Suppress the jiggy tutorial dialog + REGISTER_VB_SHOULD(VB_JIGGY_COLLECT_TUTORIAL, EVENT_PRIORITY_NORMAL, { + (void)args; + *should = false; + }); + + // This MMM empty honeycomb doesn't require the pumpkin + REGISTER_VB_SHOULD(VB_HONEYCOMB_PUMPKIN_REQUIREMENT, EVENT_PRIORITY_NORMAL, { + (void)args; + *should = false; + }); + + // The sky timer never advances, so skybox layers hold their initial rotation + REGISTER_VB_SHOULD(VB_SKY_UPDATE, EVENT_PRIORITY_NORMAL, { + (void)args; + *should = false; + }); + + // No fullscreen clear behind the skybox when sky models are present + REGISTER_VB_SHOULD(VB_SKY_DRAW_BACKDROP_RECT, EVENT_PRIORITY_NORMAL, { + (void)args; + *should = false; + }); + + // Suppress Brentilda's heal dialog + REGISTER_VB_SHOULD(VB_BRENTILDA_HEAL_DIALOG, EVENT_PRIORITY_NORMAL, { + (void)args; + *should = false; + }); +} diff --git a/src/port/Romhack/Specific/JiggiesOfTime.cpp b/src/port/Romhack/Specific/JiggiesOfTime.cpp new file mode 100644 index 000000000..614288a40 --- /dev/null +++ b/src/port/Romhack/Specific/JiggiesOfTime.cpp @@ -0,0 +1,31 @@ +/* + * Jiggies of Time Fun Facts + * + * The Collywobble actor is marker-swapped to prevent a spawn. This is rarely seen anyway, since BB enforces + * file select as the default boot. With vanilla, if you were to view the intro sequence after a game over, + * you'd see a stray Collywobble spawned during the concert when it shouldn't be there at all. + * + * An unused vanilla marker 0x54 spawns ASSET_50B_MODEL_X_BARREL_TOP, which in Jiggies of Time is model-swapped + * with a random honeycomb drop. + * + */ + +#include +#include "port/Romhack/Shared/HackShared.h" + +extern "C" { +#include "enums.h" +#include "functions.h" + +extern ActorInfo chXBarrelTop; +extern ActorInfo gChVegetablesCollywobbleB; +} + +void RegisterJiggiesOfTimePatches() { + chXBarrelTop.markerId = 0x54; + gChVegetablesCollywobbleB.markerId = MARKER_1F1_GRUNTLING_BLACK; + + // JoT's note signs are repurposed Red Question Marks. + // Source: https://github.com/Mr-Wiseguy/JiggiesOfTimeRecomp/blob/main/src/note_signs.c + HackShared_EnableNoteSignSuppression(ACTOR_54_RED_QUESTION_MARK); +} diff --git a/src/port/Romhack/Specific/NewHorizons.cpp b/src/port/Romhack/Specific/NewHorizons.cpp new file mode 100644 index 000000000..67d671680 --- /dev/null +++ b/src/port/Romhack/Specific/NewHorizons.cpp @@ -0,0 +1,25 @@ +/* + * New Horizons Fun Facts + * + * Beyond the BKCF-covered data tables, New Horizons patches two ActorInfo + * marker bindings inside its copy of the globalized-overlay blob. + * + */ + +#include +#include "port/Enhancements/Events/Hooks/Events.h" + +extern "C" { +#include "enums.h" +#include "functions.h" + +// { MARKER_235_CRACKED_SKYLIGHT, ACTOR_23F_CRACKED_SKYLIGHT, ... } +extern ActorInfo chCrackedSkylight; +// { 0x220, 0x22C, ... } +extern ActorInfo D_80392994; +} + +void RegisterNewHorizonsPatches() { + chCrackedSkylight.markerId = MARKER_60_BLUE_EGG_COLLECTIBLE; + D_80392994.markerId = MARKER_60_BLUE_EGG_COLLECTIBLE; +} diff --git a/src/port/Romhack/Specific/Nostalgia64.cpp b/src/port/Romhack/Specific/Nostalgia64.cpp new file mode 100644 index 000000000..faf6b5de0 --- /dev/null +++ b/src/port/Romhack/Specific/Nostalgia64.cpp @@ -0,0 +1,90 @@ +#include +#include "port/Enhancements/Events/Hooks/Events.h" +#include "port/Romhack/Shared/HackShared.h" + +extern "C" { +#include "enums.h" +#include "functions.h" +#include "actor.h" + +extern ActorInfo D_80393378; +extern ActorInfo chGruntlingBlack; +extern ActorInfo chCellarHatch; +extern ActorInfo chMMMWideWindow; + +void chGruntling_initialize(Actor* thisx); +void func_802D3CE8(Actor* thisx); +} + +struct HitboxRow { + u16 markerId; + u16 flags; + u16 vals[11]; +}; +extern "C" HitboxRow collision_table[]; + +namespace { + +// Black Gruntling is recycled to use the Beta Vent enemy +bool sBlackGruntlingAttack = false; + +extern "C" void Nostalgia64_VentUpdate(Actor* thisx) { + Humanoid_Baddies_Actor* local = (Humanoid_Baddies_Actor*)&thisx->local; + if (!thisx->volatile_initialized) { + local->baddieSpecific = (thisx->modelCacheIndex == ACTOR_367_GRUNTLING_RED) ? 2 + : (thisx->modelCacheIndex == ACTOR_3BF_GRUNTLING_BLUE) ? 1 + : 0; + chGruntling_initialize(thisx); + } + humanoidBaddie_update(thisx); + if (thisx->state == 5) { + bool swipeFrame = actor_animationIsAt(thisx, 0.18f); + if (swipeFrame) { + sfx_playFadeShorthandDefault(SFX_2_CLAW_SWIPE, 1.0f, 28000, thisx->position, 1250, 2500); + } + sBlackGruntlingAttack = true; + if (swipeFrame) { + sfx_playFadeShorthandDefault(SFX_1F_HITTING_AN_ENEMY_3, 1.0f, 28000, thisx->position, 1250, 2500); + } + } +} + +// Banjo takes damage while the vent is open +extern "C" void Nostalgia64_VentSmokeUpdate(Actor* thisx) { + func_802D3CE8(thisx); + for (int i = 0; i < 0xBB; i++) { + if (collision_table[i].markerId == MARKER_1F1_GRUNTLING_BLACK) { + collision_table[i].vals[10] = 0x7000; + break; + } + } + if (sBlackGruntlingAttack) { + item_adjustByDiffWithHud(ITEM_14_HEALTH, -item_getCount(ITEM_14_HEALTH)); + bs_setState(BS_41_DIE); + sBlackGruntlingAttack = false; + } +} + +// The 1881 Barrel Top was swapped for a breakable door +extern "C" void Nostalgia64_BreakableDoorUpdate(Actor* thisx) { + func_802D3CE8(thisx); + for (int i = 0; i < 0xBB; i++) { + if (collision_table[i].markerId == MARKER_9A_1881_BARREL_TOP) { + collision_table[i].flags = 0x0804; + break; + } + } +} + +} // namespace + +void RegisterNostalgia64Patches() { + D_80393378.markerId = MARKER_65_SHRAPNEL; + + chGruntlingBlack.update_func = Nostalgia64_VentUpdate; + chCellarHatch.update_func = Nostalgia64_VentSmokeUpdate; + chMMMWideWindow.update_func = Nostalgia64_BreakableDoorUpdate; + + // The N64 cube stands in for the note signs + HackShared_EnableNoteSignSuppression(ACTOR_93_INTRO_N64_CUBE); +} diff --git a/src/port/Romhack/Specific/TheGruntch.cpp b/src/port/Romhack/Specific/TheGruntch.cpp new file mode 100644 index 000000000..077c539f0 --- /dev/null +++ b/src/port/Romhack/Specific/TheGruntch.cpp @@ -0,0 +1,383 @@ +/* + * All hack-specific code here is shared + between Gruntch and Santa's Village. + */ + +#include +#include "port/Enhancements/Events/Hooks/Events.h" +#include "port/Romhack/Shared/HackShared.h" +#include "port/Romhack/Shared/Storybook.h" +#include "port/Romhack/Shared/ProximityDialogs.h" + +extern "C" { +#include "enums.h" +#include "functions.h" +#include "macros.h" +#include "actor.h" +#include "core1/ml.h" +#include "core2/timedfunc.h" + +extern f32 D_8037C5B0[3]; +extern PfsManagerControllerData D_80281138[4]; + +typedef struct struct_1A_s { + f32 delay; + f32 unk4; + u8* str; + s16 y; + u8 portrait; + u8 unkF; +} PauseTotalsRow; +extern PauseTotalsRow D_8036C520[4]; +extern s8 D_8036C5F4[]; +} + +void TooieJiggyDance_ForceEnable(); + +// Suppressed dialogs +constexpr int kGruntchSuppressedDialogs[] = { + ASSET_A6F_DIALOG_RUBEE_MEET, + ASSET_C8B_DIALOG_GRUNTY_LONG_SWITCH_MISS, + ASSET_CCF_DIALOG_GNAWTY_MEET_SUMMER, + ASSET_DA3_DIALOG_EXTRA_LIFE_MEET, + 0xF78, + ASSET_D9C_DIALOG_MUSIC_NOTE_MEET, + ASSET_D9D_DIALOG_MUMBO_TOKEN_MEET, + ASSET_D9E_DIALOG_BLUE_EGG_MEET, + ASSET_D9F_DIALOG_RED_FEATHER_MEET, + ASSET_DA0_DIALOG_GOLD_FEATHER_MEET, + ASSET_DA1_DIALOG_HONEYCOMB_MEET, +}; + +// ---------------------------------------------------------- Proximity dialogs +constexpr s32 kDialogFlags8A = 0x8A; +constexpr s32 kDialogFlags82 = 0x82; +constexpr s32 kDialogFlagsA = 0x0A; +constexpr f32 kDialogRadius = 300.0f; + +// Storybook page dialogs +constexpr ProximityDialogPage kPages37[] = { + { { -7500.0f, 0.0f, 0.0f }, + kDialogRadius, + 0xA1D, + kDialogFlags8A, + 0, + 0x8000, + MUMBOTOKEN_12_CC_TUNNEL_RIGHT_OF_CLANKER }, + { { -5000.0f, 0.0f, 0.0f }, kDialogRadius, 0xA1E, kDialogFlags8A, 0, 0x4000, -1 }, + { { -2500.0f, 0.0f, 0.0f }, kDialogRadius, 0xA29, kDialogFlags8A, 0, 0x2000, -1 }, +}; + +constexpr ProximityDialogPage kPages38[] = { + { { -7500.0f, 0.0f, 0.0f }, kDialogRadius, 0xA77, kDialogFlags8A, 0, 0x0040, -1 }, +}; + +constexpr ProximityDialogPage kPages3E[] = { + { { -7500.0f, 0.0f, 0.0f }, kDialogRadius, 0xA70, kDialogFlags8A, 0, 0x1000, -1 }, + { { -5000.0f, 0.0f, 0.0f }, kDialogRadius, 0xA72, kDialogFlags8A, 0, 0x0800, -1 }, + { { -2500.0f, 0.0f, 0.0f }, kDialogRadius, 0xA73, kDialogFlags8A, 0, 0x0400, -1 }, + { { 0.0f, 0.0f, 0.0f }, kDialogRadius, 0xA74, kDialogFlags8A, 0, 0x0200, -1 }, + { { 2500.0f, 0.0f, 0.0f }, kDialogRadius, 0xA75, kDialogFlags8A, 0, 0x0100, -1 }, + { { 5000.0f, 0.0f, 0.0f }, kDialogRadius, 0xA76, kDialogFlags8A, 0, 0x0080, -1 }, +}; + +constexpr ProximityDialogPage kPages3C[] = { + { { -140.0f, 100.0f, -30.0f }, kDialogRadius, 0xA83, kDialogFlags8A, 1, 0x0080, -1 }, +}; + +constexpr ProximityDialogPage kPages72[] = { + { { 315.0f, 95.0f, -2085.0f }, 200.0f, 0xA7C, kDialogFlags8A, 1, 0x0200, -1 }, +}; + +constexpr ProximityDialogPage kPages28[] = { + { { 280.0f, 0.0f, -230.0f }, + kDialogRadius, + 0xA12, + kDialogFlags8A, + 0, + 0x0000, + MUMBOTOKEN_11_CC_ABOVE_LEVEL_ENTRANCE }, +}; + +// Gameplay proximity dialogs +constexpr f32 kDialog15Pos[3] = { -568.0f, 128.0f, -180.0f }; +constexpr ProximityDialogPage kPages15[] = { + { { -200.0f, 130.0f, -100.0f }, 220.0f, 0xA82, kDialogFlags8A, 1, 0x0100, -1, kDialog15Pos }, +}; + +constexpr ProximityDialogPage kPages22[] = { + { { -2800.0f, 590.0f, 800.0f }, + 300.0f, + 0xA19, + kDialogFlags8A, + 1, + 0x1000, + -1, + NULL, + JIGGY_8_MM_ORANGE_PADS, + -1, + -1 }, + { { -180.0f, 235.0f, 370.0f }, 700.0f, 0xA1B, kDialogFlags82, 1, 0x0800, -1, NULL, JIGGY_5_MM_HUTS, 0, 0 }, +}; + +constexpr f32 kDialog1BPos[3] = { -15.0f, 798.0f, -360.0f }; +constexpr ProximityDialogPage kPages1B[] = { + { { 0.0f, 720.0f, -360.0f }, + 270.0f, + 0xA13, + kDialogFlagsA, + 1, + 0x8000, + -1, + kDialog1BPos, + -1, + -1, + FILEPROG_38_RBB_OPEN }, + { { 0.0f, 720.0f, -360.0f }, + 270.0f, + 0xA7D, + kDialogFlagsA, + 1, + 0x4000, + -1, + kDialog1BPos, + -1, + FILEPROG_38_RBB_OPEN, + -1 }, +}; + +constexpr ProximityDialogPage kPages29[] = { + { { 230.0f, 660.0f, 100.0f }, 200.0f, 0xA1C, kDialogFlags82, 1, 0x2000, -1, NULL }, +}; + +static bool GruntchDialogGate15() { + if (jiggyscore_isCollected(JIGGY_34_LAIR_MM_WITCH_SWITCH) || + !fileProgressFlag_get(FILEPROG_18_MM_WITCH_SWITCH_JIGGY_PRESSED)) { + return false; + } + fileProgressFlag_set(FILEPROG_88_TRIED_LOGGO_AS_BEAR, 1); + return true; +} + +static bool GruntchDialogGate1B() { + if (ProximityDialogs_IsShown(1, 0xC000) && player_isStable()) { + f32 reArm[3] = { 0.0f, 720.0f, -360.0f }; + if (ml_vec3f_distance(reArm, D_8037C5B0) < 170.0f && D_80281138[0].face_button[1] == 1) { + ProximityDialogs_ClearShown(1, 0xC000); + } + } + return true; +} + +// Storybook pages +constexpr ProximityDialogMap kGruntchStorybookPages[] = { + { MAP_37_RBB_CONTAINER_1, kPages37, ARRAY_COUNT(kPages37), nullptr }, + { MAP_38_RBB_CONTAINER_3, kPages38, ARRAY_COUNT(kPages38), nullptr }, + { MAP_3E_RBB_CONTAINER_2, kPages3E, ARRAY_COUNT(kPages3E), nullptr }, +}; + +// Map the player warps to when resuming save +constexpr StorybookConfig kGruntchStorybook = { + kGruntchStorybookPages, + ARRAY_COUNT(kGruntchStorybookPages), + 0x2802, + MUMBOTOKEN_12_CC_TUNNEL_RIGHT_OF_CLANKER, +}; + +// Gameplay dialogs +constexpr ProximityDialogMap kGruntchGameplayDialogs[] = { + { MAP_3C_RBB_KITCHEN, kPages3C, ARRAY_COUNT(kPages3C), nullptr }, + { MAP_28_MMM_EGG_ROOM, kPages28, ARRAY_COUNT(kPages28), nullptr }, + { MAP_72_GL_BGS_LOBBY, kPages72, ARRAY_COUNT(kPages72), nullptr }, + { MAP_15_GV_WATER_PYRAMID, kPages15, ARRAY_COUNT(kPages15), GruntchDialogGate15 }, + { MAP_1B_MMM_MAD_MONSTER_MANSION, kPages1B, ARRAY_COUNT(kPages1B), GruntchDialogGate1B }, + { MAP_22_CC_INSIDE_CLANKER, kPages22, ARRAY_COUNT(kPages22), nullptr }, + { MAP_29_MMM_NOTE_ROOM, kPages29, ARRAY_COUNT(kPages29), nullptr }, +}; + +// ---------------------------------------------------------- Conditional actors +static bool sConditionalActorsEnabled = false; + +extern "C" void romhack_RewriteActorSpawn(void* actorInfo, u32* flags) { + if (!sConditionalActorsEnabled || actorInfo == NULL || flags == NULL) { + return; + } + ActorInfo* info = (ActorInfo*)actorInfo; + switch (info->actorId) { + case 0x131: + *flags = (*flags & ~0x02u) | 0x40u; + break; + case 0xF: + case 0xF1: + case ACTOR_340_XMAS_TREE_ICE: + *flags |= 0x400u; + info->draw_distance = 0x8000; + break; + default: + break; + } +} + +// Draw the Giant Christmas Tree only if it's been "purchased" +static void Gruntch_EnableConditionalActors() { + sConditionalActorsEnabled = true; + COND_VB_SHOULD(VB_XMAS_TREE_ICE_UPDATE, EVENT_PRIORITY_NORMAL, sConditionalActorsEnabled, { + Actor* self = va_arg(args, Actor*); + if (gsworld_getMap() == MAP_1B_MMM_MAD_MONSTER_MANSION && + self != NULL && self->marker != NULL && self->marker->propPtr != NULL) { + bool open = fileProgressFlag_get(FILEPROG_38_RBB_OPEN) != 0; + self->marker->propPtr->unk8_3 = open; + self->unk38_31 = !open; + *should = false; + } + }); + + // Force Boggy to be visible + COND_VB_SHOULD(VB_BOGGY_HOME_VISIBLE, EVENT_PRIORITY_NORMAL, sConditionalActorsEnabled, { + *should = true; + }); +} + +// --------------------------------------------------------------- Mumbo reward +namespace { +constexpr f32 kJiggyDelay = 4.15f; +constexpr f32 kStateDelay = 3.85f; +constexpr f32 kStateValue = 1.1f; +constexpr f32 kCameraReleaseDelay = 0.5f; +constexpr s32 kRewardJiggy = 3; +constexpr s32 kCameraMotor = 1; +constexpr s32 kLeaveHutText = 0xA7E; +constexpr s32 kLeaveHutFlags = 0x02; + +f32 sJiggyPos[3] = { 0.0f, 500.0f, -95.0f }; +f32 sMumboState = 0.0f; +bool sMumboRewardEnabled = false; + +void MumboReward_spawnJiggy() { + jiggy_spawn((enum jiggy_e)kRewardJiggy, sJiggyPos); + func_802BB3DC(kCameraMotor, 3.0f, 1.0f); + timedFunc_set_1(kCameraReleaseDelay, (GenFunction_1)func_802BB41C, kCameraMotor); +} + +void MumboReward_setState() { + sMumboState = kStateValue; +} +} // namespace + +extern "C" s32 romhack_mumboTransform(s32 transformId) { + if (!sMumboRewardEnabled || gsworld_getMap() != MAP_48_FP_MUMBOS_SKULL) { + return player_transform((enum transformation_e)transformId); + } + timedFunc_set_0(kJiggyDelay, MumboReward_spawnJiggy); + timedFunc_set_0(kStateDelay, MumboReward_setState); + gcdialog_showDialog(kLeaveHutText, kLeaveHutFlags, NULL, NULL, NULL, NULL); + return 1; +} + +extern "C" s32 romhack_mumboWishwashyId(void) { + return sMumboRewardEnabled ? 9 : TRANSFORM_7_WISHWASHY; +} + +extern "C" s32 romhack_mumboRandomEventsAllowed(void) { + return sMumboRewardEnabled ? 0 : 1; +} + +static void Gruntch_EnableMumboReward() { + sMumboRewardEnabled = true; +} + +// ------------------------------------------------------- Jiggy consolidation +constexpr s32 kJiggyToMM[] = { 0x14, 0x20, 0x2E, 0x4A }; +constexpr s32 kJiggyToMMM[] = { 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3E }; + +static bool JiggyMovedFromVanillaLevel(s32 id) { + for (s32 m : kJiggyToMM) { + if (m == id) { + return true; + } + } + for (s32 m : kJiggyToMMM) { + if (m == id) { + return true; + } + } + return false; +} + +// Pause-menu totals layout for Gruntch and Santa's Village +static void Gruntch_EnablePauseTotalsLayout() { + static const s16 kRowY[4] = { 46, 85, -100, 122 }; + static const s8 kScrollStep[4] = { 2, 2, 3, 3 }; + for (int i = 0; i < 4; i++) { + D_8036C520[i].y = kRowY[i]; + D_8036C5F4[i] = kScrollStep[i]; + } +} + +static void Gruntch_EnableJiggyTally() { + REGISTER_VB_SHOULD(VB_JIGGYSCORE_LEVEL_TOTAL, EVENT_PRIORITY_NORMAL, { + s32 lvl = va_arg(args, s32); + s32* result = va_arg(args, s32*); + s32 cnt = 0; + if (lvl >= 1 && lvl <= 0xA) { + for (s32 id = (lvl - 1) * 10 + 1; id <= lvl * 10; id++) { + if (!JiggyMovedFromVanillaLevel(id) && jiggyscore_isCollected((enum jiggy_e)id)) { + cnt++; + } + } + if (lvl == 1) { + for (s32 id : kJiggyToMM) { + if (jiggyscore_isCollected((enum jiggy_e)id)) { + cnt++; + } + } + } else if (lvl == 0xA) { + for (s32 id : kJiggyToMMM) { + if (jiggyscore_isCollected((enum jiggy_e)id)) { + cnt++; + } + } + } + } + *result = cnt; + *should = false; + }); + + // Hide Mt Grumpit's notes and jiggies + REGISTER_VB_SHOULD(VB_PAUSEMENU_ROW_VISIBLE, EVENT_PRIORITY_NORMAL, { + s32 lvl = va_arg(args, s32); + s32 row = va_arg(args, s32); + if (lvl == LEVEL_2_TREASURE_TROVE_COVE) { + *should = (row != 0 && row != 1); + } + }); +} + +// The second act stays locked until the RBB level-open flag is set +static void Gruntch_EnableActGate() { + REGISTER_VB_SHOULD(VB_WARP_DISPATCH, EVENT_PRIORITY_NORMAL, { + if (va_arg(args, int) == 0xAA && !fileProgressFlag_get(FILEPROG_38_RBB_OPEN)) { + *should = false; + } + }); +} + +// ------------------------------------------------------- Patch registration +void RegisterGruntchPatches() { + TooieJiggyDance_ForceEnable(); + Storybook_Enable(kGruntchStorybook); + ProximityDialogs_Enable(kGruntchGameplayDialogs); + Gruntch_EnableActGate(); + Gruntch_EnableConditionalActors(); + Gruntch_EnableMumboReward(); + Gruntch_EnablePauseTotalsLayout(); + Gruntch_EnableJiggyTally(); + HackShared_EnableDialogSuppression(kGruntchSuppressedDialogs); + + /* MISSING FEATURES + * Static camera pan for mumbo's reward + * Stealth minigame in Gruntch's room (RBB Kitchen) + * Possible retention of turbo trainers through cauldron warp + * Game over respawn to Gruntch Cave + */ +} diff --git a/src/port/UI/LighthouseMenuEnhancements.cpp b/src/port/UI/LighthouseMenuEnhancements.cpp index fa47e3106..7084c8792 100644 --- a/src/port/UI/LighthouseMenuEnhancements.cpp +++ b/src/port/UI/LighthouseMenuEnhancements.cpp @@ -77,16 +77,31 @@ void LighthouseMenu::AddMenuEnhancements() { AddWidget(path, "Allow Start to Skip Boot Logos", WIDGET_CVAR_CHECKBOX) .CVar(CVAR_ENHANCEMENT("Cutscenes.SkipBootLogos")) .RaceDisable(false) + .PreFunc([](WidgetInfo& info) { + if (mLighthouseMenu->disabledMap.at(DISABLE_FOR_ROMHACK).active) { + info.activeDisables.push_back(DISABLE_FOR_ROMHACK); + } + }) .Options(CheckboxOptions().Tooltip("Press Start to skip the Rareware and Nintendo logos on boot.")); AddWidget(path, "Allow Start to Skip Intro Cutscenes", WIDGET_CVAR_CHECKBOX) .CVar(CVAR_ENHANCEMENT("Cutscenes.StartSkipIntro")) .RaceDisable(false) + .PreFunc([](WidgetInfo& info) { + if (mLighthouseMenu->disabledMap.at(DISABLE_FOR_ROMHACK).active) { + info.activeDisables.push_back(DISABLE_FOR_ROMHACK); + } + }) .Options(CheckboxOptions().Tooltip("Press Start to Skip Intro Cutscenes.")); AddWidget(path, "Allow Start to Skip Misc Cutscenes", WIDGET_CVAR_CHECKBOX) .CVar(CVAR_ENHANCEMENT("Cutscenes.SkipMiscCutscenes")) .RaceDisable(false) + .PreFunc([](WidgetInfo& info) { + if (mLighthouseMenu->disabledMap.at(DISABLE_FOR_ROMHACK).active) { + info.activeDisables.push_back(DISABLE_FOR_ROMHACK); + } + }) .Options(CheckboxOptions().Tooltip("Press Start to skip the Gruntilda's Lair and Game Over cutscenes.")); AddWidget(path, "Skip Jiggy Dance", WIDGET_CVAR_CHECKBOX) @@ -297,11 +312,21 @@ void LighthouseMenu::AddMenuEnhancements() { AddWidget(path, "Fix CCW Gnawty Rock (Spring)", WIDGET_CVAR_CHECKBOX) .CVar(CVAR_ENHANCEMENT("Fixes.GnawtySpringRock")) .RaceDisable(false) + .PreFunc([](WidgetInfo& info) { + if (mLighthouseMenu->disabledMap.at(DISABLE_FOR_ROMHACK).active) { + info.activeDisables.push_back(DISABLE_FOR_ROMHACK); + } + }) .Options(CheckboxOptions().Tooltip("Makes Gnawty's rock indestructible in CCW Spring.")); AddWidget(path, "Fix Termite Mound Slopes", WIDGET_CVAR_CHECKBOX) .CVar(CVAR_ENHANCEMENT("Fixes.TermiteMoundSlopes")) .RaceDisable(false) + .PreFunc([](WidgetInfo& info) { + if (mLighthouseMenu->disabledMap.at(DISABLE_FOR_ROMHACK).active) { + info.activeDisables.push_back(DISABLE_FOR_ROMHACK); + } + }) .Options(CheckboxOptions().Tooltip("Makes slopes in the Mumbo's Mountain termite mound slide instantly.")); AddWidget(path, "Fix Early Claw Swipe During Slide", WIDGET_CVAR_CHECKBOX) @@ -347,6 +372,11 @@ void LighthouseMenu::AddMenuEnhancements() { AddWidget(path, "Fix Conga's Name", WIDGET_CVAR_CHECKBOX) .CVar(CVAR_ENHANCEMENT("Fixes.CongaText")) .RaceDisable(false) + .PreFunc([](WidgetInfo& info) { + if (mLighthouseMenu->disabledMap.at(DISABLE_FOR_ROMHACK).active) { + info.activeDisables.push_back(DISABLE_FOR_ROMHACK); + } + }) .Options(CheckboxOptions().Tooltip("Corrects a spelling error when meeting Conga as a termite.")); // Enhancements -> Restorations @@ -606,6 +636,11 @@ void LighthouseMenu::AddMenuEnhancements() { AddWidget(path, "Fast Transformation", WIDGET_CVAR_CHECKBOX) .CVar(CVAR_ENHANCEMENT("Cheats.FastTransform")) .RaceDisable(false) + .PreFunc([](WidgetInfo& info) { + if (mLighthouseMenu->disabledMap.at(DISABLE_FOR_ROMHACK).active) { + info.activeDisables.push_back(DISABLE_FOR_ROMHACK); + } + }) .Options(CheckboxOptions().Tooltip("Speeds up Mumbo transformation animation by 3x.")); AddWidget(path, "D-pad Cycle Transform", WIDGET_CVAR_CHECKBOX) @@ -617,6 +652,11 @@ void LighthouseMenu::AddMenuEnhancements() { AddWidget(path, "No Mumbo Untransform", WIDGET_CVAR_CHECKBOX) .CVar(CVAR_ENHANCEMENT("Cheats.NoMumboUntransform")) .RaceDisable(false) + .PreFunc([](WidgetInfo& info) { + if (mLighthouseMenu->disabledMap.at(DISABLE_FOR_ROMHACK).active) { + info.activeDisables.push_back(DISABLE_FOR_ROMHACK); + } + }) .Options(CheckboxOptions().Tooltip( "Disables Mumbo untransforming you when going too far and skips his warning dialog.")); diff --git a/src/port/UI/LighthouseModMenuWindow.cpp b/src/port/UI/LighthouseModMenuWindow.cpp index 90018371b..cd4adf8b1 100644 --- a/src/port/UI/LighthouseModMenuWindow.cpp +++ b/src/port/UI/LighthouseModMenuWindow.cpp @@ -466,7 +466,7 @@ static void DrawModInfo(std::string file) { using ModFilter = std::function; -static void DrawMods(bool enabled, const ModFilter& shown) { +static void DrawMods(bool enabled, const ModFilter& shown, bool alphabetical) { std::vector& selectedModFiles = GetModFiles(enabled); std::vector visible; @@ -482,10 +482,10 @@ static void DrawMods(bool enabled, const ModFilter& shown) { bool madeAnyChange = false; size_t switchFromIndex = 0; size_t switchToIndex = 0; + std::string pendingMoveFile; - // Highest priority (largest real index) draws at the top, matching the - // "top overrides bottom" rule. - for (size_t vpos = visible.size() - 1; vpos != SIZE_MAX; vpos--) { + for (size_t k = 0; k < visible.size(); k++) { + size_t vpos = alphabetical ? k : (visible.size() - 1 - k); size_t i = visible[vpos]; std::string file = selectedModFiles[i]; if (enabled) { @@ -496,14 +496,10 @@ static void DrawMods(bool enabled, const ModFilter& shown) { // (to the disabled list), disabled mods get an arrow pointing left. if (UIWidgets::StateButton((file + "_left_right").c_str(), enabled ? ICON_FA_ARROW_RIGHT : ICON_FA_ARROW_LEFT, ImVec2(25, 25), UIWidgets::ButtonOptions().Color(THEME_COLOR))) { - if (enabled) { - DisableMod(file); - } else { - EnableMod(file); - } + pendingMoveFile = file; } - if (enabled) { + if (enabled && !alphabetical) { const bool atTop = (vpos == visible.size() - 1); const bool atBottom = (vpos == 0); @@ -551,11 +547,19 @@ static void DrawMods(bool enabled, const ModFilter& shown) { std::iter_swap(selectedModFiles.begin() + switchFromIndex, selectedModFiles.begin() + switchToIndex); AfterModChange(); } + + if (!pendingMoveFile.empty()) { + if (enabled) { + DisableMod(pendingMoveFile); + } else { + EnableMod(pendingMoveFile); + } + } } static bool editing = false; -static void DrawModManager(const char* tableId, const ModFilter& shown) { +static void DrawModManager(const char* tableId, const ModFilter& shown, bool alphabetical = false) { auto editOpts = UIWidgets::ButtonOptions().Size(UIWidgets::Sizes::Inline).Color(THEME_COLOR); editOpts.Disabled(editing); editOpts.DisabledTooltip("Already editing..."); @@ -610,7 +614,7 @@ static void DrawModManager(const char* tableId, const ModFilter& shown) { ImGui::TableNextColumn(); if (ImGui::BeginChild("Enabled Mods", ImVec2(0, -8))) { - DrawMods(true, shown); + DrawMods(true, shown, alphabetical); ImGui::EndChild(); } @@ -618,7 +622,7 @@ static void DrawModManager(const char* tableId, const ModFilter& shown) { ImGui::TableNextColumn(); if (ImGui::BeginChild("Disabled Mods", ImVec2(0, -8))) { - DrawMods(false, shown); + DrawMods(false, shown, alphabetical); ImGui::EndChild(); } @@ -662,7 +666,10 @@ void LighthouseRomhackMenuWindow::DrawElement() { "Romhack overlays live in mods/~romhacks/. Changes require a restart, and only one\n" "romhack can be active at a time."); - DrawModManager("tableRomhacks", [](const std::string& name) { return IsRomhackOverlay(name); }); + // Romhacks are one-at-a-time, so there's no load order to preserve: list them + // alphabetically instead of by priority. + DrawModManager( + "tableRomhacks", [](const std::string& name) { return IsRomhackOverlay(name); }, true); } void LighthouseModMenuWindow::InitElement() { From ad4bd93ef7167204ba54452848c63047fad64b22 Mon Sep 17 00:00:00 2001 From: Malkierian Date: Sat, 25 Jul 2026 12:22:37 -0700 Subject: [PATCH 021/131] Mute Chimpy Stump on MM load enhancement. (#261) A bit of decomp catchup renaming. --- src/MM/ch/chimpystump.c | 6 +- src/port/Enhancements/Events/Hooks/Events.h | 2 + src/port/Enhancements/Fixes/GameFixes.cpp | 11 +++ src/port/Network/Anchor/DummyPlayer.cpp | 72 +++++++++---------- src/port/Network/Anchor/DummyPlayer.h | 14 ++-- .../Network/Anchor/Packets/PlayerUpdate.cpp | 22 +++--- src/port/UI/LighthouseMenuEnhancements.cpp | 9 ++- 7 files changed, 80 insertions(+), 56 deletions(-) diff --git a/src/MM/ch/chimpystump.c b/src/MM/ch/chimpystump.c index cd5aaf4fa..43c85bec8 100644 --- a/src/MM/ch/chimpystump.c +++ b/src/MM/ch/chimpystump.c @@ -34,7 +34,11 @@ void __chchimpystump_updateShaking(Actor *this) { if (this->unk10_12 == 0) { this->unk10_12 = 1; func_802BB3DC(1, 3.0f, 1.0f); - core1_7090_initSfxSource(0, 0x6A, 0x7FF8, 0.2f); + // [port] Vanilla replays Chimpy's walk-off, and with it this rise, on every entry to MM + // once his jiggy has spawned. The rumble can be muted for those replays. + if (EventSystem_Should(VB_MM_CHIMPY_STUMP_RUMBLE, true)) { + core1_7090_initSfxSource(0, 0x6A, 0x7FF8, 0.2f); + } }//L80386D0C this->position_x = ((globalTimer_getTime() & 1) * 2) ^ (s32) this->position_x; diff --git a/src/port/Enhancements/Events/Hooks/Events.h b/src/port/Enhancements/Events/Hooks/Events.h index 938f46a36..bb5256259 100644 --- a/src/port/Enhancements/Events/Hooks/Events.h +++ b/src/port/Enhancements/Events/Hooks/Events.h @@ -28,6 +28,8 @@ typedef enum VBehaviorID { VB_CLAW_SWIPE_SLIDE, VB_BOGGY_RACE_GAME_OVER, VB_JINJO_CHARGE_SOUND, + // MM Chimpy stump: gates the rumble sfx that starts when the stump begins shaking. + VB_MM_CHIMPY_STUMP_RUMBLE, VB_YUMYUM_DROP, VB_OVERRIDE_BOTTLES_TEXT_CALLBACK, VB_OVERRIDE_MOLEHILL_ABILITY, diff --git a/src/port/Enhancements/Fixes/GameFixes.cpp b/src/port/Enhancements/Fixes/GameFixes.cpp index ddb299fdb..af7be8b47 100644 --- a/src/port/Enhancements/Fixes/GameFixes.cpp +++ b/src/port/Enhancements/Fixes/GameFixes.cpp @@ -34,6 +34,7 @@ extern "C" int port_isInCharacterParade(void) { #define CVAR_JINJO_SOUND CVAR_ENHANCEMENT("Fixes.JinjoChargeSound") #define CVAR_GRUNTY_BOUNCE CVAR_ENHANCEMENT("Fixes.GruntyBounce") #define CVAR_CONGA_TEXT CVAR_ENHANCEMENT("Fixes.CongaText") +#define CVAR_STUMP_RUMBLE CVAR_ENHANCEMENT("Fixes.ChimpyStumpRumble") void RegisterVoidOutGameOver_Init() { COND_VB_SHOULD(VB_VOID_OUT_GAME_OVER, EVENT_PRIORITY_NORMAL, CVarGetInteger(CVAR_VOID_OUT, 0), @@ -140,6 +141,15 @@ void RegisterCongaDialog_Init() { }); } +// MM Chimpy stump: Chimpy respawns and walks off again on every entry to MM once his jiggy has +// spawned, so the stump drops in low and grinds back up with the rumble sfx each time. Mute the +// rumble for those replays only; the first rise (jiggy spawns 2.9s after the shake starts, so it +// isn't marked spawned yet) keeps its sound. +void RegisterChimpyStumpRumble_Init() { + COND_VB_SHOULD(VB_MM_CHIMPY_STUMP_RUMBLE, EVENT_PRIORITY_NORMAL, CVarGetInteger(CVAR_STUMP_RUMBLE, 1), + { *should = !jiggyscore_isSpawned(JIGGY_9_MM_CHIMPY); }); +} + // Mumbo token duplicate-id fix: rewrite the resolved id for the two tokens that share an id. void RegisterMumboTokenIdResolve_Init() { COND_HOOK(OnMumboTokenIdResolve, EVENT_PRIORITY_NORMAL, @@ -171,5 +181,6 @@ static RegisterShipInitFunc initJinjoChargeSoundFunc(RegisterJinjoChargeSound_In static RegisterShipInitFunc initGruntyBounceFunc(RegisterGruntyBounce_Init, { CVAR_GRUNTY_BOUNCE }); static RegisterShipInitFunc initYumYumDropFunc(RegisterYumYumDrop_Init); static RegisterShipInitFunc initCongaDialogFunc(RegisterCongaDialog_Init, { CVAR_CONGA_TEXT }); +static RegisterShipInitFunc initChimpyStumpRumbleFunc(RegisterChimpyStumpRumble_Init, { CVAR_STUMP_RUMBLE }); static RegisterShipInitFunc initMumboTokenIdResolveFunc(RegisterMumboTokenIdResolve_Init, { CVAR_TOKEN_MMM, CVAR_TOKEN_CCW }); diff --git a/src/port/Network/Anchor/DummyPlayer.cpp b/src/port/Network/Anchor/DummyPlayer.cpp index 930d41a5c..f04798ddb 100644 --- a/src/port/Network/Anchor/DummyPlayer.cpp +++ b/src/port/Network/Anchor/DummyPlayer.cpp @@ -59,12 +59,12 @@ void DummyPlayer::dummy_func_8029DBF0(void) { switch (dummy_getModelId()) { case ASSET_34D_MODEL_BANJOKAZOOIE_LOW_POLY: // L8029DC24 case ASSET_34E_MODEL_BANJOKAZOOIE_HIGH_POLY: // L8029DC24 - temp_s0 = (s32)ml_interpolate_f(dummy_modelEyeBlendUpper, 1.0f, 8.0f); + temp_s0 = (s32)ml_interpolate_f(dummy_banjoLeftEye, 1.0f, 8.0f); modelRender_setAppendageVisibility(0x1B, temp_s0); modelRender_setAppendageVisibility(0x1D, temp_s0); modelRender_setAppendageVisibility(0x1F, temp_s0); modelRender_setAppendageVisibility(0x21, temp_s0); - temp_s0 = (s32)ml_interpolate_f(dummy_modelEyeBlendLower, 1.0f, 8.0f); + temp_s0 = (s32)ml_interpolate_f(dummy_banjoRightEye, 1.0f, 8.0f); modelRender_setAppendageVisibility(0x1A, temp_s0); modelRender_setAppendageVisibility(0x1C, temp_s0); modelRender_setAppendageVisibility(0x1E, temp_s0); @@ -75,12 +75,12 @@ void DummyPlayer::dummy_func_8029DBF0(void) { case ASSET_359_MODEL_BANJO_WALRUS: // L8029DCCC case ASSET_36F_MODEL_BANJO_PUMPKIN: // L8029DCCC case ASSET_374_MODEL_BANJO_CROC: // L8029DCCC - modelRender_setAppendageVisibility(0x1B, (s32)ml_interpolate_f(dummy_modelEyeBlendUpper, 1.0f, 6.0f)); - modelRender_setAppendageVisibility(0x1A, (s32)ml_interpolate_f(dummy_modelEyeBlendLower, 1.0f, 6.0f)); + modelRender_setAppendageVisibility(0x1B, (s32)ml_interpolate_f(dummy_banjoLeftEye, 1.0f, 6.0f)); + modelRender_setAppendageVisibility(0x1A, (s32)ml_interpolate_f(dummy_banjoRightEye, 1.0f, 6.0f)); break; case ASSET_356_MODEL_BANJO_WISHYWASHY: // L8029DD2C - modelRender_setAppendageVisibility(1, (s32)ml_interpolate_f(dummy_modelEyeBlendLower, 1.0f, 4.0f)); + modelRender_setAppendageVisibility(1, (s32)ml_interpolate_f(dummy_banjoRightEye, 1.0f, 4.0f)); break; } } @@ -90,8 +90,8 @@ AnimCtrl* DummyPlayer::dummy_getAnimCtrl() { } void DummyPlayer::dummy_setEyeState(bool squint, bool wink, bool isHat) { - dummy_modelSquint = squint; - dummy_modelWink = wink; + dummy_kazooieLower = squint; + dummy_kazooieFeet = wink; dummy_D_8037D230 = 1.0f; dummy_D_8037D234 = isHat; } @@ -103,19 +103,19 @@ void DummyPlayer::modelAppendages_loadAppendage(void) { switch (dummy_getModelId()) { case ASSET_34D_MODEL_BANJOKAZOOIE_LOW_POLY: case ASSET_34E_MODEL_BANJOKAZOOIE_HIGH_POLY: - modelRender_setAppendageVisibility(1, dummy_kazooieVisible); - modelRender_setAppendageVisibility(9, dummy_kazooieVisible); - modelRender_setAppendageVisibility(0xC, dummy_kazooieVisible); - modelRender_setAppendageVisibility(0xF, dummy_kazooieVisible); - modelRender_setAppendageVisibility(2, dummy_modelWink); - modelRender_setAppendageVisibility(0xA, dummy_modelWink); - modelRender_setAppendageVisibility(0xD, dummy_modelWink); - modelRender_setAppendageVisibility(0x10, dummy_modelWink); - modelRender_setAppendageVisibility(8, dummy_modelSquint); - modelRender_setAppendageVisibility(0xB, dummy_modelSquint); - modelRender_setAppendageVisibility(0xE, dummy_modelSquint); - modelRender_setAppendageVisibility(0x11, dummy_modelSquint); - temp_s0 = dummy_modelMouth1 + 1; + modelRender_setAppendageVisibility(1, dummy_kazooieUpper); + modelRender_setAppendageVisibility(9, dummy_kazooieUpper); + modelRender_setAppendageVisibility(0xC, dummy_kazooieUpper); + modelRender_setAppendageVisibility(0xF, dummy_kazooieUpper); + modelRender_setAppendageVisibility(2, dummy_kazooieFeet); + modelRender_setAppendageVisibility(0xA, dummy_kazooieFeet); + modelRender_setAppendageVisibility(0xD, dummy_kazooieFeet); + modelRender_setAppendageVisibility(0x10, dummy_kazooieFeet); + modelRender_setAppendageVisibility(8, dummy_kazooieLower); + modelRender_setAppendageVisibility(0xB, dummy_kazooieLower); + modelRender_setAppendageVisibility(0xE, dummy_kazooieLower); + modelRender_setAppendageVisibility(0x11, dummy_kazooieLower); + temp_s0 = dummy_kazooieTurbos + 1; modelRender_setAppendageVisibility(0x12, temp_s0); modelRender_setAppendageVisibility(0x14, temp_s0); modelRender_setAppendageVisibility(0x16, temp_s0); @@ -124,7 +124,7 @@ void DummyPlayer::modelAppendages_loadAppendage(void) { modelRender_setAppendageVisibility(0x15, temp_s0); modelRender_setAppendageVisibility(0x17, temp_s0); modelRender_setAppendageVisibility(0x19, temp_s0); - temp_s0 = dummy_modelMouth2 + 1; + temp_s0 = dummy_kazooieBoots + 1; modelRender_setAppendageVisibility(0x22, temp_s0); modelRender_setAppendageVisibility(0x24, temp_s0); modelRender_setAppendageVisibility(0x26, temp_s0); @@ -138,7 +138,7 @@ void DummyPlayer::modelAppendages_loadAppendage(void) { modelRender_setAppendageVisibility(3, dummy_D_8037D23A); break; case ASSET_374_MODEL_BANJO_CROC: - temp_s0 = dummy_modelMouth1 + 1; + temp_s0 = dummy_kazooieTurbos + 1; modelRender_setAppendageVisibility(4, temp_s0); modelRender_setAppendageVisibility(5, temp_s0); modelRender_setAppendageVisibility(6, temp_s0); @@ -320,13 +320,13 @@ void DummyPlayer::dummy_free(void) { void DummyPlayer::dummyAnim_reset() { dummy_D_8037D230 = 0; dummy_D_8037D234 = 0; - dummy_kazooieVisible = 0; - dummy_modelWink = 0; - dummy_modelSquint = 0; - dummy_modelEyeBlendUpper = 0.0f; - dummy_modelEyeBlendLower = 0.0f; - dummy_modelMouth1 = 0; - dummy_modelMouth2 = 0; + dummy_kazooieUpper = 0; + dummy_kazooieFeet = 0; + dummy_kazooieLower = 0; + dummy_banjoLeftEye = 0.0f; + dummy_banjoRightEye = 0.0f; + dummy_kazooieTurbos = 0; + dummy_kazooieBoots = 0; dummy_D_8037D23A = 0; } @@ -544,13 +544,13 @@ void DummyPlayer::dummyAnim_update(void) { void DummyPlayer::setModelSubStates(bool kazooie, bool squint, bool wink, bool mouth1, bool mouth2, f32 eyeBlendUpper, f32 eyeBlendLower) { - dummy_kazooieVisible = kazooie; - dummy_modelSquint = squint; - dummy_modelWink = wink; - dummy_modelMouth1 = mouth1; - dummy_modelMouth2 = mouth2; - dummy_modelEyeBlendUpper = eyeBlendUpper; - dummy_modelEyeBlendLower = eyeBlendLower; + dummy_kazooieUpper = kazooie; + dummy_kazooieLower = squint; + dummy_kazooieFeet = wink; + dummy_kazooieTurbos = mouth1; + dummy_kazooieBoots = mouth2; + dummy_banjoLeftEye = eyeBlendUpper; + dummy_banjoRightEye = eyeBlendLower; } void DummyPlayer::dummyAnim_setUpdateType(s32 state) { diff --git a/src/port/Network/Anchor/DummyPlayer.h b/src/port/Network/Anchor/DummyPlayer.h index 860e11f52..825e36091 100644 --- a/src/port/Network/Anchor/DummyPlayer.h +++ b/src/port/Network/Anchor/DummyPlayer.h @@ -128,14 +128,14 @@ class DummyPlayer { f32 dummy_D_8037D230; u8 dummy_D_8037D234; - u8 dummy_modelSquint; - u8 dummy_modelWink; - u8 dummy_modelMouth1; - u8 dummy_kazooieVisible; - u8 dummy_modelMouth2; + u8 dummy_kazooieLower; + u8 dummy_kazooieFeet; + u8 dummy_kazooieTurbos; + u8 dummy_kazooieUpper; + u8 dummy_kazooieBoots; u8 dummy_D_8037D23A; - f32 dummy_modelEyeBlendUpper; - f32 dummy_modelEyeBlendLower; + f32 dummy_banjoLeftEye; + f32 dummy_banjoRightEye; Transformation dummy_transformation; s32 dummyBottlesBonus = 0; }; \ No newline at end of file diff --git a/src/port/Network/Anchor/Packets/PlayerUpdate.cpp b/src/port/Network/Anchor/Packets/PlayerUpdate.cpp index d42f8e5e6..71987a608 100644 --- a/src/port/Network/Anchor/Packets/PlayerUpdate.cpp +++ b/src/port/Network/Anchor/Packets/PlayerUpdate.cpp @@ -173,13 +173,13 @@ void Anchor::SendPacket_PlayerUpdate(bool full, uint32_t targetClientId) { anctrl_getSubRange(baanim_getAnimCtrlPtr(), &sub_start, &sub_end); payload["subrange_end"] = sub_end; } - payload["kazooieVisible"] = modelAppendages_showKazooiesUpperHalf(); // Kazooie visibility (Kazooie popped out) - payload["modelSquint"] = modelAppendages_showKazooiesAss(); // Kazooie's ass visibility - payload["modelWink"] = modelAppendages_showKazooiesFeetAndShoes(); // Kazooie's feet & shoes visibility - payload["modelMouth1"] = modelAppendages_hideTurboTrainers(); // turbo trainers hidden - payload["modelMouth2"] = modelAppendages_hideWadingBoots(); // wading boots hidden - payload["modelEyeBlendUpper"] = modelAppendages_showBanjosLeftEye(); // Banjo's left eye blend - payload["modelEyeBlendLower"] = modelAppendages_showBanjosRightEye(); // Banjo's right eye blend + payload["kazooieUpper"] = modelAppendages_showKazooiesUpperHalf(); + payload["kazooieLower"] = modelAppendages_showKazooiesAss(); + payload["kazooieFeet"] = modelAppendages_showKazooiesFeetAndShoes(); + payload["kazooieTurbos"] = modelAppendages_hideTurboTrainers(); + payload["kazooieBoots"] = modelAppendages_hideWadingBoots(); + payload["banjoLeftEye"] = modelAppendages_showBanjosLeftEye(); + payload["banjoRightEye"] = modelAppendages_showBanjosRightEye(); payload["bottlesBonus"] = baanim_getActiveBottlesBonusMask(); { // Carried-collectible marker id (0 = none); skipped once thrown (unk138_21 = in flight). @@ -263,10 +263,10 @@ void Anchor::HandlePacket_PlayerUpdate(nlohmann::json& payload) { (AnimControl)payload.value("anim_control", (int)ANIMCTRL_LOOP), 0.0f, payload.value("subrange_end", 1.0f), false); } - client.dummy->setModelSubStates(payload.value("kazooieVisible", false), payload.value("modelSquint", false), - payload.value("modelWink", false), payload.value("modelMouth1", false), - payload.value("modelMouth2", false), payload.value("modelEyeBlendUpper", 0.0f), - payload.value("modelEyeBlendLower", 0.0f)); + client.dummy->setModelSubStates(payload.value("kazooieUpper", false), payload.value("kazooieLower", false), + payload.value("kazooieFeet", false), payload.value("kazooieTurbos", false), + payload.value("kazooieBoots", false), payload.value("banjoLeftEye", 0.0f), + payload.value("banjoRightEye", 0.0f)); client.dummy->dummy_setBottlesBonus(payload.value("bottlesBonus", 0)); { f32 carryOff[3] = { 0.0f, 0.0f, 0.0f }; diff --git a/src/port/UI/LighthouseMenuEnhancements.cpp b/src/port/UI/LighthouseMenuEnhancements.cpp index 7084c8792..595d1e8a3 100644 --- a/src/port/UI/LighthouseMenuEnhancements.cpp +++ b/src/port/UI/LighthouseMenuEnhancements.cpp @@ -354,6 +354,13 @@ void LighthouseMenu::AddMenuEnhancements() { .RaceDisable(false) .Options(CheckboxOptions().Tooltip("Stops the Jinjo charge-up sound the instant it hits Grunty.")); + AddWidget(path, "Mute Chimpy Stump Replay", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("Fixes.ChimpyStumpRumble")) + .RaceDisable(false) + .Options(CheckboxOptions().DefaultValue(true).Tooltip( + "Mutes the rumbling sound when Chimpy's stump rises again on every return trip to " + "Mumbo's Mountain. The first rise keeps its sound.")); + AddWidget(path, "Fix Cutscene Audio Sync", WIDGET_CVAR_CHECKBOX) .CVar(CVAR_ENHANCEMENT("Fix.CutsceneSync")) .RaceDisable(false) @@ -647,7 +654,7 @@ void LighthouseMenu::AddMenuEnhancements() { .CVar(CVAR_ENHANCEMENT("Cheats.CycleTransform")) .RaceDisable(false) .Options(CheckboxOptions().Tooltip("Press D-pad Up/Down to cycle through transformation forms.\nUp: Forward " - "(Banjo→Mumbo→...→Wishy→Banjo), Down: Backward.")); + "(Banjo→Termite→...→Bee→Banjo), Down: Backward.")); AddWidget(path, "No Mumbo Untransform", WIDGET_CVAR_CHECKBOX) .CVar(CVAR_ENHANCEMENT("Cheats.NoMumboUntransform")) From c462c06d9c155eb1ebf3bb77824410bb22a86548 Mon Sep 17 00:00:00 2001 From: Malkierian Date: Sat, 25 Jul 2026 12:45:44 -0700 Subject: [PATCH 022/131] Fix romhack extern. --- src/port/Romhack/Specific/CutThroatCoast.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/port/Romhack/Specific/CutThroatCoast.cpp b/src/port/Romhack/Specific/CutThroatCoast.cpp index 01223d183..4ef92627e 100644 --- a/src/port/Romhack/Specific/CutThroatCoast.cpp +++ b/src/port/Romhack/Specific/CutThroatCoast.cpp @@ -13,7 +13,7 @@ extern "C" { extern struct1Cs_1 D_8036C58C[0xD]; // Acorn replaced with collectible doubloon -extern ActorInfo D_8038F460; +extern ActorInfo chCarriedAcorn; void chCarriedAcorn_update(Actor* thisx); typedef struct { @@ -147,7 +147,7 @@ extern "C" void CutThroatCoast_DoubloonUpdate(Actor* thisx) { void RegisterCutThroatCoastPatches() { RebuildPauseMenuTable(); ApplyDataPatches(); - D_8038F460.update_func = CutThroatCoast_DoubloonUpdate; + chCarriedAcorn.update_func = CutThroatCoast_DoubloonUpdate; // Sweep the lighthouse beam REGISTER_LISTENER(GameFrameUpdate, EVENT_PRIORITY_NORMAL, [](IEvent* event) { From c8840f17a09a3a28288ffcacd02f09bf1790d9f0 Mon Sep 17 00:00:00 2001 From: Malkierian Date: Sat, 25 Jul 2026 13:33:33 -0700 Subject: [PATCH 023/131] Fix Windows and Macports workflows. --- .github/macports.yml | 2 ++ .github/workflows/main.yml | 8 ++++---- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/.github/macports.yml b/.github/macports.yml index 976224723..de075020d 100644 --- a/.github/macports.yml +++ b/.github/macports.yml @@ -1,6 +1,8 @@ ports: - name: libsdl2 select: [ universal ] + - name: libsdl2_net + select: [ universal ] - name: libpng select: [ universal ] - name: glew diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 8fb69d3a2..8be3f18b1 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -63,14 +63,14 @@ jobs: uses: actions/download-artifact@v4 with: name: lighthouse.o2r - path: ./build/x64/Release + path: ./build/x64 - name: Create Package run: | mkdir lighthouse-release mkdir lighthouse-release/debug - mv build/x64/Release/Lighthouse.exe lighthouse-release/ - mv build/x64/Release/lighthouse.o2r lighthouse-release/ - mv build/x64/Release/*.pdb lighthouse-release/debug/ + mv build/x64/Lighthouse.exe lighthouse-release/ + mv build/x64/lighthouse.o2r lighthouse-release/ + mv build/x64/*.pdb lighthouse-release/ mv README.md lighthouse-release/readme.txt mv config.yml lighthouse-release/ mv assets lighthouse-release/ From d045fb810f1761256eec9c822b46a74e1b157194 Mon Sep 17 00:00:00 2001 From: Jeod <47716344+JeodC@users.noreply.github.com> Date: Sat, 25 Jul 2026 22:34:39 -0400 Subject: [PATCH 024/131] Linux compile errors and a couple decomp pass bugs (#262) --- include/functions.h | 11 +++++++---- src/BGS/ch/croctus.c | 8 +++----- src/BGS/ch/pinkegg.c | 2 +- src/BGS/ch/tiptup.c | 4 ++-- src/CCW/ch/ccwgobi.c | 8 ++++---- src/CCW/ch/indoorsgnawty.c | 4 ++-- src/CCW/zubba_hive_npc.c | 4 ++-- src/FP/ma/slalom.c | 2 +- src/MM/ch/conga.c | 3 +-- src/MM/ch/jujuhitbox.c | 2 +- src/MMM/ch/tumblar.c | 3 ++- src/SM/ch/attacktutorial.c | 2 +- src/SM/smspawnqueue.c | 1 - src/core2/actor_array.c | 1 - src/core2/anim/anim_defrag.c | 2 +- src/core2/ba/marker.c | 1 - src/core2/ch/jiggy.h | 1 - src/core2/ch/levelcollectible.c | 4 ++-- src/core2/collision/filter.c | 18 +++++++++--------- src/core2/dialog/binload.c | 3 ++- src/core2/fx/badShad.c | 2 +- src/core2/mumboshandwithpicture.c | 5 ++--- src/core2/nc/camera_nodemanager.c | 2 +- src/core2/spawnqueue.c | 30 +++++++++++++++--------------- src/fight/chfinalboss.c | 1 - src/port/ResourceHelpers.cpp | 9 +++++++-- 26 files changed, 67 insertions(+), 66 deletions(-) diff --git a/include/functions.h b/include/functions.h index 1112a3c6c..90dac6627 100644 --- a/include/functions.h +++ b/include/functions.h @@ -561,13 +561,16 @@ void func_80293D48(f32, f32); void func_80343DEC(Actor *self); // --- core2/spawnqueue.c --- -void __spawnQueue_add_0(void (*arg0)(void)); -void __spawnQueue_add_2(void (*arg0)(void), uintptr_t arg1, uintptr_t arg2); Actor *spawnQueue_actor_f32(enum actor_e actor_id, uintptr_t x, uintptr_t y, uintptr_t z); +Actor *spawnQueue_actor_s32(uintptr_t actor_id, uintptr_t x, uintptr_t y, uintptr_t z); +Actor *spawnQueue_actor_s16(uintptr_t actor_id, uintptr_t x, uintptr_t y, uintptr_t z); +void __spawnQueue_add_0(GenFunction_0); void __spawnQueue_add_1(GenFunction_1, uintptr_t); -#define SPAWNQUEUE_ADD_1(method, arg0) __spawnQueue_add_1((GenFunction_1) (method), reinterpret_cast(uintptr_t, (arg0))) +void __spawnQueue_add_2(GenFunction_2, uintptr_t, uintptr_t); void __spawnQueue_add_3(GenFunction_3, uintptr_t, uintptr_t, uintptr_t); void __spawnQueue_add_4(GenFunction_4, uintptr_t, uintptr_t, uintptr_t, uintptr_t); +void __spawnQueue_add_5(GenFunction_5, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t); +#define SPAWNQUEUE_ADD_1(method, arg0) __spawnQueue_add_1((GenFunction_1) (method), reinterpret_cast(uintptr_t, (arg0))) // --- core2/fx/commonParticle.c --- void commonParticle_add(ActorMarker *arg0, s32 arg1, FuncUnk40 arg2); @@ -2266,7 +2269,7 @@ void func_802E4214(enum map_e map_id); void func_802E4384(void); void func_802E4A70(void); void func_802E4A80(void); -void game_draw(s32 arg0); +void game_draw(bool arg0); // --- core2/frame/rendermem.c --- void dummy_func_802E35D0(void); diff --git a/src/BGS/ch/croctus.c b/src/BGS/ch/croctus.c index cd1db93c0..6c429088b 100644 --- a/src/BGS/ch/croctus.c +++ b/src/BGS/ch/croctus.c @@ -14,7 +14,6 @@ extern void func_80324CFC(f32, enum comusic_e, s32); extern void func_803289EC(Actor *, f32, s32); extern void func_80326310(Actor *); extern void actor_setOpacity(Actor *, s32); -extern void __spawnQueue_add_2(void (*)(s32, s32), s32, s32); extern void gcStaticCamera_activate(s32 arg0); void func_80387D18(ActorMarker *, u32); @@ -86,12 +85,11 @@ void *chCroctus_jiggySpawn(ActorMarker * arg0){ coMusicPlayer_playMusic(COMUSIC_2D_PUZZLE_SOLVED_FANFARE, 0x7FFF); } -void func_80387E00(s32 arg0){ - ActorMarker *marker = reinterpret_cast(ActorMarker *, arg0); - Actor * this = marker_getActor(marker); +void func_80387E00(ActorMarker *arg0){ + Actor * this = marker_getActor(arg0); func_803262E4(this); - __spawnQueue_add_2((GenFunction_2)func_80387D18, reinterpret_cast(uintptr_t, marker), 0x1E); + __spawnQueue_add_2((GenFunction_2)func_80387D18, reinterpret_cast(uintptr_t, arg0), 0x1E); } void func_80387E40(ActorMarker * arg0){ diff --git a/src/BGS/ch/pinkegg.c b/src/BGS/ch/pinkegg.c index 2c12b5e50..1e513513d 100644 --- a/src/BGS/ch/pinkegg.c +++ b/src/BGS/ch/pinkegg.c @@ -95,7 +95,7 @@ void chPinkEgg_collision(ActorMarker *this, ActorMarker *other_marker){ tmp = (ActorLocal_PinkEgg *) &thisActor->local; port_puzzleStep_orBits(ANCHOR_PUZZLE_BGS_PINKEGG, 1 << tmp->unk0); if(D_803906C4[tmp->unk0] != 0){ - __spawnQueue_add_2((void (*)(void))chPinkEgg_spawnNext, (uintptr_t)thisActor->marker, tmp->unk0); + __spawnQueue_add_2((GenFunction_2)chPinkEgg_spawnNext, (uintptr_t)thisActor->marker, tmp->unk0); } else if(!jiggyscore_isSpawned(JIGGY_21_BGS_PINKEGG)){ jiggy_spawn(JIGGY_21_BGS_PINKEGG, thisActor->position); coMusicPlayer_playMusic(COMUSIC_2D_PUZZLE_SOLVED_FANFARE, 28000); diff --git a/src/BGS/ch/tiptup.c b/src/BGS/ch/tiptup.c index a4d4cf73b..cf2bd5323 100644 --- a/src/BGS/ch/tiptup.c +++ b/src/BGS/ch/tiptup.c @@ -31,14 +31,14 @@ ActorInfo gChTiptup = { }; s16 chTiptupRepeatDialogs[] = { - NULL, + 0, // [port] decomp uses NULL; these are asset ids, not pointers VER_SELECT(ASSET_C78_DIALOG_TIPTUP_LESSON_1_REPEAT, 0x9BB, 0, 0), VER_SELECT(ASSET_C7A_DIALOG_TIPTUP_LESSON_2_REPEAT, 0x9BD, 0, 0), VER_SELECT(ASSET_C7C_DIALOG_TIPTUP_LESSON_3_REPEAT, 0x9BF, 0, 0) }; s16 chTiptupSuccessDialogs[] = { - NULL, + 0, // [port] decomp uses NULL; these are asset ids, not pointers VER_SELECT(ASSET_C77_DIALOG_TIPTUP_LESSON_1_COMPLETE, 0x9BA, 0, 0), VER_SELECT(ASSET_C79_DIALOG_TIPTUP_LESSON_2_COMPLETE, 0x9BC, 0, 0), VER_SELECT(ASSET_C7B_DIALOG_TIPTUP_LESSON_3_COMPLETE, 0x9BE, 0, 0) diff --git a/src/CCW/ch/ccwgobi.c b/src/CCW/ch/ccwgobi.c index 945a72d3e..3b1525d25 100644 --- a/src/CCW/ch/ccwgobi.c +++ b/src/CCW/ch/ccwgobi.c @@ -26,12 +26,12 @@ CH_CCW_Gobi_Dialogs chCCWGobiDialogs[] = { MAP_44_CCW_SUMMER, VER_SELECT(ASSET_CDE_DIALOG_CCW_GOBI_MEET_SUMMER, 0x09F3, 0, 0), VER_SELECT(ASSET_CDF_DIALOG_CCW_GOBI_COMPLETE_SUMMER, 0x09F4, 0, 0), - NULL + 0 // [port] decomp uses NULL; dialog fields are asset ids, not pointers }, { MAP_45_CCW_AUTUMN, - NULL, - NULL, + 0, + 0, VER_SELECT(ASSET_CE0_DIALOG_CCW_GOBI_COMPLETE_FALL, 0x09F5, 0, 0) }, { 0 } // [port] decomp uses NULL; first field is an integer and clang errors on -Wint-conversion @@ -69,7 +69,7 @@ void chCCWGobi_setState(Actor *this, s32 next_state) { skeletalAnim_set(this->unk148, ASSET_F4_ANIM_GOBI_IDLE, 0.5f, 12.0f); } if (next_state == CH_CCW_GOBI_STATE_2_SPITTING) { - if (local->dialogs->summerCompleteDialog != NULL) { + if (local->dialogs->summerCompleteDialog != 0) { gcdialog_showDialog(local->dialogs->summerCompleteDialog, 4, NULL, NULL, NULL, NULL); } skeletalAnim_set(this->unk148, ASSET_FC_ANIM_GOBI_SPITTING, 0.2f, 3.0f); diff --git a/src/CCW/ch/indoorsgnawty.c b/src/CCW/ch/indoorsgnawty.c index dd9facb2d..325748fa0 100644 --- a/src/CCW/ch/indoorsgnawty.c +++ b/src/CCW/ch/indoorsgnawty.c @@ -21,7 +21,7 @@ CH_Indoors_Gnawty_Dialogs chIndoorsGnawtyDialogs[] = { { MAP_45_CCW_AUTUMN, VER_SELECT(ASSET_CD2_DIALOG_GNAWTY_MEET_FALL_INSIDE, 0x9E7, 0, 0), - NULL + 0 // [port] decomp uses NULL; dialog fields are asset ids, not pointers }, { MAP_46_CCW_WINTER, @@ -70,7 +70,7 @@ void chIndoorsGnawty_update(Actor *this) { this->volatile_initialized = true; this->has_met_before = false; local->dialogs = chIndoorsGnawtyDialogs; - while (local->dialogs->map != NULL && gsworld_getMap() != local->dialogs->map) { + while (local->dialogs->map != 0 && gsworld_getMap() != local->dialogs->map) { local->dialogs++; } diff --git a/src/CCW/zubba_hive_npc.c b/src/CCW/zubba_hive_npc.c index 499b1abb7..d6097dbbb 100644 --- a/src/CCW/zubba_hive_npc.c +++ b/src/CCW/zubba_hive_npc.c @@ -37,7 +37,7 @@ Zubba_Docile_Dialog chZubbaDocileDialog[] = { { MAP_5C_CCW_AUTUMN_ZUBBA_HIVE, CCW_ZUBBA_SPECIFIC_FLAG_8_AUTUMN_DIALOG, - NULL, + 0, // [port] decomp uses NULL; jiggyId is an integer, not a pointer VER_SELECT(ASSET_CE5_DIALOG_ZUBBA_MEET_FALL, 0x09FA, 0, 0) }, { 0 } // [port] decomp uses NULL; first field is an integer and clang errors on -Wint-conversion @@ -96,7 +96,7 @@ void chZubbaDocile_update(Actor *this) { this->volatile_initialized = true; this->marker->actorFreeFunc = chZubbaDocile_free; local->dialog = &chZubbaDocileDialog[0]; - while((local->dialog->map != NULL) && (gsworld_getMap() != local->dialog->map)) { + while((local->dialog->map != 0) && (gsworld_getMap() != local->dialog->map)) { local->dialog++; } local->sfxsourceIdx = sfxsource_createSfxsourceAndReturnIndex(); diff --git a/src/FP/ma/slalom.c b/src/FP/ma/slalom.c index fc25a098d..293d651c7 100644 --- a/src/FP/ma/slalom.c +++ b/src/FP/ma/slalom.c @@ -127,7 +127,7 @@ void __maSlalom_spawnGate(s32 indx, s32 arg1){ } void maSlalom_spawnGate(s32 indx, s32 arg1){ - __spawnQueue_add_2((void (*)(void))__maSlalom_spawnGate, indx, arg1); + __spawnQueue_add_2((GenFunction_2)__maSlalom_spawnGate, indx, arg1); } void __maSlalom_despawnGate(s32 indx){ diff --git a/src/MM/ch/conga.c b/src/MM/ch/conga.c index 0fa98a1b5..e3d799e09 100644 --- a/src/MM/ch/conga.c +++ b/src/MM/ch/conga.c @@ -21,7 +21,6 @@ void subaddie_turnToYaw(Actor *, f32); void subaddie_set_state_with_direction(Actor*, s32, f32, s32); void bundle_setYaw(f32); void timed_exitStaticCamera(f32); -Actor *actor_spawnWithYaw_s32(s32 actor_id, s32 position[3], s32 yaw); void MM_checkMMChecksums(void); void chConga_update(Actor *); @@ -187,7 +186,7 @@ void __chConga_sendOrangeProjectile(ActorMarker *congaMarker){ congaPtr->unk10_12 -= (congaPtr->unk10_12 && ( conga_state == 7)); MM_checkMMChecksums(); congaPtr->actor_specific_1_f = 2.0f; - orangePtr = actor_spawnWithYaw_s32(ACTOR_14_ORANGE_PROJECTILE, conga_localPtr->orangeSpawnPosition, congaPtr->yaw); + orangePtr = actor_spawnWithYaw_s32(ACTOR_14_ORANGE_PROJECTILE, &conga_localPtr->orangeSpawnPosition, congaPtr->yaw); if(orangePtr != NULL){ player_getPosition(plyr.pos); diff --git a/src/MM/ch/jujuhitbox.c b/src/MM/ch/jujuhitbox.c index 016fbc12c..8fb9b5c0d 100644 --- a/src/MM/ch/jujuhitbox.c +++ b/src/MM/ch/jujuhitbox.c @@ -146,7 +146,7 @@ void chjujuhitbox_update(Actor *this) { marker_despawn(this->marker); return; } - __spawnQueue_add_2((void (*)(void)) __chjujuhitbox_initialize_all, (uintptr_t)this->marker, jujuCtlPtr->unk4); + __spawnQueue_add_2((GenFunction_2) __chjujuhitbox_initialize_all, (uintptr_t)this->marker, jujuCtlPtr->unk4); __chjujuhitbox_playRubbingSfx(this); return; } diff --git a/src/MMM/ch/tumblar.c b/src/MMM/ch/tumblar.c index b0e74dd94..6a234fe65 100644 --- a/src/MMM/ch/tumblar.c +++ b/src/MMM/ch/tumblar.c @@ -126,7 +126,8 @@ void __chTumblar_congratulationTextCallback(ActorMarker *marker, enum asset_e te mapSpecificFlags_set(MMM_SPECIFIC_FLAG_TUMBLAR_BROKEN, true); } -void chTumblar_congratulate(Struct_MMM_47D0_0 *arg0, s32 arg1) { +void chTumblar_congratulate(void *arg0_, s32 arg1) { + Struct_MMM_47D0_0 *arg0 = (Struct_MMM_47D0_0 *)arg0_; gcdialog_showDialog(VER_SELECT(ASSET_ADB_DIALOG_TUMBLAR_COMPLETE, 0x94D, 0, 0), 4, NULL, arg0->jiggy_marker, __chTumblar_congratulationTextCallback, NULL); arg0->state = TUMBLAR_STATE_1_CONGRATULATING; } diff --git a/src/SM/ch/attacktutorial.c b/src/SM/ch/attacktutorial.c index 4fb42b15f..130fc3fcf 100644 --- a/src/SM/ch/attacktutorial.c +++ b/src/SM/ch/attacktutorial.c @@ -59,7 +59,7 @@ static s32 __chAttackTutorial_spawnEnemyActor(Actor *this, s32 already_killed_en : ACTOR_164_COLLYWOBBLE_THE_CAULIFLOWER_A; } - __spawnQueue_add_2((void (*)(void))__chAttackTutorial_spawnEnemyActorForMarker, (uintptr_t)this->marker, sp1C); + __spawnQueue_add_2((GenFunction_2)__chAttackTutorial_spawnEnemyActorForMarker, (uintptr_t)this->marker, sp1C); return 0; } diff --git a/src/SM/smspawnqueue.c b/src/SM/smspawnqueue.c index a22fff34e..45e81f3b1 100644 --- a/src/SM/smspawnqueue.c +++ b/src/SM/smspawnqueue.c @@ -6,7 +6,6 @@ #include "actor.h" #include "checksums.h" -int ability_hasLearned(s32); diff --git a/src/core2/actor_array.c b/src/core2/actor_array.c index 100a6ede3..28a07620c 100644 --- a/src/core2/actor_array.c +++ b/src/core2/actor_array.c @@ -31,7 +31,6 @@ f32 player_getYaw(void); extern void func_8032B3A0(Actor *, ActorMarker *); extern void func_8032EE0C(GenFunction_2, uintptr_t); extern void func_8032EE20(void); -extern void __spawnQueue_add_5(GenFunction_5, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t); void func_8032A6A8(Actor *arg0); diff --git a/src/core2/anim/anim_defrag.c b/src/core2/anim/anim_defrag.c index 10767a17d..33b82d692 100644 --- a/src/core2/anim/anim_defrag.c +++ b/src/core2/anim/anim_defrag.c @@ -33,7 +33,7 @@ MtxF *animMtxList_get(AnimMtxList *this, s32 arg1){ } // [port] bounds check - on N64 this never happens but corrupt data can cause OOB if (arg1 < 0 || arg1 >= this->size) { - BK_LOG_WARN("[port] animMtxList_get: OOB index %d (size=%d)", arg1, this->size); + BK_LOG_WARN("animMtxList_get: OOB index %d (size=%d)", arg1, this->size); return &this->default_matrix; // fallback to identity } return &this->data[arg1]; diff --git a/src/core2/ba/marker.c b/src/core2/ba/marker.c index d6431fd47..82519a10e 100644 --- a/src/core2/ba/marker.c +++ b/src/core2/ba/marker.c @@ -11,7 +11,6 @@ extern void func_803012F8(void); extern void __baMarker_8028BA00(s32); -extern Actor *spawnQueue_actor_s16(uintptr_t, uintptr_t, uintptr_t, uintptr_t); extern void func_802A6388(f32); extern f32 chwadingboots_802D6E4C(Actor *); extern void set_turbo_duration(f32); diff --git a/src/core2/ch/jiggy.h b/src/core2/ch/jiggy.h index 96c5c1c1d..b66c45a28 100644 --- a/src/core2/ch/jiggy.h +++ b/src/core2/ch/jiggy.h @@ -7,7 +7,6 @@ typedef struct chjiggy_s { u32 id; } ActorLocal_Jiggy; -Actor *spawnQueue_actor_s32(f32, f32, f32); Actor *chjiggy_draw(ActorMarker *this, Gfx **gdl, Mtx **mptr, Vtx **arg3); void chjiggy_update_2(Actor * arg0); void chjiggy_update(Actor *this); diff --git a/src/core2/ch/levelcollectible.c b/src/core2/ch/levelcollectible.c index f93c8b323..2591e199d 100644 --- a/src/core2/ch/levelcollectible.c +++ b/src/core2/ch/levelcollectible.c @@ -179,7 +179,7 @@ void port_remoteCarry_setCarried(u32 clientId, s32 markerId, f32 offset[3], f32 sRemoteCarry[slot].marker = NULL; sRemoteCarry[slot].throwPending = 0; __remoteCarry_setPose(slot, offset, yawOffset); - __spawnQueue_add_2((void (*)(void))__remoteCarry_spawnMethod, markerId, clientId); + __spawnQueue_add_2((GenFunction_2)__remoteCarry_spawnMethod, markerId, clientId); } void port_remoteCarry_throw(u32 clientId, s32 markerId, f32 start[3], f32 target[3]) { @@ -200,7 +200,7 @@ void port_remoteCarry_throw(u32 clientId, s32 markerId, f32 start[3], f32 target return; } sRemoteCarry[slot].clientId = clientId; - __spawnQueue_add_2((void (*)(void))__remoteCarry_spawnMethod, markerId, clientId); + __spawnQueue_add_2((GenFunction_2)__remoteCarry_spawnMethod, markerId, clientId); } sRemoteCarry[slot].markerId = markerId; sRemoteCarry[slot].throwPending = 1; diff --git a/src/core2/collision/filter.c b/src/core2/collision/filter.c index 0c98679d4..b74354afa 100644 --- a/src/core2/collision/filter.c +++ b/src/core2/collision/filter.c @@ -57,7 +57,7 @@ extern void func_80351FE0(void *, Struct68s *); void func_80351E60(Struct6Bs *, Struct68s *, f32); extern void chTumblar_update(void *, Struct68s *, f32); extern void func_8038B790(void *, Struct68s *, f32); -extern void chZubbaDocile_update(void *, Struct68s *, f32); +extern void CC_func_80387A40(void *, Struct68s *, f32); extern void func_80352114(void *, Struct68s *, f32); Struct_Core2_C9F00_0 D_803725F4[] = { @@ -66,14 +66,14 @@ Struct_Core2_C9F00_0 D_803725F4[] = { {chTumblar_init, chTumblar_update}, { NULL, NULL}, { NULL, func_8038B790}, - {func_80387940, chZubbaDocile_update}, - {CC_func_80387960, chZubbaDocile_update}, - {func_80387980, chZubbaDocile_update}, - {func_803879A0, chZubbaDocile_update}, - {func_803879C0, chZubbaDocile_update}, - {CC_func_803879E0, chZubbaDocile_update}, - {CC_func_80387A00, chZubbaDocile_update}, - {CC_func_80387A20, chZubbaDocile_update}, + {func_80387940, CC_func_80387A40}, + {CC_func_80387960, CC_func_80387A40}, + {func_80387980, CC_func_80387A40}, + {func_803879A0, CC_func_80387A40}, + {func_803879C0, CC_func_80387A40}, + {CC_func_803879E0, CC_func_80387A40}, + {CC_func_80387A00, CC_func_80387A40}, + {CC_func_80387A20, CC_func_80387A40}, {func_80351FE0, func_80352114} }; diff --git a/src/core2/dialog/binload.c b/src/core2/dialog/binload.c index 24b0ad99b..192ee134b 100644 --- a/src/core2/dialog/binload.c +++ b/src/core2/dialog/binload.c @@ -19,7 +19,8 @@ s32 code94620_func_8031B5B0(void) { return s_dialogBin.unk0; } -s32 func_8031B5BC(void){ return VER_SELECT(1, 3, 0, 0); } +// s32 func_8031B5BC(void){ return VER_SELECT(1, 3, 0, 0); } +s32 func_8031B5BC(void){ return ResourceMgr_GetDialogLanguageCount(); } void func_8031B5C4(s32 arg0) { if ((arg0 >= 0) && (arg0 < func_8031B5BC())) { diff --git a/src/core2/fx/badShad.c b/src/core2/fx/badShad.c index d13e3ccc9..c1e040137 100644 --- a/src/core2/fx/badShad.c +++ b/src/core2/fx/badShad.c @@ -144,7 +144,7 @@ void func_802D729C(Actor *actor, f32 arg1){ return; } if(!actor->unk104){ - __spawnQueue_add_2((void (*)(void))func_802D71A0, (uintptr_t)actor->marker, reinterpret_cast(s32, arg1)); + __spawnQueue_add_2((GenFunction_2)func_802D71A0, (uintptr_t)actor->marker, reinterpret_cast(s32, arg1)); return; } diff --git a/src/core2/mumboshandwithpicture.c b/src/core2/mumboshandwithpicture.c index 206a7b634..7a6f3bb94 100644 --- a/src/core2/mumboshandwithpicture.c +++ b/src/core2/mumboshandwithpicture.c @@ -5,7 +5,6 @@ extern void actor_postdrawMethod(ActorMarker *); extern void chBottlesBonus_func_802DD080(Gfx **, Mtx **); -extern void func_80311714(s32); #include "port/Patches/Patches.h" Actor *chMumbosHandWithPicture_draw(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx); @@ -131,9 +130,9 @@ void chMumbosHandWithPicture_update(Actor *this) { break; } time = (f32) ((f64) (level_id_2 + 1) * 0.75); - timedFunc_set_1(time, func_80311714, 0); + timedFunc_set_1(time, (GenFunction_1)func_80311714, 0); func_80324DBC(time, text_id, 0x80, NULL, NULL, NULL, NULL); - timedFunc_set_1(time, func_80311714, 1); + timedFunc_set_1(time, (GenFunction_1)func_80311714, 1); D_8037DFE4 = level_id_1; } switch(this->state){ diff --git a/src/core2/nc/camera_nodemanager.c b/src/core2/nc/camera_nodemanager.c index 4502df634..23b7dda8f 100644 --- a/src/core2/nc/camera_nodemanager.c +++ b/src/core2/nc/camera_nodemanager.c @@ -362,7 +362,7 @@ void func_802BC2CC(s32 arg0) { viewport_setPosition_vec3f(D_8037D908); viewport_setRotation_vec3f(D_8037D918); viewport_update(); - __spawnQueue_add_2((void (*)(void))func_802BC2A0, (uintptr_t)sp24, (uintptr_t)sp20); + __spawnQueue_add_2((GenFunction_2)func_802BC2A0, (uintptr_t)sp24, (uintptr_t)sp20); if (ncCameraType == CAMERA_TYPE_2_DYNAMIC) { func_802BE720(); if (sp1C != 0x63) { diff --git a/src/core2/spawnqueue.c b/src/core2/spawnqueue.c index 75607c657..2e039a1c8 100644 --- a/src/core2/spawnqueue.c +++ b/src/core2/spawnqueue.c @@ -515,60 +515,60 @@ void spawnQueue_lock(void) { spawnQueueLock = TRUE; } -void __spawnQueue_add_0(void (* arg0)(void)){ +void __spawnQueue_add_0(GenFunction_0 arg0){ u32 tmp = __spawnQueue_getMax(); if(tmp > spawnQueueLength){ // [port] decomp used !=; < also holds if length ever exceeds tmp spawnQueue[spawnQueueLength].func0 = arg0; spawnQueue[spawnQueueLength].arg_cnt = 0; spawnQueueLength++; } else { - BK_LOG_WARN("[port] spawnQueue FULL (%d entries) — dropped add_0 entry", tmp); + BK_LOG_WARN("spawnQueue FULL (%d entries) — dropped add_0 entry", tmp); } } void __spawnQueue_add_1(GenFunction_1 arg0, uintptr_t arg1){ u32 tmp = __spawnQueue_getMax(); if(tmp > spawnQueueLength){ // [port] decomp used !=; < also holds if length ever exceeds tmp - spawnQueue[spawnQueueLength].func0 = (void (*)(void))arg0; + spawnQueue[spawnQueueLength].func1 = arg0; spawnQueue[spawnQueueLength].arg[0] = arg1; spawnQueue[spawnQueueLength].arg_cnt = 1; spawnQueueLength++; } else { - BK_LOG_WARN("[port] spawnQueue FULL (%d entries) — dropped add_1 entry", tmp); + BK_LOG_WARN("spawnQueue FULL (%d entries) — dropped add_1 entry", tmp); } } -void __spawnQueue_add_2(void (* arg0)(void), uintptr_t arg1, uintptr_t arg2){ +void __spawnQueue_add_2(GenFunction_2 arg0, uintptr_t arg1, uintptr_t arg2){ u32 tmp = __spawnQueue_getMax(); if(tmp > spawnQueueLength){ // [port] decomp used !=; < also holds if length ever exceeds tmp - spawnQueue[spawnQueueLength].func0 = arg0; + spawnQueue[spawnQueueLength].func2 = arg0; spawnQueue[spawnQueueLength].arg[0] = arg1; spawnQueue[spawnQueueLength].arg[1] = arg2; spawnQueue[spawnQueueLength].arg_cnt = 2; spawnQueueLength++; } else { - BK_LOG_WARN("[port] spawnQueue FULL (%d entries) — dropped add_2 entry", tmp); + BK_LOG_WARN("spawnQueue FULL (%d entries) — dropped add_2 entry", tmp); } } -void __spawnQueue_add_3(void (* arg0)(void), uintptr_t arg1, uintptr_t arg2, uintptr_t arg3){ +void __spawnQueue_add_3(GenFunction_3 arg0, uintptr_t arg1, uintptr_t arg2, uintptr_t arg3){ u32 tmp = __spawnQueue_getMax(); if(tmp > spawnQueueLength){ // [port] decomp used !=; < also holds if length ever exceeds tmp - spawnQueue[spawnQueueLength].func0 = arg0; + spawnQueue[spawnQueueLength].func3 = arg0; spawnQueue[spawnQueueLength].arg[0] = arg1; spawnQueue[spawnQueueLength].arg[1] = arg2; spawnQueue[spawnQueueLength].arg[2] = arg3; spawnQueue[spawnQueueLength].arg_cnt = 3; spawnQueueLength++; } else { - BK_LOG_WARN("[port] spawnQueue FULL (%d entries) — dropped add_3 entry", tmp); + BK_LOG_WARN("spawnQueue FULL (%d entries) — dropped add_3 entry", tmp); } } void __spawnQueue_add_4(GenFunction_4 arg0, uintptr_t arg1, uintptr_t arg2, uintptr_t arg3, uintptr_t arg4){ u32 tmp = __spawnQueue_getMax(); if(tmp > spawnQueueLength){ // [port] decomp used !=; < also holds if length ever exceeds tmp - spawnQueue[spawnQueueLength].func0 = (void (*)(void))arg0; + spawnQueue[spawnQueueLength].func4 = arg0; spawnQueue[spawnQueueLength].arg[0] = arg1; spawnQueue[spawnQueueLength].arg[1] = arg2; spawnQueue[spawnQueueLength].arg[2] = arg3; @@ -576,14 +576,14 @@ void __spawnQueue_add_4(GenFunction_4 arg0, uintptr_t arg1, uintptr_t arg2, uint spawnQueue[spawnQueueLength].arg_cnt = 4; spawnQueueLength++; } else { - BK_LOG_WARN("[port] spawnQueue FULL (%d entries) — dropped add_4 entry", tmp); + BK_LOG_WARN("spawnQueue FULL (%d entries) — dropped add_4 entry", tmp); } } -void __spawnQueue_add_5(void (* arg0)(void), uintptr_t arg1, uintptr_t arg2, uintptr_t arg3, uintptr_t arg4, uintptr_t arg5){ +void __spawnQueue_add_5(GenFunction_5 arg0, uintptr_t arg1, uintptr_t arg2, uintptr_t arg3, uintptr_t arg4, uintptr_t arg5){ u32 tmp = __spawnQueue_getMax(); if(tmp > spawnQueueLength){ // [port] decomp used !=; < also holds if length ever exceeds tmp - spawnQueue[spawnQueueLength].func0 = arg0; + spawnQueue[spawnQueueLength].func5 = arg0; spawnQueue[spawnQueueLength].arg[0] = arg1; spawnQueue[spawnQueueLength].arg[1] = arg2; spawnQueue[spawnQueueLength].arg[2] = arg3; @@ -592,7 +592,7 @@ void __spawnQueue_add_5(void (* arg0)(void), uintptr_t arg1, uintptr_t arg2, uin spawnQueue[spawnQueueLength].arg_cnt = 5; spawnQueueLength++; } else { - BK_LOG_WARN("[port] spawnQueue FULL (%d entries) — dropped add_5 entry", tmp); + BK_LOG_WARN("spawnQueue FULL (%d entries) — dropped add_5 entry", tmp); } } diff --git a/src/fight/chfinalboss.c b/src/fight/chfinalboss.c index a228d23c5..5b2b3f511 100644 --- a/src/fight/chfinalboss.c +++ b/src/fight/chfinalboss.c @@ -11,7 +11,6 @@ extern bool func_8028F4B8(f32[3], f32, f32); extern int func_80320ED8(ActorMarker *, f32, s32); s32 subaddie_getYawToPosition(Actor*, f32*); -Actor *actor_spawnWithYaw_f32(); extern Actor* func_80329958(ActorMarker *this, s32 arg1); extern void func_803298D8(); extern void func_80324CFC(f32, enum comusic_e, s32); diff --git a/src/port/ResourceHelpers.cpp b/src/port/ResourceHelpers.cpp index 922d6c435..75146490a 100644 --- a/src/port/ResourceHelpers.cpp +++ b/src/port/ResourceHelpers.cpp @@ -370,7 +370,12 @@ void ResourceHelpers_ApplyLanguage(std::unordered_map dia } ++sLanguageGeneration; // invalidates re-pointed models on their next draw sIsJapanese = isJapanese; - sDialogLanguageCount = dialogCount; + sDialogLanguageCount = (dialogCount > 0) ? dialogCount : 1; + if (dialogIndex < 0 || dialogIndex >= sDialogLanguageCount) { + SPDLOG_WARN("[ResourceHelpers] Dialog language index {} out of range for a {}-language source; using 0", + dialogIndex, sDialogLanguageCount); + dialogIndex = 0; + } sDialogLanguage = dialogIndex; // keep ResourceMgr_GetDialogLanguage() in sync - func_8031B5C4(dialogIndex); // clamps against sDialogLanguageCount + func_8031B5C4(dialogIndex); } From 40d62394ae5441500c21d39a6a9b39dc58e305d3 Mon Sep 17 00:00:00 2001 From: Malkierian Date: Sat, 25 Jul 2026 19:35:23 -0700 Subject: [PATCH 025/131] Exclude `unused` folder from build list. --- CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 360b6670b..dc81e8e02 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -218,6 +218,8 @@ file(GLOB_RECURSE ALL_FILES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "${CMAKE_CURRENT_SOURCE_DIR}/include/*" ) +list(FILTER ALL_FILES EXCLUDE REGEX "src/unused/") + list(APPEND ALL_FILES ${CMAKE_CURRENT_SOURCE_DIR}/Resource.rc) From e3202c09cd935e8b2589b1f8cff609c184bd5084 Mon Sep 17 00:00:00 2001 From: Malkierian Date: Sat, 25 Jul 2026 23:07:58 -0700 Subject: [PATCH 026/131] Restore ActorID to eliminate warning about unnamed typedef. Undo exclusion of unused folder because of references of functions housed there causing linking errors. Handle switches without default branches. Suppress MSVC warning for zero-sized c99 flexible arrays (C4200). --- CMakeLists.txt | 3 +-- include/enums.h | 2 +- src/port/Rando/Logic/Logic.h | 2 ++ src/port/Rando/ObjectBehavior/Bundle.cpp | 3 +++ 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index dc81e8e02..f90e73b93 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -218,8 +218,6 @@ file(GLOB_RECURSE ALL_FILES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "${CMAKE_CURRENT_SOURCE_DIR}/include/*" ) -list(FILTER ALL_FILES EXCLUDE REGEX "src/unused/") - list(APPEND ALL_FILES ${CMAKE_CURRENT_SOURCE_DIR}/Resource.rc) @@ -543,6 +541,7 @@ if(MSVC) /we4311; # pointer truncation (e.g. void* to int) /we4312; # conversion to pointer of greater size (e.g. int to void*) /we4133; # incompatible pointer types + /wd4200; # we don't care about zero-sized flexible arrays ${DEFAULT_CXX_DEBUG_INFORMATION_FORMAT}; ${DEFAULT_CXX_EXCEPTION_HANDLING} ) diff --git a/include/enums.h b/include/enums.h index bf7e8ae57..02b9f532a 100644 --- a/include/enums.h +++ b/include/enums.h @@ -2427,7 +2427,7 @@ typedef enum actor_e ACTOR_3CA_ROCK_TRAPPING_GRUNTY, ACTOR_3CB_UNKNOWN, ACTOR_3CC_DUMMY_PLAYER_ANCHOR = 0x3CC // Lighthouse [port] network anchor dummy player -}; +} ActorID; enum bundle_e { BUNDLE_0_MM_HUT_MUSIC_NOTE, diff --git a/src/port/Rando/Logic/Logic.h b/src/port/Rando/Logic/Logic.h index 3e7bedaed..7f6edbe7e 100644 --- a/src/port/Rando/Logic/Logic.h +++ b/src/port/Rando/Logic/Logic.h @@ -347,6 +347,8 @@ inline bool CanKillEnemy(actor_e enemyType) { canKillEnemy = true; } break; + default: + break; } return canKillEnemy; diff --git a/src/port/Rando/ObjectBehavior/Bundle.cpp b/src/port/Rando/ObjectBehavior/Bundle.cpp index 7d4c1fe2f..fff4dda9b 100644 --- a/src/port/Rando/ObjectBehavior/Bundle.cpp +++ b/src/port/Rando/ObjectBehavior/Bundle.cpp @@ -188,6 +188,8 @@ void Rando::ObjectBehavior::InitBundleBehavior() { case BUNDLE_7__JIGGY: randoCheckId = RC_FP_JIGGY_BOGGY_RACE_2; break; + default: + break; } break; case LEVEL_6_LAIR: @@ -240,6 +242,7 @@ void Rando::ObjectBehavior::InitBundleBehavior() { break; case BUNDLE_D__EMPTY_HONEYCOMB: randoCheckId = RC_GV_EMPTY_HONEYCOMB_GOBI; + break; default: break; } From faa89292b0ec209a4ed13e6cee78cf6b95b65eeb Mon Sep 17 00:00:00 2001 From: Malkierian Date: Sun, 26 Jul 2026 01:19:12 -0700 Subject: [PATCH 027/131] Bump Torch. Add shader copy to port O2R generation workflow. --- .github/workflows/main.yml | 1 + Torch | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 8be3f18b1..c8cdb4eff 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -41,6 +41,7 @@ jobs: run: | export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH" make -C Torch type=release -j3 + cp -r ./libultraship/src/fast/shaders ./port Torch/cmake-build-release/torch pack port lighthouse.o2r o2r -u ${{ steps.extract_version.outputs.version }} - uses: actions/upload-artifact@v4 with: diff --git a/Torch b/Torch index 205bd3e8b..e92c2103e 160000 --- a/Torch +++ b/Torch @@ -1 +1 @@ -Subproject commit 205bd3e8be07df1544d7938ae8f5827f5d90b77f +Subproject commit e92c2103e22281b892e65760b4b11d81d4795c86 From a4f5ad8dc515459a61e2b1f387f6092c2ef495fe Mon Sep 17 00:00:00 2001 From: Jeod <47716344+JeodC@users.noreply.github.com> Date: Sun, 26 Jul 2026 13:03:42 -0400 Subject: [PATCH 028/131] Clean calls to src/unused, filter out the unused files, make ReadStampedCrc endianness-agnostic (#263) * Clean calls to src/unused, filter out the unused files, make ReadStampedCrc endianness-agnostic * Update mod subfolder paths * Adjust orbit camera snapback --- CMakeLists.txt | 2 ++ Torch | 2 +- config.yml | 6 ++-- docs/modding/LANGUAGE PACKS.md | 4 +-- include/file_and_line.h | 19 ++++++++--- include/version.h | 3 ++ .../include/{assert.h => ultra_assert.h} | 0 src/core1/init.c | 2 +- src/core1/n_audio/n_csplayer.c | 2 +- src/core1/n_audio/n_env.c | 2 +- src/core1/n_audio/n_seqplayer.c | 2 +- src/core1/vimgr.c | 2 +- src/core2/gameloop.c | 2 +- src/port/Engine.cpp | 9 ++--- .../Enhancements/Camera/OrbitCameraCore.cpp | 2 +- src/port/GameVersion/BaseGameVersion.cpp | 33 +++++++++++++++---- src/port/Localization/Language.cpp | 2 +- src/port/ResourceHelpers.cpp | 3 +- src/port/Romhack/Shared/HackShared.h | 3 +- src/port/Romhack/Shared/ProximityDialogs.cpp | 5 ++- src/port/Romhack/Shared/ProximityDialogs.h | 11 +++---- src/port/Romhack/Specific/TheGruntch.cpp | 10 +++--- src/port/UI/LighthouseModMenuWindow.cpp | 12 +++---- 23 files changed, 84 insertions(+), 54 deletions(-) rename lib/ultralib/include/{assert.h => ultra_assert.h} (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index f90e73b93..8d773d2a4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -218,6 +218,8 @@ file(GLOB_RECURSE ALL_FILES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "${CMAKE_CURRENT_SOURCE_DIR}/include/*" ) +list(FILTER ALL_FILES EXCLUDE REGEX "src/unused/") + list(APPEND ALL_FILES ${CMAKE_CURRENT_SOURCE_DIR}/Resource.rc) diff --git a/Torch b/Torch index e92c2103e..b4b75e664 160000 --- a/Torch +++ b/Torch @@ -1 +1 @@ -Subproject commit e92c2103e22281b892e65760b4b11d81d4795c86 +Subproject commit b4b75e6649d66c028f56116f0bf48a119862b1bb diff --git a/config.yml b/config.yml index 92309861a..270dfe886 100644 --- a/config.yml +++ b/config.yml @@ -19,7 +19,7 @@ ded6ee166e740ad1bc810fd678a84b48e245ab80: config: gbi: F3DEX_BK64 sort: OFFSET - logging: ERROR + logging: WARN textures: ADDITIONAL_DEFINES include_autogen: true output: @@ -34,7 +34,7 @@ bb359a75941df74bf7290212c89fbc6e2c5601fe: config: gbi: F3DEX_BK64 sort: OFFSET - logging: ERROR + logging: WARN textures: ADDITIONAL_DEFINES include_autogen: true output: @@ -49,7 +49,7 @@ bb359a75941df74bf7290212c89fbc6e2c5601fe: config: gbi: F3DEX_BK64 sort: OFFSET - logging: ERROR + logging: WARN textures: ADDITIONAL_DEFINES include_autogen: true output: diff --git a/docs/modding/LANGUAGE PACKS.md b/docs/modding/LANGUAGE PACKS.md index 8164704e8..3ce7f7d3c 100644 --- a/docs/modding/LANGUAGE PACKS.md +++ b/docs/modding/LANGUAGE PACKS.md @@ -1,6 +1,6 @@ # Making a Language Pack -A language pack is a small companion archive that adds a new in-game language alongside the retail `bkpal.o2r` / `bkjp.o2r`. Players drop it into their `mods/lang/` folder and pick the new language from the options menu. +A language pack is a small companion archive that adds a new in-game language alongside the retail `bkpal.o2r` / `bkjp.o2r`. Players drop it into their `mods/~lang/` folder and pick the new language from the options menu. This guide walks through building one pack end to end: a **Spanish** translation, from the first export to a finished `bkes.o2r`. @@ -199,7 +199,7 @@ config: torch modding import o2r -s -d ``` -The importer walks the asset list: your edited yamls are re-encoded from ``, everything else parses straight from the ROM, and `dialog_pack` strips the result down to the language assets plus `langinfo`. The finished pack lands in **`mods/lang/`** automatically, named from your `output.binary` - `bkes.o2r` in our case. Copy that into the game's `mods/lang/` folder and it shows up in the options menu. +The importer walks the asset list: your edited yamls are re-encoded from ``, everything else parses straight from the ROM, and `dialog_pack` strips the result down to the language assets plus `langinfo`. The finished pack lands in **`mods/~lang/`** automatically, named from your `output.binary` - `bkes.o2r` in our case. Copy that into the game's `mods/~lang/` folder and it shows up in the options menu. --- diff --git a/include/file_and_line.h b/include/file_and_line.h index a931d6b5e..93f44d73f 100644 --- a/include/file_and_line.h +++ b/include/file_and_line.h @@ -1,8 +1,11 @@ #ifndef _FILE_AND_LINE_H_ #define _FILE_AND_LINE_H_ + #include -extern void __assert(const char *, const char *, int); +#if 0 +extern void __assert(const char *, const char *, int); +#endif #ifdef NONMATCHING #define LINE(line_num) __LINE__ @@ -10,18 +13,24 @@ extern void __assert(const char *, const char *, int); #define matching_assert(EX, F, L) assert(EX) #else #define LINE(line_num) line_num + #ifdef __ANSI_CPP__ - #define FILE(file_name) # file_name + #define FILE(file_name) #file_name #else #define FILE(file_name) "file_name" #endif +#if 0 #ifdef __ANSI_CPP__ - #define matching_assert(EX, F, L) ((EX)?((void)0):__assert( # EX , # F, L)) + #define matching_assert(EX, F, L) \ + ((EX) ? ((void)0) : __assert(#EX, #F, L)) #else - #define matching_assert(EX, F , L) ((EX)?((void)0):__assert("EX", "F", L)) + #define matching_assert(EX, F, L) \ + ((EX) ? ((void)0) : __assert("EX", "F", L)) #endif #endif - + #define matching_assert(EX, F, L) ((void)0) #endif + +#endif \ No newline at end of file diff --git a/include/version.h b/include/version.h index 0f24f9c16..3efff4330 100644 --- a/include/version.h +++ b/include/version.h @@ -31,6 +31,9 @@ #define JP_EXCLUSIVE(body) #endif +// [port] AssetVersionRemap.h keys on usa0 +#define VER_SELECT(usa0, pal, usa1, jp) usa0 + #if VERSION == VERSION_USA_1_0 #define VER_SELECT(usa0, pal, usa1, jp) usa0 #elif VERSION == VERSION_PAL diff --git a/lib/ultralib/include/assert.h b/lib/ultralib/include/ultra_assert.h similarity index 100% rename from lib/ultralib/include/assert.h rename to lib/ultralib/include/ultra_assert.h diff --git a/src/core1/init.c b/src/core1/init.c index 01dbbf464..e7073d9df 100644 --- a/src/core1/init.c +++ b/src/core1/init.c @@ -117,7 +117,7 @@ void core1_init(void) { // [port] Irrelevant and replaced with system malloc // heap_init(); core1_15B30_init(); - dummy_func_8025AFB0(); + // dummy_func_8025AFB0(); // [port] Irrelevant and replaced with system malloc // allocUnusedBlock(); assetCache_init(); diff --git a/src/core1/n_audio/n_csplayer.c b/src/core1/n_audio/n_csplayer.c index 7a2cf5eda..a92c0852d 100644 --- a/src/core1/n_audio/n_csplayer.c +++ b/src/core1/n_audio/n_csplayer.c @@ -9,7 +9,7 @@ #include #include -extern void __assert(const char *, const char *, int); +//extern void __assert(const char *, const char *, int); void n_alSynSetVol( N_ALVoice *v, s16 volume, ALMicroTime t); s16 __n_vsVol(ALVoiceState *voice, ALSeqPlayer *seqp); ALVoiceState *__n_lookupVoice(ALSeqPlayer *, u8, u8); diff --git a/src/core1/n_audio/n_env.c b/src/core1/n_audio/n_env.c index aafaea970..c1671f37b 100644 --- a/src/core1/n_audio/n_env.c +++ b/src/core1/n_audio/n_env.c @@ -3,7 +3,7 @@ #include "n_synth.h" #include "functions.h" #include "variables.h" -#include "assert.h" +#include "ultra_assert.h" Acmd *n_alResamplePull(N_PVoice *e, s16 *outp, Acmd *p); diff --git a/src/core1/n_audio/n_seqplayer.c b/src/core1/n_audio/n_seqplayer.c index 5577b44de..71735dac4 100644 --- a/src/core1/n_audio/n_seqplayer.c +++ b/src/core1/n_audio/n_seqplayer.c @@ -2,7 +2,7 @@ #include #include "n_synth.h" #include "file_and_line.h" -#include "assert.h" +#include "ultra_assert.h" //#include #include // #include "functions.h" diff --git a/src/core1/vimgr.c b/src/core1/vimgr.c index 24c3aa90b..928ed8d2e 100644 --- a/src/core1/vimgr.c +++ b/src/core1/vimgr.c @@ -209,7 +209,7 @@ void viMgr_func_8024BFD8(s32 arg0){ void viMgr_func_8024C1B4(void){ viMgr_func_8024BFD8(0); - dummy_func_8025AFB8(); + // dummy_func_8025AFB8(); } void viMgr_func_8024C1DC(void){ diff --git a/src/core2/gameloop.c b/src/core2/gameloop.c index 05e7c61ac..8d3fcdc3b 100644 --- a/src/core2/gameloop.c +++ b/src/core2/gameloop.c @@ -168,7 +168,7 @@ void func_802E39D0(Gfx **gfx, Mtx **mtx, Vtx **vtx, s32 framebuffer_idx, bool ar gcpausemenu_draw(gfx, mtx, vtx); if(!game_is_frozen() && !capturing){ - dummy_func_8025AFC0(gfx, mtx, vtx); + // dummy_func_8025AFC0(gfx, mtx, vtx); } if (!capturing) { diff --git a/src/port/Engine.cpp b/src/port/Engine.cpp index 5365a55e7..7aaa45dfc 100644 --- a/src/port/Engine.cpp +++ b/src/port/Engine.cpp @@ -247,7 +247,8 @@ void CheckAndCreateModFolder() { if (std::filesystem::create_directories(modsPath)) { std::ofstream(filePath).close(); std::filesystem::create_directories(modsPath + "/~romhacks"); // BK romhacks go here - std::filesystem::create_directories(modsPath + "/shared"); // Mods usable by everything go here + std::filesystem::create_directories(modsPath + "/~lang"); // Language packs go here + std::filesystem::create_directories(modsPath + "/~shared"); // Mods usable by everything go here } } } catch (std::filesystem::filesystem_error const&) { @@ -326,7 +327,7 @@ static void LoadLooseModDirectories(const std::string& patches_path) { continue; } const std::string dirName = p.path().filename().generic_string(); - if (dirName == "~romhacks" || dirName == "shared" || dirName == "lang" || IsScopedModFolderName(dirName)) { + if (dirName == "~romhacks" || dirName == "~shared" || dirName == "~lang" || IsScopedModFolderName(dirName)) { continue; } SPDLOG_INFO("Found mod directory: {}", p.path().generic_string()); @@ -335,9 +336,9 @@ static void LoadLooseModDirectories(const std::string& patches_path) { } } -// Load every .o2r language pack from mods/lang into the ArchiveManager. +// Load every .o2r language pack from mods/~lang into the ArchiveManager. static void LoadLanguagePacks() { - const std::string lang_path = Ship::Context::GetPathRelativeToAppDirectory("mods/lang"); + const std::string lang_path = Ship::Context::GetPathRelativeToAppDirectory("mods/~lang"); if (lang_path.empty() || !std::filesystem::is_directory(lang_path)) { return; } diff --git a/src/port/Enhancements/Camera/OrbitCameraCore.cpp b/src/port/Enhancements/Camera/OrbitCameraCore.cpp index 6efe6520d..6e0b294d7 100644 --- a/src/port/Enhancements/Camera/OrbitCameraCore.cpp +++ b/src/port/Enhancements/Camera/OrbitCameraCore.cpp @@ -102,7 +102,7 @@ extern "C" void OrbitCamera_Update(OrbitCamera* c, float yawDelta, float pitchDe if (c->smoothValid && zoomTarget > 0.0f) { float rgx = center[0] - c->smoothPos[0]; float rgz = center[2] - c->smoothPos[2]; - float limit = zoomTarget * 2.0f; + float limit = zoomTarget * 1.05f; if ((rgx * rgx + rgz * rgz) > (limit * limit)) { c->distance = zoomTarget; c->smoothValid = 0; diff --git a/src/port/GameVersion/BaseGameVersion.cpp b/src/port/GameVersion/BaseGameVersion.cpp index 43fe141cf..52b16fb37 100644 --- a/src/port/GameVersion/BaseGameVersion.cpp +++ b/src/port/GameVersion/BaseGameVersion.cpp @@ -23,13 +23,32 @@ bool ReadStampedCrc(const std::string& archivePath, uint32_t& outCrc) { if (zip_int64_t idx = zip_name_locate(z, "version", 0); idx >= 0) { if (zip_file_t* f = zip_fopen_index(z, idx, 0)) { uint8_t buf[5] = {}; - if (zip_fread(f, buf, sizeof(buf)) == static_cast(sizeof(buf))) { - const bool big = buf[0] != 0; - outCrc = big ? (static_cast(buf[1]) << 24 | static_cast(buf[2]) << 16 | - static_cast(buf[3]) << 8 | static_cast(buf[4])) - : (static_cast(buf[4]) << 24 | static_cast(buf[3]) << 16 | - static_cast(buf[2]) << 8 | static_cast(buf[1])); - ok = true; + if (zip_fread(f, buf, sizeof(buf)) == sizeof(buf)) { + const uint32_t crcBE = (static_cast(buf[1]) << 24) | (static_cast(buf[2]) << 16) | + (static_cast(buf[3]) << 8) | static_cast(buf[4]); + + const uint32_t crcLE = (static_cast(buf[4]) << 24) | (static_cast(buf[3]) << 16) | + (static_cast(buf[2]) << 8) | static_cast(buf[1]); + + auto isKnownVersion = [](uint32_t crc) { + switch (crc) { + case BK_VER_US_10: + case BK_VER_US_11: + case BK_VER_PAL: + case BK_VER_JP: + return true; + default: + return false; + } + }; + + if (isKnownVersion(crcBE)) { + outCrc = crcBE; + ok = true; + } else if (isKnownVersion(crcLE)) { + outCrc = crcLE; + ok = true; + } } zip_fclose(f); } diff --git a/src/port/Localization/Language.cpp b/src/port/Localization/Language.cpp index 4318c10e6..78bfea80c 100644 --- a/src/port/Localization/Language.cpp +++ b/src/port/Localization/Language.cpp @@ -272,7 +272,7 @@ void SetActiveLanguage(const std::string& name) { // Hand the computed language to the resource layer const size_t repointed = dialogOverride.size(); ResourceHelpers_ApplyLanguage(std::move(dialogOverride), entry->script == SCRIPT_JP, entry->count, entry->index); - SPDLOG_INFO("[Lang] Active language '{}' ({} ids re-pointed)", name, repointed); + SPDLOG_INFO("[Lang] Active language '{}'", name, repointed); } void RescanLanguages() { diff --git a/src/port/ResourceHelpers.cpp b/src/port/ResourceHelpers.cpp index 75146490a..cdc500ff2 100644 --- a/src/port/ResourceHelpers.cpp +++ b/src/port/ResourceHelpers.cpp @@ -103,7 +103,7 @@ const std::unordered_map& GetAssetSymbolMap() { switch (Lighthouse::GetBaseVersion()) { case BK_VER_US_11: remapTable = &sV10toV11Remap; - SPDLOG_INFO("Loaded v1.1 o2r with {} entries", symbolMap.size()); + SPDLOG_INFO("Loaded US v1.1 o2r with {} entries", symbolMap.size()); break; case BK_VER_PAL: remapTable = &sV10toPALRemap; @@ -115,6 +115,7 @@ const std::unordered_map& GetAssetSymbolMap() { break; case BK_VER_US_10: default: + SPDLOG_INFO("Loaded US v1.0 o2r"); // v1.0 or a v1.0-based romhack: decomp IDs are already correct. break; } diff --git a/src/port/Romhack/Shared/HackShared.h b/src/port/Romhack/Shared/HackShared.h index f0da30635..24b555236 100644 --- a/src/port/Romhack/Shared/HackShared.h +++ b/src/port/Romhack/Shared/HackShared.h @@ -3,7 +3,6 @@ void HackShared_EnableNoteSignSuppression(int signActorId); void HackShared_EnableDialogSuppression(const int* dialogIds, int count); -template -inline void HackShared_EnableDialogSuppression(const int (&dialogIds)[N]) { +template inline void HackShared_EnableDialogSuppression(const int (&dialogIds)[N]) { HackShared_EnableDialogSuppression(dialogIds, N); } diff --git a/src/port/Romhack/Shared/ProximityDialogs.cpp b/src/port/Romhack/Shared/ProximityDialogs.cpp index 75c09762b..ba05f6829 100644 --- a/src/port/Romhack/Shared/ProximityDialogs.cpp +++ b/src/port/Romhack/Shared/ProximityDialogs.cpp @@ -67,9 +67,8 @@ void ProximityDialogs_Run(const ProximityDialogMap* maps, int count) { void ProximityDialogs_Enable(const ProximityDialogMap* maps, int count) { sWorldMaps = maps; sWorldMapCount = count; - COND_HOOK(GameFrameUpdate, EVENT_PRIORITY_NORMAL, sWorldMapCount > 0, [](IEvent*) { - ProximityDialogs_Run(sWorldMaps, sWorldMapCount); - }); + COND_HOOK(GameFrameUpdate, EVENT_PRIORITY_NORMAL, sWorldMapCount > 0, + [](IEvent*) { ProximityDialogs_Run(sWorldMaps, sWorldMapCount); }); } bool ProximityDialogs_IsShown(int word, unsigned bits) { diff --git a/src/port/Romhack/Shared/ProximityDialogs.h b/src/port/Romhack/Shared/ProximityDialogs.h index 96ed1a095..aac61acc8 100644 --- a/src/port/Romhack/Shared/ProximityDialogs.h +++ b/src/port/Romhack/Shared/ProximityDialogs.h @@ -6,12 +6,12 @@ struct ProximityDialogPage { int textId; int dialogFlags; unsigned char word; // which sDialogShown word tracks this page - unsigned short doneBit; // bit within that word; 0 means "guarded by token instead" + unsigned short doneBit; // bit within that word; 0 means "guarded by token instead" int token; // mumbotoken to guard on / bank (-1 = none) const float* dialogPos; - int skipIfJiggy; // skip if this jiggy is collected (>0) - int needFlag; // skip unless this FILEPROG flag is set (>0) - int needFlagClear; // skip if this FILEPROG flag is set (>0) + int skipIfJiggy; // skip if this jiggy is collected (>0) + int needFlag; // skip unless this FILEPROG flag is set (>0) + int needFlagClear; // skip if this FILEPROG flag is set (>0) }; struct ProximityDialogMap { @@ -30,8 +30,7 @@ void ProximityDialogs_Run(const ProximityDialogMap* maps, int count); void ProximityDialogs_Enable(const ProximityDialogMap* maps, int count); // Deduce the count from a fixed table so callers pass just the table. -template -inline void ProximityDialogs_Enable(const ProximityDialogMap (&maps)[N]) { +template inline void ProximityDialogs_Enable(const ProximityDialogMap (&maps)[N]) { ProximityDialogs_Enable(maps, N); } diff --git a/src/port/Romhack/Specific/TheGruntch.cpp b/src/port/Romhack/Specific/TheGruntch.cpp index 077c539f0..488750ecd 100644 --- a/src/port/Romhack/Specific/TheGruntch.cpp +++ b/src/port/Romhack/Specific/TheGruntch.cpp @@ -223,8 +223,8 @@ static void Gruntch_EnableConditionalActors() { sConditionalActorsEnabled = true; COND_VB_SHOULD(VB_XMAS_TREE_ICE_UPDATE, EVENT_PRIORITY_NORMAL, sConditionalActorsEnabled, { Actor* self = va_arg(args, Actor*); - if (gsworld_getMap() == MAP_1B_MMM_MAD_MONSTER_MANSION && - self != NULL && self->marker != NULL && self->marker->propPtr != NULL) { + if (gsworld_getMap() == MAP_1B_MMM_MAD_MONSTER_MANSION && self != NULL && self->marker != NULL && + self->marker->propPtr != NULL) { bool open = fileProgressFlag_get(FILEPROG_38_RBB_OPEN) != 0; self->marker->propPtr->unk8_3 = open; self->unk38_31 = !open; @@ -233,9 +233,7 @@ static void Gruntch_EnableConditionalActors() { }); // Force Boggy to be visible - COND_VB_SHOULD(VB_BOGGY_HOME_VISIBLE, EVENT_PRIORITY_NORMAL, sConditionalActorsEnabled, { - *should = true; - }); + COND_VB_SHOULD(VB_BOGGY_HOME_VISIBLE, EVENT_PRIORITY_NORMAL, sConditionalActorsEnabled, { *should = true; }); } // --------------------------------------------------------------- Mumbo reward @@ -379,5 +377,5 @@ void RegisterGruntchPatches() { * Stealth minigame in Gruntch's room (RBB Kitchen) * Possible retention of turbo trainers through cauldron warp * Game over respawn to Gruntch Cave - */ + */ } diff --git a/src/port/UI/LighthouseModMenuWindow.cpp b/src/port/UI/LighthouseModMenuWindow.cpp index cd4adf8b1..0693fc30f 100644 --- a/src/port/UI/LighthouseModMenuWindow.cpp +++ b/src/port/UI/LighthouseModMenuWindow.cpp @@ -84,8 +84,8 @@ static std::vector sRomhackBaseMismatch; // Romhacks and universally shared mods get special folders // The lang folder is skipped in scans #define ROMHACKS_DIR "~romhacks" -#define SHARED_DIR "shared" -#define LANG_DIR "lang" +#define SHARED_DIR "~shared" +#define LANG_DIR "~lang" static std::string JoinModList(const std::vector& list) { std::string s; @@ -313,7 +313,7 @@ void UpdateModFiles(bool init, bool reset) { if (!IsValidExtension(p.path().extension().generic_string())) { continue; } - // Skip reserved folders (e.g. mods/lang/ language packs) — they + // Skip reserved folders (e.g. mods/~lang/ language packs) — they // aren't user-toggleable mods and must not appear in either menu. if (IsReservedModPath(modsPath, p.path())) { continue; @@ -883,8 +883,8 @@ void RequestInlineLanguagePackExtraction() { return; } // Re-extracting a region overwrites its existing pack (e.g. to refresh it - // after an update), so a pre-existing mods/lang/bk.o2r is fine. - const std::string langDir = Ship::Context::GetPathRelativeToAppDirectory("mods/lang"); + // after an update), so a pre-existing mods/~lang/bk.o2r is fine. + const std::string langDir = Ship::Context::GetPathRelativeToAppDirectory("mods/~lang"); std::error_code ec; std::filesystem::create_directories(langDir, ec); @@ -931,7 +931,7 @@ void DrawInlineModExtraction() { const std::string packPath = GameExtractor::sLastOutputPath; if (!packPath.empty() && GetArchiveManager()->AddArchive(packPath) == nullptr) { // Shouldn't happen for an o2r we just wrote; if it does, the pack is - // still in mods/lang and loads on the next launch. + // still in mods/~lang and loads on the next launch. SPDLOG_WARN("[Lang] Pack '{}' didn't register live; it will load on the next launch.", packPath); } Lighthouse::RescanLanguages(); From a0b2afc7dd09323843c0cf0956d88ddbb271f274 Mon Sep 17 00:00:00 2001 From: Malkierian Date: Sun, 26 Jul 2026 10:16:02 -0700 Subject: [PATCH 029/131] Fix Linux packaging. --- .github/workflows/main.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index c8cdb4eff..259975992 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -202,6 +202,9 @@ jobs: name: Lighthouse-linux path: | lighthouse.appimage + config.yml + readme.txt + assets gamecontrollerdb.txt build-switch: From 297b6654ee611c762d6a2cd2e7c593a83c9ce248 Mon Sep 17 00:00:00 2001 From: Malkierian Date: Sun, 26 Jul 2026 12:05:38 -0700 Subject: [PATCH 030/131] Rc cleanup 1 (#268) * Remove remote collect sim. * Another attempt at fixing packaging for Linux. * Fix Mumbo's Hut fast transformations. * Remove frame drop warning. * Add to Easier Boggy Races enhancement to mention the need for a map reload to take effect. --- .github/workflows/main.yml | 2 - CMakeLists.txt | 2 + src/core2/mumbo.c | 4 + src/port/DevTools/RemoteCollectSim.cpp | 106 -------------------- src/port/Enhancements/Cheats/Cheats.cpp | 64 ++++++++++++ src/port/Enhancements/Events/Hooks/Events.h | 2 + src/port/UI/LighthouseMenuDevTools.cpp | 7 -- src/port/UI/LighthouseMenuEnhancements.cpp | 3 +- src/port/UI/ResolutionEditor.cpp | 28 +++--- src/port/UI/ResolutionEditor.h | 2 +- 10 files changed, 89 insertions(+), 131 deletions(-) delete mode 100644 src/port/DevTools/RemoteCollectSim.cpp diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 259975992..1b109aa19 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -202,9 +202,7 @@ jobs: name: Lighthouse-linux path: | lighthouse.appimage - config.yml readme.txt - assets gamecontrollerdb.txt build-switch: diff --git a/CMakeLists.txt b/CMakeLists.txt index 8d773d2a4..814995a3c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -766,6 +766,8 @@ add_custom_target( if("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux") install(FILES "${CMAKE_BINARY_DIR}/lighthouse.o2r" DESTINATION . COMPONENT ${PROJECT_NAME}) + install(DIRECTORY "${CMAKE_SOURCE_DIR}/assets/" DESTINATION ./assets COMPONENT ${PROJECT_NAME}) + install(FILES "${CMAKE_BINARY_DIR}/config.yml" DESTINATION . COMPONENT ${PROJECT_NAME}) endif() if(CMAKE_SYSTEM_NAME MATCHES "Darwin") diff --git a/src/core2/mumbo.c b/src/core2/mumbo.c index ceb5bf2c6..aff67980d 100644 --- a/src/core2/mumbo.c +++ b/src/core2/mumbo.c @@ -375,6 +375,10 @@ void chMumbo_update(Actor *this) { break; case 5: //L802D2488 + // [port] Fast Transformation drives this state from Cheats.cpp instead. + if (!EventSystem_Should(VB_MUMBO_HUT_TRANSFORM_CUTSCENE, true, this)) { + break; + } actor_playAnimationOnce(this); if (actor_animationIsAt(this, 0.35f)){ sfxSource_func_8030E2C4(this->unk44_31); diff --git a/src/port/DevTools/RemoteCollectSim.cpp b/src/port/DevTools/RemoteCollectSim.cpp deleted file mode 100644 index 208b7d09a..000000000 --- a/src/port/DevTools/RemoteCollectSim.cpp +++ /dev/null @@ -1,106 +0,0 @@ -// Dev tool: simulates a teammate's remote note/jinjo collects locally. Toggled by Dev Tools > -// General "Simulate Remote Collects". -// -// libultraship first: core2/timedfunc.h redefines `reinterpret_cast`, breaking MSVC's stdlib. -#include -#include "port/ShipInit.hpp" -#include "port/Enhancements/Events/PortEnhancements.h" -#include "port/Enhancements/Events/Hooks/Events.h" -#include "port/Enhancements/Retention/Retention.h" -#include "port/UI/cvar_prefixes.h" -#include "port/UI/Notification.h" - -#include -#include - -#include "functions.h" -extern "C" { -#include "enums.h" -} - -extern "C" void port_noteRetention_applyRemoteCollect(int32_t mapId, int32_t noteIndex, int32_t sameMap); -extern "C" int32_t port_noteRetention_debugPickLive(int32_t mapId); -extern "C" void port_jinjoRetention_applyRemoteCollect(int32_t map, int32_t bit, int32_t sameMap); -extern "C" int32_t port_jinjoRetention_debugPickLive(void); - -#define CVAR_SIM_REMOTE_COLLECT CVAR_DEVELOPER_TOOLS("SimRemoteCollect") - -namespace { - -using Clock = std::chrono::steady_clock; -constexpr std::chrono::seconds kInterval{ 30 }; - -bool sArmed = false; -int32_t sLastMap = -1; -Clock::time_point sNextFire; -bool sPreferNote = true; // alternate note/jinjo across successful ticks - -const char* jinjoColorName(int32_t bit) { - switch (bit) { - case 1 << 0: - return "blue"; - case 1 << 1: - return "green"; - case 1 << 2: - return "orange"; - case 1 << 3: - return "pink"; - case 1 << 4: - return "yellow"; - default: - return "?"; - } -} - -bool SimulateOne(bool note, int32_t map) { - if (note) { - int32_t idx = port_noteRetention_debugPickLive(map); - if (idx < 0) { - return false; - } - port_noteRetention_applyRemoteCollect(map, idx, 1); - Notification::Emit({ .message = "[Sim] remote note collect #" + std::to_string(idx) }); - return true; - } - int32_t bit = port_jinjoRetention_debugPickLive(); - if (bit == 0) { - return false; - } - port_jinjoRetention_applyRemoteCollect(map, bit, 1); - Notification::Emit({ .message = std::string("[Sim] remote jinjo collect (") + jinjoColorName(bit) + ")" }); - return true; -} - -void Tick() { - if (!retention::systemActive()) { - sArmed = false; - return; - } - int32_t map = (int32_t)gsworld_getMap(); - Clock::time_point now = Clock::now(); - if (!sArmed || map != sLastMap) { - sArmed = true; - sLastMap = map; - sNextFire = now + kInterval; - return; - } - if (now < sNextFire) { - return; - } - sNextFire = now + kInterval; - if (SimulateOne(sPreferNote, map)) { - sPreferNote = !sPreferNote; - } else { - SimulateOne(!sPreferNote, map); - } -} - -void RegisterRemoteCollectSim_Init() { - sArmed = false; - COND_HOOK(GameFrameUpdate, EVENT_PRIORITY_NORMAL, CVarGetInteger(CVAR_SIM_REMOTE_COLLECT, 0), - [](IEvent*) { Tick(); }); -} - -RegisterShipInitFunc initRemoteCollectSim(RegisterRemoteCollectSim_Init, { CVAR_SIM_REMOTE_COLLECT }); - -} // namespace diff --git a/src/port/Enhancements/Cheats/Cheats.cpp b/src/port/Enhancements/Cheats/Cheats.cpp index a9b21b2a8..46c67d665 100644 --- a/src/port/Enhancements/Cheats/Cheats.cpp +++ b/src/port/Enhancements/Cheats/Cheats.cpp @@ -247,6 +247,48 @@ void RegisterCycleTransform_Init() { }); } +// Copies of chMumbo_update state 5's 0.01 and 0.999 beats minus the audio; keep in step with it. +extern "C" { +void chMumbo_func_802D1B8C(Actor* actor, enum transformation_e transform_id); +extern u8 D_8037DDF0; // the transformation this hut offers +} + +static bool sMumboFastXformStarted = false; + +static void FastTransform_startHutTransform(Actor* actor) { + if (actor->has_met_before || + (actor->unk10_12 == 0 && (s32)player_getTransformation() != TRANSFORM_1_BANJO && + (s32)player_getTransformation() != romhack_mumboWishwashyId())) { + romhack_mumboTransform(TRANSFORM_1_BANJO); + return; + } + if (romhack_mumboTransform(D_8037DDF0)) { + if (D_8037DDF0 != romhack_mumboWishwashyId()) { + enum file_progress_e paidFlag = + (enum file_progress_e)((D_8037DDF0 - TRANSFORM_2_TERMITE) + FILEPROG_90_PAID_TERMITE_COST); + if (fileProgressFlag_getAndSet(paidFlag, true)) { + actor->velocity[0] = 1.0f; + } + actor->unk38_31 = 0; + } + if (actor->unk10_12 == 1) { + actor->unk10_12 = 0; + } + } +} + +// No has_met_before branch: those sequences are left to vanilla below. +static void FastTransform_endHutTransform(Actor* actor) { + func_8028F918(0); // pops the look-at lock state 4 pushed + if ((s32)player_getTransformation() != TRANSFORM_1_BANJO) { + subaddie_set_state(actor, 3); + chMumbo_func_802D1B8C(actor, (enum transformation_e)D_8037DDF0); + return; + } + gcpausemenu_80314AC8(1); + subaddie_set_state(actor, 4); +} + // Fast Transformation — speeds up Mumbo transformation animation by 3x void RegisterFastTransform_Init() { COND_HOOK(GameFrameUpdate, EVENT_PRIORITY_NORMAL, CVarGetInteger(CVAR_FAST_TRANSFORM, 0), [](IEvent* event) { @@ -260,6 +302,28 @@ void RegisterFastTransform_Init() { } } }); + + // Hut transforms ignore that timer; Mumbo's state 5 paces off his own 7.5s animation instead. + COND_VB_SHOULD(VB_MUMBO_HUT_TRANSFORM_CUTSCENE, EVENT_PRIORITY_NORMAL, CVarGetInteger(CVAR_FAST_TRANSFORM, 0), { + Actor* actor = va_arg(args, Actor*); + // T-Rex/mistake gags end in a dialog wired to a callback private to mumbo.c. + if (actor != nullptr && !actor->has_met_before) { + if (!sMumboFastXformStarted) { + sMumboFastXformStarted = true; + FastTransform_startHutTransform(actor); + } else if (!baflag_isTrue(BA_FLAG_1B_TRANSFORMING)) { + // player_transform sets the flag synchronously, so this can't fire on the + // frame the transform starts. + sMumboFastXformStarted = false; + FastTransform_endHutTransform(actor); + } + *should = false; + } + }); + + // A map torn down mid-transform would leave the next one thinking it had already run. + COND_HOOK(OnMapLoad, EVENT_PRIORITY_NORMAL, CVarGetInteger(CVAR_FAST_TRANSFORM, 0), + [](IEvent* event) { sMumboFastXformStarted = false; }); } // ============================================================================ diff --git a/src/port/Enhancements/Events/Hooks/Events.h b/src/port/Enhancements/Events/Hooks/Events.h index bb5256259..6992ee126 100644 --- a/src/port/Enhancements/Events/Hooks/Events.h +++ b/src/port/Enhancements/Events/Hooks/Events.h @@ -30,6 +30,8 @@ typedef enum VBehaviorID { VB_JINJO_CHARGE_SOUND, // MM Chimpy stump: gates the rumble sfx that starts when the stump begins shaking. VB_MM_CHIMPY_STUMP_RUMBLE, + // Cancelling hands Mumbo's transform state to the listener. Args: (Actor *mumbo). + VB_MUMBO_HUT_TRANSFORM_CUTSCENE, VB_YUMYUM_DROP, VB_OVERRIDE_BOTTLES_TEXT_CALLBACK, VB_OVERRIDE_MOLEHILL_ABILITY, diff --git a/src/port/UI/LighthouseMenuDevTools.cpp b/src/port/UI/LighthouseMenuDevTools.cpp index 9c6b40369..7b4318cfc 100644 --- a/src/port/UI/LighthouseMenuDevTools.cpp +++ b/src/port/UI/LighthouseMenuDevTools.cpp @@ -74,13 +74,6 @@ void LighthouseMenu::AddMenuDevTools() { AddWidget(path, "Nametag Distance", WIDGET_CVAR_SLIDER_FLOAT) .CVar(CVAR_DEVELOPER_TOOLS("NametagDist")) .Options(FloatSliderOptions().DefaultValue(3000.0f).Min(1000.0f).Max(10000.0f).Step(10.0f)); - AddWidget(path, "Simulate Remote Collects", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_DEVELOPER_TOOLS("SimRemoteCollect")) - .Options(CheckboxOptions().Tooltip( - "Every 30 seconds while in a map with live uncollected notes or jinjos, feeds one through the " - "remote-collect path (retention record + live despawn) as if a teammate collected it — for testing " - "the Anchor collection sync without a second machine. Requires note/jinjo retention to be active " - "(enhancement on, or connected to Anchor).")); /*AddWidget(path, "Debug Mode", WIDGET_CVAR_CHECKBOX) .CVar(CVAR_DEVELOPER_TOOLS("DebugMode")) .Options(CheckboxOptions().Tooltip("Various debug features, including a level selector from the main menu."));*/ diff --git a/src/port/UI/LighthouseMenuEnhancements.cpp b/src/port/UI/LighthouseMenuEnhancements.cpp index 595d1e8a3..90e33a1e4 100644 --- a/src/port/UI/LighthouseMenuEnhancements.cpp +++ b/src/port/UI/LighthouseMenuEnhancements.cpp @@ -486,7 +486,8 @@ void LighthouseMenu::AddMenuEnhancements() { info.activeDisables.push_back(DISABLE_FOR_ROMHACK); } }) - .Options(CheckboxOptions().Tooltip("Reduces Boggy's max speed during both sled races in Freezeezy Peak.")); + .Options(CheckboxOptions().Tooltip("Reduces Boggy's max speed during both sled races in Freezeezy Peak.\n" + "Requires a map reload to take effect.")); AddWidget(path, "Easier Mr Vile", WIDGET_CVAR_CHECKBOX) .CVar(CVAR_ENHANCEMENT("EasierMrVile")) diff --git a/src/port/UI/ResolutionEditor.cpp b/src/port/UI/ResolutionEditor.cpp index 433f8cc41..cbcee5911 100644 --- a/src/port/UI/ResolutionEditor.cpp +++ b/src/port/UI/ResolutionEditor.cpp @@ -404,13 +404,13 @@ void RegisterResolutionWidgets() { .CVar(CVAR_PREFIX_ADVANCED_RESOLUTION ".Enabled") .RaceDisable(false); // Error/Warning display - mLighthouseMenu - ->AddWidget(path, ICON_FA_EXCLAMATION_TRIANGLE " Significant frame rate (FPS) drops may be occuring.", - WIDGET_TEXT) - .RaceDisable(false) - .PreFunc( - [](WidgetInfo& info) { info.isHidden = !(!CVarGetInteger(CVAR_LOW_RES_MODE, 0) && IsDroppingFrames()); }) - .Options(TextOptions().Color(Colors::Orange)); + //mLighthouseMenu + // ->AddWidget(path, ICON_FA_EXCLAMATION_TRIANGLE " Significant frame rate (FPS) drops may be occuring.", + // WIDGET_TEXT) + // .RaceDisable(false) + // .PreFunc( + // [](WidgetInfo& info) { info.isHidden = !(!CVarGetInteger(CVAR_LOW_RES_MODE, 0) && IsDroppingFrames()); }) + // .Options(TextOptions().Color(Colors::Orange)); mLighthouseMenu->AddWidget(path, ICON_FA_QUESTION_CIRCLE " \"N64 Mode\" is overriding these settings.", WIDGET_TEXT) .RaceDisable(false) .PreFunc([](WidgetInfo& info) { info.isHidden = !CVarGetInteger(CVAR_LOW_RES_MODE, 0); }) @@ -589,13 +589,13 @@ void UpdateResolutionVars() { disabled_pixelCount = !CVarGetInteger(CVAR_PREFIX_ADVANCED_RESOLUTION ".VerticalResolutionToggle", 0); } -bool IsDroppingFrames() { - // a rather imprecise way of checking for frame drops. - // but it's mostly there to inform the player of large drops. - const short targetFPS = GameEngine::Instance->GetInterpolationFPS(); - const float threshold = targetFPS / 20.0f + 4.1f; - return ImGui::GetIO().Framerate < targetFPS - threshold; -} +//bool IsDroppingFrames() { +// // a rather imprecise way of checking for frame drops. +// // but it's mostly there to inform the player of large drops. +// const short targetFPS = GameEngine::Instance->GetInterpolationFPS(); +// const float threshold = targetFPS / 20.0f + 4.1f; +// return ImGui::GetIO().Framerate < targetFPS - threshold; +//} static RegisterMenuUpdateFunc updateFunc(UpdateResolutionVars, "Settings", "Graphics"); static RegisterMenuInitFunc menuInitFunc(RegisterResolutionWidgets); diff --git a/src/port/UI/ResolutionEditor.h b/src/port/UI/ResolutionEditor.h index a640b1e2c..c0eed1680 100644 --- a/src/port/UI/ResolutionEditor.h +++ b/src/port/UI/ResolutionEditor.h @@ -2,7 +2,7 @@ #define RESOLUTIONEDITOR_H namespace LighthouseGui { -bool IsDroppingFrames(); +//bool IsDroppingFrames(); void RegisterResolutionWidgets(); void UpdateResolutionVars(); } // namespace LighthouseGui From a70f02afbada93a5c5d194b399d50f73de6fd047 Mon Sep 17 00:00:00 2001 From: aMannus Date: Mon, 27 Jul 2026 21:53:42 +0200 Subject: [PATCH 031/131] Switch focus to molehills + AP items only --- src/core2/actor_cubepropsystem.c | 4 +- .../CustomCollectible/CustomCollectible.cpp | 110 ++++++++---------- .../CustomCollectible/CustomCollectible.h | 9 +- .../CustomCollectibleDrawCustom.cpp | 2 +- .../CustomCollectibleDrawCustom.h | 2 + src/port/Rando/StaticData/Items.cpp | 1 + src/port/Rando/Types.h | 2 + src/port/UI/DeveloperTools/GameplayTools.cpp | 4 +- 8 files changed, 59 insertions(+), 75 deletions(-) diff --git a/src/core2/actor_cubepropsystem.c b/src/core2/actor_cubepropsystem.c index 1f0c1ea07..466e31455 100644 --- a/src/core2/actor_cubepropsystem.c +++ b/src/core2/actor_cubepropsystem.c @@ -1785,7 +1785,7 @@ BKSpriteDisplayData *func_80330E54(ActorMarker *marker, BKSprite **sprite_ptr) { return 0; } model_cache_ptr = &modelCache[marker_getActor(marker)->modelCacheIndex]; - if (model_cache_ptr->unk4 == 0 || marker->id == MARKER_300_CUSTOM_COLLECTIBLE) { + if (model_cache_ptr->unk4 == 0) { model_cache_ptr->unk4 = codeB3A80_getSprite(marker->modelId, &model_cache_ptr->unk8); } model_cache_ptr->unk10 = globalTimer_getTime(); @@ -2200,7 +2200,7 @@ f32 func_80331E34(Prop *arg0){ f32 func_80331E64(ActorMarker *marker) { f32 sp24; - if (marker->modelId == 0 || marker->id == MARKER_300_CUSTOM_COLLECTIBLE) { + if (marker->modelId == 0) { return 0.0f; } sp24 = func_80331D20(func_80330F50(marker)); diff --git a/src/port/Rando/CustomCollectible/CustomCollectible.cpp b/src/port/Rando/CustomCollectible/CustomCollectible.cpp index 563aca093..2ff1bbe3c 100644 --- a/src/port/Rando/CustomCollectible/CustomCollectible.cpp +++ b/src/port/Rando/CustomCollectible/CustomCollectible.cpp @@ -1,6 +1,5 @@ #include "CustomCollectible.h" #include "CustomCollectibleDrawCustom.h" -#include "actor.h" #include #include "port/Rando/Rando.h" #include @@ -12,28 +11,29 @@ Actor* actor_draw(ActorMarker* marker, Gfx** gfx, Mtx** mtx, Vtx** vtx); Actor* fxTouchSparkle_draw(ActorMarker* marker, Gfx** gfx, Mtx** mtx, Vtx** vtx); Actor* marker_getActor(ActorMarker* thisx); void marker_despawn(ActorMarker* marker); -Actor* func_802D41C4(ActorMarker* marker, Gfx** gfx, Mtx** mtx, Vtx** vtx); + +Actor* func_802D94B4(ActorMarker* marker, Gfx** gfx, Mtx** mtx, Vtx** vtx); +void func_8028E964(f32 pos[3]); +int func_80257F18(f32 src[3], f32 target[3], f32* yaw); +bool func_8028AED4(f32 arg0[3], f32 arg1); +void coMusicPlayer_playMusic(enum comusic_e track_id, s32 volume); +void __chJinjo_802CDC9C(Actor* actor, s16 arg1); +void fxSparkle_honeycomb(s16 position[3]); } -std::unordered_map customCollectibleDrawInfo = { - { ACTOR_47_EMPTY_HONEYCOMB, { ASSET_361_MODEL_EMPTY_HONEYCOMB, CCT_VANILLA_MODEL } }, - { ACTOR_46_JIGGY, { ASSET_35F_MODEL_JIGGY, CCT_VANILLA_MODEL } }, - { ACTOR_60_JINJO_BLUE, { ASSET_3C0_MODEL_JINJO_BLUE, CCT_VANILLA_MODEL } }, - { ACTOR_62_JINJO_GREEN, { ASSET_3C2_MODEL_JINJO_GREEN, CCT_VANILLA_MODEL } }, - { ACTOR_5F_JINJO_ORANGE, { ASSET_3BC_MODEL_JINJO_ORANGE, CCT_VANILLA_MODEL } }, - { ACTOR_61_JINJO_PINK, { ASSET_3C1_MODEL_JINJO_PINK, CCT_VANILLA_MODEL } }, - { ACTOR_5E_JINJO_YELLOW, { ASSET_3BB_MODEL_JINJO_YELLOW, CCT_VANILLA_MODEL } }, - { ACTOR_12C_MOLEHILL, { ASSET_388_MODEL_MOLEHILL, CCT_VANILLA_MODEL } }, - { ACTOR_2D_MUMBO_TOKEN, { ASSET_41A_SPRITE_MUMBO_TOKEN, CCT_VANILLA_SPRITE } }, - { ACTOR_51_MUSIC_NOTE, { ASSET_6D6_SPRITE_MUSIC_NOTE, CCT_VANILLA_SPRITE } }, - { ACTOR_25E_SNS_EGG, { ASSET_50D_MODEL_SNS_EGG, CCT_VANILLA_SNS_EGG } }, - { ACTOR_25D_ICE_KEY, { ASSET_0_NONE, CCT_CUSTOM_MODEL } }, +ActorAnimationInfo moleAnimations[] = { + { 0, 0.0f }, + { ASSET_13A_ANIM_BOTTLES_ENTER, 2000000000.0f }, + { ASSET_13A_ANIM_BOTTLES_ENTER, 4.5f }, + { ASSET_13B_ANIM_BOTTLES_IDLE, 7.0f }, + { ASSET_139_ANIM_BOTTLES_EXIT, 1.7f }, + { ASSET_13A_ANIM_BOTTLES_ENTER, 2000000000.0f }, }; ActorInfo customActorInfo = { MARKER_300_CUSTOM_COLLECTIBLE, ACTOR_3CD_CUSTOM_COLLECTIBLE, - ASSET_0_NONE, - 1, + ASSET_387_MODEL_BOTTLES, + 3, NULL, CustomCollectible_Update, NULL, @@ -49,17 +49,28 @@ void CustomCollectible_Update(Actor* actor) { if (!actor->initialized) { actor->initialized = true; actor->marker->collidable = true; + } - if (customLocal->randoItemId >= RI_MUSIC_NOTE_BUBBLEGLOOP_SWAMP && - customLocal->randoItemId <= RI_MUSIC_NOTE_TREASURE_TROVE_COVE) { - actor->scale = 0.4f; - } else if (customLocal->randoItemId >= RI_STOP_N_SWOP_EGG_BLUE && - customLocal->randoItemId <= RI_STOP_N_SWOP_EGG_YELLOW) { - actor->scale = 0.4f; - } + RandoItemType itemType = Rando::StaticData::Items[(RandoItemId)customLocal->randoItemId].randoItemType; + if (itemType == RITYPE_MOLEHILL) { + CustomCollectible::FacePlayer(actor); + } else { + actor->yaw += 5.0f; } +} - actor->yaw += 5.0f; +void CustomCollectible::FacePlayer(Actor* actor) { + // Copied from source code inside jinjo.c + f32 sp7C[3]; + f32 sp6C; + f32* sp30 = actor->position; + func_8028E964(sp7C); + func_80257F18(sp30, sp7C, &sp6C); + s16 sp64 = (actor->yaw * 182.04444); + s16 sp66 = (s32)(sp6C * 182.04444); + sp66 = sp64 - sp66; + s32 sp60 = func_8028AED4(sp30, 55.0f); + __chJinjo_802CDC9C(actor, sp66); } Actor* CustomCollectible::AttachCustomVariables(int32_t randoItemId, Actor* customCollectible) { @@ -76,8 +87,8 @@ Actor* CustomCollectible::Spawn(int32_t position[3], RandoItemId randoItemId) { // Custom models exported for OoT are centered instead of offset to the marker, so they appear underground otherwise actor_e actorId = (actor_e)Rando::StaticData::Items[randoItemId].actorId; - auto drawInfo = customCollectibleDrawInfo[actorId]; - if (drawInfo.drawType == CCT_CUSTOM_MODEL) { + RandoItemType itemType = Rando::StaticData::Items[randoItemId].randoItemType; + if (itemType == RITYPE_AP_ITEM) { spawnPosition[1] += 50; } @@ -86,54 +97,27 @@ Actor* CustomCollectible::Spawn(int32_t position[3], RandoItemId randoItemId) { ActorInfo& collectibleInfo = sActorInfoCache[randoItemId]; collectibleInfo = CustomCollectible::GetActorAndDrawInfo(randoItemId); + // Spawn actor Actor* customCollectible = actor_new(spawnPosition, 0, &collectibleInfo, flags); - if (Rando::StaticData::Items[randoItemId].randoItemType == RITYPE_SNS_EGG) { - customCollectible->actorTypeSpecificField = CustomCollectible::GetSNSEggColor(randoItemId); - } customCollectible->marker->collisionFunc = CustomCollectible::OnCollect; customCollectible = CustomCollectible::AttachCustomVariables(randoItemId, customCollectible); return customCollectible; } -uint32_t CustomCollectible::GetSNSEggColor(RandoItemId randoItemId) { - switch (randoItemId) { - case RI_STOP_N_SWOP_EGG_BLUE: - return (uint32_t)SNS_ITEM_EGG_BLUE; - case RI_STOP_N_SWOP_EGG_CYAN: - return (uint32_t)SNS_ITEM_EGG_CYAN; - case RI_STOP_N_SWOP_EGG_GREEN: - return (uint32_t)SNS_ITEM_EGG_GREEN; - case RI_STOP_N_SWOP_EGG_PINK: - return (uint32_t)SNS_ITEM_EGG_PINK; - case RI_STOP_N_SWOP_EGG_RED: - return (uint32_t)SNS_ITEM_EGG_RED; - case RI_STOP_N_SWOP_EGG_YELLOW: - return (uint32_t)SNS_ITEM_EGG_YELLOW; - default: - return (uint32_t)SNS_ITEM_EGG_CYAN; - } -} - ActorInfo CustomCollectible::GetActorAndDrawInfo(RandoItemId randoItemId) { ActorInfo collectibleInfo = customActorInfo; actor_e actorId = (actor_e)Rando::StaticData::Items[randoItemId].actorId; - auto drawInfo = customCollectibleDrawInfo[actorId]; - - collectibleInfo.modelId = drawInfo.drawModel; + RandoItemType itemType = Rando::StaticData::Items[randoItemId].randoItemType; - switch (drawInfo.drawType) { - case CCT_VANILLA_MODEL: - collectibleInfo.draw_func = actor_draw; - break; - case CCT_VANILLA_SPRITE: - collectibleInfo.draw_func = fxTouchSparkle_draw; - break; - case CCT_VANILLA_SNS_EGG: - collectibleInfo.draw_func = func_802D41C4; + switch (itemType) { + case RITYPE_MOLEHILL: + collectibleInfo.draw_func = func_802D94B4; + collectibleInfo.modelId = ASSET_387_MODEL_BOTTLES; + collectibleInfo.animations = moleAnimations; break; - case CCT_CUSTOM_MODEL: + case RITYPE_AP_ITEM: collectibleInfo.draw_func = CustomCollectible_DrawCustomModel; break; default: @@ -144,5 +128,7 @@ ActorInfo CustomCollectible::GetActorAndDrawInfo(RandoItemId randoItemId) { } void CustomCollectible::OnCollect(struct actorMarker_s* self, struct actorMarker_s* other) { + fxSparkle_honeycomb(&self->propPtr->x); + coMusicPlayer_playMusic(COMUSIC_9_NOTE_COLLECTED, 16000); marker_despawn(self); } diff --git a/src/port/Rando/CustomCollectible/CustomCollectible.h b/src/port/Rando/CustomCollectible/CustomCollectible.h index 7e1ed00c4..2c5b12ada 100644 --- a/src/port/Rando/CustomCollectible/CustomCollectible.h +++ b/src/port/Rando/CustomCollectible/CustomCollectible.h @@ -6,13 +6,6 @@ typedef struct { uint16_t randoItemId; } ActorLocal_CustomCollectible; -enum CustomCollectibleDrawTypes { CCT_VANILLA_MODEL, CCT_VANILLA_SPRITE, CCT_VANILLA_SNS_EGG, CCT_CUSTOM_MODEL }; - -typedef struct { - asset_e drawModel; - CustomCollectibleDrawTypes drawType; -} CustomCollectibleDrawInfo; - void CustomCollectible_Update(Actor* actor); class CustomCollectible { @@ -20,8 +13,8 @@ class CustomCollectible { static Actor* AttachCustomVariables(int32_t randoItemId, Actor* customCollectible); static void OnCollect(struct actorMarker_s* self, struct actorMarker_s* other); static ActorInfo GetActorAndDrawInfo(RandoItemId randoItemId); - static uint32_t GetSNSEggColor(RandoItemId randoItemId); public: static Actor* Spawn(int32_t position[3], RandoItemId randoItemId); + static void FacePlayer(Actor* actor); }; diff --git a/src/port/Rando/CustomCollectible/CustomCollectibleDrawCustom.cpp b/src/port/Rando/CustomCollectible/CustomCollectibleDrawCustom.cpp index 6a0aec25b..0a619dcf5 100644 --- a/src/port/Rando/CustomCollectible/CustomCollectibleDrawCustom.cpp +++ b/src/port/Rando/CustomCollectible/CustomCollectibleDrawCustom.cpp @@ -71,7 +71,7 @@ Actor* CustomCollectible_DrawCustomModel(ActorMarker* marker, Gfx** gfx, Mtx** m CustomItemModel model; switch (customLocal->randoItemId) { - case RI_STOP_N_SWOP_ICE_KEY: + case RI_AP_ITEM_PROGRESSION: model = ARCHIPELAGO_MODEL_PROGRESSIVE; break; default: diff --git a/src/port/Rando/CustomCollectible/CustomCollectibleDrawCustom.h b/src/port/Rando/CustomCollectible/CustomCollectibleDrawCustom.h index ce87b41bf..5a31b3d24 100644 --- a/src/port/Rando/CustomCollectible/CustomCollectibleDrawCustom.h +++ b/src/port/Rando/CustomCollectible/CustomCollectibleDrawCustom.h @@ -4,6 +4,8 @@ #include #include +#include "actor.h" + #ifdef __cplusplus extern "C" { #endif diff --git a/src/port/Rando/StaticData/Items.cpp b/src/port/Rando/StaticData/Items.cpp index 415740927..825f0e965 100644 --- a/src/port/Rando/StaticData/Items.cpp +++ b/src/port/Rando/StaticData/Items.cpp @@ -159,6 +159,7 @@ std::map Items = { RI(RI_STOP_N_SWOP_EGG_RED, "a", "Red Egg", RITYPE_SNS_EGG, ACTOR_25E_SNS_EGG, LEVEL_9_RUSTY_BUCKET_BAY), RI(RI_STOP_N_SWOP_EGG_YELLOW, "a", "Yellow Egg", RITYPE_SNS_EGG, ACTOR_25E_SNS_EGG, LEVEL_8_CLICK_CLOCK_WOOD), RI(RI_STOP_N_SWOP_ICE_KEY, "an", "Ice Key", RITYPE_SNS_KEY, ACTOR_25D_ICE_KEY, LEVEL_5_FREEZEEZY_PEAK), + RI(RI_AP_ITEM_PROGRESSION, "a", "AP Progression Item", RITYPE_AP_ITEM, ACTOR_3CD_CUSTOM_COLLECTIBLE, LEVEL_D_CUTSCENE), }; // clang-format on diff --git a/src/port/Rando/Types.h b/src/port/Rando/Types.h index ba6b63e3f..8b32a24aa 100644 --- a/src/port/Rando/Types.h +++ b/src/port/Rando/Types.h @@ -2040,6 +2040,7 @@ typedef enum { RITYPE_MUSIC_NOTE, RITYPE_SNS_EGG, RITYPE_SNS_KEY, + RITYPE_AP_ITEM, RITYPE_MAX, } RandoItemType; @@ -2184,6 +2185,7 @@ typedef enum { RI_STOP_N_SWOP_EGG_RED, RI_STOP_N_SWOP_EGG_YELLOW, RI_STOP_N_SWOP_ICE_KEY, + RI_AP_ITEM_PROGRESSION, RI_MAX, } RandoItemId; diff --git a/src/port/UI/DeveloperTools/GameplayTools.cpp b/src/port/UI/DeveloperTools/GameplayTools.cpp index d4267fdf1..7a8499e8c 100644 --- a/src/port/UI/DeveloperTools/GameplayTools.cpp +++ b/src/port/UI/DeveloperTools/GameplayTools.cpp @@ -435,8 +435,8 @@ void GameplayTools_ObjectSpawner() { UIWidgets::SliderInt("##customCollectibleIndex", &selectedCustomCollectible, UIWidgets::IntSliderOptions() .Color(THEME_COLOR) - .Min(RI_EMPTY_HONEYCOMB_BUBBLEGLOOP_SWAMP) - .Max(RI_STOP_N_SWOP_ICE_KEY) + .Min(RI_UNKNOWN + 1) + .Max(RI_MAX - 1) .DefaultValue(RI_EMPTY_HONEYCOMB_BUBBLEGLOOP_SWAMP) .Format(customCollectibleText.c_str()) .LabelPosition(UIWidgets::LabelPositions::None)); From e96fab351e0974d42e69a4c20a45aee9aaf344fe Mon Sep 17 00:00:00 2001 From: Jeod <47716344+JeodC@users.noreply.github.com> Date: Mon, 27 Jul 2026 17:49:10 -0400 Subject: [PATCH 032/131] Rc fixes 2 (#274) * Filter OoT factories from Torch * Correct jiggy hud element centering * Carry segment-address provenance instead of inferring it from pointer value * Patch Banjo's belt buckle depth (VB, on by default) * Bump libulttraship and add imgui file picker for gamepad-only users * Correct snow particle interpolation with unique id and rename weather related files for accuracy * Anchor" adjust bottles tutorial handling and add honeycomb bundle spawn sync * Fix lookup paths for appimage * Clang format * Interpolation: clean dead code, optimize adaptivefps and draw distance --- CMakeLists.txt | 1 + include/functions.h | 13 +- include/structs.h | 1 + libultraship | 2 +- src/GV/ch/gobi3.c | 1 + src/SM/ch/attacktutorial.c | 17 +- src/SM/ch/smbottles.c | 38 +++ src/SM/ch/vegetables.c | 4 +- src/SM/quarrie.c | 5 +- src/core1/mlmtx.c | 9 - src/core2/ba/model.c | 7 +- src/core2/ch/honeycomb.c | 16 + src/core2/{sfx/init.c => fx/weather.c} | 0 .../{effect_soundemit.c => weather_emitter.c} | 0 .../{sfx/playstate.c => fx/weather_leaves.c} | 2 +- .../{sfx/streamctrl.c => fx/weather_rain.c} | 2 +- .../{sfx/filedata.c => fx/weather_snow.c} | 11 +- src/core2/scorequeue/common3score.c | 5 +- src/core2/sprite/screenoverlay.c | 8 +- src/port/Engine.cpp | 84 +++++- src/port/Enhancements/Backports/EggAim.cpp | 2 +- src/port/Enhancements/Cheats/Cheats.cpp | 5 +- src/port/Enhancements/Events/Hooks/Events.h | 8 + .../Events/Hooks/List/GameEvent.h | 1 + .../Enhancements/Events/PortEnhancements.cpp | 1 + src/port/Extractor/GameExtractor.cpp | 72 ++--- src/port/Extractor/GameExtractor.h | 8 +- src/port/FilePicker.cpp | 62 ++++ src/port/FilePicker.h | 34 +++ src/port/Game.cpp | 5 + src/port/Interpolation/AdaptiveFps.cpp | 35 ++- src/port/Interpolation/FrameInterpolation.cpp | 282 +++--------------- src/port/Interpolation/FrameInterpolation.h | 11 +- src/port/Network/Anchor/Anchor.cpp | 2 + src/port/Network/Anchor/Anchor.h | 3 + src/port/Network/Anchor/Authority.cpp | 1 + src/port/Network/Anchor/Authority.h | 1 + src/port/Network/Anchor/DummyPlayer.cpp | 6 +- src/port/Network/Anchor/HookHandlers.cpp | 34 ++- .../Network/Anchor/Packets/SetAbility.cpp | 11 + .../Network/Anchor/Packets/SpawnHoneycomb.cpp | 47 +++ src/port/Patches/GraphicsPatches.cpp | 63 +++- src/port/Patches/Patches.h | 3 + src/port/Resource/GfxBridge.c | 30 +- src/port/Save/SaveConverter.cpp | 53 +++- src/port/Save/SaveConverter.h | 8 +- src/port/UI/LighthouseMenuSettings.cpp | 26 +- src/port/UI/LighthouseModMenuWindow.cpp | 90 +++--- src/port/UI/LighthouseModals.cpp | 7 +- src/port/UI/ResolutionEditor.cpp | 16 +- src/port/UI/ResolutionEditor.h | 2 +- 51 files changed, 691 insertions(+), 464 deletions(-) rename src/core2/{sfx/init.c => fx/weather.c} (100%) rename src/core2/fx/{effect_soundemit.c => weather_emitter.c} (100%) rename src/core2/{sfx/playstate.c => fx/weather_leaves.c} (98%) rename src/core2/{sfx/streamctrl.c => fx/weather_rain.c} (98%) rename src/core2/{sfx/filedata.c => fx/weather_snow.c} (94%) create mode 100644 src/port/FilePicker.cpp create mode 100644 src/port/FilePicker.h create mode 100644 src/port/Network/Anchor/Packets/SpawnHoneycomb.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 814995a3c..fd4aa5d33 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -499,6 +499,7 @@ option(BUILD_SM64 "Build with Super Mario 64 support" OFF) option(BUILD_MK64 "Build with Mario Kart 64 support" OFF) option(BUILD_SF64 "Build with Star Fox 64 support" OFF) option(BUILD_FZERO "Build with F-Zero X support" OFF) +option(BUILD_OOT "Build with Ocarina of Time support" OFF) option(BUILD_MARIO_ARTIST "Build with Mario Artist support" OFF) option(BUILD_NAUDIO "Build with NAudio support" OFF) add_subdirectory(Torch) diff --git a/include/functions.h b/include/functions.h index 90dac6627..7e899b363 100644 --- a/include/functions.h +++ b/include/functions.h @@ -649,6 +649,7 @@ void gSPSegmentLoadRes(void* value, int segNum, uintptr_t target); void gSPDisplayList(Gfx* pkt, Gfx* dl); void gSPDisplayListOffset(Gfx* pkt, Gfx* dl, int offset); void gSPVertex(Gfx* pkt, uintptr_t v, int n, int v0); +void gSPVertexSeg(Gfx* pkt, u32 seg, uintptr_t off, int n, int v0); void gSPInvalidateTexCache(Gfx* pkt, uintptr_t texAddr); int ResourceMgr_OTRSigCheck(char* imgData); @@ -2821,7 +2822,7 @@ void saveData_load(void *savedata); void savedata_init(void); void savedata_update_crc(void *buffer, s32 size); -// --- core2/sfx/filedata.c --- +// --- core2/fx/weather_snow.c --- void func_802F8FF0(void); void func_802F8FFC(void); void func_802F9054(void); @@ -2830,7 +2831,7 @@ void func_802F9114(void); void func_802F919C(void); void func_802F962C(Gfx **gfx, Mtx **mtx, Vtx **vtx); -// --- core2/sfx/init.c --- +// --- core2/fx/weather.c --- struct3s * func_802F7C7C(void); struct6s * func_802F7C38(void); void func_802F7CC0(void); @@ -2840,7 +2841,7 @@ void func_802F7D44(void); void func_802F7DE4(void); void func_802F7E54(void); -// --- core2/sfx/playstate.c --- +// --- core2/fx/weather_leaves.c --- void func_802F8A70(struct6s *self); void func_802F8A90(struct6s *self, Gfx **gdl, Mtx **mptr, Vtx **vptr); void func_802F8B8C(struct6s *self); @@ -2875,7 +2876,7 @@ void sfxSource_setCallbackByIndex(u8 indx, void (*arg1)(u8)); void sfxSource_triggerCallbackByIndex(u8 indx); void func_8030DFB4(u8 indx, s32 arg1); -// --- core2/sfx/streamctrl.c --- +// --- core2/fx/weather_rain.c --- void func_802F80F0(struct3s *self); void func_802F8110(struct3s *self, Gfx **gdl, Mtx **mptr, u32 arg3); void func_802F8214(struct3s * self); @@ -3400,7 +3401,7 @@ f32 roll_get(void); void roll_setAngularVelocity(f32, f32); void roll_setIdeal(f32); -// --- core2/sfx/playstate.c --- +// --- core2/fx/weather_leaves.c --- struct6s *func_802F8BE0(s32 arg0); // --- core2/sfx/randompitch.c --- @@ -3410,7 +3411,7 @@ void func_802F9F80(s32, f32, f32, f32); void func_802F9FD0(s32, f32, f32, f32); void func_802FA060(s32, s32, s32, f32); -// --- core2/sfx/streamctrl.c --- +// --- core2/fx/weather_rain.c --- struct3s *func_802F8264(s32 arg0); // --- core2/fx/projectile_anim.c --- diff --git a/include/structs.h b/include/structs.h index 3c6eac19f..ce50d76ab 100644 --- a/include/structs.h +++ b/include/structs.h @@ -437,6 +437,7 @@ typedef struct{ typedef struct struct_4D_s{ f32 unk0[3]; f32 unkC[3]; + u32 id; // [port] stable identity for frame interpolation }struct4Ds; typedef struct{ diff --git a/libultraship b/libultraship index 8a67fa4b9..f57f4d255 160000 --- a/libultraship +++ b/libultraship @@ -1 +1 @@ -Subproject commit 8a67fa4b9c6d8302cba4aeecd02411d16d28d818 +Subproject commit f57f4d2552453cf330fb48f2d6f780137f33c221 diff --git a/src/GV/ch/gobi3.c b/src/GV/ch/gobi3.c index 1552e5897..c82666e66 100644 --- a/src/GV/ch/gobi3.c +++ b/src/GV/ch/gobi3.c @@ -28,6 +28,7 @@ void __chGobi3_spawnHoneyComb(Actor *this){ bundle_setYaw(this->yaw); func_802CA1CC(HONEYCOMB_C_GV_GOBI_3); bundle_spawn_f32(BUNDLE_D__EMPTY_HONEYCOMB, sp18); + CALL_EVENT(OnHoneycombDropSpawn, HONEYCOMB_C_GV_GOBI_3, BUNDLE_D__EMPTY_HONEYCOMB, sp18[0], sp18[1], sp18[2]); } void __chGobi3_runaway(ActorMarker *caller, enum asset_e text_id, s32 arg2){ diff --git a/src/SM/ch/attacktutorial.c b/src/SM/ch/attacktutorial.c index 130fc3fcf..10b7ef264 100644 --- a/src/SM/ch/attacktutorial.c +++ b/src/SM/ch/attacktutorial.c @@ -8,6 +8,10 @@ extern void timed_exitStaticCamera(f32 time); extern void func_8028F918(s32); +// [port] Spare actor bit repurposed: the claw/roll/rap trio was already known when this +// actor spawned (or a local opt-out just unlocked it). +#define movesKnownAtSpawn unk38_0 + enum ch_attack_tutorial_states { CH_ATTACK_TUTORIAL_STATE_1_UNKNOWN = 0x1, // L80387610 CH_ATTACK_TUTORIAL_STATE_2_APPLY_LEARNED_MOVE, // L803873E0 @@ -132,6 +136,14 @@ static bool __chAttackTutorial_areLearnableAbilitiesUnlocked() { && ability_isUnlocked(ABILITY_B_RATATAT_RAP); } +// [port] A local tutorial opt-out unlocks every move mid-session; re-arm the spawn latch. +void chAttackTutorial_onTutorialSkipped(void) { + Actor *tutorial = actorArray_findActorFromActorId(ACTOR_167_ATTACK_TUTORIAL); + if (tutorial != NULL) { + tutorial->movesKnownAtSpawn = 1; + } +} + static void __chAttackTutorial_update(Actor *this) { f32 minimum_distance; Actor *bottles; @@ -153,6 +165,9 @@ static void __chAttackTutorial_update(Actor *this) { ? 1 : 0; + // [port] Latch "moves already known" at spawn. + this->movesKnownAtSpawn = __chAttackTutorial_areLearnableAbilitiesUnlocked(); + this->initialized = true; } @@ -161,7 +176,7 @@ static void __chAttackTutorial_update(Actor *this) { if (mapSpecificFlags_get(SM_SPECIFIC_FLAG_4)) __chAttackTutorial_setState(this, CH_ATTACK_TUTORIAL_STATE_5_SHOW_LEARN_MOVE_DIALOG); - if (__chAttackTutorial_areLearnableAbilitiesUnlocked() || volatileFlag_get(VOLATILE_FLAG_C1_IN_FINAL_CHARACTER_PARADE)) + if (this->movesKnownAtSpawn || volatileFlag_get(VOLATILE_FLAG_C1_IN_FINAL_CHARACTER_PARADE)) __chAttackTutorial_setState(this, CH_ATTACK_TUTORIAL_STATE_4_TUTORIAL_COMPLETED); break; diff --git a/src/SM/ch/smbottles.c b/src/SM/ch/smbottles.c index 13c2512da..cfc4e046f 100644 --- a/src/SM/ch/smbottles.c +++ b/src/SM/ch/smbottles.c @@ -3,7 +3,10 @@ #include "functions.h" #include "variables.h" +#include "port/Patches/Patches.h" + /* extern functions */ +void chAttackTutorial_onTutorialSkipped(void); Actor *func_802D94B4(ActorMarker *, Gfx **, Mtx **, Vtx **); void func_8028E668(f32 *, f32, f32, f32); void subaddie_turnToYaw(Actor *, f32); @@ -110,6 +113,19 @@ void __chSmBottles_skipIntroTutorial(void) { ability_unlock(ABILITY_5_CLIMB); __chSmBottles_setHasUsedSpiralMountainAbilities(); mapSpecificFlags_set(SM_SPECIFIC_FLAG_3_ALL_SM_ABILITIES_LEARNED, true); + // [port] Vanilla parity: a local opt-out pops the bonus Collywobble this session. + chAttackTutorial_onTutorialSkipped(); +} + +// [port] Anchor: a remote unlock completed the SM move set mid-session. Apply the same +// completion state the init block derives from abilities at map load. +void chSmBottles_netApplyTutorialComplete(void) { + mapSpecificFlags_set(SM_SPECIFIC_FLAG_1_TALKED_TO_BOTTLES, true); + mapSpecificFlags_set(SM_SPECIFIC_FLAG_3_ALL_SM_ABILITIES_LEARNED, true); + mapSpecificFlags_set(SM_SPECIFIC_FLAG_2, true); + mapSpecificFlags_set(SM_SPECIFIC_FLAG_C, true); + mapSpecificFlags_set(SM_SPECIFIC_FLAG_F, true); + chAttackTutorial_onTutorialSkipped(); } /** @@ -496,6 +512,13 @@ void chSmBottles_update(Actor *this) { this->yaw_ideal = (f32) subaddie_getYawToPlayer(this); subaddie_turnToYaw(this, 4.0f); + // [port] Anchor: ability molehills stay inert until the team's tutorial choice + // is made, so nobody can start a tutorial the pending decision would invalidate. + if (this->actorTypeSpecificField != 1 && this->actorTypeSpecificField != 8 && + !EventSystem_Should(VB_SM_MOLEHILL_ACTIVE, true, this)) { + break; + } + if ((this->actorTypeSpecificField == 1 && !mapSpecificFlags_get(SM_SPECIFIC_FLAG_1_TALKED_TO_BOTTLES)) || (this->actorTypeSpecificField == 8 && !mapSpecificFlags_get(SM_SPECIFIC_FLAG_2)) || (this->actorTypeSpecificField == 8 && mapSpecificFlags_get(SM_SPECIFIC_FLAG_3_ALL_SM_ABILITIES_LEARNED) && !mapSpecificFlags_get(SM_SPECIFIC_FLAG_F)) @@ -503,6 +526,13 @@ void chSmBottles_update(Actor *this) { if (((ml_vec3f_distance(plyr_pos, this->unk1C) < this->actor_specific_1_f) && player_isStableWithExtraSteps()) || mapSpecificFlags_get(SM_SPECIFIC_FLAG_10) ) {//L80389C8C + // [port] Anchor: the intro tutorial offer is a team decision. + if (this->actorTypeSpecificField == 1 && + !EventSystem_Should(VB_SM_TUTORIAL_CHOICE_OPEN, true, this)) { + mapSpecificFlags_set(SM_SPECIFIC_FLAG_1_TALKED_TO_BOTTLES, true); + break; + } + if (subaddie_playerIsWithinSphereAndActive(this, 0x96)) { func_8028F45C(9, this->position); } @@ -614,6 +644,14 @@ void chSmBottles_update(Actor *this) { }//L8038A218 if (bakey_pressed != -1) { + // [port] Anchor: if the tutorial decision belongs to a teammate (or moves + // are already being learned), fold a local opt-out into an opt-in. + if (bakey_pressed == 0 && !EventSystem_Should(VB_SM_TUTORIAL_CHOICE_OPEN, true, this)) { + bakey_pressed = 1; + } + // Record the answer team-wide the moment it lands, so a second pending + // offer folds even before any move is learned. + port_puzzleStep_orBits(ANCHOR_PUZZLE_SM_TUTORIAL, 1); fileProgressFlag_set(FILEPROG_DB_SKIPPED_TUTORIAL, bakey_pressed ? 0 : 1); gcdialog_showDialog(bakey_pressed ? ASSET_E07_DIALOG_BOTTLES_UNKNOWN : ASSET_E09_DIALOG_BOTTLES_SKIPPED_TUTORIAL, 0xe, this->position, this->marker, __chSmBottles_textCallback,__chSmBottles_textActions); diff --git a/src/SM/ch/vegetables.c b/src/SM/ch/vegetables.c index a06ad7f2d..7a0f3a919 100644 --- a/src/SM/ch/vegetables.c +++ b/src/SM/ch/vegetables.c @@ -218,10 +218,12 @@ static void __chVegetables_vegetableDeathParticles(Actor* this) { __chVegetables_setSpriteDustParticles(partEmitMgr_newEmitter(8), particles_position, 8); } - if (this->unk38_31) { + // [port] Anchor: skip the drop if a teammate's synced drop already put one here. + if (this->unk38_31 && !actorArray_findHoneycombMarkerById(HONEYCOMB_17_SM_COLLIWOBBLE)) { this->position_y += 100.0f; func_802CA1CC(HONEYCOMB_17_SM_COLLIWOBBLE); __spawnQueue_add_4((GenFunction_4) spawnQueue_bundle_f32, BUNDLE_1F_SM_EMPTY_HONEYCOMB, reinterpret_cast(s32, this->position_x), reinterpret_cast(s32, this->position_y), reinterpret_cast(s32, this->position_z)); + CALL_EVENT(OnHoneycombDropSpawn, HONEYCOMB_17_SM_COLLIWOBBLE, BUNDLE_1F_SM_EMPTY_HONEYCOMB, this->position_x, this->position_y, this->position_z); } timed_mapSpecificFlags_setTrue(1.5f, SM_SPECIFIC_FLAG_7); diff --git a/src/SM/quarrie.c b/src/SM/quarrie.c index d60843118..83d9c4006 100644 --- a/src/SM/quarrie.c +++ b/src/SM/quarrie.c @@ -112,9 +112,12 @@ void SM_func_80386D68(Actor *this){ func_80386B04(partEmitMgr_newEmitter(0xA), this->position, 0xA, this->scale); func_80386C2C(partEmitMgr_newEmitter(0x10), this->position, 0x10, this->scale); - if (this->partnerActor && codeBF0_shouldSpawnQuarrieHoneyComb(this->partnerActor)) { + // [port] Anchor: skip the drop if a teammate's synced drop already put one here. + if (this->partnerActor && codeBF0_shouldSpawnQuarrieHoneyComb(this->partnerActor) && + !actorArray_findHoneycombMarkerById(HONEYCOMB_18_SM_QUARRIES)) { func_802CA1CC(HONEYCOMB_18_SM_QUARRIES); __spawnQueue_add_4((GenFunction_4) spawnQueue_bundle_f32, BUNDLE_1F_SM_EMPTY_HONEYCOMB, reinterpret_cast(s32, this->position[0]), reinterpret_cast(s32, this->position[1]), reinterpret_cast(s32, this->position[2])); + CALL_EVENT(OnHoneycombDropSpawn, HONEYCOMB_18_SM_QUARRIES, BUNDLE_1F_SM_EMPTY_HONEYCOMB, this->position[0], this->position[1], this->position[2]); } marker_despawn(this->marker); diff --git a/src/core1/mlmtx.c b/src/core1/mlmtx.c index 6b5002193..b2f8a9101 100644 --- a/src/core1/mlmtx.c +++ b/src/core1/mlmtx.c @@ -217,7 +217,6 @@ void mlMtx_push_multiplied_2(MtxF * l_mtx, MtxF * r_mtx) { } } s_mtx_stack = (dst + 0); - FrameInterpolation_RecordMatrixMult(l_mtx->mf, r_mtx->mf); } //mlMtx @@ -233,7 +232,6 @@ void mlMtxIdent(void){ v0 += 5; } v0[0] = 1.0f; - FrameInterpolation_RecordMatrixIdent(); } void func_80251B5C(f32 x, f32 y, f32 z){ @@ -256,7 +254,6 @@ void mlMtxSet(MtxF* arg0) { *dst++ = *src++; } } - FrameInterpolation_RecordMatrixSet(arg0->mf); } void mlMtxRotate(f32 a, f32 x, f32 y, f32 z) { @@ -270,7 +267,6 @@ void mlMtxRotPitch(f32 arg0) { f32 var_f10; f32 var_f18; - FrameInterpolation_RecordMatrixRotPitch(arg0); if (arg0 != 0.0f) { arg0 *= D_80276578; sin = sinf(arg0); @@ -299,7 +295,6 @@ void mlMtxRotYaw(f32 arg0) { f32 var_f18; s32 i; - FrameInterpolation_RecordMatrixRotYaw(arg0); if (arg0 != 0.0f) { arg0 *= BAD_DTOR; sin = sinf(arg0); @@ -319,7 +314,6 @@ void mlMtxRotRoll(f32 arg0) { f32 var_f10; f32 var_f18; - FrameInterpolation_RecordMatrixRotRoll(arg0); if (arg0 != 0.0f) { arg0 *= D_8027657C; sin = sinf(arg0); @@ -391,7 +385,6 @@ void mlMtxRotatePYR(f32 pitch, f32 yaw, f32 roll){ void mlMtxScale_xyz(f32 x, f32 y, f32 z){ int i; - FrameInterpolation_RecordMatrixScale(x, y, z); for(i = 0; i < 3; i++){ s_mtx_stack->mf[0][i] *= x; s_mtx_stack->mf[1][i] *= y; @@ -401,7 +394,6 @@ void mlMtxScale_xyz(f32 x, f32 y, f32 z){ void mlMtxScale(f32 scale){ int i; - FrameInterpolation_RecordMatrixScale(scale, scale, scale); for(i = 0; i < 3; i++){ s_mtx_stack->mf[0][i] *= scale; s_mtx_stack->mf[1][i] *= scale; @@ -516,7 +508,6 @@ void mlMtxTranslate(f32 x, f32 y, f32 z) { f32 phi_f16; s32 phi_v1; - FrameInterpolation_RecordMatrixTranslate(x, y, z); for(phi_v1 = 0; phi_v1 < 3; phi_v1++){ phi_f18 = s_mtx_stack->mf[0][phi_v1] * x; phi_f16 = s_mtx_stack->mf[1][phi_v1] * y; diff --git a/src/core2/ba/model.c b/src/core2/ba/model.c index 4b16065fd..0f0894088 100644 --- a/src/core2/ba/model.c +++ b/src/core2/ba/model.c @@ -6,6 +6,7 @@ #include "core2/ba/model.h" #include "core2/ba/physics.h" #include "bk_math.h" +#include "port/Patches/Patches.h" void assetcache_release(void *); //assetcache_free void modelRender_func_8033A280(f32); @@ -205,8 +206,12 @@ void baModel_set(enum asset_e asset_id){ baModelBin = NULL; } baModelId = asset_id; - if(baModelId) + if(baModelId) { baModelBin = assetcache_get(baModelId); + if (!EventSystem_Should(VB_MODEL_XLU_DEPTH_WRITE, true, baModelBin, baModelId)) { + port_patchModelXluDepthWrite(baModelBin, baModelId); + } + } } } diff --git a/src/core2/ch/honeycomb.c b/src/core2/ch/honeycomb.c index 9ae9cf22a..fb5cc016b 100644 --- a/src/core2/ch/honeycomb.c +++ b/src/core2/ch/honeycomb.c @@ -201,3 +201,19 @@ enum honeycomb_e func_802CA1C4(Actor *this){ void func_802CA1CC(enum honeycomb_e id){ D_8037DDC0 = id; } + +// [port] Anchor: spawn a teammate's dropped empty honeycomb locally. Spawned through the +// same per-map bundle as the local drop so it gets the pickup drop physics. +static void __chHoneycomb_netSpawnDrop(uintptr_t uid, uintptr_t bundle, uintptr_t x, uintptr_t y, uintptr_t z){ + f32 pos[3]; + pos[0] = reinterpret_cast(f32, x); + pos[1] = reinterpret_cast(f32, y); + pos[2] = reinterpret_cast(f32, z); + func_802CA1CC((enum honeycomb_e)uid); + bundle_spawn_f32((enum bundle_e)bundle, pos); +} + +void chHoneycomb_netSpawnDropAt(s32 uid, s32 bundleId, f32 x, f32 y, f32 z){ + __spawnQueue_add_5((GenFunction_5)__chHoneycomb_netSpawnDrop, (uintptr_t)uid, (uintptr_t)bundleId, + reinterpret_cast(s32, x), reinterpret_cast(s32, y), reinterpret_cast(s32, z)); +} diff --git a/src/core2/sfx/init.c b/src/core2/fx/weather.c similarity index 100% rename from src/core2/sfx/init.c rename to src/core2/fx/weather.c diff --git a/src/core2/fx/effect_soundemit.c b/src/core2/fx/weather_emitter.c similarity index 100% rename from src/core2/fx/effect_soundemit.c rename to src/core2/fx/weather_emitter.c diff --git a/src/core2/sfx/playstate.c b/src/core2/fx/weather_leaves.c similarity index 98% rename from src/core2/sfx/playstate.c rename to src/core2/fx/weather_leaves.c index bd8e25259..557496177 100644 --- a/src/core2/sfx/playstate.c +++ b/src/core2/fx/weather_leaves.c @@ -80,7 +80,7 @@ void func_802F8A90(struct6s *this, Gfx **gdl, Mtx **mptr, Vtx **vptr){ struct5s * endPtr = bk_vector_getEnd(this->unk1C); for(iPtr = startPtr; iPtr < endPtr; iPtr++){ // [port] Stable scope per entry; vector count fluctuates. - FrameInterpolation_RecordOpenChild("playstate", (uintptr_t)(iPtr - startPtr)); + FrameInterpolation_RecordOpenChild("weather_leaf", (uintptr_t)(iPtr - startPtr)); modelRender_setDepthMode(MODEL_RENDER_DEPTH_COMPARE); modelRender_draw(gdl, mptr, iPtr->unk4, iPtr->unk1C, 1.0f, NULL, iPtr->unk0); iPtr->unk34 = modelRender_func_8033A170(); diff --git a/src/core2/sfx/streamctrl.c b/src/core2/fx/weather_rain.c similarity index 98% rename from src/core2/sfx/streamctrl.c rename to src/core2/fx/weather_rain.c index 0e323c9f4..b43602f00 100644 --- a/src/core2/sfx/streamctrl.c +++ b/src/core2/fx/weather_rain.c @@ -69,7 +69,7 @@ void func_802F8110(struct3s *this, Gfx **gdl, Mtx **mptr, u32 arg3){ endPtr = bk_vector_getEnd(this->unk20); for(iPtr = startPtr; iPtr < endPtr; iPtr++){ // [port] Per-entry stable scope — vector count varies, indices shift. - FrameInterpolation_RecordOpenChild("streamctrl", (uintptr_t)(iPtr - startPtr)); + FrameInterpolation_RecordOpenChild("weather_rain", (uintptr_t)(iPtr - startPtr)); modelRender_setDepthMode(MODEL_RENDER_DEPTH_COMPARE); modelRender_draw(gdl, mptr, iPtr->unk0, 0, 1.0f, 0, this->unk2C); iPtr->unk18 = modelRender_func_8033A170(); diff --git a/src/core2/sfx/filedata.c b/src/core2/fx/weather_snow.c similarity index 94% rename from src/core2/sfx/filedata.c rename to src/core2/fx/weather_snow.c index 61ad4c82f..cf10f14db 100644 --- a/src/core2/sfx/filedata.c +++ b/src/core2/fx/weather_snow.c @@ -57,6 +57,7 @@ f32 D_80381080[3]; f32 D_8038108C; Gfx *D_80381090; Struct_core2_72060_0 *D_80381094; +static u32 sSnowNextId = 0; // [port] Monotonic spawn id bool func_802F989C(Gfx **gfx, Mtx **mtx, f32 arg2[3]); @@ -179,6 +180,7 @@ void func_802F919C(void) { sp40->unkC[0] = 0.0f; sp40->unkC[1] = randf2(-150.0f, -50.0f); sp40->unkC[2] = 0.0f; + sp40->id = ++sSnowNextId; } } } @@ -213,13 +215,8 @@ void func_802F962C(Gfx **gfx, Mtx **mtx, Vtx **vtx) { D_80381094 = (Struct_core2_72060_0 *)((uintptr_t)D_80369288 + D_80369288->geo_list_offset); for(phi_s0 = D_80369280->unk1C; phi_s0 < D_80369280->unk1C + D_80369284; phi_s0++) { - // [port] Scope keyed on position — array shrinks below the - // height threshold and frustum culls inside func_802F989C, so - // index-based pairing would mismatch surviving items. - FrameInterpolation_RecordOpenChildHash3("grass_item", - FrameInterpolation_FloatBits(phi_s0->unk0[0]), - FrameInterpolation_FloatBits(phi_s0->unk0[1]), - FrameInterpolation_FloatBits(phi_s0->unk0[2])); + // [port] Scope keyed on spawn id + FrameInterpolation_RecordOpenChild("weather_snow", phi_s0->id); if ((func_802F989C(gfx, mtx, phi_s0->unk0) == 0) && (phi_s0->unk0[1] < D_8038104C)) { func_802F9134(phi_s0 - D_80369280->unk1C); phi_s0--; diff --git a/src/core2/scorequeue/common3score.c b/src/core2/scorequeue/common3score.c index a4bd65fb8..e63b6e40b 100644 --- a/src/core2/scorequeue/common3score.c +++ b/src/core2/scorequeue/common3score.c @@ -214,7 +214,10 @@ void fxcommon3score_draw(enum item_e item_id, void *arg1, Gfx **gfx, Mtx **mtx, if(a1->unk6C == 0.0f){ a1->unk6C = 1.1*(vtxList_getGlobalNorm(modelbin_getVtxList(a1->model)) * a1->unk3C); } - depthbuffer_clearRegion(gfx, a1->unk30 - a1->unk6C, sp40 - a1->unk6C, 2*a1->unk6C, 2*a1->unk6C, gFramebuffers[getActiveFramebuffer()]); + // [port] Clear against draw_x, not unk30: the model is drawn at the widescreen-anchored + // position, so the depth hole has to move with it or the icon gets z-clipped by the world. + // depthbuffer_clearRegion(gfx, a1->unk30 - a1->unk6C, sp40 - a1->unk6C, 2*a1->unk6C, 2*a1->unk6C, gFramebuffers[getActiveFramebuffer()]); + depthbuffer_clearRegion(gfx, draw_x - a1->unk6C, sp40 - a1->unk6C, 2*a1->unk6C, 2*a1->unk6C, gFramebuffers[getActiveFramebuffer()]); if(a1->anim_ctrl != NULL){ anctrl_drawSetup(a1->anim_ctrl, sp5C, 1); } diff --git a/src/core2/sprite/screenoverlay.c b/src/core2/sprite/screenoverlay.c index a0110f11d..132012a8f 100644 --- a/src/core2/sprite/screenoverlay.c +++ b/src/core2/sprite/screenoverlay.c @@ -286,7 +286,7 @@ void spriteRender_drawWithSegment(Gfx **gfx, Vtx **vtx, BKSprite *sprite, u32 fr sp1B4 = *gfx; sp1B0 = var_a3; if(segment != 0){ - gSPVertex((*gfx)++, SEGMENT_ADDR(segment, (uintptr_t)sp1B0 - (uintptr_t)vtx_start), 0, 0); + gSPVertexSeg((*gfx)++, segment, (uintptr_t)sp1B0 - (uintptr_t)vtx_start, 0, 0); }else{ gSPVertex((*gfx)++, (uintptr_t)sp1B0, 0, 0); } @@ -336,7 +336,7 @@ void spriteRender_drawWithSegment(Gfx **gfx, Vtx **vtx, BKSprite *sprite, u32 fr if (i_vtx == 0x10) { i_vtx = 0; if(segment != 0){ - gSPVertex(sp1B4, SEGMENT_ADDR(segment, (uintptr_t)sp1B0 - (uintptr_t)vtx_start), 16, 0); + gSPVertexSeg(sp1B4, segment, (uintptr_t)sp1B0 - (uintptr_t)vtx_start, 16, 0); }else{ gSPVertex(sp1B4, (uintptr_t)sp1B0, 16, 0); } @@ -344,7 +344,7 @@ void spriteRender_drawWithSegment(Gfx **gfx, Vtx **vtx, BKSprite *sprite, u32 fr sp1B4 = *gfx; sp1B0 = var_a3; if (segment) { - gSPVertex((*gfx)++, SEGMENT_ADDR(segment, (uintptr_t)sp1B0 - (uintptr_t)vtx_start), 0, 0); + gSPVertexSeg((*gfx)++, segment, (uintptr_t)sp1B0 - (uintptr_t)vtx_start, 0, 0); } else { gSPVertex((*gfx)++, (uintptr_t)sp1B0, 0, 0); } @@ -358,7 +358,7 @@ void spriteRender_drawWithSegment(Gfx **gfx, Vtx **vtx, BKSprite *sprite, u32 fr //rewrite vtx seg start with correct vtx count if (i_vtx > 0) { if(segment != 0){ - gSPVertex(sp1B4, SEGMENT_ADDR(segment, (uintptr_t)sp1B0 - (uintptr_t)vtx_start), i_vtx, 0); + gSPVertexSeg(sp1B4, segment, (uintptr_t)sp1B0 - (uintptr_t)vtx_start, i_vtx, 0); }else{ if(1); gSPVertex(sp1B4, (uintptr_t)sp1B0, i_vtx, 0); diff --git a/src/port/Engine.cpp b/src/port/Engine.cpp index 7aaa45dfc..91590aad7 100644 --- a/src/port/Engine.cpp +++ b/src/port/Engine.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #if defined(__linux__) || defined(__APPLE__) #include #include @@ -31,6 +32,7 @@ #include "Audio/GameAudio.h" #include "build.h" #include "Extractor/GameExtractor.h" +#include "ship/window/gui/FileBrowserWindow.h" #include "Interpolation/AdaptiveFps.h" #include "Interpolation/FrameInterpolation.h" #include "Network/Anchor/Anchor.h" @@ -211,6 +213,7 @@ typedef enum PromptSteps { PS_FILE_CHECK, PS_LOCAL, PS_FIRST, + PS_FIRST_WAIT, // waiting for the async file-pick result (resolves immediately on the native path) PS_WAIT, PS_NONE, } PromptSteps; @@ -453,6 +456,11 @@ void GameEngine::RunExtract(int argc, char* argv[]) { bool extractStarted = false; std::atomic extractCount{ 0 }, totalExtract{ 0 }; + // Async ROM selection: the result callback fires on this thread during the render step below, so + // these plain locals are safe to capture by reference. + bool romLoaded = false; + bool romResultReady = false; + std::string installPath = Ship::Context::GetAppBundlePath(); std::string file; @@ -511,7 +519,7 @@ void GameEngine::RunExtract(int argc, char* argv[]) { GameExtractor::sCustomCodePromptActive = false; }); } - if (LighthouseGui::PopupsQueued() > 0 || extracting) { + if (LighthouseGui::PopupsQueued() > 0 || extracting || Ship::FileBrowserWindow::IsOpen()) { goto render; } @@ -746,13 +754,54 @@ void GameEngine::RunExtract(int argc, char* argv[]) { continue; } case PS_FIRST: { - if (args.empty() && !extract.SelectGameFromUI()) { - promptStep = PS_FILE_CHECK; + if (args.empty()) { + // Skip the picker entirely if a baserom.us.z64 is sitting in the app + // directory: load it and go straight to extraction. + std::string baserom = Ship::Context::GetPathRelativeToAppDirectory("baserom.us.z64"); + if (std::filesystem::exists(baserom) && extract.LoadRomFromPath(baserom)) { + extracting = true; + extractStarted = true; + file = extract.GetRomPath(); + (void)threadPool->submit_task([&]() -> void { + extract.GenerateOTR(extractCount, totalExtract, "bk"); + extracting = false; + }); + continue; // stay in PS_FIRST; the completion check fires when done + } + // Otherwise open the picker (native dialog on desktop, ImGui browser on + // consoles/arm). For the browser, the IsOpen() gate above keeps the loop + // rendering until the user picks or cancels; the ROM loads before the callback. + romResultReady = false; + romLoaded = false; + extract.SelectGameFromUI([&](bool ok) { + romLoaded = ok; + romResultReady = true; + }); + promptStep = PS_FIRST_WAIT; + continue; + } + extracting = true; + extractStarted = true; + file = extract.GetRomPath(); + (void)threadPool->submit_task([&]() -> void { + extract.GenerateOTR(extractCount, totalExtract, "bk"); + extracting = false; + }); + continue; + } + case PS_FIRST_WAIT: { + if (!romResultReady) { + goto render; // browser still open; keep drawing it + } + romResultReady = false; + if (!romLoaded) { + promptStep = PS_FILE_CHECK; // cancelled or failed to load continue; } extracting = true; extractStarted = true; file = extract.GetRomPath(); + promptStep = PS_FIRST; // so the ES_EXTRACT/PS_FIRST completion check fires (void)threadPool->submit_task([&]() -> void { extract.GenerateOTR(extractCount, totalExtract, "bk"); extracting = false; @@ -1243,6 +1292,9 @@ using Clock = std::chrono::steady_clock; inline long long NsSince(Clock::time_point t0) { return std::chrono::duration_cast(Clock::now() - t0).count(); } + +// In-flight async builds of interpolated sub-frame replacement maps +std::vector> sMapBuildFutures; } // namespace void GameEngine::RunCommands(Gfx* Commands, const std::vector>& mtx_replacements, @@ -1265,18 +1317,21 @@ void GameEngine::RunCommands(Gfx* Commands, const std::vectorGetWindow(); for (size_t frameIdx = 0; frameIdx < frameCount; frameIdx++) { + if (frameIdx >= 1 && frameIdx - 1 < sMapBuildFutures.size()) { + sMapBuildFutures[frameIdx - 1].wait(); + } const auto& m = mtx_replacements[frameIdx]; bool isFinalFrame = (frameIdx == frameCount - 1); // Bypass IsFrameReady() when interpolation is active — render all // frames per tick and let vsync pace them. if (frameCount > 1 || wndBase->IsFrameReady()) { + // Sample the full CPU cost of producing this sub-frame. + auto runT0 = Clock::now(); auto gui = wndBase->GetGui(); wndBase->GetMouseStateManager()->StartFrame(); gui->StartDraw(); interpreter->StartFrame(); - auto runT0 = Clock::now(); interpreter->Run(Commands, m); - AdaptiveFps_Sample(NsSince(runT0)); // Emulate N64 osViBlack to prevent a flicker when the scene is drawn // for the falling jiggy transition framebuffer capture. if (port_isViBlack()) { @@ -1286,6 +1341,7 @@ void GameEngine::RunCommands(Gfx* Commands, const std::vectorClearFramebuffer(true, false); } gui->EndDraw(); + AdaptiveFps_Sample(NsSince(runT0)); interpreter->EndFrame(); CALL_EVENT(FrameDrawEnd); } @@ -1396,10 +1452,17 @@ void GameEngine::ProcessGfxCommands(Gfx* commands) { mtx_replacements.resize(subframesPerTick); } size_t activeFrames = 0; + sMapBuildFutures.clear(); for (int i = 1; i <= subframesPerTick; i++) { if (i < subframesPerTick) { float t = (float)i / (float)subframesPerTick; - FrameInterpolation_Interpolate(t, mtx_replacements[activeFrames]); + if (i == 1) { + FrameInterpolation_Interpolate(t, mtx_replacements[activeFrames]); + } else { + auto* map = &mtx_replacements[activeFrames]; + sMapBuildFutures.push_back( + std::async(std::launch::async, [t, map] { FrameInterpolation_Interpolate(t, *map); })); + } } else { mtx_replacements[activeFrames].clear(); } @@ -1422,6 +1485,15 @@ void GameEngine::ProcessGfxCommands(Gfx* commands) { RunCommands(commands, mtx_replacements, activeFrames); + // Drain any builds the render loop didn't consume (debugger path, early + // return) before the next tick's StartRecord resets the trees they read. + for (auto& f : sMapBuildFutures) { + if (f.valid()) { + f.wait(); + } + } + sMapBuildFutures.clear(); + // [port] Release the demo audio hold after kDemoAudioHoldFrames rendered frames. if (sHoldAudio.load() && --sHoldFramesRemaining <= 0) { sHoldAudio.store(false); diff --git a/src/port/Enhancements/Backports/EggAim.cpp b/src/port/Enhancements/Backports/EggAim.cpp index d2967c892..5fb2d4983 100644 --- a/src/port/Enhancements/Backports/EggAim.cpp +++ b/src/port/Enhancements/Backports/EggAim.cpp @@ -301,7 +301,7 @@ void EggAimCrosshairWindow::Draw() { tex.ImageDataSize = sizeof(sCrosshairTextureData); tex.ImageData = new uint8_t[sizeof(sCrosshairTextureData)]; std::memcpy(tex.ImageData, sCrosshairTextureData, sizeof(sCrosshairTextureData)); - gui->LoadGuiTexture(kCrosshairTexture, tex, ImVec4(1.0f, 1.0f, 1.0f, 1.0f)); + gui->LoadGuiTexture(kCrosshairTexture, tex, "", ImVec4(1.0f, 1.0f, 1.0f, 1.0f)); } const float t = (float)sOverlayShown / (float)kOverlayFadeDuration; // 0..1 diff --git a/src/port/Enhancements/Cheats/Cheats.cpp b/src/port/Enhancements/Cheats/Cheats.cpp index 46c67d665..9544c60f2 100644 --- a/src/port/Enhancements/Cheats/Cheats.cpp +++ b/src/port/Enhancements/Cheats/Cheats.cpp @@ -256,9 +256,8 @@ extern u8 D_8037DDF0; // the transformation this hut offers static bool sMumboFastXformStarted = false; static void FastTransform_startHutTransform(Actor* actor) { - if (actor->has_met_before || - (actor->unk10_12 == 0 && (s32)player_getTransformation() != TRANSFORM_1_BANJO && - (s32)player_getTransformation() != romhack_mumboWishwashyId())) { + if (actor->has_met_before || (actor->unk10_12 == 0 && (s32)player_getTransformation() != TRANSFORM_1_BANJO && + (s32)player_getTransformation() != romhack_mumboWishwashyId())) { romhack_mumboTransform(TRANSFORM_1_BANJO); return; } diff --git a/src/port/Enhancements/Events/Hooks/Events.h b/src/port/Enhancements/Events/Hooks/Events.h index 6992ee126..f6f311aeb 100644 --- a/src/port/Enhancements/Events/Hooks/Events.h +++ b/src/port/Enhancements/Events/Hooks/Events.h @@ -60,6 +60,13 @@ typedef enum VBehaviorID { VB_CCW_FLOWER_REMOTE_GROW, // Anchor: gates FP twinkly minigame start so only one client owns a run at a time. VB_FP_TWINKLY_START, + // Anchor: true while the SM tutorial choice is still open to the local player. Checked + // when opening the intro offer (first client to reach it claims ownership) and again + // when an answer lands (a stale opt-out folds into opt-in once the choice closed). + VB_SM_TUTORIAL_CHOICE_OPEN, + // Anchor: SM ability molehills stay inert until the tutorial choice is made, so no + // tutorial sequence can start while the decision is still open. + VB_SM_MOLEHILL_ACTIVE, // Anchor: suppresses door-open camera lock when the flag came from a teammate, not us. VB_DOOR_OPEN_CAMERA, // CC rings water snap on run teardown (Anchor): suppressed when a teammate finished the rings. @@ -90,6 +97,7 @@ typedef enum VBehaviorID { VB_WARP_DISPATCH, VB_XMAS_TREE_ICE_UPDATE, VB_BOGGY_HOME_VISIBLE, + VB_MODEL_XLU_DEPTH_WRITE, } VBehaviorID; typedef enum DoorCameraId { diff --git a/src/port/Enhancements/Events/Hooks/List/GameEvent.h b/src/port/Enhancements/Events/Hooks/List/GameEvent.h index 65faafe70..79a1fa13c 100644 --- a/src/port/Enhancements/Events/Hooks/List/GameEvent.h +++ b/src/port/Enhancements/Events/Hooks/List/GameEvent.h @@ -17,6 +17,7 @@ DEFINE_EVENT(OnCollectibleCollected, int32_t kind; int32_t id;) // move = ability_e; value = 1 learned, 0 cleared. DEFINE_EVENT(OnAbilityLearned, int32_t move; int32_t value;) DEFINE_EVENT(OnJiggySpawned, int32_t jiggyId; float x; float y; float z;) +DEFINE_EVENT(OnHoneycombDropSpawn, int32_t honeycombId; int32_t bundleId; float x; float y; float z;) DEFINE_EVENT(OnTimedJiggyExpired, int32_t jiggyId;) DEFINE_EVENT(OnPropInit, Prop* propPtr;) DEFINE_EVENT(OnBottlesBonusComplete, int32_t index;) diff --git a/src/port/Enhancements/Events/PortEnhancements.cpp b/src/port/Enhancements/Events/PortEnhancements.cpp index 523a255cc..6022ec0e0 100644 --- a/src/port/Enhancements/Events/PortEnhancements.cpp +++ b/src/port/Enhancements/Events/PortEnhancements.cpp @@ -78,6 +78,7 @@ void PortEnhancements_Register() { REGISTER_EVENT(OnCollectibleCollected); REGISTER_EVENT(OnAbilityLearned); REGISTER_EVENT(OnJiggySpawned); + REGISTER_EVENT(OnHoneycombDropSpawn); REGISTER_EVENT(OnTimedJiggyExpired); REGISTER_EVENT(OnPlayerDeath); REGISTER_EVENT(OnGameFileErase); diff --git a/src/port/Extractor/GameExtractor.cpp b/src/port/Extractor/GameExtractor.cpp index 75d09b80e..2b6b6eec8 100644 --- a/src/port/Extractor/GameExtractor.cpp +++ b/src/port/Extractor/GameExtractor.cpp @@ -14,6 +14,7 @@ #include #include "ship/Context.h" +#include "port/FilePicker.h" #include "spdlog/spdlog.h" #include @@ -29,10 +30,6 @@ #include "factories/bk64/ConfigFactory.h" #include "port/Romhack/RomhackTable.h" -#if !defined(__IOS__) && !defined(__ANDROID__) && !defined(__SWITCH__) -#include "portable-file-dialogs.h" -#endif - std::string GameExtractor::sStatusText; std::string GameExtractor::sLastError; std::string GameExtractor::sLastOutputPath; @@ -98,53 +95,21 @@ bool GameExtractor::RunStandalone(std::string rom) { return true; } -bool GameExtractor::SelectGameFromUI() { - //// Store both path and already-read data - std::string romPath; - std::vector romData; - -#if !defined(__IOS__) && !defined(__ANDROID__) && !defined(__SWITCH__) - // Desktop: fallback to file dialogue if no baserom found - // if (!foundGame) { - if (!pfd::settings::available()) { - SPDLOG_ERROR("portable-file-dialogs is not available on this system."); - return false; - } - - auto selection = pfd::open_file("Select a file", ".", { "N64 Roms", "*.z64" }).result(); - if (selection.empty()) { +// Load a ROM from disk into mGameData. The caller does the picking (asynchronously on the boot path — +// see Engine.cpp PS_FIRST/PS_FIRST_WAIT), so this is just the read. +bool GameExtractor::LoadRomFromPath(const std::string& romPath) { + if (!std::filesystem::exists(romPath)) { + SPDLOG_ERROR("Failed to find ROM at path: {}", romPath); return false; } - romPath = selection[0]; - //} -#else - // Mobile: fallback to baserom.us.z64 - if (/*!foundGame && */ !std::filesystem::exists(Ship::Context::GetPathRelativeToAppDirectory("baserom.us.z64"))) { - SPDLOG_ERROR("baserom not found"); + std::ifstream inFile(romPath, std::ios::binary); + if (!inFile.is_open()) { return false; } - // if (!foundGame) { - romPath = Ship::Context::GetPathRelativeToAppDirectory("baserom.us.z64"); - //} -#endif - - // Load file if it is not already open - if (romData.empty()) { - if (!std::filesystem::exists(romPath)) { - SPDLOG_ERROR("Failed to find ROM at path: {}", romPath); - return false; - } - - std::ifstream inFile(romPath, std::ios::binary); - if (!inFile.is_open()) { - return false; - } - - romData = std::vector(std::istreambuf_iterator(inFile), {}); - inFile.close(); - } + std::vector romData(std::istreambuf_iterator(inFile), {}); + inFile.close(); this->mGamePath = romPath; this->mGameData = std::move(romData); @@ -423,7 +388,7 @@ std::optional GameExtractor::ValidateChecksum() const { return std::nullopt; } -bool GameExtractor::SelectGameFromUI() { +bool GameExtractor::LoadRomFromPath(const std::string& romPath) { return false; } @@ -439,3 +404,18 @@ void GameExtractor::WritePortVersion() { // None } #endif + +// No #ifdef needed: Lighthouse::PickFile picks the backend (native dialog on desktop, ImGui browser +// on consoles/arm). The N64-ROM title/filters live here so libultraship stays game-agnostic. +void GameExtractor::SelectGameFromUI(std::function onComplete) { + Ship::FileBrowserRequest req; + req.Title = "Select a N64 ROM"; + req.Filters = { { "N64 ROMs (.z64, .n64, .v64)", { "*.z64", "*.n64", "*.v64" } }, { "All files", { "*" } } }; + Lighthouse::PickFile(std::move(req), + [this, onComplete = std::move(onComplete)](std::optional path) { + const bool ok = path.has_value() && LoadRomFromPath(path->string()); + if (onComplete) { + onComplete(ok); + } + }); +} diff --git a/src/port/Extractor/GameExtractor.h b/src/port/Extractor/GameExtractor.h index faa77dfcc..c754938f7 100644 --- a/src/port/Extractor/GameExtractor.h +++ b/src/port/Extractor/GameExtractor.h @@ -2,6 +2,8 @@ #include "Companion.h" #include +#include +#include #include #include #include @@ -11,7 +13,11 @@ class GameExtractor { static bool GenAssetFile(); std::optional ValidateChecksum() const; bool RunStandalone(std::string rom); - bool SelectGameFromUI(); + bool LoadRomFromPath(const std::string& romPath); + // Open the file picker for an N64 ROM, then load the choice into this extractor. onComplete + // reports whether a ROM was both picked and loaded. Treat as async: the extractor must outlive + // the pick (the boot flow keeps a long-lived instance; the Mod Menu holds a shared_ptr). + void SelectGameFromUI(std::function onComplete); void SetSearchPath(const std::string& path); void GetRoms(std::vector& roms); std::string GetRomPath(); diff --git a/src/port/FilePicker.cpp b/src/port/FilePicker.cpp new file mode 100644 index 000000000..8e75c09a7 --- /dev/null +++ b/src/port/FilePicker.cpp @@ -0,0 +1,62 @@ +#include "port/FilePicker.h" + +#if LIGHTHOUSE_NATIVE_FILE_DIALOG +#include +#include +#include "portable-file-dialogs.h" +#endif + +namespace fs = std::filesystem; + +namespace Lighthouse { + +#if LIGHTHOUSE_NATIVE_FILE_DIALOG +// portable-file-dialogs takes a flat filter list: { label, "*.a *.b", label2, "*.c", ... }. +static std::vector ToPfdFilters(const std::vector& filters) { + std::vector out; + for (const auto& filter : filters) { + out.push_back(filter.Label); + std::string patterns; + for (const auto& pattern : filter.Patterns) { + if (!patterns.empty()) { + patterns += " "; + } + patterns += pattern; + } + out.push_back(patterns); + } + if (out.empty()) { + out = { "All Files", "*" }; + } + return out; +} +#endif + +void PickFile(Ship::FileBrowserRequest request, std::function)> onResult) { +#if LIGHTHOUSE_NATIVE_FILE_DIALOG + const std::string startDir = request.StartDir.empty() ? "." : request.StartDir.string(); + const std::vector filters = ToPfdFilters(request.Filters); + + std::optional result; + if (request.Save) { + const std::string defaultPath = (fs::path(startDir) / request.DefaultName).string(); + std::string selection = pfd::save_file(request.Title, defaultPath, filters).result(); + if (!selection.empty()) { + result = fs::path(selection); + } + } else { + std::vector selection = pfd::open_file(request.Title, startDir, filters).result(); + if (!selection.empty()) { + result = fs::path(selection.front()); + } + } + if (onResult) { + onResult(result); + } +#else + request.OnResult = std::move(onResult); + Ship::FileBrowserWindow::Open(std::move(request)); +#endif +} + +} // namespace Lighthouse diff --git a/src/port/FilePicker.h b/src/port/FilePicker.h new file mode 100644 index 000000000..2cb6ff821 --- /dev/null +++ b/src/port/FilePicker.h @@ -0,0 +1,34 @@ +#pragma once + +#include +#include +#include + +#include "ship/window/gui/FileBrowserWindow.h" + +// Desktop platforms have a usable native file dialog (portable-file-dialogs). Consoles and Linux +// handhelds (arm) generally lack a native dialog / display server, so they fall back to +// libultraship's in-game ImGui file browser. Define LIGHTHOUSE_NATIVE_FILE_DIALOG to override. +#ifndef LIGHTHOUSE_NATIVE_FILE_DIALOG +#if defined(__SWITCH__) || defined(__WIIU__) || (defined(__linux__) && (defined(__aarch64__) || defined(__arm__))) +#define LIGHTHOUSE_NATIVE_FILE_DIALOG 0 +#else +#define LIGHTHOUSE_NATIVE_FILE_DIALOG 1 +#endif +#endif + +namespace Lighthouse { + +// Show a file picker described by @p request and deliver the chosen path (std::nullopt on cancel) to +// @p onResult. +// +// - Native builds (desktop): a blocking portable-file-dialogs dialog. onResult fires synchronously +// on the calling thread before PickFile returns. +// - ImGui builds (consoles / arm-linux): libultraship's FileBrowserWindow. onResult fires later on +// the render thread; PickFile returns immediately and is safe to call from any thread. +// +// Callers written for the async form (kick off, then poll a flag the callback sets) work with both +// backends unchanged: the native path just sets that flag before returning. +void PickFile(Ship::FileBrowserRequest request, std::function)> onResult); + +} // namespace Lighthouse diff --git a/src/port/Game.cpp b/src/port/Game.cpp index 9cf767564..3189e791a 100644 --- a/src/port/Game.cpp +++ b/src/port/Game.cpp @@ -102,8 +102,13 @@ int SDL_main(int argc, char* argv[]) { // when SHIP_HOME is not in use std::error_code ec; const char* shipHome = std::getenv("SHIP_HOME"); + const char* appImage = std::getenv("APPIMAGE"); if (shipHome != nullptr && shipHome[0] != '\0') { std::filesystem::current_path(shipHome, ec); + } else if (appImage != nullptr && appImage[0] != '\0') { + // Running from an AppImage: the executable lives in a read-only squashfs + // mount under /tmp, so anchor to the .AppImage file's directory instead. + std::filesystem::current_path(std::filesystem::path(appImage).parent_path(), ec); } else { std::string base = Ship::Context::GetAppBundlePath(); if (!base.empty() && base != ".") { diff --git a/src/port/Interpolation/AdaptiveFps.cpp b/src/port/Interpolation/AdaptiveFps.cpp index c2ad62710..085cdcdce 100644 --- a/src/port/Interpolation/AdaptiveFps.cpp +++ b/src/port/Interpolation/AdaptiveFps.cpp @@ -50,6 +50,10 @@ constexpr double kPeakDecay = 0.40; constexpr double kLogicRiseAlpha = 0.5; constexpr double kLogicFallAlpha = 0.1; +// How much estimated spare capacity (in sub-frames) is needed beyond the next +// tier before the cap steps up. +constexpr double kStepUpHeadroom = 0.25; + // Default game update rate (times per second) if none is given. constexpr uint32_t kDefaultTickHz = 30; @@ -65,6 +69,7 @@ struct State { Clock::time_point winStart = Clock::now(); double safety = kSafetySteady; int risingHoldRemaining = 0; + int grantedSub = 0; }; State& state() { @@ -92,6 +97,7 @@ void AdaptiveFps_Configure(uint32_t tickHz) { s.winStart = Clock::now(); s.safety = kSafetySteady; s.risingHoldRemaining = 0; + s.grantedSub = 0; } uint32_t AdaptiveFps_Cap(uint32_t userTarget) { @@ -102,21 +108,30 @@ uint32_t AdaptiveFps_Cap(uint32_t userTarget) { if (costUs <= 0.0) { return userTarget; } + int userSub = (int)(userTarget / s.tickHz); + if (userSub < 1) { + userSub = 1; + } // Set aside the time the game spent updating, then share what's left among // interpolated frames so a busy scene can't overshoot the tick's budget. double renderBudgetUs = s.tickBudgetUs - s.envLogicUs; - if (renderBudgetUs <= 0.0) { - return s.tickHz; - } - double maxSubPerTick = (renderBudgetUs * s.safety) / costUs; - if (maxSubPerTick < 1.0) { - return s.tickHz; + double maxSubPerTick = renderBudgetUs <= 0.0 ? 1.0 : (renderBudgetUs * s.safety) / costUs; + int desired = maxSubPerTick < 1.0 ? 1 : (int)maxSubPerTick; + if (desired > userSub) { + desired = userSub; } - uint32_t maxFps = (uint32_t)(maxSubPerTick * s.tickHz); - if (maxFps < s.tickHz) { - maxFps = s.tickHz; + + if (s.grantedSub == 0 || desired < s.grantedSub) { + // First measurement, or capacity dropped (or the user lowered the + // target): apply immediately, don't promise frames that can't be drawn. + s.grantedSub = desired; + } else if (desired > s.grantedSub && s.risingHoldRemaining == 0 && + maxSubPerTick >= (double)(s.grantedSub + 1) + kStepUpHeadroom) { + // Recover one tier at a time, only in steady state and with headroom. + s.grantedSub++; } - return std::min(userTarget, maxFps); + + return std::min(userTarget, (uint32_t)s.grantedSub * s.tickHz); } void AdaptiveFps_SampleTick(long long logicNs) { diff --git a/src/port/Interpolation/FrameInterpolation.cpp b/src/port/Interpolation/FrameInterpolation.cpp index c24118306..0d06f03b9 100644 --- a/src/port/Interpolation/FrameInterpolation.cpp +++ b/src/port/Interpolation/FrameInterpolation.cpp @@ -8,85 +8,18 @@ #include -// Double-buffered op recorder. Matrix primitives in core1/math/matrix_stack.c -// append into gCurrent between StartRecord/StopRecord; Interpolate(t) pairs -// ops across two consecutive ticks (gPrevious vs gCurrent) by scope-path and -// lerps the inputs. Camera projection rotations and sprite inputs go through -// angle-space lerp (not matrix-lerp) to avoid the paper-fold artifact on fast -// spins. See docs/INTERPOLATION.md for the full design. - namespace { -enum class Op : uint8_t { - OpenChild, - CloseChild, - Marker, - - MatrixIdent, - MatrixTranslate, - MatrixRotYaw, - MatrixRotPitch, - MatrixRotRoll, - MatrixScale, - MatrixSet, - MatrixMult, - MatrixToMtx, - - CameraProjectionRotation, - SpriteDraw, -}; - -// Heavy ops (Set/Mult/ToMtx/Camera/Sprite) stash their payload in per-tree -// side vectors and reference it via side_index. -struct OpNode { - Op op; - union { - struct { - float x, y, z; - } vec3; - struct { - float degrees; - } rotate; - struct { - const void* key; - uintptr_t id; - } open_child; - struct { - const char* file; - int line; - } marker; - uint32_t side_index; - }; - - OpNode() : op(Op::Marker), side_index(0) { - } -}; - -struct MatrixSetData { - float m[4][4]; -}; - -struct MatrixMultData { - float l[4][4]; - float r[4][4]; -}; - struct ToMtxData { void* dst; float src[4][4]; - // Cross-tick pairing key, built at record time from the live FNV scope - // hash; same scope path on both ticks → same sig → O(1) pair lookup. uint64_t pathSig; - // Sprites flag this so the lerp loop leaves their dst alone — cube - // culling reorders sprites between ticks so index pairing mismatches. bool noInterpolate; }; -// Sprites record raw inputs (angles for rotations, linear for pos/scale) -// rather than the final matrix, so replay can lerp in natural spaces and -// rebuild a matrix that stays consistent with the angle-lerped projection. -// Which fields matter depends on kind: billboards use camYaw/camPitch, -// FULL uses rotation[], only BILLBOARD_ROLL cares about spriteRoll. +// Sprites keep their raw inputs instead of the finished matrix so replay can +// blend angles as angles; blending the matrix itself makes billboards shear +// while the camera swings around them. struct SpriteDrawData { void* dst; float camRelPos[3]; @@ -100,9 +33,6 @@ struct SpriteDrawData { bool mirrored; }; -// We record the three Euler angles behind BK's projection rotation rather -// than the matrices, so replay can shortest-path angle-lerp and rebuild via -// guRotateF — element-wise lerp on these matrices folds during fast spins. struct CameraProjRotData { void* rollMtx; void* pitchMtx; @@ -112,6 +42,9 @@ struct CameraProjRotData { float yawDeg; }; +// Two entries pair up across ticks when they were recorded under the same +// scope path at the same index; that identity is hashed into pathSig as the +// game draws. struct ScopeFrame { uint64_t pathHash; uint32_t toMtxIdx; @@ -119,8 +52,6 @@ struct ScopeFrame { }; constexpr uint64_t kFnvSeed = 0xcbf29ce484222325ULL; -// Disambiguators so a ToMtx and a Sprite at the same in-scope index don't -// collide on a single signature. constexpr uint64_t kSigKindToMtx = 0x1ULL; constexpr uint64_t kSigKindSprite = 0x2ULL; @@ -130,13 +61,7 @@ inline uint64_t fnvMix(uint64_t h, uint64_t v) { return h; } -// Sig maps are populated live during recording. After StopRecord swaps -// trees, gPrevious already has its maps and BuildInterpolationCache can -// pair entries with O(1) lookups instead of re-walking the prev tree. struct FrameTree { - std::vector ops; - std::vector sets; - std::vector mults; std::vector toMtxs; std::vector projRots; std::vector sprites; @@ -148,9 +73,6 @@ struct FrameTree { bool valid = false; void reset() { - ops.clear(); - sets.clear(); - mults.clear(); toMtxs.clear(); projRots.clear(); sprites.clear(); @@ -172,31 +94,25 @@ bool gRecording = false; bool gShouldInterpolate = true; int gNoInterpolateDepth = 0; -// Monotonic ids for heap pointers that get reused by the allocator. Without -// these, a freed object's address gets reused by the next allocation and -// the new one inherits the dead one's matrix pairing. std::unordered_map gIdMap; uint64_t gNextId = 1; -// Per-tick cache built lazily on the first Interpolate(t) call and reused -// for every sub-frame within the tick. Stores only (curr, prev) pairs whose -// lerped output differs from c.src — no-prev and bit-identical entries are -// skipped because the interpreter's fallback path decodes the DL bytes that -// c.src was already encoded into, producing the same matrix without a map -// lookup. Shrinking the map this way speeds up every interpreter find() -// across the whole DL on top of cheaper inserts. struct PairedToMtx { uint32_t currIdx; uint32_t prevIdx; - // Hemisphere check is stable across t for a (prev, curr) pair, so we - // do it once at cache build instead of 6 fmuls + cmps per sub-frame. bool snap; }; struct PairedSprite { uint32_t currIdx; uint32_t prevIdx; }; + +// Pairing happens once per tick, on the first Interpolate() call; later +// sub-frames only read the result. Engine.cpp builds those on worker threads, +// so after `built` goes true nothing in here may be mutated until the next +// StartRecord. struct InterpolationCache { + bool built = false; bool valid = false; std::vector pairedToMtxs; std::vector pairedSprites; @@ -204,6 +120,7 @@ struct InterpolationCache { float prevCameraPos[3] = { 0.0f, 0.0f, 0.0f }; void reset() { + built = false; valid = false; pairedToMtxs.clear(); pairedSprites.clear(); @@ -212,23 +129,12 @@ struct InterpolationCache { }; InterpolationCache gCache; -OpNode& append(Op op) { - gCurrent->ops.emplace_back(); - OpNode& n = gCurrent->ops.back(); - n.op = op; - return n; -} - } // namespace extern "C" { void FrameInterpolation_StartRecord(void) { gCurrent->reset(); - // Reserve once; subsequent ticks reuse the existing capacity. - gCurrent->ops.reserve(4096); - gCurrent->sets.reserve(128); - gCurrent->mults.reserve(256); gCurrent->toMtxs.reserve(512); gCurrent->projRots.reserve(4); gCurrent->sprites.reserve(256); @@ -238,15 +144,14 @@ void FrameInterpolation_StartRecord(void) { gShouldInterpolate = true; gNoInterpolateDepth = 0; gRecording = true; - // The cache built during the prior render pass references trees that - // are about to be reused for this tick. + // The old cache indexes into the tree this tick is about to overwrite. + gCache.built = false; gCache.valid = false; } void FrameInterpolation_StopRecord(void) { gRecording = false; gCurrent->valid = gShouldInterpolate; - // What we just recorded becomes `previous` for the next tick. std::swap(gCurrent, gPrevious); } @@ -258,9 +163,6 @@ void FrameInterpolation_RecordOpenChild(const void* key, uintptr_t id) { if (!gRecording) { return; } - OpNode& n = append(Op::OpenChild); - n.open_child.key = key; - n.open_child.id = id; uint64_t h = gCurrent->scopeStack.back().pathHash; h = fnvMix(h, reinterpret_cast(key)); h = fnvMix(h, static_cast(id)); @@ -271,15 +173,12 @@ void FrameInterpolation_RecordCloseChild(void) { if (!gRecording) { return; } - append(Op::CloseChild); if (gCurrent->scopeStack.size() > 1) { gCurrent->scopeStack.pop_back(); } } uintptr_t FrameInterpolation_Hash3(uint64_t a, uint64_t b, uint64_t c) { - // Three distinct odd primes keep the three inputs separable even when - // they share most of their bytes. uint64_t h = a * 0x9E3779B97F4A7C15ULL; h ^= b * 0x100000001b3ULL; h ^= c * 0xbf58476d1ce4e5b9ULL; @@ -290,83 +189,6 @@ void FrameInterpolation_RecordOpenChildHash3(const char* key, uint64_t a, uint64 FrameInterpolation_RecordOpenChild(key, FrameInterpolation_Hash3(a, b, c)); } -void FrameInterpolation_RecordMarker(const char* file, int line) { - if (!gRecording) { - return; - } - OpNode& n = append(Op::Marker); - n.marker.file = file; - n.marker.line = line; -} - -void FrameInterpolation_RecordMatrixIdent(void) { - if (!gRecording) { - return; - } - append(Op::MatrixIdent); -} - -void FrameInterpolation_RecordMatrixTranslate(float x, float y, float z) { - if (!gRecording) { - return; - } - OpNode& n = append(Op::MatrixTranslate); - n.vec3.x = x; - n.vec3.y = y; - n.vec3.z = z; -} - -void FrameInterpolation_RecordMatrixRotYaw(float degrees) { - if (!gRecording) { - return; - } - append(Op::MatrixRotYaw).rotate.degrees = degrees; -} - -void FrameInterpolation_RecordMatrixRotPitch(float degrees) { - if (!gRecording) { - return; - } - append(Op::MatrixRotPitch).rotate.degrees = degrees; -} - -void FrameInterpolation_RecordMatrixRotRoll(float degrees) { - if (!gRecording) { - return; - } - append(Op::MatrixRotRoll).rotate.degrees = degrees; -} - -void FrameInterpolation_RecordMatrixScale(float x, float y, float z) { - if (!gRecording) { - return; - } - OpNode& n = append(Op::MatrixScale); - n.vec3.x = x; - n.vec3.y = y; - n.vec3.z = z; -} - -void FrameInterpolation_RecordMatrixSet(const float src[4][4]) { - if (!gRecording) { - return; - } - gCurrent->sets.emplace_back(); - std::memcpy(gCurrent->sets.back().m, src, sizeof(float) * 16); - append(Op::MatrixSet).side_index = static_cast(gCurrent->sets.size() - 1); -} - -void FrameInterpolation_RecordMatrixMult(const float l[4][4], const float r[4][4]) { - if (!gRecording) { - return; - } - gCurrent->mults.emplace_back(); - MatrixMultData& d = gCurrent->mults.back(); - std::memcpy(d.l, l, sizeof(float) * 16); - std::memcpy(d.r, r, sizeof(float) * 16); - append(Op::MatrixMult).side_index = static_cast(gCurrent->mults.size() - 1); -} - void FrameInterpolation_RecordMatrixToMtx(void* dst, const float src[4][4]) { if (!gRecording) { return; @@ -383,7 +205,6 @@ void FrameInterpolation_RecordMatrixToMtx(void* dst, const float src[4][4]) { d.pathSig = sig; d.noInterpolate = (gNoInterpolateDepth > 0); gCurrent->sigToToMtx.emplace(sig, idx); - append(Op::MatrixToMtx).side_index = idx; } void FrameInterpolation_RecordCameraProjectionRotation(void* rollMtx, float rollDeg, void* pitchMtx, float pitchDeg, @@ -399,7 +220,6 @@ void FrameInterpolation_RecordCameraProjectionRotation(void* rollMtx, float roll d.rollDeg = rollDeg; d.pitchDeg = pitchDeg; d.yawDeg = yawDeg; - append(Op::CameraProjectionRotation).side_index = static_cast(gCurrent->projRots.size() - 1); } void FrameInterpolation_RecordCameraPosition(const float pos[3]) { @@ -450,12 +270,9 @@ void FrameInterpolation_RecordSpriteDraw(int kind, void* dst, const float camRel d.kind = static_cast(kind); d.mirrored = (mirrored != 0); gCurrent->sigToSprite.emplace(sig, idx); - append(Op::SpriteDraw).side_index = idx; } void FrameInterpolation_DontInterpolateCamera(void) { - // Prev's matrices belong to a scene the camera just left; dropping the - // tree makes the next Interpolate() bail and replay uses curr as-is. if (gPrevious != nullptr) { gPrevious->valid = false; } @@ -478,7 +295,6 @@ uintptr_t FrameInterpolation_GetId(const void* ptr) { if (it != gIdMap.end()) { return static_cast(it->second); } - // Fallback for callers that don't Register; ABA-prone. return reinterpret_cast(ptr); } @@ -493,15 +309,14 @@ void FrameInterpolation_UnregisterId(const void* ptr) { namespace { -// Snap to curr when prev/curr point apart on X or Y (>90° rotation): -// element-wise lerp on those folds the character inside-out. +// Blending across a >90 degree turn drags the model through itself for a frame; +// snap to the new orientation instead. inline bool shouldSnap(const float pa[4][4], const float ca[4][4]) { float dotX = pa[0][0] * ca[0][0] + pa[0][1] * ca[0][1] + pa[0][2] * ca[0][2]; float dotY = pa[1][0] * ca[1][0] + pa[1][1] * ca[1][1] + pa[1][2] * ca[1][2]; return dotX < 0.0f || dotY < 0.0f; } -// Shortest-path angle lerp in degrees. inline float lerpAngleDegSP(float a, float b, float tt) { float d = b - a; d = std::fmod(d + 540.0f, 360.0f) - 180.0f; @@ -510,12 +325,11 @@ inline float lerpAngleDegSP(float a, float b, float tt) { void BuildInterpolationCache() { gCache.reset(); + gCache.built = true; if (!gPrevious->valid) { return; } - // Snapshot prev's camera pos so Interpolate's cut detector reads only - // gCache for tick-stable state. gCache.prevHasCameraPos = gPrevious->hasCameraPos; if (gCache.prevHasCameraPos) { gCache.prevCameraPos[0] = gPrevious->cameraPos[0]; @@ -533,12 +347,10 @@ void BuildInterpolationCache() { gCache.pairedToMtxs.reserve(currToMtxs.size()); gCache.pairedSprites.reserve(currSprites.size()); - // Only pair ToMtxs whose replacement actually differs from the curr - // matrix. The interpreter's fallback path decodes the DL bytes at - // c.dst, which the game wrote from the same float matrix that's now - // c.src — so unpaired AND bit-identical entries decode to the same - // result without a map lookup. Skipping them shrinks the replacement - // map and speeds up every interpreter find() across the whole DL. + // Whatever stays out of the cache falls back to the interpreter decoding + // the Mtx bytes the game itself wrote, which already hold the correct + // end-of-tick matrix. Entries with no previous partner, or whose + // matrix didn't change, can simply be dropped here. for (uint32_t i = 0; i < currToMtxs.size(); i++) { const ToMtxData& c = currToMtxs[i]; if (c.dst == nullptr || c.noInterpolate) { @@ -555,25 +367,31 @@ void BuildInterpolationCache() { gCache.pairedToMtxs.push_back({ i, it->second, shouldSnap(p.src, c.src) }); } - // Sprites always pair (or get a sentinel prev-idx) because the matrix - // must be rebuilt every sub-frame anyway — billboard rotations follow - // the lerped projection. + // Sprites whose inputs didn't move at all are dropped for the same + // reason; the rest get their matrix rebuilt every sub-frame so billboards + // keep facing the blended camera. for (uint32_t i = 0; i < currSprites.size(); i++) { const SpriteDrawData& c = currSprites[i]; auto it = prevSpriteMap.find(c.pathSig); if (it == prevSpriteMap.end() || prevSprites[it->second].kind != c.kind) { gCache.pairedSprites.push_back({ i, UINT32_MAX }); - } else { - gCache.pairedSprites.push_back({ i, it->second }); + continue; } + const SpriteDrawData& p = prevSprites[it->second]; + if (std::memcmp(p.camRelPos, c.camRelPos, sizeof(c.camRelPos)) == 0 && + std::memcmp(p.scale, c.scale, sizeof(c.scale)) == 0 && p.camYaw == c.camYaw && p.camPitch == c.camPitch && + p.spriteRoll == c.spriteRoll && std::memcmp(p.rotation, c.rotation, sizeof(c.rotation)) == 0 && + p.mirrored == c.mirrored) { + continue; + } + gCache.pairedSprites.push_back({ i, it->second }); } gCache.valid = true; } -// Build a sprite modelview from lerped inputs. Mirrors the decomp -// composition for each kind so the replay matrix stays consistent with -// the record-site one. +// Rebuilds the sprite modelview the same way sprite/render.c composes it, so +// a replayed matrix can't drift from what the game would have written. void emitSprite(const SpriteDrawData& L, std::unordered_map& replacements) { if (L.dst == nullptr) { return; @@ -582,7 +400,6 @@ void emitSprite(const SpriteDrawData& L, std::unordered_map& replace std::memset(m, 0, sizeof(m)); m[0][0] = m[1][1] = m[2][2] = m[3][3] = 1.0f; - // Rotations match the matrix_stack.c primitives — rows 0-2 only. auto rotYaw = [&](float deg) { if (deg == 0.0f) return; @@ -617,9 +434,9 @@ void emitSprite(const SpriteDrawData& L, std::unordered_map& replace } }; + // The rotation lambdas only touch rows 0-2, which is why FULL can + // translate first while billboards translate last. if (L.kind == FI_SPRITE_KIND_FULL) { - // FULL: translate first (the game's func_80252330 stomps mf[3]), - // then rotate — rotations only touch rows 0-2. m[3][0] = L.camRelPos[0]; m[3][1] = L.camRelPos[1]; m[3][2] = L.camRelPos[2]; @@ -627,8 +444,6 @@ void emitSprite(const SpriteDrawData& L, std::unordered_map& replace rotPitch(L.rotation[0]); rotRoll(L.rotation[2]); } else { - // Billboard: cam-aligned rotations, optional sprite roll, then - // translate overwrites mf[3]. rotYaw(L.camYaw); rotPitch(L.camPitch); if (L.kind == FI_SPRITE_KIND_BILLBOARD_ROLL) { @@ -639,7 +454,6 @@ void emitSprite(const SpriteDrawData& L, std::unordered_map& replace m[3][2] = L.camRelPos[2]; } - // mlMtxScale_xyz: rows 0-2 only, translation preserved. float sx = L.mirrored ? -L.scale[0] : L.scale[0]; for (int i = 0; i < 3; i++) { m[0][i] *= sx; @@ -654,24 +468,20 @@ void emitSprite(const SpriteDrawData& L, std::unordered_map& replace } // namespace void FrameInterpolation_Interpolate(float t, std::unordered_map& replacements) { - // Cache is built lazily by the first sub-frame call per render pass and - // reused; StartRecord clears it for the next tick. Caller owns - // `replacements` so its bucket array persists across sub-frames. replacements.clear(); if (!gShouldInterpolate) { return; } - if (!gCache.valid) { + if (!gCache.built) { BuildInterpolationCache(); - if (!gCache.valid) { - return; - } + } + if (!gCache.valid) { + return; } - // Cut detector: a >1000-unit camera jump means a teleport (warp, - // fixed-cam snap). Lerping across that places the world between two - // scenes for one sub-frame. + // A large camera jump means a warp or camera cut; blending across it + // would draw the world halfway between two scenes for a frame. if (gCache.prevHasCameraPos && gCurrent->hasCameraPos) { float dx = gCurrent->cameraPos[0] - gCache.prevCameraPos[0]; float dy = gCurrent->cameraPos[1] - gCache.prevCameraPos[1]; @@ -705,8 +515,6 @@ void FrameInterpolation_Interpolate(float t, std::unordered_map& rep } } - // Even unpaired sprites need a per-sub-frame matrix rebuild because - // their billboard rotations follow the lerped projection. for (const PairedSprite& pair : gCache.pairedSprites) { const SpriteDrawData& c = currSpritesData[pair.currIdx]; SpriteDrawData L = c; @@ -739,7 +547,7 @@ void FrameInterpolation_Interpolate(float t, std::unordered_map& rep MtxF& out = replacements[reinterpret_cast(dst)]; guRotateF(out.mf, deg, ax, ay, az); }; - // Axes match viewport.c: roll Z-, pitch X+, yaw Y+. + // Axis conventions per viewport.c: roll about -Z, pitch +X, yaw +Y. emitProj(c.rollMtx, lerpAngleDegSP(p.rollDeg, c.rollDeg, t), 0.0f, 0.0f, -1.0f); emitProj(c.pitchMtx, lerpAngleDegSP(p.pitchDeg, c.pitchDeg, t), 1.0f, 0.0f, 0.0f); emitProj(c.yawMtx, lerpAngleDegSP(p.yawDeg, c.yawDeg, t), 0.0f, 1.0f, 0.0f); diff --git a/src/port/Interpolation/FrameInterpolation.h b/src/port/Interpolation/FrameInterpolation.h index 44d05a9bf..25b3e32aa 100644 --- a/src/port/Interpolation/FrameInterpolation.h +++ b/src/port/Interpolation/FrameInterpolation.h @@ -24,7 +24,6 @@ void FrameInterpolation_ShouldInterpolateFrame(bool shouldInterpolate); // Hierarchical scope (cross-tick pairing identity). void FrameInterpolation_RecordOpenChild(const void* key, uintptr_t id); void FrameInterpolation_RecordCloseChild(void); -void FrameInterpolation_RecordMarker(const char* file, int line); // Mix three scalar fields into a stable scope id when no single field is // unique on its own (e.g. modelId+pos, particle spawn randomness). @@ -38,15 +37,7 @@ static inline uint64_t FrameInterpolation_FloatBits(float f) { return (uint64_t)u; } -// Low-level matrix primitives (from src/core1/math/matrix_stack.c). -void FrameInterpolation_RecordMatrixIdent(void); -void FrameInterpolation_RecordMatrixTranslate(float x, float y, float z); -void FrameInterpolation_RecordMatrixRotYaw(float degrees); -void FrameInterpolation_RecordMatrixRotPitch(float degrees); -void FrameInterpolation_RecordMatrixRotRoll(float degrees); -void FrameInterpolation_RecordMatrixScale(float x, float y, float z); -void FrameInterpolation_RecordMatrixSet(const float src[4][4]); -void FrameInterpolation_RecordMatrixMult(const float l[4][4], const float r[4][4]); +// Final matrix output of a mlMtxApply — the only matrix event replay needs. void FrameInterpolation_RecordMatrixToMtx(void* dst, const float src[4][4]); // BK puts camera rotation in projection, not modelview. We record the diff --git a/src/port/Network/Anchor/Anchor.cpp b/src/port/Network/Anchor/Anchor.cpp index 45686f6e8..f19e6bd24 100644 --- a/src/port/Network/Anchor/Anchor.cpp +++ b/src/port/Network/Anchor/Anchor.cpp @@ -229,6 +229,8 @@ void Anchor::ProcessIncomingPacketQueue() { HandlePacket_PedestalOwner(payload); else if (packetType == JIGGY_SPAWN) HandlePacket_SpawnJiggy(payload); + else if (packetType == HONEYCOMB_SPAWN) + HandlePacket_SpawnHoneycomb(payload); else if (packetType == TELEPORT_TO) HandlePacket_TeleportTo(payload); else if (packetType == UNSET_FLAG) diff --git a/src/port/Network/Anchor/Anchor.h b/src/port/Network/Anchor/Anchor.h index 1a547ae6a..1ef0b0738 100644 --- a/src/port/Network/Anchor/Anchor.h +++ b/src/port/Network/Anchor/Anchor.h @@ -117,6 +117,7 @@ class Anchor : public Network { void HandlePacket_JiggyCrane(nlohmann::json& payload); void HandlePacket_PedestalOwner(nlohmann::json& payload); void HandlePacket_SpawnJiggy(nlohmann::json& payload); + void HandlePacket_SpawnHoneycomb(nlohmann::json& payload); void HandlePacket_TeleportTo(nlohmann::json& payload); void HandlePacket_UnsetFlag(nlohmann::json& payload); void HandlePacket_UpdateClientState(nlohmann::json& payload); @@ -173,6 +174,7 @@ class Anchor : public Network { inline static const std::string JIGGY_CRANE = "JIGGY_CRANE"; inline static const std::string PEDESTAL_OWNER = "PEDESTAL_OWNER"; inline static const std::string JIGGY_SPAWN = "JIGGY_SPAWN"; + inline static const std::string HONEYCOMB_SPAWN = "HONEYCOMB_SPAWN"; inline static const std::string TELEPORT_TO = "TELEPORT_TO"; inline static const std::string UNSET_FLAG = "UNSET_FLAG"; inline static const std::string UPDATE_CLIENT_STATE = "UPDATE_CLIENT_STATE"; @@ -251,6 +253,7 @@ class Anchor : public Network { void SendPacket_JiggyCrane(s32 stage); void SendPacket_PedestalOwner(s32 id, bool claimed); void SendPacket_SpawnJiggy(s16 jiggyId, f32 x, f32 y, f32 z); + void SendPacket_SpawnHoneycomb(s16 honeycombId, s32 bundleId, f32 x, f32 y, f32 z); void SendPacket_TeleportTo(uint32_t clientId); void SendPacket_UnsetFlag(u8 flagSpace, s16 flag); void SendPacket_UpdateClientState(); diff --git a/src/port/Network/Anchor/Authority.cpp b/src/port/Network/Anchor/Authority.cpp index 1ca9012eb..cb37b5957 100644 --- a/src/port/Network/Anchor/Authority.cpp +++ b/src/port/Network/Anchor/Authority.cpp @@ -19,6 +19,7 @@ static const int32_t sActivityMap[NET_ACTIVITY_COUNT] = { MAP_10_BGS_MR_VILE, // NET_ACTIVITY_VILE_MINIGAME MAP_90_GL_BATTLEMENTS, // NET_ACTIVITY_FINAL_BOSS MAP_27_FP_FREEZEEZY_PEAK, // NET_ACTIVITY_FP_TWINKLY + MAP_1_SM_SPIRAL_MOUNTAIN, // NET_ACTIVITY_SM_TUTORIAL }; static bool Authority_IsValidActivity(NetworkActivityId activity) { diff --git a/src/port/Network/Anchor/Authority.h b/src/port/Network/Anchor/Authority.h index 82effb7d7..573d889b9 100644 --- a/src/port/Network/Anchor/Authority.h +++ b/src/port/Network/Anchor/Authority.h @@ -27,6 +27,7 @@ typedef enum NetworkActivityId { NET_ACTIVITY_VILE_MINIGAME, NET_ACTIVITY_FINAL_BOSS, NET_ACTIVITY_FP_TWINKLY, + NET_ACTIVITY_SM_TUTORIAL, NET_ACTIVITY_COUNT } NetworkActivityId; diff --git a/src/port/Network/Anchor/DummyPlayer.cpp b/src/port/Network/Anchor/DummyPlayer.cpp index f04798ddb..bd00dfc65 100644 --- a/src/port/Network/Anchor/DummyPlayer.cpp +++ b/src/port/Network/Anchor/DummyPlayer.cpp @@ -377,8 +377,12 @@ void DummyPlayer::dummy_set(enum asset_e asset_id) { dummyBin = NULL; } dummyId = asset_id; - if (dummyId) + if (dummyId) { dummyBin = static_cast(assetcache_get(dummyId)); + if (!EventSystem_Should(VB_MODEL_XLU_DEPTH_WRITE, true, dummyBin, (s32)dummyId)) { + port_patchModelXluDepthWrite(dummyBin, dummyId); + } + } } } diff --git a/src/port/Network/Anchor/HookHandlers.cpp b/src/port/Network/Anchor/HookHandlers.cpp index b665cc3e2..c4fa4f860 100644 --- a/src/port/Network/Anchor/HookHandlers.cpp +++ b/src/port/Network/Anchor/HookHandlers.cpp @@ -6,6 +6,7 @@ //#include "soh/frame_interpolation.h" #include "port/Engine.h" #include "port/UI/Notification.h" +#include "port/Patches/Patches.h" #include #include "functions.h" @@ -17,6 +18,7 @@ float OTRGetDimensionFromRightEdge(float v); s32 chMrVile_netGetAnimMode(Actor* actor); void port_jiggySpawn_remove(int32_t jiggyId); int32_t port_mapFlag_wasSetRemotely(int32_t index); +bool __chSmBottles_isAnySpiralMountainAbilityLearned(void); } extern "C" void port_fpTwinkly_release(void) { @@ -130,9 +132,9 @@ bool Anchor_ScopedFlagExcluded(s32 space, s32 index) { (index == LEVEL_FLAG_11_FP_UNKNOWN || index == LEVEL_FLAG_12_FP_UNKNOWN || index == LEVEL_FLAG_13_FP_UNKNOWN)) { return true; } - // SM_SPECIFIC_FLAG_10: Bottles-conversation position lock; kept local. - if (space == ANCHOR_FLAGSPACE_MAP_SPECIFIC && gsworld_getMap() == MAP_1_SM_SPIRAL_MOUNTAIN && - index == SM_SPECIFIC_FLAG_10) { + // SM map flags are entirely Bottles-tutorial choreography; + // syncing any of them runs someone else's state machine. + if (space == ANCHOR_FLAGSPACE_MAP_SPECIFIC && gsworld_getMap() == MAP_1_SM_SPIRAL_MOUNTAIN) { return true; } return false; @@ -506,6 +508,32 @@ void Anchor::RegisterHooks() { anchor->SendPacket_SpawnJiggy((s16)ev->jiggyId, ev->x, ev->y, ev->z); }); + COND_HOOK(OnHoneycombDropSpawn, EVENT_PRIORITY_NORMAL, isConnected, [](IEvent* event) { + auto ev = reinterpret_cast(event); + Anchor::GetInstance()->SendPacket_SpawnHoneycomb((s16)ev->honeycombId, ev->bundleId, ev->x, ev->y, ev->z); + }); + + // SM intro Bottles: the tutorial offer is first-answer-wins for the team. + COND_VB_SHOULD(VB_SM_TUTORIAL_CHOICE_OPEN, EVENT_PRIORITY_NORMAL, isConnected, { + if (__chSmBottles_isAnySpiralMountainAbilityLearned() || + (port_puzzleStep_getForMap(MAP_1_SM_SPIRAL_MOUNTAIN, ANCHOR_PUZZLE_SM_TUTORIAL) & 1)) { + *should = false; + } else if (NetAuthority_IsClaimed(NET_ACTIVITY_SM_TUTORIAL) && !NetAuthority_IsSelf(NET_ACTIVITY_SM_TUTORIAL)) { + *should = false; + } else { + NetAuthority_Claim(NET_ACTIVITY_SM_TUTORIAL); + } + }); + + // Ability molehills wake up only after the tutorial choice exists: the offer was + // answered (synced bit) or a move is already known (covers skip-tutorial saves). + COND_VB_SHOULD(VB_SM_MOLEHILL_ACTIVE, EVENT_PRIORITY_NORMAL, isConnected, { + if (!__chSmBottles_isAnySpiralMountainAbilityLearned() && + !(port_puzzleStep_getForMap(MAP_1_SM_SPIRAL_MOUNTAIN, ANCHOR_PUZZLE_SM_TUTORIAL) & 1)) { + *should = false; + } + }); + COND_HOOK(OnTimedJiggyExpired, EVENT_PRIORITY_NORMAL, isConnected, [](IEvent* event) { auto ev = reinterpret_cast(event); port_jiggySpawn_remove(ev->jiggyId); diff --git a/src/port/Network/Anchor/Packets/SetAbility.cpp b/src/port/Network/Anchor/Packets/SetAbility.cpp index 1feea56c8..903ba8c40 100644 --- a/src/port/Network/Anchor/Packets/SetAbility.cpp +++ b/src/port/Network/Anchor/Packets/SetAbility.cpp @@ -3,6 +3,9 @@ #include #include "functions.h" +extern "C" { +void chSmBottles_netApplyTutorialComplete(void); +} /** * SET_ABILITY @@ -37,4 +40,12 @@ void Anchor::HandlePacket_SetAbility(nlohmann::json& payload) { if (value) { ability_setHasUsed((enum ability_e)move); } + + // A remote unlock just completed the SM tutorial set while we're standing in Spiral + // Mountain with a pre-completion world. Apply the completion state live. + if (value && (s32)gsworld_getMap() == MAP_1_SM_SPIRAL_MOUNTAIN && + !mapSpecificFlags_get(SM_SPECIFIC_FLAG_3_ALL_SM_ABILITIES_LEARNED) && + chmole_learnedAllSpiralMountainAbilities()) { + chSmBottles_netApplyTutorialComplete(); + } } diff --git a/src/port/Network/Anchor/Packets/SpawnHoneycomb.cpp b/src/port/Network/Anchor/Packets/SpawnHoneycomb.cpp new file mode 100644 index 000000000..5441ecf81 --- /dev/null +++ b/src/port/Network/Anchor/Packets/SpawnHoneycomb.cpp @@ -0,0 +1,47 @@ +#include "port/Network/Anchor/Anchor.h" +#include +#include + +#include "functions.h" +extern "C" { +void chHoneycomb_netSpawnDropAt(s32 uid, s32 bundleId, f32 x, f32 y, f32 z); +} + +void Anchor::SendPacket_SpawnHoneycomb(s16 honeycombId, s32 bundleId, f32 x, f32 y, f32 z) { + if (!IsSaveLoaded() || !roomState.syncItemsAndFlags) { + return; + } + + nlohmann::json payload; + payload["type"] = HONEYCOMB_SPAWN; + payload["targetTeamId"] = CVarGetString(CVAR_REMOTE_ANCHOR("TeamId"), "default"); + payload["honeycombId"] = honeycombId; + payload["bundle"] = bundleId; + payload["x"] = x; + payload["y"] = y; + payload["z"] = z; + payload["ctx"] = (s32)gsworld_getMap(); + + SendJsonToRemote(payload); +} + +void Anchor::HandlePacket_SpawnHoneycomb(nlohmann::json& payload) { + if (!IsSaveLoaded() || !roomState.syncItemsAndFlags) { + return; + } + + s16 honeycombId = payload.at("honeycombId").get(); + if ((s32)gsworld_getMap() != payload.at("ctx").get()) { + return; + } + if (honeycombscore_get((enum honeycomb_e)honeycombId)) { + return; + } + // Already present locally, nothing to add. + if (actorArray_findHoneycombMarkerById((enum honeycomb_e)honeycombId) != nullptr) { + return; + } + + chHoneycomb_netSpawnDropAt(honeycombId, payload.at("bundle").get(), payload.at("x").get(), + payload.at("y").get(), payload.at("z").get()); +} diff --git a/src/port/Patches/GraphicsPatches.cpp b/src/port/Patches/GraphicsPatches.cpp index 37b4aff39..b6c073163 100644 --- a/src/port/Patches/GraphicsPatches.cpp +++ b/src/port/Patches/GraphicsPatches.cpp @@ -14,13 +14,14 @@ static int sDrawDistanceCubeWidth(int mul) { return 4 * mul; } -static int sDrawDistanceLevel = 0; +static int sDrawDistanceLevel = 1; static int sDisableLOD = 0; extern "C" { #include #include "enums.h" #include "functions.h" +#include "model.h" #include "libultraship/libultra/gbi.h" #include "port/Romhack/RomhackConfig.h" @@ -36,31 +37,62 @@ void port_modelRenderResetTLUT(Gfx** gfx) { gDPSetTextureLUT((*gfx)++, G_TT_NONE); } +// When disabling LOD, Banjo's belt buckle will render and enforce transparency +// clipping through his stomach. Patch the subDL to change the depth write. +void port_patchModelXluDepthWrite(void* model_bin, s32 asset_id) { + if (model_bin == NULL || + (asset_id != ASSET_34D_MODEL_BANJOKAZOOIE_LOW_POLY && asset_id != ASSET_34E_MODEL_BANJOKAZOOIE_HIGH_POLY)) { + return; + } + + BKGfxList* gfx_list = modelbin_getGfxList((BKModelBin*)model_bin); + if (gfx_list == NULL) { + return; + } + + for (s32 i = 0; i < (s32)gfx_list->size; i++) { + Gfx* cmd = &gfx_list->list[i]; + if ((cmd->words.w0 >> 24) != G_DL) { + continue; + } + + if ((cmd->words.w1 & ~(uintptr_t)1) == 0x03000060) { + cmd->words.w1 = (cmd->words.w1 & (uintptr_t)1) | 0x03000120; + } + } +} + +} // extern "C" + +static void RegisterModelXluDepthWrite_Init() { + COND_VB_SHOULD(VB_MODEL_XLU_DEPTH_WRITE, EVENT_PRIORITY_NORMAL, true, { *should = false; }); +} + +static RegisterShipInitFunc sModelXluDepthWriteInit(RegisterModelXluDepthWrite_Init); + +extern "C" { + // Widescreen HUD edge anchoring (centered-ortho HUD geometry). + +static const float kHudCenterBand = 32.0f; + float port_hudOrthoShift(float refX) { float halfW = (f32)gFramebufferWidth * 0.5f; float extraHalf = (f32)gFramebufferHeight * 0.5f * GameEngine_GetAspectRatio() - halfW; if (extraHalf < 0.0f) { extraHalf = 0.0f; // narrower than 4:3 (e.g. pillarboxed): never pull inward } - if (refX < halfW) { + if (refX < halfW - kHudCenterBand) { return -extraHalf; // left-anchored } - if (refX > halfW) { + if (refX > halfW + kHudCenterBand) { return extraHalf; // right-anchored } return 0.0f; // centered } int port_getDrawDistanceSetting(void) { - int mul = CVarGetInteger(CVAR_ENHANCEMENT("Graphics.DrawDistance"), 1); - if (mul < 1) { - mul = 1; - } - if (mul > kMaxDrawDistanceMul) { - mul = kMaxDrawDistanceMul; - } - return mul; + return sDrawDistanceLevel; } int port_getDrawDistanceLevel(void) { @@ -146,7 +178,14 @@ static void RegisterDrawDistanceGraphics_Init() { static RegisterShipInitFunc drawDistanceGraphicsInit(RegisterDrawDistanceGraphics_Init, { CVAR_DRAW_DISTANCE }); static void RefreshDrawDistanceCVars() { - sDrawDistanceLevel = CVarGetInteger(CVAR_DRAW_DISTANCE, 1); + int mul = CVarGetInteger(CVAR_DRAW_DISTANCE, 1); + if (mul < 1) { + mul = 1; + } + if (mul > kMaxDrawDistanceMul) { + mul = kMaxDrawDistanceMul; + } + sDrawDistanceLevel = mul; sDisableLOD = CVarGetInteger(CVAR_DISABLE_LOD, 0); } diff --git a/src/port/Patches/Patches.h b/src/port/Patches/Patches.h index 1e52205db..4929a8213 100644 --- a/src/port/Patches/Patches.h +++ b/src/port/Patches/Patches.h @@ -77,6 +77,7 @@ void port_applyModelDrawDistanceCull(int* fadeFlag, float* cullMult, float* cull int port_spriteSizeCulled(float depth, float size, float baseThreshold, int disableFlag); float port_hudOrthoShift(float refX); void port_modelRenderResetTLUT(Gfx** gfx); +void port_patchModelXluDepthWrite(void* model_bin, s32 asset_id); // Mirror (MirrorPatches.cpp) @@ -155,6 +156,8 @@ void port_eggToll_remoteApply(int32_t map, int32_t secondaryId, int32_t stage); #define ANCHOR_PUZZLE_FP_SLUSHES 13 // RBB engine-room fans: 1 bit. Transient map flag 0 (enginefan.c reads it to slow the fans); persisted across reloads. #define ANCHOR_PUZZLE_RBB_ENGINE_FANS 14 +// SM intro Bottles: bit 0 = the tutorial choice has been made. +#define ANCHOR_PUZZLE_SM_TUTORIAL 15 void port_remoteCarry_setCarried(uint32_t clientId, int32_t markerId, float offset[3], float yawOffset); void port_remoteCarry_throw(uint32_t clientId, int32_t markerId, float start[3], float target[3]); diff --git a/src/port/Resource/GfxBridge.c b/src/port/Resource/GfxBridge.c index 30c28c9a5..cf62f287f 100644 --- a/src/port/Resource/GfxBridge.c +++ b/src/port/Resource/GfxBridge.c @@ -5,6 +5,8 @@ // __OTR__ asset paths instead of raw RAM; these wrappers detect that, swap in the // loaded resource via the ResourceManager, then forward to the real __gSP* GBI ops. +#include + #include "libultraship/libultra/gbi.h" #include "libultraship/bridge/resourcebridge.h" #include "src/port/ResourceHelpers.h" @@ -12,12 +14,9 @@ int ResourceMgr_OTRSigCheck(char* imgData) { uintptr_t i = (uintptr_t)(imgData); - // [port] Reject N64 segmented addresses and special sentinels. - // Segmented addresses fit in 32 bits with a non-zero segment byte (bits 24-31). - // Bit 0 set = already-tagged segmented address from stub GBI functions. - if ((i & 1) == 1) - return 0; - if (i != 0 && i <= 0xFFFFFFFF && (i >> 24) != 0) + // [port] Guard against small integers masquerading as pointers, which arise when + // N64 code computes an address from a NULL-based buffer. + if (i < 0x10000) return 0; // if ((i & 0xFF000000) != 0xAB000000 && (i & 0xFF000000) != 0xCD000000 && i != 0) { @@ -52,20 +51,25 @@ void gSPDisplayListOffset(Gfx* pkt, Gfx* dl, int offset) { __gSPDisplayList(pkt, dl + offset); } +// [port] `v` is a host pointer or an __OTR__ path. It is never a segmented address: +// callers that mean "segment N, offset off" use gSPVertexSeg. void gSPVertex(Gfx* pkt, uintptr_t v, int n, int v0) { if (ResourceMgr_OTRSigCheck((char*)v) == 1) v = (uintptr_t)ResourceMgr_LoadVtxByName((char*)v); - // [port] Mark N64 segmented addresses with bit 0 so the interpreter's SegAddr resolves them. - // SEGMENT_ADDR(num, off) produces values like 0x01000000 without bit 0 set. - // Segmented addresses fit in 32 bits with a non-zero segment byte (bits 24-31). - if (v != 0 && v <= 0xFFFFFFFF && (v >> 24) != 0) { - v |= 1; - } - __gSPVertex(pkt, v, n, v0); } +// [port] Emit a vertex command that references segment `seg` at byte offset `off`. +// Bit 0 is the tag Fast::Interpreter::SegAddr keys on to resolve against its segment +// table; host pointers are always even, so the two can never be confused. +void gSPVertexSeg(Gfx* pkt, u32 seg, uintptr_t off, int n, int v0) { + assert(seg < 16); + assert(off <= 0x00FFFFFE); + + __gSPVertex(pkt, ((uintptr_t)(seg & 0xF) << 24) | (off & 0x00FFFFFEu) | 1u, n, v0); +} + void gSPInvalidateTexCache(Gfx* pkt, uintptr_t texAddr) { char* imgData = (char*)texAddr; diff --git a/src/port/Save/SaveConverter.cpp b/src/port/Save/SaveConverter.cpp index 116ab6077..6860a878a 100644 --- a/src/port/Save/SaveConverter.cpp +++ b/src/port/Save/SaveConverter.cpp @@ -6,7 +6,7 @@ #include #include -#include "portable-file-dialogs.h" +#include "port/FilePicker.h" #include #include #include @@ -227,23 +227,44 @@ Result ExportToRecompBin(const std::string& dstPath, int slot) { return res; } -Result PickAndImport(int slot) { - // We can't predict the file extension a save will come in, and we already validate later in the chain - // Trust the user to pick the correct file - auto selection = pfd::open_file("Select a save to import", ".", { "All Files", "*" }).result(); - if (selection.empty()) { - return {}; - } - return ImportFromRawEeprom(selection[0], slot); +void PickAndImport(int slot, std::function onComplete) { + // We can't predict the file extension a save will come in, and we already validate later in the + // chain, so trust the user to pick the correct file. + Ship::FileBrowserRequest req; + req.Title = "Select a save to import"; + req.Filters = { { "All Files", { "*" } } }; + Lighthouse::PickFile(std::move(req), [slot, onComplete](std::optional path) { + if (!path) { + if (onComplete) { + onComplete({}); // cancelled + } + return; + } + Result r = ImportFromRawEeprom(path->string(), slot); + if (onComplete) { + onComplete(r); + } + }); } -Result PickAndExport(int slot) { - auto dest = pfd::save_file("Export save", "bk.n64.us.1.0.bin", { "Save files (*.bin)", "*.bin", "All Files", "*" }) - .result(); - if (dest.empty()) { - return {}; - } - return ExportToRecompBin(dest, slot); +void PickAndExport(int slot, std::function onComplete) { + Ship::FileBrowserRequest req; + req.Title = "Export save"; + req.Save = true; + req.DefaultName = "bk.n64.us.1.0.bin"; + req.Filters = { { "Save files (*.bin)", { "*.bin" } }, { "All Files", { "*" } } }; + Lighthouse::PickFile(std::move(req), [slot, onComplete](std::optional path) { + if (!path) { + if (onComplete) { + onComplete({}); // cancelled + } + return; + } + Result r = ExportToRecompBin(path->string(), slot); + if (onComplete) { + onComplete(r); + } + }); } } // namespace SaveConverter diff --git a/src/port/Save/SaveConverter.h b/src/port/Save/SaveConverter.h index 073458320..e51b78d7e 100644 --- a/src/port/Save/SaveConverter.h +++ b/src/port/Save/SaveConverter.h @@ -1,6 +1,7 @@ #ifndef SAVE_CONVERTER_H #define SAVE_CONVERTER_H +#include #include namespace SaveConverter { @@ -15,8 +16,11 @@ struct Result { Result ImportFromRawEeprom(const std::string& srcPath, int slot = kSlotAll); Result ExportToRecompBin(const std::string& dstPath, int slot = kSlotAll); -Result PickAndImport(int slot = kSlotAll); -Result PickAndExport(int slot = kSlotAll); + +// Open the file picker, then import/export on the chosen path. onComplete runs when done; an empty +// Result.message means the user cancelled. +void PickAndImport(int slot, std::function onComplete); +void PickAndExport(int slot, std::function onComplete); } // namespace SaveConverter diff --git a/src/port/UI/LighthouseMenuSettings.cpp b/src/port/UI/LighthouseMenuSettings.cpp index 989910876..3fd2747bc 100644 --- a/src/port/UI/LighthouseMenuSettings.cpp +++ b/src/port/UI/LighthouseMenuSettings.cpp @@ -181,12 +181,13 @@ void LighthouseMenu::AddMenuSettings() { "Make sure you're playing the same game or romhack as the save you're importing.", "Select Save", "Cancel", [slot]() { - SaveConverter::Result r = SaveConverter::PickAndImport(slot); - if (r.message.empty()) { - return; // cancelled - } - LighthouseGui::mModalWindow->RegisterPopup(r.ok ? "Save Import Complete" : "Save Import Failed", - r.message, "OK", "", nullptr, nullptr); + SaveConverter::PickAndImport(slot, [](SaveConverter::Result r) { + if (r.message.empty()) { + return; // cancelled + } + LighthouseGui::mModalWindow->RegisterPopup(r.ok ? "Save Import Complete" : "Save Import Failed", + r.message, "OK", "", nullptr, nullptr); + }); }, nullptr); }) @@ -198,12 +199,13 @@ void LighthouseMenu::AddMenuSettings() { .RaceDisable(false) .Callback([](WidgetInfo& info) { int slot = CVarGetInteger(CVAR_SETTING("SaveConvertSlot"), SaveConverter::kSlotAll); - SaveConverter::Result r = SaveConverter::PickAndExport(slot); - if (r.message.empty()) { - return; // cancelled - } - LighthouseGui::mModalWindow->RegisterPopup(r.ok ? "Save Export Complete" : "Save Export Failed", r.message, - "OK", "", nullptr, nullptr); + SaveConverter::PickAndExport(slot, [](SaveConverter::Result r) { + if (r.message.empty()) { + return; // cancelled + } + LighthouseGui::mModalWindow->RegisterPopup(r.ok ? "Save Export Complete" : "Save Export Failed", + r.message, "OK", "", nullptr, nullptr); + }); }) .Options(ButtonOptions().Tooltip( "Export the save for the game you're playing to a Banjo: Recompiled file. Use the slot above " diff --git a/src/port/UI/LighthouseModMenuWindow.cpp b/src/port/UI/LighthouseModMenuWindow.cpp index 0693fc30f..49b15e3e6 100644 --- a/src/port/UI/LighthouseModMenuWindow.cpp +++ b/src/port/UI/LighthouseModMenuWindow.cpp @@ -836,19 +836,13 @@ bool IsInlineModExtractionBusy() { return sInlineExtracting.load(); } -void RequestInlineModExtraction() { - if (sInlineExtracting.load()) { - return; - } - auto extractor = std::make_unique(); - if (!extractor->SelectGameFromUI()) { - return; - } +// Kick off the (detached) extraction worker for a ROM the user already picked + loaded. +static void BeginInlineExtraction(std::shared_ptr extractor, bool langPack) { sInlineFile = extractor->GetRomPath(); sInlineCount = 0; sInlineTotal = 0; sInlineResult = 0; - sInlineLangPack = false; + sInlineLangPack = langPack; sInlineExtracting = true; std::thread([ex = std::move(extractor)]() mutable { const bool ok = ex->GenerateOTR(sInlineCount, sInlineTotal, "bk"); @@ -857,49 +851,51 @@ void RequestInlineModExtraction() { }).detach(); } -void RequestInlineLanguagePackExtraction() { +// Shared body of the two public requests: pick a ROM, load it, and start extraction. Language packs +// add a couple of region gates before the common kickoff. The extractor is a shared_ptr so it stays +// alive across the async pick (captured in the callback) and the detached extraction thread. +static void StartInlineRomExtraction(bool langPack) { if (sInlineExtracting.load()) { return; } - auto extractor = std::make_unique(); - if (!extractor->SelectGameFromUI()) { - return; - } + auto extractor = std::make_shared(); + extractor->SelectGameFromUI([extractor, langPack](bool ok) { + if (!ok) { + return; // cancelled or failed to load + } + if (langPack) { + // Refuse a pack when we already have it as bk.o2r. + const std::string region = extractor->GetRegionSlug(); + if (region.empty()) { + LighthouseGui::RegisterPopup("Unrecognized ROM", + "That file isn't a recognized Banjo-Kazooie ROM, so no\n" + "language pack could be made from it.", + "OK", "", nullptr, nullptr); + return; + } + if (region == Lighthouse::BaseRegionSlug()) { + LighthouseGui::RegisterPopup("Already Have This Language", + "Your base game data (bk.o2r) already provides this region's\n" + "dialog, so there's no need to add it as a language pack.", + "OK", "", nullptr, nullptr); + return; + } + // Re-extracting a region overwrites its existing pack (e.g. to refresh it after an + // update), so a pre-existing mods/lang/bk.o2r is fine. + std::error_code ec; + std::filesystem::create_directories(Ship::Context::GetPathRelativeToAppDirectory("mods/lang"), ec); + extractor->SetDialogPack(true); + } + BeginInlineExtraction(extractor, langPack); + }); +} - // Refuse a pack when we already have it as bk.o2r. - const std::string region = extractor->GetRegionSlug(); - if (region.empty()) { - LighthouseGui::RegisterPopup("Unrecognized ROM", - "That file isn't a recognized Banjo-Kazooie ROM, so no\n" - "language pack could be made from it.", - "OK", "", nullptr, nullptr); - return; - } - if (region == Lighthouse::BaseRegionSlug()) { - LighthouseGui::RegisterPopup("Already Have This Language", - "Your base game data (bk.o2r) already provides this region's\n" - "dialog, so there's no need to add it as a language pack.", - "OK", "", nullptr, nullptr); - return; - } - // Re-extracting a region overwrites its existing pack (e.g. to refresh it - // after an update), so a pre-existing mods/~lang/bk.o2r is fine. - const std::string langDir = Ship::Context::GetPathRelativeToAppDirectory("mods/~lang"); - std::error_code ec; - std::filesystem::create_directories(langDir, ec); +void RequestInlineModExtraction() { + StartInlineRomExtraction(false); +} - extractor->SetDialogPack(true); - sInlineFile = extractor->GetRomPath(); - sInlineCount = 0; - sInlineTotal = 0; - sInlineResult = 0; - sInlineLangPack = true; - sInlineExtracting = true; - std::thread([ex = std::move(extractor)]() mutable { - const bool ok = ex->GenerateOTR(sInlineCount, sInlineTotal, "bk"); - sInlineResult = ok ? 1 : 2; - sInlineExtracting = false; - }).detach(); +void RequestInlineLanguagePackExtraction() { + StartInlineRomExtraction(true); } void DrawInlineModExtraction() { diff --git a/src/port/UI/LighthouseModals.cpp b/src/port/UI/LighthouseModals.cpp index 05696e112..d3db2586b 100644 --- a/src/port/UI/LighthouseModals.cpp +++ b/src/port/UI/LighthouseModals.cpp @@ -33,7 +33,7 @@ void LighthouseModalWindow::DrawElement() { if (modals.size() > 0) { LighthouseModal curModal = modals.at(0); if (!ImGui::IsPopupOpen(curModal.title_.c_str())) { - ImVec2 center = ImGui::GetMainViewport()->GetCenter(); + ImVec2 center = ImGui::GetMainViewport()->GetWorkCenter(); ImGui::SetNextWindowPos(center, ImGuiCond_Appearing, ImVec2(0.5f, 0.5f)); ImGui::OpenPopup(curModal.title_.c_str()); } @@ -46,6 +46,11 @@ void LighthouseModalWindow::DrawElement() { ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoSavedSettings)) { + // Show the nav highlight on the default button (button1) the moment the popup opens, so a + // gamepad/keyboard user sees the selection immediately rather than after a first input. + if (ImGui::IsWindowAppearing()) { + ImGui::SetNavCursorVisible(true); + } ImGui::Text("%s", curModal.message_.c_str()); UIWidgets::PushStyleButton(THEME_COLOR); if (ImGui::Button(curModal.button1_.c_str())) { diff --git a/src/port/UI/ResolutionEditor.cpp b/src/port/UI/ResolutionEditor.cpp index cbcee5911..305131005 100644 --- a/src/port/UI/ResolutionEditor.cpp +++ b/src/port/UI/ResolutionEditor.cpp @@ -404,7 +404,7 @@ void RegisterResolutionWidgets() { .CVar(CVAR_PREFIX_ADVANCED_RESOLUTION ".Enabled") .RaceDisable(false); // Error/Warning display - //mLighthouseMenu + // LighthouseMenu // ->AddWidget(path, ICON_FA_EXCLAMATION_TRIANGLE " Significant frame rate (FPS) drops may be occuring.", // WIDGET_TEXT) // .RaceDisable(false) @@ -589,13 +589,13 @@ void UpdateResolutionVars() { disabled_pixelCount = !CVarGetInteger(CVAR_PREFIX_ADVANCED_RESOLUTION ".VerticalResolutionToggle", 0); } -//bool IsDroppingFrames() { -// // a rather imprecise way of checking for frame drops. -// // but it's mostly there to inform the player of large drops. -// const short targetFPS = GameEngine::Instance->GetInterpolationFPS(); -// const float threshold = targetFPS / 20.0f + 4.1f; -// return ImGui::GetIO().Framerate < targetFPS - threshold; -//} +// bool IsDroppingFrames() { +// // a rather imprecise way of checking for frame drops. +// // but it's mostly there to inform the player of large drops. +// const short targetFPS = GameEngine::Instance->GetInterpolationFPS(); +// const float threshold = targetFPS / 20.0f + 4.1f; +// return ImGui::GetIO().Framerate < targetFPS - threshold; +// } static RegisterMenuUpdateFunc updateFunc(UpdateResolutionVars, "Settings", "Graphics"); static RegisterMenuInitFunc menuInitFunc(RegisterResolutionWidgets); diff --git a/src/port/UI/ResolutionEditor.h b/src/port/UI/ResolutionEditor.h index c0eed1680..316680534 100644 --- a/src/port/UI/ResolutionEditor.h +++ b/src/port/UI/ResolutionEditor.h @@ -2,7 +2,7 @@ #define RESOLUTIONEDITOR_H namespace LighthouseGui { -//bool IsDroppingFrames(); +// bool IsDroppingFrames(); void RegisterResolutionWidgets(); void UpdateResolutionVars(); } // namespace LighthouseGui From 74d78bfbd0740e7d4e9a7688429acfc87cf22733 Mon Sep 17 00:00:00 2001 From: Jeod <47716344+JeodC@users.noreply.github.com> Date: Tue, 28 Jul 2026 12:49:05 -0400 Subject: [PATCH 033/131] RC Fixes #3 (#275) * Revert: Patch Banjo's belt buckle depth (VB, on by default) * Resolve a crash * Rework modern camera --- src/core2/ba/model.c | 7 +- src/core2/fx/effect_debris.c | 4 +- src/port/Controller/ModernCamera.cpp | 126 +++++++++++++++++--- src/port/Enhancements/Events/Hooks/Events.h | 1 - src/port/Network/Anchor/DummyPlayer.cpp | 6 +- src/port/Patches/GraphicsPatches.cpp | 36 ------ src/port/Patches/Patches.h | 1 - 7 files changed, 113 insertions(+), 68 deletions(-) diff --git a/src/core2/ba/model.c b/src/core2/ba/model.c index 0f0894088..4b16065fd 100644 --- a/src/core2/ba/model.c +++ b/src/core2/ba/model.c @@ -6,7 +6,6 @@ #include "core2/ba/model.h" #include "core2/ba/physics.h" #include "bk_math.h" -#include "port/Patches/Patches.h" void assetcache_release(void *); //assetcache_free void modelRender_func_8033A280(f32); @@ -206,12 +205,8 @@ void baModel_set(enum asset_e asset_id){ baModelBin = NULL; } baModelId = asset_id; - if(baModelId) { + if(baModelId) baModelBin = assetcache_get(baModelId); - if (!EventSystem_Should(VB_MODEL_XLU_DEPTH_WRITE, true, baModelBin, baModelId)) { - port_patchModelXluDepthWrite(baModelBin, baModelId); - } - } } } diff --git a/src/core2/fx/effect_debris.c b/src/core2/fx/effect_debris.c index e9eb01123..bf9f8c40e 100644 --- a/src/core2/fx/effect_debris.c +++ b/src/core2/fx/effect_debris.c @@ -109,12 +109,12 @@ void func_802C83F0(Actor *actor) { Actor *func_802C8484(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx) { Struct25s *temp_s1; Struct24s *phi_s0; - f32 rotation; + f32 rotation[3]; Actor *this; u32 phi_v1; s32 phi_s4; - this = marker_getActorAndRotation(marker, &rotation); + this = marker_getActorAndRotation(marker, rotation); temp_s1 = (Struct25s*)this->unk40; phi_s4 = FALSE; for(phi_s0 = temp_s1->begin; phi_s0 < temp_s1->current; phi_s0++){ diff --git a/src/port/Controller/ModernCamera.cpp b/src/port/Controller/ModernCamera.cpp index dbe1f3302..7ca406f11 100644 --- a/src/port/Controller/ModernCamera.cpp +++ b/src/port/Controller/ModernCamera.cpp @@ -1,7 +1,4 @@ // Modern control scheme camera -// -// The right stick orbits the camera in yaw around the player (no pitch). It runs -// on the shared orbit core; this file is just the modern-scheme policy. #include @@ -10,9 +7,14 @@ #include "port/UI/cvar_prefixes.h" #include "ControlSchemes.h" #include "ModernCamera.h" -#include "port/Enhancements/Camera/OrbitCameraCore.h" extern "C" { +// Math helpers +void func_80256E24(float dst[3], float pitch, float yaw, float x, float y, float z); +void ml_vec3f_add(float dst[3], float a[3], float b[3]); +void ml_vec3f_clear(float dst[3]); +float mlNormalizeAngle(float deg); + extern unsigned char D_8037C061; // current zoom level extern int D_8037C07C; // level-3 distance x; 0 means level 3 is unavailable @@ -26,6 +28,8 @@ int balookat_getState(void); // nonzero while the look-around camera is activ int player_movementGroup(void); // enum bsgroup_e int ncDynamicCamera_getState(void); +void ncDynamicCamera_setState(int state); +void ncDynamicCamera_setRotation(float src[3]); int func_8029147C(void); // current ba camera mode void func_80291488(int mode); // set the ba camera mode void func_802914CC(int state); // force a dynamic camera state (mode 1) @@ -35,6 +39,25 @@ int bainput_should_rotate_camera_right(void); int bainput_should_look_first_person_camera(void); void controller_getRightStick(int controller_index, float dst[2]); + +// Vanilla follow-camera machinery +extern float D_8037DB70; // dynamicCamB.c: orbit yaw, degrees +extern float D_8037D9C8[3]; // dynamicCamera.c: rotation spring velocity + +void func_802C0150(int mode); // select the focus target +void func_802C0370(void); // record the pre-move position (anti-flip guard) +void func_802C0394(float target[3]); // record the ideal target (anti-flip guard) +void func_802C03BC(void); // undo a collision resolve that crossed over +void func_802C0490(float dst[3]); // focus/orbit center +void func_802C04B0(void); // re-derive D_8037DB70 from the live camera + +float func_802BD51C(void); // target camera height +float func_802BD8D4(void); // target orbit distance (zoom level) +void func_802BE190(float target[3]); // position spring toward target +void func_802BE230(float gain, float damp); // position spring tuning +int func_802BE60C(void); // swept camera collision + slide +int func_802BC84C(int mode); // occluded-too-long recovery +void func_802BE6FC(float rotOut[3], float focus[3]); // look-at from the live position } #include "enums.h" // BS_7_CROUCH @@ -54,11 +77,16 @@ constexpr float kYawEnter = 0.3f; constexpr float kYawSpeed = 160.0f; constexpr float kZoomOn = 0.49f; constexpr float kZoomOff = 0.21f; -constexpr float kPosSmoothRate = 40.0f; +constexpr float kPosSpringGain = 20.0f; +constexpr float kPosSpringDamp = 80.0f; +constexpr float kHeightRate = 3.0f; +constexpr float kAimHeightRate = 8.0f; -// Flat (pitch-locked) orbit on the shared core. -OrbitCamera sModern = { /*stateId*/ MODERN_ORBIT_CAM_STATE, /*allowPitch*/ 0, - /*minPitch*/ 0.0f, /*maxPitch*/ 0.0f, /*smoothRate*/ kPosSmoothRate }; +bool sActive = false; +bool sHeightValid = false; +bool sAimValid = false; +float sHeight = 0.0f; +float sAimY = 0.0f; float clampf(float v, float lo, float hi) { return v < lo ? lo : (v > hi ? hi : v); @@ -105,8 +133,28 @@ void ReleaseSwivelMode() { } } +// Take the camera over. Everything the vanilla follow camera would set up on init is +// set up here, except that the position spring velocity is deliberately left alone. +void EnterOrbit() { + func_802C0150(2); + func_802BE230(kPosSpringGain, kPosSpringDamp); + func_802C04B0(); + + // We drive the rotation directly, so nothing services the rotation spring while we + // own the camera. Park its velocity so it cannot kick the aim when camB resumes. + ml_vec3f_clear(D_8037D9C8); + + sHeightValid = false; + sAimValid = false; + sActive = true; + ncDynamicCamera_setState(MODERN_ORBIT_CAM_STATE); +} + void ExitOrbit() { - OrbitCamera_Exit(&sModern); + sActive = false; + if (ncDynamicCamera_getState() == MODERN_ORBIT_CAM_STATE) { + ncDynamicCamera_setState(0xB); + } ReleaseSwivelMode(); } @@ -115,7 +163,7 @@ void ExitOrbit() { extern "C" int port_modernCamera_handleYaw(void) { bool schemeOk = ModernSchemeActive() && bs_getState() != BS_7_CROUCH && !IsDemoMode(); if (!schemeOk) { - if (sModern.active) { + if (sActive) { ExitOrbit(); } return 0; @@ -123,11 +171,11 @@ extern "C" int port_modernCamera_handleYaw(void) { int state = ncDynamicCamera_getState(); - if (sModern.active) { + if (sActive) { // A scripted/special camera took the state out from under us; drop the // orbit and let that camera run. if (state != MODERN_ORBIT_CAM_STATE) { - sModern.active = 0; + sActive = false; return 0; } if (ManualCameraControl()) { @@ -144,7 +192,7 @@ extern "C" int port_modernCamera_handleYaw(void) { float y; ReadStickNorm(x, y); if (std::fabs(x) > kYawEnter) { - OrbitCamera_Enter(&sModern); + EnterOrbit(); if (state == kClimbCamState) { func_80291488(kSwivelCamMode); } @@ -158,15 +206,59 @@ extern "C" void port_modernCamera_update(void) { // Drive yaw from the stick. Freeze it during look-around so it doesn't drift // while the first-person view overrides the camera. - float yawDelta = 0.0f; - if (!sModern.justEntered && !balookat_getState()) { + if (!balookat_getState()) { float x; float y; ReadStickNorm(x, y); - yawDelta = YawInput(x) * kYawSpeed * dt * port_cameraInvertXSign(); + D_8037DB70 = mlNormalizeAngle(D_8037DB70 + YawInput(x) * kYawSpeed * dt * port_cameraInvertXSign()); + } + + // From here down this is ncDynamicCamB_update with our own yaw and height filter. + float focus[3]; + float offset[3]; + float target[3]; + + func_802C0370(); + func_802C0490(focus); + func_80256E24(offset, 0.0f, D_8037DB70, 0.0f, 0.0f, func_802BD8D4()); + ml_vec3f_add(target, focus, offset); + + float wantHeight = func_802BD51C(); + if (!sHeightValid) { + sHeight = wantHeight; + sHeightValid = true; + } else { + sHeight += (wantHeight - sHeight) * clampf(kHeightRate * dt, 0.0f, 1.0f); + } + target[1] = sHeight; + + func_802C0394(target); + func_802BE190(target); + + if (func_802BE60C()) { + // Occluded too long: func_802BC84C relocates the camera outright. Otherwise + // discard a resolve that pushed the camera back the way it came. + if (!func_802BC84C(1)) { + func_802C03BC(); + } + func_802C04B0(); // the camera slid along geometry; carry the orbit yaw with it + } + + // Aim straight at the focus from wherever the spring left the camera. The position + // is already smooth, so the look-at inherits that smoothness exactly and the player + // stays centered. + func_802C0490(focus); + if (!sAimValid) { + sAimY = focus[1]; + sAimValid = true; + } else { + sAimY += (focus[1] - sAimY) * clampf(kAimHeightRate * dt, 0.0f, 1.0f); } + focus[1] = sAimY; - OrbitCamera_Update(&sModern, yawDelta, 0.0f); + float rot[3]; + func_802BE6FC(rot, focus); + ncDynamicCamera_setRotation(rot); } extern "C" int port_camera_suppressVanillaZoom(void) { diff --git a/src/port/Enhancements/Events/Hooks/Events.h b/src/port/Enhancements/Events/Hooks/Events.h index f6f311aeb..4fdc8b75e 100644 --- a/src/port/Enhancements/Events/Hooks/Events.h +++ b/src/port/Enhancements/Events/Hooks/Events.h @@ -97,7 +97,6 @@ typedef enum VBehaviorID { VB_WARP_DISPATCH, VB_XMAS_TREE_ICE_UPDATE, VB_BOGGY_HOME_VISIBLE, - VB_MODEL_XLU_DEPTH_WRITE, } VBehaviorID; typedef enum DoorCameraId { diff --git a/src/port/Network/Anchor/DummyPlayer.cpp b/src/port/Network/Anchor/DummyPlayer.cpp index bd00dfc65..f04798ddb 100644 --- a/src/port/Network/Anchor/DummyPlayer.cpp +++ b/src/port/Network/Anchor/DummyPlayer.cpp @@ -377,12 +377,8 @@ void DummyPlayer::dummy_set(enum asset_e asset_id) { dummyBin = NULL; } dummyId = asset_id; - if (dummyId) { + if (dummyId) dummyBin = static_cast(assetcache_get(dummyId)); - if (!EventSystem_Should(VB_MODEL_XLU_DEPTH_WRITE, true, dummyBin, (s32)dummyId)) { - port_patchModelXluDepthWrite(dummyBin, dummyId); - } - } } } diff --git a/src/port/Patches/GraphicsPatches.cpp b/src/port/Patches/GraphicsPatches.cpp index b6c073163..c13103f38 100644 --- a/src/port/Patches/GraphicsPatches.cpp +++ b/src/port/Patches/GraphicsPatches.cpp @@ -21,7 +21,6 @@ extern "C" { #include #include "enums.h" #include "functions.h" -#include "model.h" #include "libultraship/libultra/gbi.h" #include "port/Romhack/RomhackConfig.h" @@ -37,41 +36,6 @@ void port_modelRenderResetTLUT(Gfx** gfx) { gDPSetTextureLUT((*gfx)++, G_TT_NONE); } -// When disabling LOD, Banjo's belt buckle will render and enforce transparency -// clipping through his stomach. Patch the subDL to change the depth write. -void port_patchModelXluDepthWrite(void* model_bin, s32 asset_id) { - if (model_bin == NULL || - (asset_id != ASSET_34D_MODEL_BANJOKAZOOIE_LOW_POLY && asset_id != ASSET_34E_MODEL_BANJOKAZOOIE_HIGH_POLY)) { - return; - } - - BKGfxList* gfx_list = modelbin_getGfxList((BKModelBin*)model_bin); - if (gfx_list == NULL) { - return; - } - - for (s32 i = 0; i < (s32)gfx_list->size; i++) { - Gfx* cmd = &gfx_list->list[i]; - if ((cmd->words.w0 >> 24) != G_DL) { - continue; - } - - if ((cmd->words.w1 & ~(uintptr_t)1) == 0x03000060) { - cmd->words.w1 = (cmd->words.w1 & (uintptr_t)1) | 0x03000120; - } - } -} - -} // extern "C" - -static void RegisterModelXluDepthWrite_Init() { - COND_VB_SHOULD(VB_MODEL_XLU_DEPTH_WRITE, EVENT_PRIORITY_NORMAL, true, { *should = false; }); -} - -static RegisterShipInitFunc sModelXluDepthWriteInit(RegisterModelXluDepthWrite_Init); - -extern "C" { - // Widescreen HUD edge anchoring (centered-ortho HUD geometry). static const float kHudCenterBand = 32.0f; diff --git a/src/port/Patches/Patches.h b/src/port/Patches/Patches.h index 4929a8213..5ea045f61 100644 --- a/src/port/Patches/Patches.h +++ b/src/port/Patches/Patches.h @@ -77,7 +77,6 @@ void port_applyModelDrawDistanceCull(int* fadeFlag, float* cullMult, float* cull int port_spriteSizeCulled(float depth, float size, float baseThreshold, int disableFlag); float port_hudOrthoShift(float refX); void port_modelRenderResetTLUT(Gfx** gfx); -void port_patchModelXluDepthWrite(void* model_bin, s32 asset_id); // Mirror (MirrorPatches.cpp) From 14f7bab55cfbceb6c69af8768dcf394c232e3436 Mon Sep 17 00:00:00 2001 From: Malkierian Date: Tue, 28 Jul 2026 13:01:43 -0700 Subject: [PATCH 034/131] Menu and logging cleanup. --- src/port/Network/Anchor/Authority.cpp | 1 - src/port/Network/Anchor/HookHandlers.cpp | 1 - src/port/Network/Anchor/Menu.cpp | 25 +++++++-------- .../Network/Anchor/Packets/ScopedFlag.cpp | 1 + src/port/Network/Anchor/Packets/SetFlag.cpp | 2 -- src/port/Rando/ObjectBehavior/Bundle.cpp | 2 -- src/port/UI/LighthouseMenuSettings.cpp | 32 +++++++++---------- 7 files changed, 28 insertions(+), 36 deletions(-) diff --git a/src/port/Network/Anchor/Authority.cpp b/src/port/Network/Anchor/Authority.cpp index cb37b5957..e5fb55eb8 100644 --- a/src/port/Network/Anchor/Authority.cpp +++ b/src/port/Network/Anchor/Authority.cpp @@ -75,7 +75,6 @@ void NetAuthority_Claim(NetworkActivityId activity) { } ActivityState& state = sActivities[activity]; if (state.claimed && state.owner != anchor->ownClientId) { - SPDLOG_WARN("[Authority] Tried to claim activity {} already owned by client {}", (int)activity, state.owner); return; } if (!state.claimed || state.owner != anchor->ownClientId) { diff --git a/src/port/Network/Anchor/HookHandlers.cpp b/src/port/Network/Anchor/HookHandlers.cpp index c4fa4f860..ec4aa7176 100644 --- a/src/port/Network/Anchor/HookHandlers.cpp +++ b/src/port/Network/Anchor/HookHandlers.cpp @@ -434,7 +434,6 @@ void Anchor::RegisterHooks() { } else { bit = fileProgressFlag_get((enum file_progress_e)index); } - SPDLOG_INFO("[Anchor][flagdiag] broadcast space={} index={:#x} bit={}", ev->flagSpace, index, bit); if (bit) { anchor->SendPacket_SetFlag((u8)ev->flagSpace, (s16)index); } else { diff --git a/src/port/Network/Anchor/Menu.cpp b/src/port/Network/Anchor/Menu.cpp index 5b84ff2f2..cfa319a3a 100644 --- a/src/port/Network/Anchor/Menu.cpp +++ b/src/port/Network/Anchor/Menu.cpp @@ -193,13 +193,13 @@ void AnchorAdminMenu(WidgetInfo& info) { } UIWidgets::PopStyleButton(); - if (UIWidgets::CVarCombobox("PvP Mode:", CVAR_REMOTE_ANCHOR("RoomSettings.PvpMode"), pvpModes, - UIWidgets::ComboboxOptions() - .DefaultIndex(1) - .LabelPosition(UIWidgets::LabelPositions::Above) - .Color(THEME_COLOR))) { - anchor->SendPacket_UpdateRoomState(); - } + //if (UIWidgets::CVarCombobox("PvP Mode:", CVAR_REMOTE_ANCHOR("RoomSettings.PvpMode"), pvpModes, + // UIWidgets::ComboboxOptions() + // .DefaultIndex(1) + // .LabelPosition(UIWidgets::LabelPositions::Above) + // .Color(THEME_COLOR))) { + // anchor->SendPacket_UpdateRoomState(); + //} if (UIWidgets::CVarCombobox("Show Locations For:", CVAR_REMOTE_ANCHOR("RoomSettings.ShowLocationsMode"), showLocationsModes, UIWidgets::ComboboxOptions() @@ -236,16 +236,13 @@ void AnchorInstructionsMenu(WidgetInfo& info) { ImGui::TextWrapped("2. Come up with a unique Room ID (this is basically your password) and enter it, along with " "your desired player name and team ID and click Enable"); - ImGui::TextWrapped("3. The host should configure the randomizer settings and generate a seed, then share the newly " - "generated JSON spoiler file with other players."); - - ImGui::TextWrapped("4. All players should load the same JSON spoiler file (drag it into SoH window), make sure " - "seed icons match, then create a new file."); + ImGui::TextWrapped("3. For Rando: The host should configure the randomizer settings and generate a seed, then get " + "in game to create a save file to share."); - ImGui::TextWrapped("5. All players should now load into their game. IMPORTANT! If using an existing save/seed " + ImGui::TextWrapped("4. All players should now load into their game. IMPORTANT! If using an existing save/seed " "ensure the player with the most progress loads the file first."); - ImGui::TextWrapped("6. After everyone has loaded in, verify on the network tab that it doesn't warn about anyone " + ImGui::TextWrapped("5. After everyone has loaded in, verify on the network tab that it doesn't warn about anyone " "being on a wrong version or seed."); ImGui::Spacing(); diff --git a/src/port/Network/Anchor/Packets/ScopedFlag.cpp b/src/port/Network/Anchor/Packets/ScopedFlag.cpp index 2645b5422..19b5c8db6 100644 --- a/src/port/Network/Anchor/Packets/ScopedFlag.cpp +++ b/src/port/Network/Anchor/Packets/ScopedFlag.cpp @@ -30,6 +30,7 @@ void Anchor::SendPacket_ScopedFlag(u8 space, s16 index, u8 value) { nlohmann::json payload; payload["type"] = SCOPED_FLAG; + payload["targetTeamId"] = CVarGetString(CVAR_REMOTE_ANCHOR("TeamId"), "default"); payload["space"] = space; payload["index"] = index; payload["value"] = value; diff --git a/src/port/Network/Anchor/Packets/SetFlag.cpp b/src/port/Network/Anchor/Packets/SetFlag.cpp index dd109bcfd..35c840698 100644 --- a/src/port/Network/Anchor/Packets/SetFlag.cpp +++ b/src/port/Network/Anchor/Packets/SetFlag.cpp @@ -64,8 +64,6 @@ void Anchor::HandlePacket_SetFlag(nlohmann::json& payload) { u8 flagSpace = payload.at("flagSpace").get(); s16 flag = payload.at("flag").get(); - SPDLOG_INFO("[Anchor][flagdiag] received SetFlag space={} flag={:#x}", flagSpace, flag); - if (flagSpace == ANCHOR_FLAGSPACE_RANDO_INF) { // Non-derived rando flag; set directly. if (IS_RANDO && flag > RANDO_INF_UNKNOWN && flag < RANDO_INF_MAX) { diff --git a/src/port/Rando/ObjectBehavior/Bundle.cpp b/src/port/Rando/ObjectBehavior/Bundle.cpp index fff4dda9b..ba605d73a 100644 --- a/src/port/Rando/ObjectBehavior/Bundle.cpp +++ b/src/port/Rando/ObjectBehavior/Bundle.cpp @@ -58,8 +58,6 @@ void Rando::ObjectBehavior::InitBundleBehavior() { spawnPosition[1] = (int32_t)position[1]; spawnPosition[2] = (int32_t)position[2]; - SPDLOG_INFO("Bundle Spawn: {}", std::to_string(bundleId)); - if (bundleId == BUNDLE_16__HONEYCOMB && (currentMap == MAP_43_CCW_SPRING || currentMap == MAP_B_CC_CLANKERS_CAVERN)) { if (CheckEnemyOverlapPosition(spawnPosition)) { diff --git a/src/port/UI/LighthouseMenuSettings.cpp b/src/port/UI/LighthouseMenuSettings.cpp index 3fd2747bc..d586c734a 100644 --- a/src/port/UI/LighthouseMenuSettings.cpp +++ b/src/port/UI/LighthouseMenuSettings.cpp @@ -297,34 +297,34 @@ void LighthouseMenu::AddMenuSettings() { .CVar(CVAR_SETTING("Volume.Master")) .RaceDisable(false) .Options(IntSliderOptions().Min(0).Max(100).DefaultValue(40).ShowButtons(true).Format("")); - AddWidget(path, "Main Music Volume: %d %%", WIDGET_CVAR_SLIDER_INT) - .CVar(CVAR_SETTING("Volume.MainMusic")) - .RaceDisable(false) - .Options(IntSliderOptions().Min(0).Max(100).DefaultValue(100).ShowButtons(true).Format("")); + //AddWidget(path, "Main Music Volume: %d %%", WIDGET_CVAR_SLIDER_INT) + // .CVar(CVAR_SETTING("Volume.MainMusic")) + // .RaceDisable(false) + // .Options(IntSliderOptions().Min(0).Max(100).DefaultValue(100).ShowButtons(true).Format("")); //.Callback([](WidgetInfo& info) { // Audio_SetGameVolume(SEQ_PLAYER_BGM_MAIN, // ((float)CVarGetInteger(CVAR_SETTING("Volume.MainMusic"), 100) / 100.0f)); //}); - AddWidget(path, "Sub Music Volume: %d %%", WIDGET_CVAR_SLIDER_INT) - .CVar(CVAR_SETTING("Volume.SubMusic")) - .RaceDisable(false) - .Options(IntSliderOptions().Min(0).Max(100).DefaultValue(100).ShowButtons(true).Format("")); + //AddWidget(path, "Sub Music Volume: %d %%", WIDGET_CVAR_SLIDER_INT) + // .CVar(CVAR_SETTING("Volume.SubMusic")) + // .RaceDisable(false) + // .Options(IntSliderOptions().Min(0).Max(100).DefaultValue(100).ShowButtons(true).Format("")); //.Callback([](WidgetInfo& info) { // Audio_SetGameVolume(SEQ_PLAYER_BGM_SUB, // ((float)CVarGetInteger(CVAR_SETTING("Volume.SubMusic"), 100) / 100.0f)); //}); - AddWidget(path, "Fanfare Volume: %d %%", WIDGET_CVAR_SLIDER_INT) - .CVar(CVAR_SETTING("Volume.Fanfare")) - .RaceDisable(false) - .Options(IntSliderOptions().Min(0).Max(100).DefaultValue(100).ShowButtons(true).Format("")); + //AddWidget(path, "Fanfare Volume: %d %%", WIDGET_CVAR_SLIDER_INT) + // .CVar(CVAR_SETTING("Volume.Fanfare")) + // .RaceDisable(false) + // .Options(IntSliderOptions().Min(0).Max(100).DefaultValue(100).ShowButtons(true).Format("")); //.Callback([](WidgetInfo& info) { // Audio_SetGameVolume(SEQ_PLAYER_FANFARE, // ((float)CVarGetInteger(CVAR_SETTING("Volume.Fanfare"), 100) / 100.0f)); //}); - AddWidget(path, "Sound Effects Volume: %d %%", WIDGET_CVAR_SLIDER_INT) - .CVar(CVAR_SETTING("Volume.SFX")) - .RaceDisable(false) - .Options(IntSliderOptions().Min(0).Max(100).DefaultValue(100).ShowButtons(true).Format("")); + //AddWidget(path, "Sound Effects Volume: %d %%", WIDGET_CVAR_SLIDER_INT) + // .CVar(CVAR_SETTING("Volume.SFX")) + // .RaceDisable(false) + // .Options(IntSliderOptions().Min(0).Max(100).DefaultValue(100).ShowButtons(true).Format("")); //.Callback([](WidgetInfo& info) { // Audio_SetGameVolume(SEQ_PLAYER_SFX, ((float)CVarGetInteger(CVAR_SETTING("Volume.SFX"), 100) / 100.0f)); //}); From f78003d6d42ac3ffb6a5616467b05169abc10d88 Mon Sep 17 00:00:00 2001 From: Malkierian Date: Tue, 28 Jul 2026 17:07:47 -0700 Subject: [PATCH 035/131] Apply modern camera changes back to free look. (#277) * Apply modern camera changes back to free look. * Free look takes precedence over modern camera. --- src/port/Controller/ModernCamera.cpp | 6 +- .../Enhancements/Camera/FreeLookCamera.cpp | 201 +++++++++++++----- .../Enhancements/Camera/OrbitCameraCore.cpp | 193 ----------------- .../Enhancements/Camera/OrbitCameraCore.h | 52 ----- 4 files changed, 150 insertions(+), 302 deletions(-) delete mode 100644 src/port/Enhancements/Camera/OrbitCameraCore.cpp delete mode 100644 src/port/Enhancements/Camera/OrbitCameraCore.h diff --git a/src/port/Controller/ModernCamera.cpp b/src/port/Controller/ModernCamera.cpp index 7ca406f11..57e45ae32 100644 --- a/src/port/Controller/ModernCamera.cpp +++ b/src/port/Controller/ModernCamera.cpp @@ -7,6 +7,7 @@ #include "port/UI/cvar_prefixes.h" #include "ControlSchemes.h" #include "ModernCamera.h" +#include "port/Enhancements/Camera/FreeLookCamera.h" extern "C" { // Math helpers @@ -66,7 +67,8 @@ void func_802BE6FC(float rotOut[3], float focus[3]); // look-at from the live po namespace { bool ModernSchemeActive() { - return CVarGetInteger(CVAR_SETTING("Controls.Scheme"), CONTROL_SCHEME_RETRO) == CONTROL_SCHEME_MODERN; + return CVarGetInteger(CVAR_SETTING("Controls.Scheme"), CONTROL_SCHEME_RETRO) == CONTROL_SCHEME_MODERN && + !port_freeLook_isEnabled(); } constexpr int kClimbCamState = 0x10; @@ -262,7 +264,7 @@ extern "C" void port_modernCamera_update(void) { } extern "C" int port_camera_suppressVanillaZoom(void) { - if (IsDemoMode()) { + if (IsDemoMode() || port_freeLook_isEnabled()) { return 0; } int scheme = CVarGetInteger(CVAR_SETTING("Controls.Scheme"), CONTROL_SCHEME_RETRO); diff --git a/src/port/Enhancements/Camera/FreeLookCamera.cpp b/src/port/Enhancements/Camera/FreeLookCamera.cpp index 46381bd59..64a7e88db 100644 --- a/src/port/Enhancements/Camera/FreeLookCamera.cpp +++ b/src/port/Enhancements/Camera/FreeLookCamera.cpp @@ -1,21 +1,49 @@ +// Free look camera + +#include + #include #include "port/UI/cvar_prefixes.h" #include "port/Enhancements/Camera/FreeLookCamera.h" -#include "port/Enhancements/Camera/OrbitCameraCore.h" -// Vanilla camera / input entry points (decomp C API). extern "C" { -int ncDynamicCamera_getState(void); +// Math helpers +void func_80256E24(float dst[3], float pitch, float yaw, float x, float y, float z); +void ml_vec3f_add(float dst[3], float a[3], float b[3]); +void ml_vec3f_clear(float dst[3]); +float mlNormalizeAngle(float deg); float time_getDelta(void); -float gu_sqrtf(float x); void controller_getRightStick(int controller_index, float dst[2]); int bainput_should_rotate_camera_left(void); int bainput_should_rotate_camera_right(void); int bainput_should_look_first_person_camera(void); + +int ncDynamicCamera_getState(void); +void ncDynamicCamera_setState(int state); +void ncDynamicCamera_getPosition(float dst[3]); +void ncDynamicCamera_setRotation(float src[3]); + +// Vanilla follow-camera machinery +extern float D_8037DB70; // dynamicCamB.c: orbit yaw, degrees +extern float D_8037D9C8[3]; // dynamicCamera.c: rotation spring velocity + +void func_802C0150(int mode); // select the focus target +void func_802C0370(void); // record the pre-move position (anti-flip guard) +void func_802C0394(float target[3]); // record the ideal target (anti-flip guard) +void func_802C03BC(void); // undo a collision resolve that crossed over +void func_802C0490(float dst[3]); // focus/orbit center +void func_802C04B0(void); // re-derive D_8037DB70 from the live camera + +float func_802BD8D4(void); // target orbit distance (zoom level) +void func_802BE190(float target[3]); // position spring toward target +void func_802BE230(float gain, float damp); // position spring tuning +int func_802BE60C(void); // swept camera collision + slide +int func_802BC84C(int mode); // occluded-too-long recovery +void func_802BE6FC(float rotOut[3], float focus[3]); // look-at from the live position } namespace { @@ -26,50 +54,90 @@ namespace { #define CVAR_FREELOOK_INVERT_Y CVAR_ENHANCEMENT("Camera.FreeLook.InvertY") #define CVAR_FREELOOK_SMOOTH_RATE CVAR_ENHANCEMENT("Camera.FreeLook.SmoothRate") -// Tuning -constexpr float deadzone = 0.15f; -constexpr float enterThreshold = 0.30f; -constexpr float horizontalSpeed = 160.0f; -constexpr float verticalSpeed = 100.0f; +constexpr float kDeadzone = 0.15f; +constexpr float kEnterThreshold = 0.30f; +constexpr float kYawSpeed = 160.0f; +constexpr float kPitchSpeed = 100.0f; -constexpr float minPitch = -85.0f; // high overhead, looking down -constexpr float maxPitch = 40.0f; // low, looking up at the player +constexpr float kMinPitch = -85.0f; +constexpr float kMaxPitch = 40.0f; -// position smoothing rate (1/sec); higher = snappier -constexpr float defaultSmoothRate = 40.0f; +constexpr float kAimHeightRate = 8.0f; +constexpr float kDefaultSmooth = 40.0f; +constexpr float kSmoothToGain = 0.5f; +constexpr float kDampRatio = 4.0f; -// Pitch-enabled orbit on the shared core. Distance tracks the vanilla zoom level -// (same as the modern-scheme camera) so the normal follow distances are honored. -OrbitCamera sFreeLook = { /*stateId*/ FREELOOK_CAM_STATE, /*allowPitch*/ 1, - /*minPitch*/ minPitch, /*maxPitch*/ maxPitch, /*smoothRate*/ defaultSmoothRate }; +constexpr float kRadToDeg = 57.29577951308232f; -// Right stick with a radial deadzone, rescaled so motion ramps from 0 at the -// deadzone edge to 1 at full deflection. -float readStick(float out[2]) { +bool sActive = false; +bool sAimValid = false; +float sPitch = 0.0f; +float sAimY = 0.0f; + +float clampf(float v, float lo, float hi) { + return v < lo ? lo : (v > hi ? hi : v); +} + +float SpringGain() { + return CVarGetFloat(CVAR_FREELOOK_SMOOTH_RATE, kDefaultSmooth) * kSmoothToGain; +} + +float ReadStick(float out[2]) { controller_getRightStick(0, out); - float mag = gu_sqrtf(out[0] * out[0] + out[1] * out[1]); - if (mag < deadzone) { + float mag = std::sqrt(out[0] * out[0] + out[1] * out[1]); + if (mag < kDeadzone) { out[0] = out[1] = 0.0f; return 0.0f; } if (mag > 1.0f) { mag = 1.0f; } - float scaled = (mag - deadzone) / (1.0f - deadzone); + float scaled = (mag - kDeadzone) / (1.0f - kDeadzone); float k = scaled / mag; out[0] *= k; out[1] *= k; return scaled; } -// Explicit camera commands hand the frame back to the normal camera. Zoom is not -// one of them: it adjusts the vanilla zoom level, which free look tracks, so the -// player can re-zoom without dropping out of free look. -bool cButtonCameraControl() { +bool ManualCameraControl() { return bainput_should_rotate_camera_left() || bainput_should_rotate_camera_right() || bainput_should_look_first_person_camera(); } +float CapturePitch() { + float camPos[3]; + float focus[3]; + ncDynamicCamera_getPosition(camPos); + func_802C0490(focus); + + float diff[3] = { camPos[0] - focus[0], camPos[1] - focus[1], camPos[2] - focus[2] }; + float dist = std::sqrt(diff[0] * diff[0] + diff[1] * diff[1] + diff[2] * diff[2]); + if (dist < 1.0f) { + return 0.0f; + } + return clampf(std::asin(clampf(-diff[1] / dist, -1.0f, 1.0f)) * kRadToDeg, kMinPitch, kMaxPitch); +} + +void EnterOrbit() { + func_802C0150(2); + func_802BE230(SpringGain(), SpringGain() * kDampRatio); + func_802C04B0(); + sPitch = CapturePitch(); + + ml_vec3f_clear(D_8037D9C8); + + sAimValid = false; + sActive = true; + ncDynamicCamera_setState(FREELOOK_CAM_STATE); +} + +void ExitOrbit() { + sActive = false; + if (ncDynamicCamera_getState() == FREELOOK_CAM_STATE) { + ncDynamicCamera_setState(0xB); + } +} + } // namespace extern "C" int port_freeLook_isEnabled(void) { @@ -78,38 +146,37 @@ extern "C" int port_freeLook_isEnabled(void) { extern "C" int port_freeLook_handle(void) { if (!port_freeLook_isEnabled()) { - if (sFreeLook.active) { - OrbitCamera_Exit(&sFreeLook); + if (sActive) { + ExitOrbit(); } return 0; } int state = ncDynamicCamera_getState(); - if (sFreeLook.active) { + if (sActive) { if (state != FREELOOK_CAM_STATE) { - sFreeLook.active = 0; + sActive = false; return 0; } - if (cButtonCameraControl()) { - OrbitCamera_Exit(&sFreeLook); + if (ManualCameraControl()) { + ExitOrbit(); return 0; } - return 1; // hold the angle; consume the frame + return 1; } - if (cButtonCameraControl()) { + if (ManualCameraControl()) { return 0; } - // Only enter from a normal follow/orbit camera. if (state != 0xB && state != 0x1 && state != 0xA) { return 0; } float stick[2]; - if (readStick(stick) >= enterThreshold) { - OrbitCamera_Enter(&sFreeLook); + if (ReadStick(stick) >= kEnterThreshold) { + EnterOrbit(); return 1; } @@ -118,23 +185,47 @@ extern "C" int port_freeLook_handle(void) { extern "C" void port_freeLookCamera_update(void) { float dt = time_getDelta(); - sFreeLook.smoothRate = CVarGetFloat(CVAR_FREELOOK_SMOOTH_RATE, defaultSmoothRate); - - float yawDelta = 0.0f; - float pitchDelta = 0.0f; - if (!sFreeLook.justEntered) { - float stick[2]; - readStick(stick); - - float yawSens = CVarGetFloat(CVAR_FREELOOK_YAW_SENS, 1.0f); - float pitchSens = CVarGetFloat(CVAR_FREELOOK_PITCH_SENS, 1.0f); - bool invertX = CVarGetInteger(CVAR_FREELOOK_INVERT_X, 0) != 0; - bool invertY = CVarGetInteger(CVAR_FREELOOK_INVERT_Y, 0) != 0; - - yawDelta = (invertX ? -stick[0] : stick[0]) * horizontalSpeed * yawSens * dt; - // Default: push up -> camera rises and looks down (overhead). InvertY flips it. - pitchDelta = (invertY ? stick[1] : -stick[1]) * verticalSpeed * pitchSens * dt; + + float stick[2]; + ReadStick(stick); + + float yawSens = CVarGetFloat(CVAR_FREELOOK_YAW_SENS, 1.0f); + float pitchSens = CVarGetFloat(CVAR_FREELOOK_PITCH_SENS, 1.0f); + bool invertX = CVarGetInteger(CVAR_FREELOOK_INVERT_X, 0) != 0; + bool invertY = CVarGetInteger(CVAR_FREELOOK_INVERT_Y, 0) != 0; + + D_8037DB70 = mlNormalizeAngle(D_8037DB70 + (invertX ? -stick[0] : stick[0]) * kYawSpeed * yawSens * dt); + sPitch = clampf(sPitch + (invertY ? stick[1] : -stick[1]) * kPitchSpeed * pitchSens * dt, kMinPitch, kMaxPitch); + + float focus[3]; + float offset[3]; + float target[3]; + + func_802C0370(); + func_802C0490(focus); + func_80256E24(offset, sPitch, D_8037DB70, 0.0f, 0.0f, func_802BD8D4()); + ml_vec3f_add(target, focus, offset); + + func_802C0394(target); + func_802BE190(target); + + if (func_802BE60C()) { + if (!func_802BC84C(1)) { + func_802C03BC(); + } + func_802C04B0(); + } + + func_802C0490(focus); + if (!sAimValid) { + sAimY = focus[1]; + sAimValid = true; + } else { + sAimY += (focus[1] - sAimY) * clampf(kAimHeightRate * dt, 0.0f, 1.0f); } + focus[1] = sAimY; - OrbitCamera_Update(&sFreeLook, yawDelta, pitchDelta); + float rot[3]; + func_802BE6FC(rot, focus); + ncDynamicCamera_setRotation(rot); } diff --git a/src/port/Enhancements/Camera/OrbitCameraCore.cpp b/src/port/Enhancements/Camera/OrbitCameraCore.cpp deleted file mode 100644 index 6e0b294d7..000000000 --- a/src/port/Enhancements/Camera/OrbitCameraCore.cpp +++ /dev/null @@ -1,193 +0,0 @@ -// Shared right-stick orbit camera core. See OrbitCameraCore.h. - -#include "port/Enhancements/Camera/OrbitCameraCore.h" - -extern "C" { -// Vanilla camera / math entry points used to drive the orbit state. -void ncDynamicCamera_getPosition(float dst[3]); -void ncDynamicCamera_setPosition(float src[3]); -void ncDynamicCamera_setRotation(float src[3]); -int ncDynamicCamera_getState(void); -void ncDynamicCamera_setState(int state); - -void func_802C02D4(float center[3]); // camera focus/orbit center -void func_802C0150(int mode); // select the focus target -void func_80256E24(float dst[3], float pitch, float yaw, float x, float y, float z); // spherical -> offset -int func_8025801C(float vec[3], float* yaw); // vector -> yaw (degrees) -void func_802BC434(float rotOut[3], float fromPos[3], float targetPos[3]); // look-at rotation -int func_802BE60C(void); // swept camera collision + slide -extern float D_8037D948[3]; // dynamicCamera.c collision anchor: the point the camera stays visible from -float func_802BD8D4(void); // target orbit distance (zoom level) -float func_802BD51C(void); // target camera height - -float ml_acosf(float x); -float mlNormalizeAngle(float deg); -float mlDiffDegF(float a, float b); // shortest signed a-b in degrees -float gu_sqrtf(float x); -float time_getDelta(void); -} - -namespace { - -constexpr float kDistanceRate = 8.0f; -constexpr float kReturnRateFactor = 0.2f; // collision offset relaxes this much slower than it deepens -constexpr float kHeightRate = 2.0f; -constexpr float kAimHeightRate = 8.0f; -constexpr float kRotRate = 12.0f; // look-at damping, mirroring the vanilla follow camera - -float clampf(float v, float lo, float hi) { - return v < lo ? lo : (v > hi ? hi : v); -} - -} // namespace - -extern "C" void OrbitCamera_Capture(OrbitCamera* c) { - func_802C0150(2); - - float camPos[3]; - float center[3]; - ncDynamicCamera_getPosition(camPos); - func_802C02D4(center); - - float diff[3] = { camPos[0] - center[0], camPos[1] - center[1], camPos[2] - center[2] }; - - c->yaw = 0.0f; - func_8025801C(diff, &c->yaw); - - if (c->allowPitch) { - float dist = gu_sqrtf(diff[0] * diff[0] + diff[1] * diff[1] + diff[2] * diff[2]); - c->distance = dist; - float sinPitch = clampf(-diff[1] / dist, -1.0f, 1.0f); - float pitchMag = ml_acosf(sinPitch); - c->pitch = clampf(sinPitch < 0.0f ? -pitchMag : pitchMag, c->minPitch, c->maxPitch); - } else { - c->distance = gu_sqrtf(diff[0] * diff[0] + diff[2] * diff[2]); - c->height = camPos[1]; - c->pitch = 0.0f; - } - - c->justEntered = 1; - c->smoothValid = 0; - c->aimValid = 0; - c->rotValid = 0; -} - -extern "C" void OrbitCamera_Enter(OrbitCamera* c) { - OrbitCamera_Capture(c); - c->active = 1; - ncDynamicCamera_setState(c->stateId); -} - -extern "C" void OrbitCamera_Exit(OrbitCamera* c) { - c->active = 0; - if (ncDynamicCamera_getState() == c->stateId) { - ncDynamicCamera_setState(0xB); // hand back to the normal follow camera - } -} - -extern "C" void OrbitCamera_Update(OrbitCamera* c, float yawDelta, float pitchDelta) { - float dt = time_getDelta(); - float center[3]; - func_802C02D4(center); - - c->yaw = mlNormalizeAngle(c->yaw + yawDelta); - if (c->allowPitch) { - c->pitch = clampf(c->pitch + pitchDelta, c->minPitch, c->maxPitch); - } - c->justEntered = 0; - - // The collision resolve can trap the camera far from the player; snap home when the gap runs away. - bool driftEscape = false; - float zoomTarget = func_802BD8D4(); - if (c->smoothValid && zoomTarget > 0.0f) { - float rgx = center[0] - c->smoothPos[0]; - float rgz = center[2] - c->smoothPos[2]; - float limit = zoomTarget * 1.05f; - if ((rgx * rgx + rgz * rgz) > (limit * limit)) { - c->distance = zoomTarget; - c->smoothValid = 0; - driftEscape = true; - } - } - - // Track the vanilla zoom-level distance so zoom controls still apply while orbiting. - float distTrack = clampf(kDistanceRate * dt, 0.0f, 1.0f); - c->distance += (func_802BD8D4() - c->distance) * distTrack; - - float offset[3]; - func_80256E24(offset, c->allowPitch ? c->pitch : 0.0f, c->yaw, 0.0f, 0.0f, c->distance); - - float pos[3]; - pos[0] = center[0] + offset[0]; - pos[2] = center[2] + offset[2]; - if (c->allowPitch) { - pos[1] = center[1] + offset[1]; // pitch carries the vertical offset - } else { - // Flat orbit: height low-passes the vanilla target, filtering plank/step floor churn. - c->height += (func_802BD51C() - c->height) * clampf(kHeightRate * dt, 0.0f, 1.0f); - pos[1] = c->height; - } - ncDynamicCamera_setPosition(pos); - - // Resolve geometry; on a drift escape, anchor at the player so the resolve pulls back in. - if (driftEscape) { - D_8037D948[0] = center[0]; - D_8037D948[1] = center[1]; - D_8037D948[2] = center[2]; - } - func_802BE60C(); - - float resolved[3]; - ncDynamicCamera_getPosition(resolved); - - // pos already follows the player smoothly; the shake near thin/translucent geometry lives in the - // collision correction, so smooth only that (damps every direction with no added follow lag). - float corr[3] = { resolved[0] - pos[0], resolved[1] - pos[1], resolved[2] - pos[2] }; - if (!c->smoothValid) { - c->collisionOffset[0] = corr[0]; - c->collisionOffset[1] = corr[1]; - c->collisionOffset[2] = corr[2]; - c->smoothValid = 1; - } else { - // Deepen the pull-in fast (never clip through geometry), relax slowly so a flickering - // collision settles at its deep value instead of oscillating. - float newSq = corr[0] * corr[0] + corr[1] * corr[1] + corr[2] * corr[2]; - float curSq = c->collisionOffset[0] * c->collisionOffset[0] + c->collisionOffset[1] * c->collisionOffset[1] + - c->collisionOffset[2] * c->collisionOffset[2]; - float rate = (newSq > curSq) ? c->smoothRate : c->smoothRate * kReturnRateFactor; - float f = clampf(rate * dt, 0.0f, 1.0f); - c->collisionOffset[0] += (corr[0] - c->collisionOffset[0]) * f; - c->collisionOffset[1] += (corr[1] - c->collisionOffset[1]) * f; - c->collisionOffset[2] += (corr[2] - c->collisionOffset[2]) * f; - } - c->smoothPos[0] = pos[0] + c->collisionOffset[0]; - c->smoothPos[1] = pos[1] + c->collisionOffset[1]; - c->smoothPos[2] = pos[2] + c->collisionOffset[2]; - ncDynamicCamera_setPosition(c->smoothPos); - - // Aim at the player; smooth only the target Y (X/Z follow directly for responsive horizontal aim). - if (!c->aimValid) { - c->aimCenterY = center[1]; - c->aimValid = 1; - } else { - c->aimCenterY += (center[1] - c->aimCenterY) * clampf(kAimHeightRate * dt, 0.0f, 1.0f); - } - float aimCenter[3] = { center[0], c->aimCenterY, center[2] }; - - float rot[3]; - func_802BC434(rot, aimCenter, c->smoothPos); - - // Damp the look-at instead of snapping to it, like the vanilla camera; filters residual aim wobble. - if (!c->rotValid) { - c->smoothRot[0] = rot[0]; - c->smoothRot[1] = rot[1]; - c->smoothRot[2] = rot[2]; - c->rotValid = 1; - } else { - float rf = clampf(kRotRate * dt, 0.0f, 1.0f); - c->smoothRot[0] = mlNormalizeAngle(c->smoothRot[0] + mlDiffDegF(rot[0], c->smoothRot[0]) * rf); - c->smoothRot[1] = mlNormalizeAngle(c->smoothRot[1] + mlDiffDegF(rot[1], c->smoothRot[1]) * rf); - c->smoothRot[2] = rot[2]; - } - ncDynamicCamera_setRotation(c->smoothRot); -} diff --git a/src/port/Enhancements/Camera/OrbitCameraCore.h b/src/port/Enhancements/Camera/OrbitCameraCore.h deleted file mode 100644 index 434dcd6c4..000000000 --- a/src/port/Enhancements/Camera/OrbitCameraCore.h +++ /dev/null @@ -1,52 +0,0 @@ -#ifndef PORT_ORBIT_CAMERA_CORE_H -#define PORT_ORBIT_CAMERA_CORE_H - -// Shared right-stick orbit camera core: capture the live camera, drive yaw (and optionally pitch) -// from the stick, track the vanilla zoom distance, resolve collision, smooth, and aim at the player. -// The modern-scheme yaw orbit and Free Look are the same machinery with different policy and tuning. - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct { - // Config (set by the owner) - int stateId; // dynamic camera state this orbit runs as - int allowPitch; // 1: stick Y drives pitch; 0: pitch locked flat, height tracks the vanilla target - float minPitch; // pitch clamp, degrees (only used when allowPitch) - float maxPitch; - float smoothRate; // position smoothing rate, 1/sec - - // Runtime state - int active; - int justEntered; - int smoothValid; - int aimValid; - float yaw; - float pitch; - float distance; // spherical radius; tracks the vanilla zoom-level target - float height; // absolute Y, only used when !allowPitch - float aimCenterY; // smoothed Y of the look-at target - float smoothPos[3]; - float collisionOffset[3]; // smoothed collision correction, kept separate from the follow motion - float smoothRot[3]; // damped look-at rotation - int rotValid; -} OrbitCamera; - -// Seed yaw/pitch/distance(/height) from the live camera so the orbit starts without a jump. -void OrbitCamera_Capture(OrbitCamera* c); - -// Capture and take ownership of the camera state. -void OrbitCamera_Enter(OrbitCamera* c); - -// Release the camera state back to the normal follow camera (state 0xB). -void OrbitCamera_Exit(OrbitCamera* c); - -// Advance one frame. -void OrbitCamera_Update(OrbitCamera* c, float yawDelta, float pitchDelta); - -#ifdef __cplusplus -} -#endif - -#endif // PORT_ORBIT_CAMERA_CORE_H From 22ecb73848f04b7ecbfe1f852047c6a47366bf0e Mon Sep 17 00:00:00 2001 From: Malkierian Date: Wed, 29 Jul 2026 10:25:58 -0700 Subject: [PATCH 036/131] Adds a built-in mapper to create or edit mapping strings for controllers the game doesn't recognize or are improperly mapped. (#278) --- port/textures/mapping-xbox.png | Bin 0 -> 79348 bytes src/port/Controller/Mapper.cpp | 1709 ++++++++++++++++++++++++++++++++ src/port/Controller/Mapper.h | 182 ++++ src/port/UI/LighthouseGui.cpp | 7 + 4 files changed, 1898 insertions(+) create mode 100644 port/textures/mapping-xbox.png create mode 100644 src/port/Controller/Mapper.cpp create mode 100644 src/port/Controller/Mapper.h diff --git a/port/textures/mapping-xbox.png b/port/textures/mapping-xbox.png new file mode 100644 index 0000000000000000000000000000000000000000..58db098481033eb933c8d4d8a5e43b06935963de GIT binary patch literal 79348 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 z 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 +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "src/port/Engine.h" +#include "src/port/UI/LighthouseGui.hpp" +#include "src/port/UI/LighthouseMenu.h" +#include "src/port/UI/UIWidgets.hpp" +#include "src/port/UI/cvar_prefixes.h" + +#include + +namespace LighthouseGui { +extern std::shared_ptr mLighthouseMenu; +} + +namespace Mapper { + +using namespace UIWidgets; + +static const char* kUserMappingsFileName = "usergamepadmappings.txt"; + +static const char* kDiagramTextureName = "Gamepad-Mapper-Diagram"; +static const char* kDiagramTexturePath = "textures/mapping-xbox.png"; + +// --------------------------------------------------------------------------------------------------- +// Binding metadata +// --------------------------------------------------------------------------------------------------- + +static const char* kButtonNames[SDL_CONTROLLER_BUTTON_MAX] = { + "A", + "B", + "X", + "Y", + "Back", + "Guide", + "Start", + "Left Stick Click", + "Right Stick Click", + "Left Bumper", + "Right Bumper", + "D-Pad Up", + "D-Pad Down", + "D-Pad Left", + "D-Pad Right", + "Misc 1", + "Paddle 1", + "Paddle 2", + "Paddle 3", + "Paddle 4", + "Touchpad", +}; + +static const char* kAxisNames[AXIS_BINDING_MAX] = { + "Left Stick Left", "Left Stick Right", "Left Stick Up", "Left Stick Down", "Right Stick Left", + "Right Stick Right", "Right Stick Up", "Right Stick Down", "Left Trigger", "Right Trigger", +}; + +const char* BindingName(int32_t binding) { + if (binding < 0 || binding >= BINDING_COUNT) { + return "?"; + } + if (binding < SDL_CONTROLLER_BUTTON_MAX) { + return kButtonNames[binding]; + } + return kAxisNames[binding - SDL_CONTROLLER_BUTTON_MAX]; +} + +struct StickAxisPair { + SDL_GameControllerAxis axis; + int32_t negative; + int32_t positive; +}; + +static const StickAxisPair kStickAxes[] = { + { SDL_CONTROLLER_AXIS_LEFTX, AXIS_LEFTX_NEGATIVE, AXIS_LEFTX_POSITIVE }, + { SDL_CONTROLLER_AXIS_LEFTY, AXIS_LEFTY_NEGATIVE, AXIS_LEFTY_POSITIVE }, + { SDL_CONTROLLER_AXIS_RIGHTX, AXIS_RIGHTX_NEGATIVE, AXIS_RIGHTX_POSITIVE }, + { SDL_CONTROLLER_AXIS_RIGHTY, AXIS_RIGHTY_NEGATIVE, AXIS_RIGHTY_POSITIVE }, +}; + +static const int32_t kCoreBindingOrder[] = { + SDL_CONTROLLER_BUTTON_A, + SDL_CONTROLLER_BUTTON_B, + SDL_CONTROLLER_BUTTON_X, + SDL_CONTROLLER_BUTTON_Y, + SDL_CONTROLLER_BUTTON_BACK, + SDL_CONTROLLER_BUTTON_START, + SDL_CONTROLLER_BUTTON_LEFTSHOULDER, + SDL_CONTROLLER_BUTTON_RIGHTSHOULDER, + SDL_CONTROLLER_BUTTON_LEFTSTICK, + SDL_CONTROLLER_BUTTON_RIGHTSTICK, + SDL_CONTROLLER_BUTTON_DPAD_UP, + SDL_CONTROLLER_BUTTON_DPAD_DOWN, + SDL_CONTROLLER_BUTTON_DPAD_LEFT, + SDL_CONTROLLER_BUTTON_DPAD_RIGHT, + SDL_CONTROLLER_BUTTON_MAX + AXIS_LEFTX_NEGATIVE, + SDL_CONTROLLER_BUTTON_MAX + AXIS_LEFTX_POSITIVE, + SDL_CONTROLLER_BUTTON_MAX + AXIS_LEFTY_NEGATIVE, + SDL_CONTROLLER_BUTTON_MAX + AXIS_LEFTY_POSITIVE, + SDL_CONTROLLER_BUTTON_MAX + AXIS_RIGHTX_NEGATIVE, + SDL_CONTROLLER_BUTTON_MAX + AXIS_RIGHTX_POSITIVE, + SDL_CONTROLLER_BUTTON_MAX + AXIS_RIGHTY_NEGATIVE, + SDL_CONTROLLER_BUTTON_MAX + AXIS_RIGHTY_POSITIVE, + SDL_CONTROLLER_BUTTON_MAX + AXIS_TRIGGERLEFT, + SDL_CONTROLLER_BUTTON_MAX + AXIS_TRIGGERRIGHT, +}; + +static const int32_t kExtraBindings[] = { + SDL_CONTROLLER_BUTTON_GUIDE, SDL_CONTROLLER_BUTTON_MISC1, SDL_CONTROLLER_BUTTON_PADDLE1, + SDL_CONTROLLER_BUTTON_PADDLE2, SDL_CONTROLLER_BUTTON_PADDLE3, SDL_CONTROLLER_BUTTON_PADDLE4, + SDL_CONTROLLER_BUTTON_TOUCHPAD, +}; + +// --------------------------------------------------------------------------------------------------- +// Binding helpers +// --------------------------------------------------------------------------------------------------- + +static ExtendedBind NoBind() { + ExtendedBind bind = {}; + bind.bindType = SDL_CONTROLLER_BINDTYPE_NONE; + return bind; +} + +void ClearBindings(ExtendedBind (&bindings)[BINDING_COUNT]) { + for (int32_t i = 0; i < BINDING_COUNT; i++) { + bindings[i] = NoBind(); + } +} + +bool HasAnyBinding(const ExtendedBind (&bindings)[BINDING_COUNT]) { + for (int32_t i = 0; i < BINDING_COUNT; i++) { + if (bindings[i].bindType != SDL_CONTROLLER_BINDTYPE_NONE) { + return true; + } + } + return false; +} + +static bool IsFullRangeAxis(const ExtendedBind& bind) { + if (bind.bindType != SDL_CONTROLLER_BINDTYPE_AXIS) { + return false; + } + return (bind.value.axis.axisMin == SDL_JOYSTICK_AXIS_MIN && bind.value.axis.axisMax == SDL_JOYSTICK_AXIS_MAX) || + (bind.value.axis.axisMin == SDL_JOYSTICK_AXIS_MAX && bind.value.axis.axisMax == SDL_JOYSTICK_AXIS_MIN); +} + +static bool MergeAxisBindings(ExtendedBind (&bindings)[BINDING_COUNT], int32_t negative, int32_t positive) { + ExtendedBind& a = bindings[negative]; + ExtendedBind& b = bindings[positive]; + if (a.bindType == SDL_CONTROLLER_BINDTYPE_AXIS && b.bindType == SDL_CONTROLLER_BINDTYPE_AXIS && + a.value.axis.axis == b.value.axis.axis && a.value.axis.axisMin == b.value.axis.axisMin) { + a.value.axis.axisMin = a.value.axis.axisMax; + a.value.axis.axisMax = b.value.axis.axisMax; + b = NoBind(); + return true; + } + return false; +} + +static std::string EncodeBindElement(const ExtendedBind& bind) { + switch (bind.bindType) { + case SDL_CONTROLLER_BINDTYPE_BUTTON: + return StringHelper::Sprintf("b%d", bind.value.button); + case SDL_CONTROLLER_BINDTYPE_AXIS: + if (bind.value.axis.axisMin == 0 && bind.value.axis.axisMax == SDL_JOYSTICK_AXIS_MIN) { + return StringHelper::Sprintf("-a%d", bind.value.axis.axis); + } + if (bind.value.axis.axisMin == 0 && bind.value.axis.axisMax == SDL_JOYSTICK_AXIS_MAX) { + return StringHelper::Sprintf("+a%d", bind.value.axis.axis); + } + return StringHelper::Sprintf("a%d%s", bind.value.axis.axis, + bind.value.axis.axisMin > bind.value.axis.axisMax ? "~" : ""); + case SDL_CONTROLLER_BINDTYPE_HAT: + return StringHelper::Sprintf("h%d.%d", bind.value.hat.hat, bind.value.hat.hatMask); + default: + return ""; + } +} + +static const char* HatMaskName(int32_t mask) { + switch (mask) { + case SDL_HAT_UP: + return "Up"; + case SDL_HAT_DOWN: + return "Down"; + case SDL_HAT_LEFT: + return "Left"; + case SDL_HAT_RIGHT: + return "Right"; + case SDL_HAT_LEFTUP: + return "Up-Left"; + case SDL_HAT_RIGHTUP: + return "Up-Right"; + case SDL_HAT_LEFTDOWN: + return "Down-Left"; + case SDL_HAT_RIGHTDOWN: + return "Down-Right"; + default: + return "?"; + } +} + +std::string DescribeBind(const ExtendedBind& bind) { + switch (bind.bindType) { + case SDL_CONTROLLER_BINDTYPE_BUTTON: + return StringHelper::Sprintf("Button %d", bind.value.button); + case SDL_CONTROLLER_BINDTYPE_AXIS: + if (IsFullRangeAxis(bind)) { + return StringHelper::Sprintf("Axis %d%s", bind.value.axis.axis, + bind.value.axis.axisMin > bind.value.axis.axisMax ? " inv" : ""); + } + return StringHelper::Sprintf("Axis %d %s", bind.value.axis.axis, + bind.value.axis.axisMax < bind.value.axis.axisMin ? "-" : "+"); + case SDL_CONTROLLER_BINDTYPE_HAT: + return StringHelper::Sprintf("Hat %d %s", bind.value.hat.hat, HatMaskName(bind.value.hat.hatMask)); + default: + return ""; + } +} + +// --------------------------------------------------------------------------------------------------- +// Mapping string generation / parsing +// --------------------------------------------------------------------------------------------------- + +static std::string SanitizeName(const std::string& name) { + std::string result = name; + std::replace(result.begin(), result.end(), ',', ' '); + return result; +} + +std::string GenerateMappingString(SDL_Joystick* joystick, const ExtendedBind (&bindings)[BINDING_COUNT], + const std::string& nameOverride) { + if (joystick == nullptr) { + return ""; + } + + SDL_JoystickGUID guid = SDL_JoystickGetGUID(joystick); + uint16_t crc = 0; +#if SDL_VERSION_ATLEAST(2, 26, 0) + SDL_GetJoystickGUIDInfo(guid, nullptr, nullptr, nullptr, &crc); + if (crc != 0) { + guid.data[2] = 0; + guid.data[3] = 0; + } +#endif + + char guidString[33] = ""; + SDL_JoystickGetGUIDString(guid, guidString, sizeof(guidString)); + + const char* rawName = SDL_JoystickName(joystick); + std::string name = SanitizeName(nameOverride); + if (name.find_first_not_of(' ') == std::string::npos) { + name = SanitizeName(rawName != nullptr ? rawName : guidString); + } + + std::string mapping = StringHelper::Sprintf("%s,%s,platform:%s,", guidString, name.c_str(), SDL_GetPlatform()); + if (crc != 0) { + mapping += StringHelper::Sprintf("crc:%.4x,", crc); + } + + ExtendedBind work[BINDING_COUNT]; + for (int32_t i = 0; i < BINDING_COUNT; i++) { + work[i] = bindings[i]; + } + + for (int32_t i = 0; i < SDL_CONTROLLER_BUTTON_MAX; i++) { + if (work[i].bindType == SDL_CONTROLLER_BINDTYPE_NONE) { + continue; + } + const char* name = SDL_GameControllerGetStringForButton((SDL_GameControllerButton)i); + if (name == nullptr) { + continue; + } + mapping += StringHelper::Sprintf("%s:%s,", name, EncodeBindElement(work[i]).c_str()); + } + + for (const auto& stick : kStickAxes) { + const int32_t negative = SDL_CONTROLLER_BUTTON_MAX + stick.negative; + const int32_t positive = SDL_CONTROLLER_BUTTON_MAX + stick.positive; + const char* name = SDL_GameControllerGetStringForAxis(stick.axis); + if (name == nullptr) { + continue; + } + + MergeAxisBindings(work, negative, positive); + + if (work[negative].bindType != SDL_CONTROLLER_BINDTYPE_NONE) { + const char* prefix = IsFullRangeAxis(work[negative]) ? "" : "-"; + mapping += StringHelper::Sprintf("%s%s:%s,", prefix, name, EncodeBindElement(work[negative]).c_str()); + } + if (work[positive].bindType != SDL_CONTROLLER_BINDTYPE_NONE) { + mapping += StringHelper::Sprintf("+%s:%s,", name, EncodeBindElement(work[positive]).c_str()); + } + } + + const std::pair triggers[] = { + { SDL_CONTROLLER_BUTTON_MAX + AXIS_TRIGGERLEFT, SDL_CONTROLLER_AXIS_TRIGGERLEFT }, + { SDL_CONTROLLER_BUTTON_MAX + AXIS_TRIGGERRIGHT, SDL_CONTROLLER_AXIS_TRIGGERRIGHT }, + }; + for (const auto& trigger : triggers) { + if (work[trigger.first].bindType == SDL_CONTROLLER_BINDTYPE_NONE) { + continue; + } + const char* name = SDL_GameControllerGetStringForAxis(trigger.second); + if (name == nullptr) { + continue; + } + mapping += StringHelper::Sprintf("%s:%s,", name, EncodeBindElement(work[trigger.first]).c_str()); + } + + return mapping; +} + +static int32_t BindingIndexForKey(const std::string& key) { + std::string name = key; + char sign = 0; + if (!name.empty() && (name.front() == '+' || name.front() == '-')) { + sign = name.front(); + name.erase(0, 1); + } + + const SDL_GameControllerAxis axis = SDL_GameControllerGetAxisFromString(name.c_str()); + if (axis != SDL_CONTROLLER_AXIS_INVALID) { + switch (axis) { + case SDL_CONTROLLER_AXIS_LEFTX: + return SDL_CONTROLLER_BUTTON_MAX + (sign == '+' ? AXIS_LEFTX_POSITIVE : AXIS_LEFTX_NEGATIVE); + case SDL_CONTROLLER_AXIS_LEFTY: + return SDL_CONTROLLER_BUTTON_MAX + (sign == '+' ? AXIS_LEFTY_POSITIVE : AXIS_LEFTY_NEGATIVE); + case SDL_CONTROLLER_AXIS_RIGHTX: + return SDL_CONTROLLER_BUTTON_MAX + (sign == '+' ? AXIS_RIGHTX_POSITIVE : AXIS_RIGHTX_NEGATIVE); + case SDL_CONTROLLER_AXIS_RIGHTY: + return SDL_CONTROLLER_BUTTON_MAX + (sign == '+' ? AXIS_RIGHTY_POSITIVE : AXIS_RIGHTY_NEGATIVE); + case SDL_CONTROLLER_AXIS_TRIGGERLEFT: + return SDL_CONTROLLER_BUTTON_MAX + AXIS_TRIGGERLEFT; + case SDL_CONTROLLER_AXIS_TRIGGERRIGHT: + return SDL_CONTROLLER_BUTTON_MAX + AXIS_TRIGGERRIGHT; + default: + return -1; + } + } + + if (sign != 0) { + return -1; + } + const SDL_GameControllerButton button = SDL_GameControllerGetButtonFromString(name.c_str()); + return button != SDL_CONTROLLER_BUTTON_INVALID ? (int32_t)button : -1; +} + +static bool DecodeBindElement(const std::string& value, ExtendedBind& out) { + std::string element = value; + bool inverted = false; + if (!element.empty() && element.back() == '~') { + inverted = true; + element.pop_back(); + } + + char sign = 0; + if (!element.empty() && (element.front() == '+' || element.front() == '-')) { + sign = element.front(); + element.erase(0, 1); + } + if (element.size() < 2) { + return false; + } + + out = {}; + out.committed = true; + + switch (element.front()) { + case 'b': + out.bindType = SDL_CONTROLLER_BINDTYPE_BUTTON; + out.value.button = std::atoi(element.c_str() + 1); + return true; + case 'a': + out.bindType = SDL_CONTROLLER_BINDTYPE_AXIS; + out.value.axis.axis = std::atoi(element.c_str() + 1); + if (sign == '-') { + out.value.axis.axisMin = 0; + out.value.axis.axisMax = SDL_JOYSTICK_AXIS_MIN; + } else if (sign == '+') { + out.value.axis.axisMin = 0; + out.value.axis.axisMax = SDL_JOYSTICK_AXIS_MAX; + } else { + out.value.axis.axisMin = inverted ? SDL_JOYSTICK_AXIS_MAX : SDL_JOYSTICK_AXIS_MIN; + out.value.axis.axisMax = inverted ? SDL_JOYSTICK_AXIS_MIN : SDL_JOYSTICK_AXIS_MAX; + } + return true; + case 'h': { + int32_t hat = 0; + int32_t mask = 0; + if (std::sscanf(element.c_str() + 1, "%d.%d", &hat, &mask) != 2) { + return false; + } + out.bindType = SDL_CONTROLLER_BINDTYPE_HAT; + out.value.hat.hat = hat; + out.value.hat.hatMask = mask; + return true; + } + default: + out = NoBind(); + return false; + } +} + +int32_t ParseMappingString(const std::string& mapping, ExtendedBind (&bindings)[BINDING_COUNT]) { + ClearBindings(bindings); + + int32_t recovered = 0; + size_t start = 0; + while (start <= mapping.size()) { + const size_t end = mapping.find(',', start); + const std::string field = mapping.substr(start, end == std::string::npos ? std::string::npos : end - start); + start = end == std::string::npos ? mapping.size() + 1 : end + 1; + + const size_t colon = field.find(':'); + if (colon == std::string::npos) { + continue; + } + + const int32_t index = BindingIndexForKey(field.substr(0, colon)); + if (index < 0) { + continue; + } + if (DecodeBindElement(field.substr(colon + 1), bindings[index])) { + recovered++; + } + } + + for (const auto& stick : kStickAxes) { + const int32_t negative = SDL_CONTROLLER_BUTTON_MAX + stick.negative; + const int32_t positive = SDL_CONTROLLER_BUTTON_MAX + stick.positive; + if (!IsFullRangeAxis(bindings[negative]) || bindings[positive].bindType != SDL_CONTROLLER_BINDTYPE_NONE) { + continue; + } + + const bool axisInverted = bindings[negative].value.axis.axisMin > bindings[negative].value.axis.axisMax; + bindings[positive] = bindings[negative]; + bindings[negative].value.axis.axisMin = 0; + bindings[negative].value.axis.axisMax = axisInverted ? SDL_JOYSTICK_AXIS_MAX : SDL_JOYSTICK_AXIS_MIN; + bindings[positive].value.axis.axisMin = 0; + bindings[positive].value.axis.axisMax = axisInverted ? SDL_JOYSTICK_AXIS_MIN : SDL_JOYSTICK_AXIS_MAX; + } + + return recovered; +} + +// --------------------------------------------------------------------------------------------------- +// MappingSession +// --------------------------------------------------------------------------------------------------- + +MappingSession::MappingSession() + : mBindings{}, mCurrentStep(0), mPendingAdvanceTime(0), mActive(false), mComplete(false) { + ClearBindings(mBindings); +} + +void MappingSession::Start(SDL_Joystick* joystick, const std::vector& order) { + mOrder = order; + mCurrentStep = 0; + mComplete = mOrder.empty(); + mActive = !mOrder.empty(); + mPendingAdvanceTime = 0; + + const int32_t axisCount = joystick != nullptr ? SDL_JoystickNumAxes(joystick) : 0; + mAxisState.assign(axisCount > 0 ? (size_t)axisCount : 0, AxisState{}); + for (int32_t i = 0; i < axisCount; i++) { + Sint16 initialValue = 0; + mAxisState[i].moving = SDL_JoystickGetAxisInitialState(joystick, i, &initialValue) == SDL_TRUE; + mAxisState[i].lastValue = initialValue; + mAxisState[i].startingValue = initialValue; + mAxisState[i].farthestValue = initialValue; + } + + if (mActive) { + mBindings[mOrder[0]] = NoBind(); + } +} + +void MappingSession::Stop() { + mActive = false; + mComplete = false; + mOrder.clear(); + mAxisState.clear(); + mPendingAdvanceTime = 0; +} + +bool MappingSession::IsActive() const { + return mActive; +} + +bool MappingSession::IsComplete() const { + return mComplete; +} + +int32_t MappingSession::CurrentStep() const { + return mCurrentStep; +} + +int32_t MappingSession::StepCount() const { + return (int32_t)mOrder.size(); +} + +int32_t MappingSession::CurrentBinding() const { + if (mCurrentStep < 0 || mCurrentStep >= (int32_t)mOrder.size()) { + return -1; + } + return mOrder[mCurrentStep]; +} + +void MappingSession::GoToStep(int32_t step) { + if (step < 0) { + return; + } + if (step >= (int32_t)mOrder.size()) { + mComplete = true; + mActive = false; + return; + } + + mCurrentStep = step; + + mBindings[mOrder[mCurrentStep]] = NoBind(); + for (auto& state : mAxisState) { + state.farthestValue = state.startingValue; + } + mPendingAdvanceTime = 0; +} + +void MappingSession::Advance() { + GoToStep(mCurrentStep + 1); +} + +void MappingSession::GoBack() { + GoToStep(mCurrentStep - 1); +} + +const ExtendedBind& MappingSession::GetBinding(int32_t index) const { + return mBindings[index]; +} + +void MappingSession::SetBindings(const ExtendedBind (&bindings)[BINDING_COUNT]) { + for (int32_t i = 0; i < BINDING_COUNT; i++) { + mBindings[i] = bindings[i]; + } +} + +void MappingSession::CopyBindingsTo(ExtendedBind (&out)[BINDING_COUNT]) const { + for (int32_t i = 0; i < BINDING_COUNT; i++) { + out[i] = mBindings[i]; + } +} + +bool MappingSession::BindingContainsBinding(const ExtendedBind& a, const ExtendedBind& b) const { + if (a.bindType != b.bindType) { + return false; + } + + if (a.bindType == SDL_CONTROLLER_BINDTYPE_AXIS) { + if (a.value.axis.axis != b.value.axis.axis || !a.committed) { + return false; + } + const int32_t minA = std::min(a.value.axis.axisMin, a.value.axis.axisMax); + const int32_t maxA = std::max(a.value.axis.axisMin, a.value.axis.axisMax); + const int32_t minB = std::min(b.value.axis.axisMin, b.value.axis.axisMax); + const int32_t maxB = std::max(b.value.axis.axisMin, b.value.axis.axisMax); + return minA <= minB && maxA >= maxB; + } + + return std::memcmp(&a, &b, sizeof(a)) == 0; +} + +void MappingSession::ConfigureBinding(const ExtendedBind& binding) { + const int32_t currentElement = CurrentBinding(); + if (currentElement < 0) { + return; + } + + for (int32_t i = 0; i < BINDING_COUNT; i++) { + if (BindingContainsBinding(mBindings[i], binding)) { + return; + } + } + + ExtendedBind& current = mBindings[currentElement]; + if (current.bindType != SDL_CONTROLLER_BINDTYPE_NONE) { + const bool nativeDPad = + currentElement == SDL_CONTROLLER_BUTTON_DPAD_UP || currentElement == SDL_CONTROLLER_BUTTON_DPAD_DOWN || + currentElement == SDL_CONTROLLER_BUTTON_DPAD_LEFT || currentElement == SDL_CONTROLLER_BUTTON_DPAD_RIGHT; + if (nativeDPad && current.bindType == SDL_CONTROLLER_BINDTYPE_HAT) { + return; + } + + const bool nativeAxis = currentElement >= SDL_CONTROLLER_BUTTON_MAX; + const bool currentIsAxis = current.bindType == SDL_CONTROLLER_BINDTYPE_AXIS; + if (nativeAxis == currentIsAxis && + (binding.bindType != SDL_CONTROLLER_BINDTYPE_AXIS || binding.value.axis.axis != current.value.axis.axis)) { + return; + } + } + + current = binding; + mPendingAdvanceTime = binding.committed ? SDL_GetTicks() : 0; +} + +void MappingSession::ProcessButtonDown(int32_t button) { + if (!mActive) { + return; + } + ExtendedBind binding = {}; + binding.bindType = SDL_CONTROLLER_BINDTYPE_BUTTON; + binding.value.button = button; + binding.committed = true; + ConfigureBinding(binding); +} + +void MappingSession::ProcessHatMotion(int32_t hat, int32_t value) { + if (!mActive || value == SDL_HAT_CENTERED) { + return; + } + ExtendedBind binding = {}; + binding.bindType = SDL_CONTROLLER_BINDTYPE_HAT; + binding.value.hat.hat = hat; + binding.value.hat.hatMask = value; + binding.committed = true; + ConfigureBinding(binding); +} + +static int32_t StandardizeAxisValue(int32_t value) { + if (value > SDL_JOYSTICK_AXIS_MAX / 2) { + return SDL_JOYSTICK_AXIS_MAX; + } + if (value < SDL_JOYSTICK_AXIS_MIN / 2) { + return SDL_JOYSTICK_AXIS_MIN; + } + return 0; +} + +void MappingSession::ProcessAxisMotion(int32_t axis, int32_t value, SDL_Joystick* joystick) { + if (!mActive || axis < 0 || axis >= (int32_t)mAxisState.size()) { + return; + } + + constexpr int32_t MAX_ALLOWED_JITTER = SDL_JOYSTICK_AXIS_MAX / 80; + AxisState& state = mAxisState[axis]; + + if (!state.moving) { + Sint16 initialValue = 0; + state.moving = SDL_JoystickGetAxisInitialState(joystick, axis, &initialValue) == SDL_TRUE; + state.lastValue = value; + state.startingValue = initialValue; + state.farthestValue = initialValue; + } else if (std::abs(value - state.lastValue) <= MAX_ALLOWED_JITTER) { + return; + } else { + state.lastValue = value; + } + + const int32_t currentDistance = std::abs(value - state.startingValue); + int32_t farthestDistance = std::abs(state.farthestValue - state.startingValue); + if (currentDistance > farthestDistance) { + state.farthestValue = value; + farthestDistance = std::abs(state.farthestValue - state.startingValue); + } + + if (farthestDistance < AXIS_COMMIT_DISTANCE) { + return; + } + + ExtendedBind binding = {}; + binding.bindType = SDL_CONTROLLER_BINDTYPE_AXIS; + binding.value.axis.axis = axis; + binding.value.axis.axisMin = StandardizeAxisValue(state.startingValue); + binding.value.axis.axisMax = StandardizeAxisValue(state.farthestValue); + binding.committed = currentDistance <= AXIS_RETURN_DISTANCE; + ConfigureBinding(binding); +} + +void MappingSession::CheckPendingAdvance() { + if (!mActive || mPendingAdvanceTime == 0) { + return; + } + if (SDL_GetTicks() - mPendingAdvanceTime >= PENDING_ADVANCE_DELAY_MS) { + Advance(); + } +} + +// --------------------------------------------------------------------------------------------------- +// usergamepadmappings.txt +// --------------------------------------------------------------------------------------------------- + +std::string GetUserMappingsPath() { + return Ship::Context::GetPathRelativeToAppDirectory(kUserMappingsFileName); +} + +static std::string StripCrcFromGuid(const std::string& guid) { + if (guid.length() < 32) { + return guid; + } + return guid.substr(0, 4) + "0000" + guid.substr(8); +} + +static std::string MappingKey(const std::string& mapping) { + const size_t comma = mapping.find(','); + if (comma == std::string::npos || comma == 0) { + return ""; + } + std::string key = StripCrcFromGuid(mapping.substr(0, comma)); + + const size_t crcPos = mapping.find(",crc:"); + if (crcPos != std::string::npos) { + const size_t valueStart = crcPos + 1; + size_t valueEnd = mapping.find(',', valueStart); + if (valueEnd == std::string::npos) { + valueEnd = mapping.length(); + } + key += "," + mapping.substr(valueStart, valueEnd - valueStart); + } + return key; +} + +static bool IsMappingLine(const std::string& line) { + return !line.empty() && line.front() != '#'; +} + +static std::vector ReadUserMappingLines() { + std::vector lines; + std::ifstream file(GetUserMappingsPath()); + if (!file.is_open()) { + return lines; + } + + std::string line; + while (std::getline(file, line)) { + if (!line.empty() && line.back() == '\r') { + line.pop_back(); + } + lines.push_back(line); + } + return lines; +} + +static bool WriteUserMappingLines(const std::vector& lines) { + const std::string path = GetUserMappingsPath(); + const std::string tempPath = path + ".tmp"; + + { + std::ofstream file(tempPath, std::ios::binary | std::ios::trunc); + if (!file.is_open()) { + SPDLOG_ERROR("Failed to open \"{}\" for writing", tempPath); + return false; + } + file << "# SoH user gamepad mappings, written by the built-in gamepad mapper.\n"; + file << "# Loaded on top of gamecontrollerdb.txt, so entries here win.\n"; + for (const auto& line : lines) { + file << line << "\n"; + } + if (!file.good()) { + SPDLOG_ERROR("Failed while writing \"{}\"", tempPath); + return false; + } + } + + std::error_code error; + std::filesystem::rename(tempPath, path, error); + if (error) { + SPDLOG_ERROR("Failed to move \"{}\" into place: {}", tempPath, error.message()); + std::filesystem::remove(tempPath, error); + return false; + } + return true; +} + +std::string FindUserMapping(const std::string& guid) { + const std::string base = StripCrcFromGuid(guid); + for (const auto& line : ReadUserMappingLines()) { + if (!IsMappingLine(line)) { + continue; + } + const size_t comma = line.find(','); + if (comma != std::string::npos && StripCrcFromGuid(line.substr(0, comma)) == base) { + return line; + } + } + return ""; +} + +std::string MappingName(const std::string& mapping) { + const size_t first = mapping.find(','); + if (first == std::string::npos) { + return ""; + } + const size_t second = mapping.find(',', first + 1); + return mapping.substr(first + 1, second == std::string::npos ? std::string::npos : second - first - 1); +} + +bool LoadUserMappings() { + const std::string path = GetUserMappingsPath(); + + std::error_code error; + if (!std::filesystem::exists(path, error)) { + return false; + } + + const int32_t added = SDL_GameControllerAddMappingsFromFile(path.c_str()); + if (added < 0) { + SPDLOG_ERROR("Failed to add user gamepad mappings from \"{}\": {}", path, SDL_GetError()); + return false; + } + + SPDLOG_INFO("Added {} user gamepad mapping(s) from \"{}\"", added, path); + Ship::Context::GetRawInstance() + ->GetControlDeck() + ->GetConnectedPhysicalDeviceManager() + ->RefreshConnectedSDLGamepads(); + return true; +} + +bool SaveUserMapping(const std::string& mapping) { + const std::string key = MappingKey(mapping); + if (key.empty()) { + SPDLOG_ERROR("Refusing to save a gamepad mapping with no GUID"); + return false; + } + + std::vector lines; + for (const auto& line : ReadUserMappingLines()) { + if (!IsMappingLine(line)) { + continue; + } + if (MappingKey(line) == key) { + continue; + } + lines.push_back(line); + } + lines.push_back(mapping); + + if (!WriteUserMappingLines(lines)) { + return false; + } + + if (SDL_GameControllerAddMapping(mapping.c_str()) < 0) { + SPDLOG_ERROR("SDL rejected the generated mapping \"{}\": {}", mapping, SDL_GetError()); + return false; + } + + Ship::Context::GetRawInstance() + ->GetControlDeck() + ->GetConnectedPhysicalDeviceManager() + ->RefreshConnectedSDLGamepads(); + return true; +} + +bool DeleteUserMapping(const std::string& guid) { + const std::string base = StripCrcFromGuid(guid); + + std::vector lines; + bool found = false; + for (const auto& line : ReadUserMappingLines()) { + if (!IsMappingLine(line)) { + continue; + } + const size_t comma = line.find(','); + if (comma != std::string::npos && StripCrcFromGuid(line.substr(0, comma)) == base) { + found = true; + continue; + } + lines.push_back(line); + } + + if (!found) { + return false; + } + if (!WriteUserMappingLines(lines)) { + return false; + } + + Ship::Context::GetRawInstance() + ->GetControlDeck() + ->GetConnectedPhysicalDeviceManager() + ->RefreshConnectedSDLGamepads(); + return true; +} + +// --------------------------------------------------------------------------------------------------- +// Diagram layout +// --------------------------------------------------------------------------------------------------- + +struct DiagramEntry { + int32_t binding; + ImVec2 hotspot; + bool labelOnRight; +}; + +static constexpr float MAX_IMAGE_SPAN = 0.52f; +static constexpr float MIN_IMAGE_WIDTH = 360.0f; +static constexpr float FALLBACK_ART_ASPECT = 1850.0f / 1302.0f; +static constexpr ImU32 NAME_COLOR = IM_COL32(138, 144, 156, 255); + +static const DiagramEntry kDiagram[] = { + { SDL_CONTROLLER_BUTTON_MAX + AXIS_TRIGGERLEFT, ImVec2(0.081f, 0.110f), false }, + { SDL_CONTROLLER_BUTTON_LEFTSHOULDER, ImVec2(0.234f, 0.092f), false }, + { SDL_CONTROLLER_BUTTON_BACK, ImVec2(0.426f, 0.408f), false }, + { SDL_CONTROLLER_BUTTON_MAX + AXIS_LEFTY_NEGATIVE, ImVec2(0.241f, 0.315f), false }, + { SDL_CONTROLLER_BUTTON_MAX + AXIS_LEFTX_NEGATIVE, ImVec2(0.185f, 0.401f), false }, + { SDL_CONTROLLER_BUTTON_MAX + AXIS_LEFTX_POSITIVE, ImVec2(0.297f, 0.401f), false }, + { SDL_CONTROLLER_BUTTON_MAX + AXIS_LEFTY_POSITIVE, ImVec2(0.241f, 0.487f), false }, + { SDL_CONTROLLER_BUTTON_LEFTSTICK, ImVec2(0.241f, 0.401f), false }, + { SDL_CONTROLLER_BUTTON_DPAD_UP, ImVec2(0.368f, 0.540f), false }, + { SDL_CONTROLLER_BUTTON_DPAD_LEFT, ImVec2(0.310f, 0.614f), false }, + { SDL_CONTROLLER_BUTTON_DPAD_RIGHT, ImVec2(0.416f, 0.614f), false }, + { SDL_CONTROLLER_BUTTON_DPAD_DOWN, ImVec2(0.368f, 0.690f), false }, + + { SDL_CONTROLLER_BUTTON_MAX + AXIS_TRIGGERRIGHT, ImVec2(0.919f, 0.110f), true }, + { SDL_CONTROLLER_BUTTON_RIGHTSHOULDER, ImVec2(0.766f, 0.092f), true }, + { SDL_CONTROLLER_BUTTON_START, ImVec2(0.570f, 0.408f), true }, + { SDL_CONTROLLER_BUTTON_Y, ImVec2(0.752f, 0.328f), true }, + { SDL_CONTROLLER_BUTTON_X, ImVec2(0.689f, 0.412f), true }, + { SDL_CONTROLLER_BUTTON_B, ImVec2(0.816f, 0.412f), true }, + { SDL_CONTROLLER_BUTTON_A, ImVec2(0.752f, 0.497f), true }, + { SDL_CONTROLLER_BUTTON_MAX + AXIS_RIGHTY_NEGATIVE, ImVec2(0.628f, 0.518f), true }, + { SDL_CONTROLLER_BUTTON_MAX + AXIS_RIGHTX_NEGATIVE, ImVec2(0.570f, 0.595f), true }, + { SDL_CONTROLLER_BUTTON_MAX + AXIS_RIGHTX_POSITIVE, ImVec2(0.686f, 0.595f), true }, + { SDL_CONTROLLER_BUTTON_MAX + AXIS_RIGHTY_POSITIVE, ImVec2(0.628f, 0.682f), true }, + { SDL_CONTROLLER_BUTTON_RIGHTSTICK, ImVec2(0.628f, 0.595f), true }, +}; + +// --------------------------------------------------------------------------------------------------- +// MapperWindow +// --------------------------------------------------------------------------------------------------- + +#define MAPPER_WINDOW_GAME_INPUT_BLOCK_ID 95237930 + +static constexpr uint32_t DEVICE_SCAN_INTERVAL_MS = 500; +static constexpr uint32_t FILE_WATCH_INTERVAL_MS = 1000; + +MapperWindow::~MapperWindow() { + CloseJoystick(); +} + +void MapperWindow::InitElement() { + ClearBindings(mBindings); +} + +// Records the joystick's current digital state as the baseline for edge detection, so a button already +// held when a prompt appears has to be released and pressed again to count. +void MapperWindow::SnapshotDeviceState() { + mPreviousButtons.clear(); + mPreviousHats.clear(); + if (mJoystick == nullptr) { + return; + } + + SDL_JoystickUpdate(); + for (int32_t i = 0; i < SDL_JoystickNumButtons(mJoystick); i++) { + mPreviousButtons.push_back(SDL_JoystickGetButton(mJoystick, i)); + } + for (int32_t i = 0; i < SDL_JoystickNumHats(mJoystick); i++) { + mPreviousHats.push_back(SDL_JoystickGetHat(mJoystick, i)); + } +} + +void MapperWindow::PollDeviceForSession() { + if (mJoystick == nullptr) { + return; + } + + if (SDL_JoystickGetAttached(mJoystick) == SDL_FALSE) { + EndSession(false); + mStatusMessage = "Device disconnected during mapping."; + return; + } + + SDL_JoystickUpdate(); + + const int32_t buttonCount = SDL_JoystickNumButtons(mJoystick); + mPreviousButtons.resize((size_t)std::max(buttonCount, 0), 0); + for (int32_t i = 0; i < buttonCount; i++) { + const uint8_t state = SDL_JoystickGetButton(mJoystick, i); + if (state != 0 && mPreviousButtons[i] == 0) { + mSession.ProcessButtonDown(i); + } + mPreviousButtons[i] = state; + } + + const int32_t hatCount = SDL_JoystickNumHats(mJoystick); + mPreviousHats.resize((size_t)std::max(hatCount, 0), SDL_HAT_CENTERED); + for (int32_t i = 0; i < hatCount; i++) { + const uint8_t state = SDL_JoystickGetHat(mJoystick, i); + if (state != mPreviousHats[i] && state != SDL_HAT_CENTERED) { + mSession.ProcessHatMotion(i, state); + } + mPreviousHats[i] = state; + } + + for (int32_t i = 0; i < SDL_JoystickNumAxes(mJoystick); i++) { + mSession.ProcessAxisMotion(i, SDL_JoystickGetAxis(mJoystick, i), mJoystick); + } +} + +void MapperWindow::CloseJoystick() { + if (mJoystick != nullptr) { + SDL_JoystickClose(mJoystick); + mJoystick = nullptr; + } + mPreviousButtons.clear(); + mPreviousHats.clear(); +} + +void MapperWindow::RefreshDeviceList() { + const SDL_JoystickID previousInstanceId = + mSelectedDevice >= 0 && mSelectedDevice < (int32_t)mDevices.size() ? mDevices[mSelectedDevice].instanceId : -1; + + mDevices.clear(); + + const std::vector userLines = ReadUserMappingLines(); + + for (int32_t i = 0; i < SDL_NumJoysticks(); i++) { + char guidString[33] = ""; + SDL_JoystickGetGUIDString(SDL_JoystickGetDeviceGUID(i), guidString, sizeof(guidString)); + + DeviceInfo info = {}; + info.deviceIndex = i; + info.instanceId = SDL_JoystickGetDeviceInstanceID(i); + const char* name = SDL_JoystickNameForIndex(i); + info.name = name != nullptr ? name : guidString; + info.guid = guidString; + info.hasMapping = SDL_IsGameController(i) == SDL_TRUE; + info.hasUserMapping = false; + + const std::string base = StripCrcFromGuid(info.guid); + for (const auto& line : userLines) { + if (!IsMappingLine(line)) { + continue; + } + const size_t comma = line.find(','); + if (comma != std::string::npos && StripCrcFromGuid(line.substr(0, comma)) == base) { + info.hasUserMapping = true; + break; + } + } + + mDevices.push_back(info); + } + + for (int32_t i = 0; i < (int32_t)mDevices.size(); i++) { + if (mDevices[i].instanceId == previousInstanceId) { + mSelectedDevice = i; + return; + } + } + + SelectDevice(mDevices.empty() ? -1 : 0); +} + +void MapperWindow::SelectDevice(int32_t listIndex) { + if (mSession.IsActive()) { + EndSession(false); + } + + CloseJoystick(); + ClearBindings(mBindings); + mDirty = false; + mStatusMessage.clear(); + mSelectedDevice = listIndex; + + if (listIndex < 0 || listIndex >= (int32_t)mDevices.size()) { + return; + } + + mJoystick = SDL_JoystickOpen(mDevices[listIndex].deviceIndex); + if (mJoystick == nullptr) { + mStatusMessage = StringHelper::Sprintf("Could not open device: %s", SDL_GetError()); + return; + } + + LoadBindingsForDevice(); +} + +void MapperWindow::LoadBindingsForDevice() { + ClearBindings(mBindings); + mCustomName.clear(); + if (mJoystick == nullptr) { + return; + } + + char guidString[33] = ""; + SDL_JoystickGetGUIDString(SDL_JoystickGetGUID(mJoystick), guidString, sizeof(guidString)); + + const std::string userMapping = FindUserMapping(guidString); + if (!userMapping.empty()) { + ParseMappingString(userMapping, mBindings); + mCustomName = MappingName(userMapping); + return; + } + + const char* joystickName = SDL_JoystickName(mJoystick); + mCustomName = joystickName != nullptr ? joystickName : ""; + + char* existing = SDL_GameControllerMappingForGUID(SDL_JoystickGetGUID(mJoystick)); + if (existing == nullptr) { + return; + } + ParseMappingString(existing, mBindings); + SDL_free(existing); +} + +void MapperWindow::StartSession(const std::vector& order) { + if (mJoystick == nullptr || order.empty()) { + return; + } + + mStatusMessage.clear(); + mSession.SetBindings(mBindings); + mSession.Start(mJoystick, order); + SnapshotDeviceState(); + + Ship::Context::GetRawInstance()->GetControlDeck()->BlockGameInput(MAPPER_WINDOW_GAME_INPUT_BLOCK_ID); + Ship::Context::GetRawInstance()->GetWindow()->GetGui()->BlockGamepadNavigation(); +} + +void MapperWindow::EndSession(bool applyResult) { + if (applyResult) { + mSession.CopyBindingsTo(mBindings); + mDirty = true; + } + mSession.Stop(); + mPreviousButtons.clear(); + mPreviousHats.clear(); + + mGameInputBlockTimer = 20; + Ship::Context::GetRawInstance()->GetWindow()->GetGui()->UnblockGamepadNavigation(); +} + +void MapperWindow::UpdateElement() { + const uint32_t now = SDL_GetTicks(); + + if (now - mLastUserFileCheckTicks >= FILE_WATCH_INTERVAL_MS || mLastUserFileCheckTicks == 0) { + mLastUserFileCheckTicks = now; + + std::error_code error; + const std::filesystem::path path = GetUserMappingsPath(); + if (std::filesystem::exists(path, error)) { + const auto writeTime = std::filesystem::last_write_time(path, error); + const uint64_t stamp = (uint64_t)writeTime.time_since_epoch().count(); + if (!error && stamp != mLastUserFileWriteTime) { + const bool firstLoad = mLastUserFileWriteTime == 0; + mLastUserFileWriteTime = stamp; + LoadUserMappings(); + if (!firstLoad && !mSession.IsActive() && !mDirty) { + LoadBindingsForDevice(); + } + } + } else { + mLastUserFileWriteTime = 0; + } + } + + if (mGameInputBlockTimer != INT32_MAX && !mSession.IsActive()) { + mGameInputBlockTimer--; + if (mGameInputBlockTimer <= 0) { + Ship::Context::GetRawInstance()->GetControlDeck()->UnblockGameInput(MAPPER_WINDOW_GAME_INPUT_BLOCK_ID); + mGameInputBlockTimer = INT32_MAX; + } + } + + if (!IsVisible()) { + if (mSession.IsActive()) { + EndSession(false); + } + if (mJoystick != nullptr) { + CloseJoystick(); + mSelectedDevice = -1; + mDevices.clear(); + } + return; + } + + if (!mSession.IsActive() && (mDevices.empty() || now - mLastDeviceScanTicks >= DEVICE_SCAN_INTERVAL_MS)) { + mLastDeviceScanTicks = now; + RefreshDeviceList(); + } + + if (mSession.IsActive()) { + Ship::Context::GetRawInstance()->GetControlDeck()->BlockGameInput(MAPPER_WINDOW_GAME_INPUT_BLOCK_ID); + Ship::Context::GetRawInstance()->GetWindow()->GetGui()->BlockGamepadNavigation(); + + PollDeviceForSession(); + mSession.CheckPendingAdvance(); + + if (mSession.IsComplete()) { + EndSession(true); + mStatusMessage = "Mapping captured. Check the diagram, then Save Mapping."; + } + } +} + +bool MapperWindow::IsBindingLive(int32_t binding) const { + if (mJoystick == nullptr || binding < 0 || binding >= BINDING_COUNT) { + return false; + } + + const ExtendedBind& bind = mSession.IsActive() ? mSession.GetBinding(binding) : mBindings[binding]; + + switch (bind.bindType) { + case SDL_CONTROLLER_BINDTYPE_BUTTON: + return SDL_JoystickGetButton(mJoystick, bind.value.button) != 0; + case SDL_CONTROLLER_BINDTYPE_AXIS: { + const int32_t value = SDL_JoystickGetAxis(mJoystick, bind.value.axis.axis); + if (IsFullRangeAxis(bind)) { + Sint16 rest = 0; + SDL_JoystickGetAxisInitialState(mJoystick, bind.value.axis.axis, &rest); + return std::abs(value - rest) > SDL_JOYSTICK_AXIS_MAX / 2; + } + // A half-axis counts as active once the reading is most of the way toward axisMax. + const int32_t threshold = bind.value.axis.axisMax / 2; + return bind.value.axis.axisMax < 0 ? value <= threshold : value >= threshold; + } + case SDL_CONTROLLER_BINDTYPE_HAT: + return (SDL_JoystickGetHat(mJoystick, bind.value.hat.hat) & bind.value.hat.hatMask) == + bind.value.hat.hatMask; + default: + return false; + } +} + +// --------------------------------------------------------------------------------------------------- +// Drawing +// --------------------------------------------------------------------------------------------------- + +void MapperWindow::DrawDeviceSelector() { + ImGui::AlignTextToFramePadding(); + ImGui::Text("Device"); + ImGui::SameLine(); + + std::string preview = "No joysticks detected"; + if (mSelectedDevice >= 0 && mSelectedDevice < (int32_t)mDevices.size()) { + preview = mDevices[mSelectedDevice].name; + } + + ImGui::BeginDisabled(mSession.IsActive() || mDevices.empty()); + PushStyleCombobox(THEME_COLOR); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x * 0.6f); + if (ImGui::BeginCombo("##mapperDevice", preview.c_str())) { + for (int32_t i = 0; i < (int32_t)mDevices.size(); i++) { + const DeviceInfo& device = mDevices[i]; + const char* status = device.hasUserMapping ? " [user mapping]" : (device.hasMapping ? "" : " [unmapped]"); + if (ImGui::Selectable(StringHelper::Sprintf("%s%s##dev%d", device.name.c_str(), status, i).c_str(), + i == mSelectedDevice)) { + SelectDevice(i); + } + } + ImGui::EndCombo(); + } + PopStyleCombobox(); + ImGui::EndDisabled(); + + if (mSelectedDevice < 0 || mSelectedDevice >= (int32_t)mDevices.size()) { + ImGui::TextDisabled("Connect a gamepad to get started."); + return; + } + + const DeviceInfo& device = mDevices[mSelectedDevice]; + ImGui::TextDisabled("GUID %s", device.guid.c_str()); + if (mJoystick != nullptr) { + ImGui::SameLine(); + ImGui::TextDisabled("| %d buttons, %d axes, %d hats", SDL_JoystickNumButtons(mJoystick), + SDL_JoystickNumAxes(mJoystick), SDL_JoystickNumHats(mJoystick)); + } + + if (!device.hasMapping) { + ImGui::TextColored(ImVec4(1.0f, 0.75f, 0.2f, 1.0f), + "This device has no SDL mapping, so the game cannot see it yet. Map it below."); + } else if (device.hasUserMapping) { + ImGui::TextColored(ImVec4(0.4f, 0.85f, 0.4f, 1.0f), "Using a mapping from %s.", kUserMappingsFileName); + } +} + +void MapperWindow::DrawDiagram() { + auto gui = std::dynamic_pointer_cast(Ship::Context::GetRawInstance()->GetWindow()->GetGui()); + const bool haveArt = gui != nullptr && gui->HasTextureByName(kDiagramTextureName); + + float artAspect = FALLBACK_ART_ASPECT; + if (haveArt) { + const ImVec2 artSize = gui->GetTextureSize(kDiagramTextureName); + if (artSize.x > 0.0f && artSize.y > 0.0f) { + artAspect = artSize.x / artSize.y; + } + } + + std::string values[IM_ARRAYSIZE(kDiagram)]; + int32_t rowsPerGutter[2] = { 0, 0 }; + float widestName = 0.0f; + float widestValue = 0.0f; + for (int32_t i = 0; i < (int32_t)IM_ARRAYSIZE(kDiagram); i++) { + const DiagramEntry& entry = kDiagram[i]; + const ExtendedBind& bind = mSession.IsActive() ? mSession.GetBinding(entry.binding) : mBindings[entry.binding]; + values[i] = bind.bindType != SDL_CONTROLLER_BINDTYPE_NONE ? DescribeBind(bind) : "-"; + widestValue = std::max(widestValue, ImGui::CalcTextSize(values[i].c_str()).x); + widestName = std::max(widestName, ImGui::CalcTextSize(BindingName(entry.binding)).x); + rowsPerGutter[entry.labelOnRight ? 1 : 0]++; + } + const int32_t maxRows = std::max(rowsPerGutter[0], rowsPerGutter[1]); + + const float valueColumnWidth = std::max(widestValue, ImGui::GetFontSize() * 6.0f); + + const float valueGap = ImGui::CalcTextSize(" ").x; + + const float gutterWidth = widestName + valueColumnWidth + valueGap + ImGui::GetFontSize() * 3.0f; + const float width = std::max(ImGui::GetContentRegionAvail().x, gutterWidth * 2.0f + MIN_IMAGE_WIDTH); + const float imageWidth = std::min(width - gutterWidth * 2.0f, width * MAX_IMAGE_SPAN); + const float imageHeight = imageWidth / artAspect; + const float rowHeight = ImGui::GetTextLineHeightWithSpacing() * 1.35f; + const float height = std::max(imageHeight, rowHeight * maxRows); + + const ImVec2 origin = ImGui::GetCursorScreenPos(); + const ImVec2 canvas(width, height); + ImDrawList* drawList = ImGui::GetWindowDrawList(); + + const ImVec2 imageMin(origin.x + (width - imageWidth) * 0.5f, origin.y + (height - imageHeight) * 0.5f); + const ImVec2 imageMax(imageMin.x + imageWidth, imageMin.y + imageHeight); + + const auto toArt = [&](const ImVec2& uv) { + return ImVec2(imageMin.x + uv.x * imageWidth, imageMin.y + uv.y * imageHeight); + }; + + if (haveArt) { + drawList->AddImage(gui->GetTextureByName(kDiagramTextureName), imageMin, imageMax); + } else { + drawList->AddRectFilled(imageMin, imageMax, IM_COL32(40, 44, 52, 255), 12.0f); + drawList->AddRect(imageMin, imageMax, IM_COL32(90, 96, 110, 255), 12.0f, 0, 2.0f); + const char* placeholder = "controller image"; + const ImVec2 textSize = ImGui::CalcTextSize(placeholder); + drawList->AddText( + ImVec2((imageMin.x + imageMax.x - textSize.x) * 0.5f, (imageMin.y + imageMax.y - textSize.y) * 0.5f), + IM_COL32(120, 126, 140, 255), placeholder); + } + + const int32_t currentBinding = mSession.IsActive() ? mSession.CurrentBinding() : -1; + const float pulse = 0.55f + 0.45f * std::sin((float)ImGui::GetTime() * 6.0f); + + int32_t rowUsed[2] = { 0, 0 }; + for (int32_t i = 0; i < (int32_t)IM_ARRAYSIZE(kDiagram); i++) { + const DiagramEntry& entry = kDiagram[i]; + const ExtendedBind& bind = mSession.IsActive() ? mSession.GetBinding(entry.binding) : mBindings[entry.binding]; + const bool bound = bind.bindType != SDL_CONTROLLER_BINDTYPE_NONE; + const bool active = entry.binding == currentBinding; + const bool live = IsBindingLive(entry.binding); + + const bool onRight = entry.labelOnRight; + const float lineHeight = ImGui::GetTextLineHeight(); + const ImVec2 valueSize = ImGui::CalcTextSize(values[i].c_str()); + + const int32_t gutter = onRight ? 1 : 0; + const int32_t row = rowUsed[gutter]++; + const float rowCenterY = origin.y + (row + 0.5f) * (height / rowsPerGutter[gutter]); + + const float run = ImGui::GetFontSize(); + const float elbowX = + onRight ? imageMax.x + ImGui::GetFontSize() * 0.6f : imageMin.x - ImGui::GetFontSize() * 0.6f; + const float valueEdgeX = onRight ? elbowX + run + valueGap : elbowX - run - valueGap; + + const ImVec2 cellMin(onRight ? valueEdgeX : valueEdgeX - valueColumnWidth, + rowCenterY - lineHeight * 0.5f - 2.0f); + const ImVec2 cellMax(cellMin.x + valueColumnWidth, cellMin.y + lineHeight + 4.0f); + + ImGui::SetCursorScreenPos(cellMin); + ImGui::InvisibleButton(StringHelper::Sprintf("##mapperRow%d", i).c_str(), + ImVec2(cellMax.x - cellMin.x, cellMax.y - cellMin.y), + ImGuiButtonFlags_MouseButtonLeft | ImGuiButtonFlags_MouseButtonRight); + const bool hovered = ImGui::IsItemHovered(); + if (hovered && !mSession.IsActive() && mJoystick != nullptr) { + Tooltip("Click to map this control. Right-click to clear it."); + if (ImGui::IsItemClicked(ImGuiMouseButton_Left)) { + StartSession({ entry.binding }); + } else if (ImGui::IsItemClicked(ImGuiMouseButton_Right) && bound) { + mBindings[entry.binding] = NoBind(); + mDirty = true; + } + } + + ImU32 color; + if (active) { + color = IM_COL32(255, (int32_t)(200.0f * pulse), 60, 255); + } else if (live) { + color = IM_COL32(110, 220, 110, 255); + } else if (bound) { + color = IM_COL32(215, 220, 230, 255); + } else { + color = IM_COL32(130, 135, 145, 255); + } + + if (hovered) { + drawList->AddRectFilled(cellMin, cellMax, IM_COL32(255, 255, 255, 24), 3.0f); + } + + const ImVec2 hotspot = toArt(entry.hotspot); + const float lineStartX = onRight ? cellMin.x - valueGap : cellMax.x + valueGap; + const ImU32 lineColor = active ? color : (bound ? IM_COL32(150, 156, 168, 255) : IM_COL32(90, 94, 104, 255)); + drawList->AddLine(ImVec2(lineStartX, rowCenterY), ImVec2(elbowX, rowCenterY), lineColor, 1.5f); + drawList->AddLine(ImVec2(elbowX, rowCenterY), hotspot, lineColor, 1.5f); + drawList->AddCircleFilled(hotspot, active || live ? 5.0f : 3.5f, color); + + drawList->AddText(ImVec2(onRight ? cellMin.x : cellMax.x - valueSize.x, rowCenterY - valueSize.y * 0.5f), color, + values[i].c_str()); + + const char* name = BindingName(entry.binding); + const ImVec2 nameSize = ImGui::CalcTextSize(name); + drawList->AddText( + ImVec2(onRight ? origin.x + width - 4.0f - nameSize.x : origin.x + 4.0f, rowCenterY - nameSize.y * 0.5f), + NAME_COLOR, name); + } + + ImGui::SetCursorScreenPos(ImVec2(origin.x, origin.y + canvas.y)); + ImGui::Dummy(ImVec2(1.0f, 0.0f)); + + if (!mIncludeExtraButtons) { + return; + } + + ImGui::SeparatorText("Extra buttons"); + for (int32_t i = 0; i < (int32_t)IM_ARRAYSIZE(kExtraBindings); i++) { + const int32_t binding = kExtraBindings[i]; + const ExtendedBind& bind = mSession.IsActive() ? mSession.GetBinding(binding) : mBindings[binding]; + const bool bound = bind.bindType != SDL_CONTROLLER_BINDTYPE_NONE; + const bool active = mSession.IsActive() && mSession.CurrentBinding() == binding; + + ImGui::BeginDisabled(mSession.IsActive() || mJoystick == nullptr); + PushStyleButton(active ? Colors::Orange : THEME_COLOR); + if (ImGui::Button(StringHelper::Sprintf("%s: %s##extra%d", BindingName(binding), + bound ? DescribeBind(bind).c_str() : "-", i) + .c_str())) { + StartSession({ binding }); + } + PopStyleButton(); + ImGui::EndDisabled(); + if (i % 3 != 2 && i != (int32_t)IM_ARRAYSIZE(kExtraBindings) - 1) { + ImGui::SameLine(); + } + } +} + +void MapperWindow::DrawSessionPrompt() { + if (!mSession.IsActive()) { + return; + } + + const int32_t binding = mSession.CurrentBinding(); + const ImGuiStyle& style = ImGui::GetStyle(); + + PushStyleButton(THEME_COLOR); + const float buttonHeight = ImGui::GetFrameHeight(); + PopStyleButton(); + + const float promptHeight = + style.WindowPadding.y * 2.0f + ImGui::GetTextLineHeightWithSpacing() * 2.0f + buttonHeight; + + ImGui::PushStyleColor(ImGuiCol_ChildBg, ImVec4(0.16f, 0.14f, 0.06f, 1.0f)); + ImGui::BeginChild("##mapperPrompt", ImVec2(0.0f, promptHeight), true, ImGuiWindowFlags_NoScrollbar); + + ImGui::Text("Press or move: %s", binding >= 0 ? BindingName(binding) : "?"); + if (mSession.StepCount() > 1) { + ImGui::SameLine(); + ImGui::TextDisabled("(%d / %d)", mSession.CurrentStep() + 1, mSession.StepCount()); + } + ImGui::TextDisabled("Sticks and triggers: push all the way, then let go. Space skips, Escape cancels."); + + PushStyleButton(THEME_COLOR); + const bool skip = ImGui::Button("Skip") || ImGui::IsKeyPressed(ImGuiKey_Space, false); + ImGui::SameLine(); + ImGui::BeginDisabled(mSession.CurrentStep() == 0); + const bool back = ImGui::Button("Back"); + ImGui::EndDisabled(); + ImGui::SameLine(); + const bool cancel = ImGui::Button("Cancel") || ImGui::IsKeyPressed(ImGuiKey_Escape, false); + PopStyleButton(); + + ImGui::EndChild(); + ImGui::PopStyleColor(); + + if (cancel) { + EndSession(false); + mStatusMessage = "Mapping cancelled; nothing was changed."; + } else if (back) { + mSession.GoBack(); + } else if (skip) { + mSession.Advance(); + if (mSession.IsComplete()) { + EndSession(true); + mStatusMessage = "Mapping captured. Check the diagram, then Save Mapping."; + } + } +} + +void MapperWindow::DrawActionButtons() { + const bool haveDevice = mJoystick != nullptr; + const bool busy = mSession.IsActive(); + + char nameBuffer[128] = ""; + SDL_strlcpy(nameBuffer, mCustomName.c_str(), sizeof(nameBuffer)); + ImGui::BeginDisabled(busy || !haveDevice); + PushStyleInput(THEME_COLOR); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x * 0.45f); + if (ImGui::InputText("Controller Name", nameBuffer, sizeof(nameBuffer))) { + mCustomName = nameBuffer; + mDirty = true; + } + PopStyleInput(); + ImGui::EndDisabled(); + Tooltip("Name saved into usergamepadmappings.txt for this device. Commas are replaced with spaces."); + + ImGui::BeginDisabled(busy || !haveDevice); + PushStyleButton(THEME_COLOR); + if (ImGui::Button("Map All")) { + std::vector order(std::begin(kCoreBindingOrder), std::end(kCoreBindingOrder)); + if (mIncludeExtraButtons) { + order.insert(order.end(), std::begin(kExtraBindings), std::end(kExtraBindings)); + } + StartSession(order); + } + PopStyleButton(); + ImGui::EndDisabled(); + Tooltip(haveDevice ? "Walks every control on the pad, asking for one input at a time." : "Select a device first."); + + ImGui::SameLine(); + ImGui::BeginDisabled(busy || !haveDevice || !mDirty); + PushStyleButton(THEME_COLOR); + if (ImGui::Button("Save Mapping")) { + char guidString[33] = ""; + SDL_JoystickGetGUIDString(SDL_JoystickGetGUID(mJoystick), guidString, sizeof(guidString)); + + bool ok; + if (!HasAnyBinding(mBindings)) { + ok = DeleteUserMapping(guidString); + mStatusMessage = + ok ? StringHelper::Sprintf("Removed from %s. SDL keeps the device registered until you restart.", + kUserMappingsFileName) + : "Nothing to remove; this device has no saved mapping."; + ok = true; + } else { + const std::string mapping = GenerateMappingString(mJoystick, mBindings, mCustomName); + ok = !mapping.empty() && SaveUserMapping(mapping); + mStatusMessage = ok ? StringHelper::Sprintf("Saved to %s.", kUserMappingsFileName) + : "Failed to save the mapping; see the log for details."; + } + + if (ok) { + mDirty = false; + std::error_code error; + const auto writeTime = std::filesystem::last_write_time(GetUserMappingsPath(), error); + if (!error) { + mLastUserFileWriteTime = (uint64_t)writeTime.time_since_epoch().count(); + } + RefreshDeviceList(); + } + } + PopStyleButton(); + ImGui::EndDisabled(); + + ImGui::SameLine(); + ImGui::BeginDisabled(busy || !haveDevice); + PushStyleButton(THEME_COLOR); + if (ImGui::Button("Revert")) { + LoadBindingsForDevice(); + mDirty = false; + mStatusMessage = "Reverted to the mapping SDL is currently using."; + } + PopStyleButton(); + ImGui::EndDisabled(); + Tooltip("Discards unsaved changes and reloads the mapping SDL is using for this device."); + + ImGui::SameLine(); + ImGui::BeginDisabled(busy || !haveDevice); + PushStyleButton(THEME_COLOR); + if (ImGui::Button("Clear All Bindings")) { + ClearBindings(mBindings); + mDirty = true; + } + PopStyleButton(); + ImGui::EndDisabled(); + + const bool haveUserMapping = + mSelectedDevice >= 0 && mSelectedDevice < (int32_t)mDevices.size() && mDevices[mSelectedDevice].hasUserMapping; + + ImGui::BeginDisabled(busy || !haveUserMapping); + PushStyleButton(Colors::DarkRed); + if (ImGui::Button("Delete Saved Mapping")) { + if (DeleteUserMapping(mDevices[mSelectedDevice].guid)) { + mStatusMessage = StringHelper::Sprintf("Removed from %s. Restart to fall back to gamecontrollerdb.txt.", + kUserMappingsFileName); + RefreshDeviceList(); + } else { + mStatusMessage = "No saved mapping to remove."; + } + } + PopStyleButton(); + ImGui::EndDisabled(); + Tooltip("SDL keeps the mapping in memory until the game restarts, so the device stays usable this session."); + + ImGui::SameLine(); + ImGui::BeginDisabled(busy); + PushStyleButton(THEME_COLOR); + if (ImGui::Button("Reload From File")) { + if (LoadUserMappings()) { + LoadBindingsForDevice(); + mDirty = false; + RefreshDeviceList(); + mStatusMessage = StringHelper::Sprintf("Reloaded %s.", kUserMappingsFileName); + } else { + mStatusMessage = StringHelper::Sprintf("No %s to load.", kUserMappingsFileName); + } + } + PopStyleButton(); + ImGui::EndDisabled(); + + ImGui::SameLine(); + ImGui::BeginDisabled(busy); + Checkbox("Include extra buttons", &mIncludeExtraButtons, + CheckboxOptions() + .Color(THEME_COLOR) + .Tooltip("Adds Guide, Misc and paddle/touchpad buttons - which most pads do not have - to the " + "diagram and the Map All walk.")); + ImGui::EndDisabled(); +} + +void MapperWindow::DrawMappingStringPreview() { + if (mJoystick == nullptr || !ImGui::CollapsingHeader("Mapping string")) { + return; + } + + const std::string mapping = GenerateMappingString(mJoystick, mBindings, mCustomName); + ImGui::TextWrapped("%s", mapping.c_str()); + PushStyleButton(THEME_COLOR); + if (ImGui::Button("Copy to Clipboard")) { + ImGui::SetClipboardText(mapping.c_str()); + mStatusMessage = "Mapping string copied to the clipboard."; + } + PopStyleButton(); +} + +void MapperWindow::DrawElement() { + static bool sDiagramTextureRequested = false; + if (!sDiagramTextureRequested) { + sDiagramTextureRequested = true; + auto gui = std::dynamic_pointer_cast(Ship::Context::GetRawInstance()->GetWindow()->GetGui()); + auto archives = Ship::Context::GetRawInstance()->GetResourceManager()->GetArchiveManager(); + if (gui != nullptr && archives != nullptr && archives->HasFile(kDiagramTexturePath)) { + gui->LoadTextureFromRawImage(kDiagramTextureName, kDiagramTexturePath); + } + } + + ImGui::PushFont(GameEngine::Instance->fontMonoLarger); + + DrawDeviceSelector(); + Separator(); + DrawDiagram(); + DrawSessionPrompt(); + Separator(); + DrawActionButtons(); + + if (mDirty) { + ImGui::TextColored(ImVec4(1.0f, 0.75f, 0.2f, 1.0f), "Unsaved changes."); + } + if (!mStatusMessage.empty()) { + ImGui::TextWrapped("%s", mStatusMessage.c_str()); + } + + DrawMappingStringPreview(); + + ImGui::PopFont(); +} + +// --------------------------------------------------------------------------------------------------- +// Menu registration +// --------------------------------------------------------------------------------------------------- + +static void RegisterMapperWidgets() { + WidgetPath path = { "Settings", "Controls", SECTION_COLUMN_2 }; + LighthouseGui::mLighthouseMenu->AddWidget(path, "Gamepad Mapper", WIDGET_SEPARATOR_TEXT); + LighthouseGui::mLighthouseMenu->AddWidget(path, "Open Gamepad Mapper", WIDGET_WINDOW_BUTTON) + .CVar(CVAR_WINDOW("GamepadMapper")) + .RaceDisable(false) + .WindowName("Gamepad Mapper") + .HideInSearch(true) + .Options(WindowButtonOptions() + .Tooltip("Build an SDL mapping for a gamepad the game does not recognize, or fix one that is " + "mapped wrong. Saves to usergamepadmappings.txt.") + .EmbedWindow(false)); +} + +static RegisterMenuInitFunc menuInitFunc(RegisterMapperWidgets); + +} // namespace Mapper diff --git a/src/port/Controller/Mapper.h b/src/port/Controller/Mapper.h new file mode 100644 index 000000000..d8f72376c --- /dev/null +++ b/src/port/Controller/Mapper.h @@ -0,0 +1,182 @@ +#pragma once + +// Built-in SDL gamepad mapper. +// +// Produces `gamecontrollerdb.txt`-style mapping strings for a raw SDL joystick and persists them to +// `usergamepadmappings.txt` in the app directory. That file is loaded at boot (and whenever it changes on +// disk) on top of the bundled `gamecontrollerdb.txt`, so a user-authored mapping always wins. +// +// The binding state machine (axis commit/return distances, binding override rules, mapping string layout) +// is adapted from https://github.com/General-Arcade/sdl2-gamepad-tool (MIT), which in turn follows SDL's +// own `controllermap` test program. + +#include +#include +#include + +#include +#include +#include + +namespace Mapper { +enum AxisBinding { + AXIS_LEFTX_NEGATIVE, + AXIS_LEFTX_POSITIVE, + AXIS_LEFTY_NEGATIVE, + AXIS_LEFTY_POSITIVE, + AXIS_RIGHTX_NEGATIVE, + AXIS_RIGHTX_POSITIVE, + AXIS_RIGHTY_NEGATIVE, + AXIS_RIGHTY_POSITIVE, + AXIS_TRIGGERLEFT, + AXIS_TRIGGERRIGHT, + AXIS_BINDING_MAX, +}; + +constexpr int32_t BINDING_COUNT = SDL_CONTROLLER_BUTTON_MAX + AXIS_BINDING_MAX; + +struct ExtendedBind { + SDL_GameControllerBindType bindType; + union { + int32_t button; + + struct { + int32_t axis; + int32_t axisMin; + int32_t axisMax; + } axis; + + struct { + int32_t hat; + int32_t hatMask; + } hat; + } value; + bool committed; +}; + +struct AxisState { + bool moving; + int32_t lastValue; + int32_t startingValue; + int32_t farthestValue; +}; + +class MappingSession { + public: + static constexpr int32_t AXIS_COMMIT_DISTANCE = 16000; + static constexpr int32_t AXIS_RETURN_DISTANCE = 10000; + static constexpr uint32_t PENDING_ADVANCE_DELAY_MS = 100; + + MappingSession(); + + void Start(SDL_Joystick* joystick, const std::vector& order); + void Stop(); + + bool IsActive() const; + bool IsComplete() const; + + int32_t CurrentStep() const; + int32_t StepCount() const; + int32_t CurrentBinding() const; + + void GoToStep(int32_t step); + void Advance(); + void GoBack(); + + void ProcessButtonDown(int32_t button); + void ProcessHatMotion(int32_t hat, int32_t value); + void ProcessAxisMotion(int32_t axis, int32_t value, SDL_Joystick* joystick); + + void CheckPendingAdvance(); + + const ExtendedBind& GetBinding(int32_t index) const; + void SetBindings(const ExtendedBind (&bindings)[BINDING_COUNT]); + void CopyBindingsTo(ExtendedBind (&out)[BINDING_COUNT]) const; + + private: + void ConfigureBinding(const ExtendedBind& binding); + bool BindingContainsBinding(const ExtendedBind& a, const ExtendedBind& b) const; + + ExtendedBind mBindings[BINDING_COUNT]; + std::vector mOrder; + std::vector mAxisState; + int32_t mCurrentStep; + uint32_t mPendingAdvanceTime; + bool mActive; + bool mComplete; +}; + +void ClearBindings(ExtendedBind (&bindings)[BINDING_COUNT]); +bool HasAnyBinding(const ExtendedBind (&bindings)[BINDING_COUNT]); +std::string GenerateMappingString(SDL_Joystick* joystick, const ExtendedBind (&bindings)[BINDING_COUNT], + const std::string& nameOverride = ""); +int32_t ParseMappingString(const std::string& mapping, ExtendedBind (&bindings)[BINDING_COUNT]); +std::string DescribeBind(const ExtendedBind& bind); +const char* BindingName(int32_t binding); +std::string GetUserMappingsPath(); +std::string FindUserMapping(const std::string& guid); +std::string MappingName(const std::string& mapping); +bool LoadUserMappings(); +bool SaveUserMapping(const std::string& mapping); +bool DeleteUserMapping(const std::string& guid); + +class MapperWindow final : public Ship::GuiWindow { + public: + using GuiWindow::GuiWindow; + ~MapperWindow(); + + protected: + void InitElement() override; + void UpdateElement() override; + void DrawElement() override; + + private: + struct DeviceInfo { + int32_t deviceIndex; + SDL_JoystickID instanceId; + std::string name; + std::string guid; + bool hasMapping; + bool hasUserMapping; + }; + + void RefreshDeviceList(); + void SelectDevice(int32_t listIndex); + void CloseJoystick(); + void LoadBindingsForDevice(); + + void StartSession(const std::vector& order); + void EndSession(bool applyResult); + + void PollDeviceForSession(); + void SnapshotDeviceState(); + + void DrawDeviceSelector(); + void DrawDiagram(); + void DrawSessionPrompt(); + void DrawActionButtons(); + void DrawMappingStringPreview(); + + bool IsBindingLive(int32_t binding) const; + + std::vector mDevices; + int32_t mSelectedDevice = -1; + SDL_Joystick* mJoystick = nullptr; + + ExtendedBind mBindings[BINDING_COUNT] = {}; + MappingSession mSession; + bool mDirty = false; + bool mIncludeExtraButtons = false; + std::string mStatusMessage; + std::string mCustomName; + + std::vector mPreviousButtons; + std::vector mPreviousHats; + + int32_t mGameInputBlockTimer = INT32_MAX; + uint32_t mLastDeviceScanTicks = 0; + uint64_t mLastUserFileWriteTime = 0; + uint32_t mLastUserFileCheckTicks = 0; +}; + +} // namespace Mapper diff --git a/src/port/UI/LighthouseGui.cpp b/src/port/UI/LighthouseGui.cpp index ece79ef8c..425ca0d62 100644 --- a/src/port/UI/LighthouseGui.cpp +++ b/src/port/UI/LighthouseGui.cpp @@ -23,6 +23,7 @@ #include "port/Rando/CheckTracker/CheckTracker.h" #include "Notification.h" +#include "port/Controller/Mapper.h" #include "port/Network/Anchor/Anchor.h" #include "port/Enhancements/Backports/EggAim.h" #include "LighthouseMenu.h" @@ -44,6 +45,7 @@ std::shared_ptr mConsoleWindow; std::shared_ptr mStatsWindow; std::shared_ptr mGfxDebuggerWindow; std::shared_ptr mInputEditorWindow; +std::shared_ptr mGamepadMapperWindow; std::shared_ptr mModMenuWindow; std::shared_ptr mRomhackMenuWindow; @@ -116,6 +118,10 @@ void SetupGuiElements() { std::make_shared(CVAR_WINDOW("ControllerConfiguration"), "Configure Controller"); gui->AddGuiWindow(mInputEditorWindow); + mGamepadMapperWindow = + std::make_shared(CVAR_WINDOW("GamepadMapper"), "Gamepad Mapper", ImVec2(1280, 820)); + gui->AddGuiWindow(mGamepadMapperWindow); + mModMenuWindow = std::make_shared(CVAR_WINDOW("ModMenu"), "Mod Menu"); gui->AddGuiWindow(mModMenuWindow); @@ -219,6 +225,7 @@ void Destroy() { mConsoleWindow = nullptr; mGfxDebuggerWindow = nullptr; mInputEditorWindow = nullptr; + mGamepadMapperWindow = nullptr; // mCollisionViewerWindow = nullptr; // mEventLogWindow = nullptr; mNotificationWindow = nullptr; From 061875d9be0e3cef922874c44f3c4695abe95241 Mon Sep 17 00:00:00 2001 From: Jeod <47716344+JeodC@users.noreply.github.com> Date: Wed, 29 Jul 2026 13:27:07 -0400 Subject: [PATCH 037/131] Mute Chimpy and add a fix enhancement for Freezeezy Peak Lobby's door trim (#279) * Mute Chimpy on MM load enhancement. * Clang format * Add a fix enhancement for the FP Lobby door trim --- src/MM/ch/lmonkey.c | 3 +- src/core2/spline_pathfollow.c | 5 + src/port/Controller/ModernCamera.cpp | 12 +- .../Enhancements/Camera/FreeLookCamera.cpp | 10 +- src/port/Enhancements/Events/Hooks/Events.h | 3 + .../Events/Hooks/List/EngineEvent.h | 9 ++ .../Enhancements/Events/PortEnhancements.cpp | 1 + src/port/Enhancements/Fixes/GameFixes.cpp | 14 +++ src/port/Network/Anchor/Menu.cpp | 14 +-- src/port/Patches/GraphicsPatches.cpp | 113 ++++++++++++++++++ src/port/Resource/Importers/ModelFactory.cpp | 14 +++ src/port/UI/LighthouseMenuEnhancements.cpp | 15 ++- src/port/UI/LighthouseMenuSettings.cpp | 54 ++++----- 13 files changed, 219 insertions(+), 48 deletions(-) diff --git a/src/MM/ch/lmonkey.c b/src/MM/ch/lmonkey.c index eb3b9cb53..90f57159d 100644 --- a/src/MM/ch/lmonkey.c +++ b/src/MM/ch/lmonkey.c @@ -98,7 +98,8 @@ void chlmonkey_update(Actor *this) { func_80343DEC(this); } else {//L80388630 - if (subaddie_playerIsWithinSphereAndActive(this, 700) && !gcdialog_hasCurrentTextId()) { + if (subaddie_playerIsWithinSphereAndActive(this, 700) && !gcdialog_hasCurrentTextId() && + EventSystem_Should(VB_MM_CHIMPY_NOISE, true)) { __chlmonkey_playRandomNoise(this); }//L8038865C diff --git a/src/core2/spline_pathfollow.c b/src/core2/spline_pathfollow.c index 3d416e8d8..32ed34b5d 100644 --- a/src/core2/spline_pathfollow.c +++ b/src/core2/spline_pathfollow.c @@ -962,6 +962,11 @@ s32 func_803422D4(Actor *arg0, Union_glspline *arg1, SplineList *arg2){ break; case 3: + // [port] Path sfx nodes fire for whichever actor is walking the spline; listeners + // get the actor so a single actor's path sounds can be muted. + if (!EventSystem_Should(VB_SPLINE_PATH_SFX, true, arg0)) { + break; + } sp78 = arg1->t0.unk4.common.bit31; sp7C = arg1->t0.unk8.bit31 / 8.388608e6f; sp74 = arg1->t0.unk4.common.bit15 * 8; diff --git a/src/port/Controller/ModernCamera.cpp b/src/port/Controller/ModernCamera.cpp index 57e45ae32..4a097d403 100644 --- a/src/port/Controller/ModernCamera.cpp +++ b/src/port/Controller/ModernCamera.cpp @@ -52,12 +52,12 @@ void func_802C03BC(void); // undo a collision resolve that crossed ov void func_802C0490(float dst[3]); // focus/orbit center void func_802C04B0(void); // re-derive D_8037DB70 from the live camera -float func_802BD51C(void); // target camera height -float func_802BD8D4(void); // target orbit distance (zoom level) -void func_802BE190(float target[3]); // position spring toward target -void func_802BE230(float gain, float damp); // position spring tuning -int func_802BE60C(void); // swept camera collision + slide -int func_802BC84C(int mode); // occluded-too-long recovery +float func_802BD51C(void); // target camera height +float func_802BD8D4(void); // target orbit distance (zoom level) +void func_802BE190(float target[3]); // position spring toward target +void func_802BE230(float gain, float damp); // position spring tuning +int func_802BE60C(void); // swept camera collision + slide +int func_802BC84C(int mode); // occluded-too-long recovery void func_802BE6FC(float rotOut[3], float focus[3]); // look-at from the live position } diff --git a/src/port/Enhancements/Camera/FreeLookCamera.cpp b/src/port/Enhancements/Camera/FreeLookCamera.cpp index 64a7e88db..a4b51e96f 100644 --- a/src/port/Enhancements/Camera/FreeLookCamera.cpp +++ b/src/port/Enhancements/Camera/FreeLookCamera.cpp @@ -38,11 +38,11 @@ void func_802C03BC(void); // undo a collision resolve that crossed ov void func_802C0490(float dst[3]); // focus/orbit center void func_802C04B0(void); // re-derive D_8037DB70 from the live camera -float func_802BD8D4(void); // target orbit distance (zoom level) -void func_802BE190(float target[3]); // position spring toward target -void func_802BE230(float gain, float damp); // position spring tuning -int func_802BE60C(void); // swept camera collision + slide -int func_802BC84C(int mode); // occluded-too-long recovery +float func_802BD8D4(void); // target orbit distance (zoom level) +void func_802BE190(float target[3]); // position spring toward target +void func_802BE230(float gain, float damp); // position spring tuning +int func_802BE60C(void); // swept camera collision + slide +int func_802BC84C(int mode); // occluded-too-long recovery void func_802BE6FC(float rotOut[3], float focus[3]); // look-at from the live position } diff --git a/src/port/Enhancements/Events/Hooks/Events.h b/src/port/Enhancements/Events/Hooks/Events.h index 4fdc8b75e..641f2f740 100644 --- a/src/port/Enhancements/Events/Hooks/Events.h +++ b/src/port/Enhancements/Events/Hooks/Events.h @@ -30,6 +30,9 @@ typedef enum VBehaviorID { VB_JINJO_CHARGE_SOUND, // MM Chimpy stump: gates the rumble sfx that starts when the stump begins shaking. VB_MM_CHIMPY_STUMP_RUMBLE, + VB_MM_CHIMPY_NOISE, + // Gates the sfx a spline path node plays. Args: (Actor *pathWalker). + VB_SPLINE_PATH_SFX, // Cancelling hands Mumbo's transform state to the listener. Args: (Actor *mumbo). VB_MUMBO_HUT_TRANSFORM_CUTSCENE, VB_YUMYUM_DROP, diff --git a/src/port/Enhancements/Events/Hooks/List/EngineEvent.h b/src/port/Enhancements/Events/Hooks/List/EngineEvent.h index 885f199f5..adfb1355b 100644 --- a/src/port/Enhancements/Events/Hooks/List/EngineEvent.h +++ b/src/port/Enhancements/Events/Hooks/List/EngineEvent.h @@ -21,6 +21,15 @@ DEFINE_EVENT(OnMapLoad, GameMap prevMap; GameMap nextMap; s32 exit;); DEFINE_EVENT(OnDialogLoaded, s32 textId; char* text;); DEFINE_EVENT(OnModelLoad, s32 modelId; void* modelInfo; s32 * reload;); + +// Declared texture dimensions from a model's BKTextureInfo table. +typedef struct { + u8 width; + u8 height; +} ModelTexSize; + +DEFINE_EVENT(OnModelDisplayListLoad, const char* path; u32 * dlWords; u32 dlWordCount; const ModelTexSize* texSizes; + u16 texCount;); DEFINE_EVENT(ViewportFrustumUpdate, float* frustumX; float* frustumY;); DEFINE_EVENT(OnTransitionModelScale, Gfx** gfx; Mtx * *mtx; s32 uid; f32 * scale;); DEFINE_EVENT(OnTransitionStateUpdate, s32 modelId; s32 uid; s32 substate;); diff --git a/src/port/Enhancements/Events/PortEnhancements.cpp b/src/port/Enhancements/Events/PortEnhancements.cpp index 6022ec0e0..83e983972 100644 --- a/src/port/Enhancements/Events/PortEnhancements.cpp +++ b/src/port/Enhancements/Events/PortEnhancements.cpp @@ -24,6 +24,7 @@ void PortEnhancements_Register() { REGISTER_EVENT(OnMapLoad); REGISTER_EVENT(OnDialogLoaded); REGISTER_EVENT(OnModelLoad); + REGISTER_EVENT(OnModelDisplayListLoad); REGISTER_EVENT(ViewportFrustumUpdate); REGISTER_EVENT(OnTransitionModelScale); REGISTER_EVENT(OnTransitionStateUpdate); diff --git a/src/port/Enhancements/Fixes/GameFixes.cpp b/src/port/Enhancements/Fixes/GameFixes.cpp index af7be8b47..e61e80b4e 100644 --- a/src/port/Enhancements/Fixes/GameFixes.cpp +++ b/src/port/Enhancements/Fixes/GameFixes.cpp @@ -145,9 +145,23 @@ void RegisterCongaDialog_Init() { // spawned, so the stump drops in low and grinds back up with the rumble sfx each time. Mute the // rumble for those replays only; the first rise (jiggy spawns 2.9s after the shake starts, so it // isn't marked spawned yet) keeps its sound. +static bool IsChimpyWalkOffReplay() { + return jiggyscore_isSpawned(JIGGY_9_MM_CHIMPY) && + !mapSpecificFlags_get(MM_SPECIFIC_FLAG_2_ORANGE_HAS_BEEN_RETURNED); +} + void RegisterChimpyStumpRumble_Init() { COND_VB_SHOULD(VB_MM_CHIMPY_STUMP_RUMBLE, EVENT_PRIORITY_NORMAL, CVarGetInteger(CVAR_STUMP_RUMBLE, 1), { *should = !jiggyscore_isSpawned(JIGGY_9_MM_CHIMPY); }); + COND_VB_SHOULD(VB_MM_CHIMPY_NOISE, EVENT_PRIORITY_NORMAL, CVarGetInteger(CVAR_STUMP_RUMBLE, 1), + { *should = !IsChimpyWalkOffReplay(); }); + COND_VB_SHOULD(VB_SPLINE_PATH_SFX, EVENT_PRIORITY_NORMAL, CVarGetInteger(CVAR_STUMP_RUMBLE, 1), { + Actor* pathWalker = va_arg(args, Actor*); + if (pathWalker != NULL && pathWalker->actor_info != NULL && pathWalker->actor_info->actorId == ACTOR_F_CHIMPY && + IsChimpyWalkOffReplay()) { + *should = false; + } + }); } // Mumbo token duplicate-id fix: rewrite the resolved id for the two tokens that share an id. diff --git a/src/port/Network/Anchor/Menu.cpp b/src/port/Network/Anchor/Menu.cpp index cfa319a3a..347e6d15b 100644 --- a/src/port/Network/Anchor/Menu.cpp +++ b/src/port/Network/Anchor/Menu.cpp @@ -193,13 +193,13 @@ void AnchorAdminMenu(WidgetInfo& info) { } UIWidgets::PopStyleButton(); - //if (UIWidgets::CVarCombobox("PvP Mode:", CVAR_REMOTE_ANCHOR("RoomSettings.PvpMode"), pvpModes, - // UIWidgets::ComboboxOptions() - // .DefaultIndex(1) - // .LabelPosition(UIWidgets::LabelPositions::Above) - // .Color(THEME_COLOR))) { - // anchor->SendPacket_UpdateRoomState(); - //} + // if (UIWidgets::CVarCombobox("PvP Mode:", CVAR_REMOTE_ANCHOR("RoomSettings.PvpMode"), pvpModes, + // UIWidgets::ComboboxOptions() + // .DefaultIndex(1) + // .LabelPosition(UIWidgets::LabelPositions::Above) + // .Color(THEME_COLOR))) { + // anchor->SendPacket_UpdateRoomState(); + // } if (UIWidgets::CVarCombobox("Show Locations For:", CVAR_REMOTE_ANCHOR("RoomSettings.ShowLocationsMode"), showLocationsModes, UIWidgets::ComboboxOptions() diff --git a/src/port/Patches/GraphicsPatches.cpp b/src/port/Patches/GraphicsPatches.cpp index c13103f38..01cb14cae 100644 --- a/src/port/Patches/GraphicsPatches.cpp +++ b/src/port/Patches/GraphicsPatches.cpp @@ -1,3 +1,7 @@ +#include +#include +#include + #include #include "port/UI/cvar_prefixes.h" #include "port/Engine.h" @@ -8,6 +12,7 @@ #define CVAR_DRAW_DISTANCE CVAR_ENHANCEMENT("Graphics.DrawDistance") #define CVAR_DISABLE_LOD CVAR_ENHANCEMENT("Graphics.DisableLOD") +#define CVAR_FP_LOBBY_DOOR_TILE CVAR_ENHANCEMENT("Fixes.FPLobbyDoorTile") static const int kMaxDrawDistanceMul = 6; static int sDrawDistanceCubeWidth(int mul) { @@ -154,3 +159,111 @@ static void RefreshDrawDistanceCVars() { } static RegisterShipInitFunc drawDistanceCVarCache(RefreshDrawDistanceCVars, { CVAR_DRAW_DISTANCE, CVAR_DISABLE_LOD }); + +// ============================================================================ +// STALE TILE DESCRIPTOR — Freezeezy Peak lobby door trim +// ============================================================================ + +// F3DEX opcodes as used by BK64. +static const uint8_t kOpVtx = 0x04; +static const uint8_t kOpTri2 = 0xB1; +static const uint8_t kOpTri1 = 0xBF; +static const uint8_t kOpSetTileSize = 0xF2; +static const uint8_t kOpSetTile = 0xF5; +static const uint8_t kOpSetTImg = 0xFD; + +static const uint32_t kTxClampBit = 0x2; // G_TX_CLAMP +static const uint8_t kRenderTile = 0; // G_TX_RENDERTILE + +// Torch tags a G_SETTIMG that references an extracted texture by putting 0xFF in +// the top byte of w1 and the texture index in the low 24 bits. +static const uint32_t kTexMarker = 0xFF; + +static const char kFPLobbySuffix[] = "GL_FP_LOBBY_OPA"; + +static bool sPathEndsWith(const char* path, const char* suffix) { + if (path == NULL) { + return false; + } + size_t plen = strlen(path); + size_t slen = strlen(suffix); + return plen >= slen && strcmp(path + plen - slen, suffix) == 0; +} + +static void OnModelDisplayListLoad_StaleTile(IEvent* event) { + auto* ev = reinterpret_cast(event); + if (ev->dlWords == NULL || ev->texSizes == NULL || !sPathEndsWith(ev->path, kFPLobbySuffix)) { + return; + } + + // Walk the list tracking live render-tile state, flagging any G_SETTILE whose + // clamp causes a larger texture to be drawn through a smaller tile. + std::vector toPatch; + int curTex = -1; + uint32_t liveTile = UINT32_MAX; + uint32_t tileW = 0, tileH = 0; + + for (uint32_t i = 0; i + 1 < ev->dlWordCount; i += 2) { + uint32_t w0 = ev->dlWords[i]; + uint32_t w1 = ev->dlWords[i + 1]; + uint8_t op = (uint8_t)(w0 >> 24); + + if (op == kOpSetTImg) { + if (((w1 >> 24) & 0xFF) == kTexMarker) { + curTex = (int)(w1 & 0x00FFFFFF); + } + } else if (op == kOpSetTile) { + if (((w1 >> 24) & 0x7) == kRenderTile) { + liveTile = i; + } + } else if (op == kOpSetTileSize) { + if (((w1 >> 24) & 0x7) == kRenderTile) { + uint32_t uls = (w0 >> 12) & 0xFFF; + uint32_t ult = w0 & 0xFFF; + uint32_t lrs = (w1 >> 12) & 0xFFF; + uint32_t lrt = w1 & 0xFFF; + tileW = ((lrs - uls) / 4) + 1; + tileH = ((lrt - ult) / 4) + 1; + } + } else if (op == kOpVtx || op == kOpTri1 || op == kOpTri2) { + if (curTex < 0 || liveTile == UINT32_MAX || tileW == 0 || tileH == 0) { + continue; + } + if ((uint32_t)curTex >= ev->texCount) { + continue; + } + uint32_t declW = ev->texSizes[curTex].width; + uint32_t declH = ev->texSizes[curTex].height; + if (declW <= tileW && declH <= tileH) { + continue; + } + uint32_t tileWord = ev->dlWords[liveTile + 1]; + uint32_t cms = (tileWord >> 8) & 0x3; + uint32_t cmt = (tileWord >> 18) & 0x3; + if (((cms & kTxClampBit) == 0) && ((cmt & kTxClampBit) == 0)) { + continue; + } + // Only safe to swap clamp for wrap when the mask makes the wrap period + // exactly the texture size. + uint32_t masks = (tileWord >> 4) & 0xF; + uint32_t maskt = (tileWord >> 14) & 0xF; + if (masks == 0 || maskt == 0 || (1u << masks) != declW || (1u << maskt) != declH) { + continue; + } + if (std::find(toPatch.begin(), toPatch.end(), liveTile) == toPatch.end()) { + toPatch.push_back(liveTile); + } + } + } + + for (size_t n = 0; n < toPatch.size(); n++) { + ev->dlWords[toPatch[n] + 1] &= ~((kTxClampBit << 18) | (kTxClampBit << 8)); + } +} + +static void RegisterStaleTileFix_Init() { + COND_HOOK(OnModelDisplayListLoad, EVENT_PRIORITY_NORMAL, CVarGetInteger(CVAR_FP_LOBBY_DOOR_TILE, 0), + OnModelDisplayListLoad_StaleTile); +} + +static RegisterShipInitFunc staleTileFixInit(RegisterStaleTileFix_Init, { CVAR_FP_LOBBY_DOOR_TILE }); diff --git a/src/port/Resource/Importers/ModelFactory.cpp b/src/port/Resource/Importers/ModelFactory.cpp index 9dfbbe0e6..409d3ccf3 100644 --- a/src/port/Resource/Importers/ModelFactory.cpp +++ b/src/port/Resource/Importers/ModelFactory.cpp @@ -6,8 +6,10 @@ #include #include "port/Resource/Alt/AltPathPool.h" +#include "port/Enhancements/Events/Hooks/Events.h" #include +#include #include "model.h" @@ -130,6 +132,18 @@ ResourceFactoryBinaryModelV0::ReadResource(std::shared_ptr file, tm.type, tm.width, tm.height, tm.tlutColors, tm.textureDataOffset); } + // Let enhancements patch the raw display list before it is widened. + // Command indices must be preserved; the geo layout references them by position. + if (!rawDLWords.empty() && texCount > 0) { + std::vector texSizes; + texSizes.reserve(texMetas.size()); + for (const auto& tm : texMetas) { + texSizes.push_back(ModelTexSize{ tm.width, tm.height }); + } + CALL_EVENT(OnModelDisplayListLoad, initData->Path.c_str(), rawDLWords.data(), + static_cast(rawDLWords.size()), texSizes.data(), texCount); + } + // Raw texture data blob — full contiguous pixel area from the ROM. // Preserves animated texture frames and unlisted data between textures. uint32_t rawTexDataSize = reader->ReadUInt32(); diff --git a/src/port/UI/LighthouseMenuEnhancements.cpp b/src/port/UI/LighthouseMenuEnhancements.cpp index 90e33a1e4..8a558d380 100644 --- a/src/port/UI/LighthouseMenuEnhancements.cpp +++ b/src/port/UI/LighthouseMenuEnhancements.cpp @@ -354,11 +354,11 @@ void LighthouseMenu::AddMenuEnhancements() { .RaceDisable(false) .Options(CheckboxOptions().Tooltip("Stops the Jinjo charge-up sound the instant it hits Grunty.")); - AddWidget(path, "Mute Chimpy Stump Replay", WIDGET_CVAR_CHECKBOX) + AddWidget(path, "Mute Chimpy Replay", WIDGET_CVAR_CHECKBOX) .CVar(CVAR_ENHANCEMENT("Fixes.ChimpyStumpRumble")) .RaceDisable(false) .Options(CheckboxOptions().DefaultValue(true).Tooltip( - "Mutes the rumbling sound when Chimpy's stump rises again on every return trip to " + "Mutes Chimpy and the rumbling sound his stump makes on every return trip to " "Mumbo's Mountain. The first rise keeps its sound.")); AddWidget(path, "Fix Cutscene Audio Sync", WIDGET_CVAR_CHECKBOX) @@ -386,6 +386,17 @@ void LighthouseMenu::AddMenuEnhancements() { }) .Options(CheckboxOptions().Tooltip("Corrects a spelling error when meeting Conga as a termite.")); + AddWidget(path, "Fix Freezeezy Peak Lobby", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("Fixes.FPLobbyDoorTile")) + .RaceDisable(false) + .PreFunc([](WidgetInfo& info) { + if (mLighthouseMenu->disabledMap.at(DISABLE_FOR_ROMHACK).active) { + info.activeDisables.push_back(DISABLE_FOR_ROMHACK); + } + }) + .Options(CheckboxOptions().Tooltip("Fixes the smeared snow trim around the Freezeezy Peak entrance in " + "Gruntilda's Lair. Requires a map reload to take effect.")); + // Enhancements -> Restorations path = { "Enhancements", "Restorations", SECTION_COLUMN_1 }; AddSidebarEntry("Enhancements", path.sidebarName, 2); diff --git a/src/port/UI/LighthouseMenuSettings.cpp b/src/port/UI/LighthouseMenuSettings.cpp index d586c734a..89d2d0b61 100644 --- a/src/port/UI/LighthouseMenuSettings.cpp +++ b/src/port/UI/LighthouseMenuSettings.cpp @@ -297,37 +297,37 @@ void LighthouseMenu::AddMenuSettings() { .CVar(CVAR_SETTING("Volume.Master")) .RaceDisable(false) .Options(IntSliderOptions().Min(0).Max(100).DefaultValue(40).ShowButtons(true).Format("")); - //AddWidget(path, "Main Music Volume: %d %%", WIDGET_CVAR_SLIDER_INT) - // .CVar(CVAR_SETTING("Volume.MainMusic")) - // .RaceDisable(false) - // .Options(IntSliderOptions().Min(0).Max(100).DefaultValue(100).ShowButtons(true).Format("")); + // AddWidget(path, "Main Music Volume: %d %%", WIDGET_CVAR_SLIDER_INT) + // .CVar(CVAR_SETTING("Volume.MainMusic")) + // .RaceDisable(false) + // .Options(IntSliderOptions().Min(0).Max(100).DefaultValue(100).ShowButtons(true).Format("")); //.Callback([](WidgetInfo& info) { - // Audio_SetGameVolume(SEQ_PLAYER_BGM_MAIN, - // ((float)CVarGetInteger(CVAR_SETTING("Volume.MainMusic"), 100) / 100.0f)); - //}); - //AddWidget(path, "Sub Music Volume: %d %%", WIDGET_CVAR_SLIDER_INT) - // .CVar(CVAR_SETTING("Volume.SubMusic")) - // .RaceDisable(false) - // .Options(IntSliderOptions().Min(0).Max(100).DefaultValue(100).ShowButtons(true).Format("")); + // Audio_SetGameVolume(SEQ_PLAYER_BGM_MAIN, + // ((float)CVarGetInteger(CVAR_SETTING("Volume.MainMusic"), 100) / 100.0f)); + // }); + // AddWidget(path, "Sub Music Volume: %d %%", WIDGET_CVAR_SLIDER_INT) + // .CVar(CVAR_SETTING("Volume.SubMusic")) + // .RaceDisable(false) + // .Options(IntSliderOptions().Min(0).Max(100).DefaultValue(100).ShowButtons(true).Format("")); //.Callback([](WidgetInfo& info) { - // Audio_SetGameVolume(SEQ_PLAYER_BGM_SUB, - // ((float)CVarGetInteger(CVAR_SETTING("Volume.SubMusic"), 100) / 100.0f)); - //}); - //AddWidget(path, "Fanfare Volume: %d %%", WIDGET_CVAR_SLIDER_INT) - // .CVar(CVAR_SETTING("Volume.Fanfare")) - // .RaceDisable(false) - // .Options(IntSliderOptions().Min(0).Max(100).DefaultValue(100).ShowButtons(true).Format("")); + // Audio_SetGameVolume(SEQ_PLAYER_BGM_SUB, + // ((float)CVarGetInteger(CVAR_SETTING("Volume.SubMusic"), 100) / 100.0f)); + // }); + // AddWidget(path, "Fanfare Volume: %d %%", WIDGET_CVAR_SLIDER_INT) + // .CVar(CVAR_SETTING("Volume.Fanfare")) + // .RaceDisable(false) + // .Options(IntSliderOptions().Min(0).Max(100).DefaultValue(100).ShowButtons(true).Format("")); //.Callback([](WidgetInfo& info) { - // Audio_SetGameVolume(SEQ_PLAYER_FANFARE, - // ((float)CVarGetInteger(CVAR_SETTING("Volume.Fanfare"), 100) / 100.0f)); - //}); - //AddWidget(path, "Sound Effects Volume: %d %%", WIDGET_CVAR_SLIDER_INT) - // .CVar(CVAR_SETTING("Volume.SFX")) - // .RaceDisable(false) - // .Options(IntSliderOptions().Min(0).Max(100).DefaultValue(100).ShowButtons(true).Format("")); + // Audio_SetGameVolume(SEQ_PLAYER_FANFARE, + // ((float)CVarGetInteger(CVAR_SETTING("Volume.Fanfare"), 100) / 100.0f)); + // }); + // AddWidget(path, "Sound Effects Volume: %d %%", WIDGET_CVAR_SLIDER_INT) + // .CVar(CVAR_SETTING("Volume.SFX")) + // .RaceDisable(false) + // .Options(IntSliderOptions().Min(0).Max(100).DefaultValue(100).ShowButtons(true).Format("")); //.Callback([](WidgetInfo& info) { - // Audio_SetGameVolume(SEQ_PLAYER_SFX, ((float)CVarGetInteger(CVAR_SETTING("Volume.SFX"), 100) / 100.0f)); - //}); + // Audio_SetGameVolume(SEQ_PLAYER_SFX, ((float)CVarGetInteger(CVAR_SETTING("Volume.SFX"), 100) / 100.0f)); + // }); AddWidget(path, "Audio API (Needs reload)", WIDGET_AUDIO_BACKEND).RaceDisable(false); // Graphics Settings From 3148e2e387c8f5ff261e1c55dec653c04f9675e3 Mon Sep 17 00:00:00 2001 From: Jeod <47716344+JeodC@users.noreply.github.com> Date: Wed, 29 Jul 2026 16:37:06 -0400 Subject: [PATCH 038/131] Revive decomp os functions (#280) * os: real thread table * os: blocking message queues * os: DP status word * os: RSP task submission * interpolation: ring of trees with ownership claims * os: VI retrace source and framebuffer registers * thread5: run the decomp's graphics thread * vimgr: pace the tick from the retrace clock * os: osViBlack blank register * os: deadline timers, taking libultra/os.cpp port-side * os: SI controller reads as request and completion * fix: count the demo audio hold in ticks, not renders * pacing: drop sub-frames against the deadline instead of predicting * audio: revive the decomp's audio pipeline against the RCP * fix: keep mid-tick SI completions out of the demo's pad buffer * perf: replace four decomp hot spots through the event system * fix: memmove for overlapping ranges in bk_vector_remove * fix: drop the game-thread fallback poll in osContGetReadData * Bump LUS and make use of memoization * Add a watchdog for thread5 to log stalls * Add a thread safety for rumble * Comment out GfxDebuggerWindow --- include/core1/core1.h | 3 + include/functions.h | 26 +- lib/ultralib/include/PR/gbi.h | 2 +- libultraship | 2 +- src/core1/audio_manager.c | 16 +- src/core1/graphics_thread.c | 128 ++-- src/core1/pfsmanager.c | 22 +- src/core1/vimgr.c | 38 +- src/core2/actor_cubepropsystem.c | 4 + src/core2/frame/auxbuffer.c | 12 +- src/core2/frame/texture_capture.c | 14 +- src/core2/fx/weather_snow.c | 8 +- src/core2/gameSelect.c | 1 - src/core2/model/modelRender.c | 6 +- src/core2/vla.c | 4 +- src/core2/vtx/gclights.c | 6 + src/port/Audio/mixer.h | 30 +- src/port/DevTools/ThreadWatchdog.cpp | 545 ++++++++++++++++++ src/port/DevTools/ThreadWatchdog.h | 75 +++ src/port/Engine.cpp | 134 +---- src/port/Engine.h | 5 - src/port/Enhancements/Events/Hooks/Events.h | 4 + src/port/Game.cpp | 238 +++++++- src/port/Interpolation/AdaptiveFps.cpp | 200 ------- src/port/Interpolation/AdaptiveFps.h | 46 -- src/port/Interpolation/FrameInterpolation.cpp | 208 +++++-- src/port/Interpolation/FrameInterpolation.h | 8 + src/port/OS/OS.h | 73 +++ src/port/OS/OS_AI.cpp | 48 ++ src/port/OS/OS_Cont.cpp | 89 +++ src/port/OS/OS_Mesg.cpp | 228 ++++++++ src/port/OS/OS_RCP.cpp | 102 ++++ src/port/OS/OS_Threads.cpp | 93 +++ src/port/OS/OS_Time.cpp | 39 ++ src/port/OS/OS_Timer.cpp | 95 +++ src/port/OS/OS_VI.cpp | 111 ++++ src/port/{stub.c => OS/libultra.c} | 46 +- src/port/Patches/FramebufferPatches.cpp | 26 +- src/port/Patches/Patches.h | 13 +- src/port/Patches/PerfPatches.cpp | 230 ++++++++ src/port/Patches/TransitionPatches.cpp | 15 - src/port/Resource/Alt/AltBoldFont.cpp | 15 +- src/port/ShipUtils.cpp | 4 - src/port/ShipUtils.h | 3 - src/port/UI/LighthouseGui.cpp | 8 +- src/port/UI/LighthouseMenuDevTools.cpp | 14 +- 46 files changed, 2431 insertions(+), 606 deletions(-) create mode 100644 src/port/DevTools/ThreadWatchdog.cpp create mode 100644 src/port/DevTools/ThreadWatchdog.h delete mode 100644 src/port/Interpolation/AdaptiveFps.cpp delete mode 100644 src/port/Interpolation/AdaptiveFps.h create mode 100644 src/port/OS/OS.h create mode 100644 src/port/OS/OS_AI.cpp create mode 100644 src/port/OS/OS_Cont.cpp create mode 100644 src/port/OS/OS_Mesg.cpp create mode 100644 src/port/OS/OS_RCP.cpp create mode 100644 src/port/OS/OS_Threads.cpp create mode 100644 src/port/OS/OS_Time.cpp create mode 100644 src/port/OS/OS_Timer.cpp create mode 100644 src/port/OS/OS_VI.cpp rename src/port/{stub.c => OS/libultra.c} (62%) create mode 100644 src/port/Patches/PerfPatches.cpp diff --git a/include/core1/core1.h b/include/core1/core1.h index c071c8da2..bf301700d 100644 --- a/include/core1/core1.h +++ b/include/core1/core1.h @@ -54,6 +54,7 @@ ALHeap *audioManager_getALHeapInfo(void); OSMesgQueue *audioManager_getDMANotifyMesgQueue(void); OSIoMesg *audioManager_getExtraDMAMesg(void); OSMesgQueue *audioManager_getFrameMesgQueue(void); +OSMesgQueue *audioManager_getReplyMesgQueue(void); /* src/core1/overlay.c */ @@ -214,6 +215,8 @@ void dummy_func_80254464(void); void defragManager_init(void); void defragManager_free(void); void defragManager_setPriority(OSPri pri); +void defragManager_resume(void); +void defragManager_pause(void); #ifdef __cplusplus } diff --git a/include/functions.h b/include/functions.h index 7e899b363..01dfa036b 100644 --- a/include/functions.h +++ b/include/functions.h @@ -643,7 +643,7 @@ void CC_func_80387D4C(void); extern uintptr_t osVirtualToPhysical(void *addr); extern void *osPhysicalToVirtual(uintptr_t addr); -// GBI function prototypes (implementations in src/port/stub.c) +// GBI function prototypes void gSPSegment(void* value, int segNum, uintptr_t target); void gSPSegmentLoadRes(void* value, int segNum, uintptr_t target); void gSPDisplayList(Gfx* pkt, Gfx* dl); @@ -3044,16 +3044,30 @@ void lair_func_8038E768(Gfx **dl, Mtx **m, Vtx **v); // --- lair/jigsawpicture.c --- bool jigsawPicture_isJigsawPictureComplete(s32 arg0); -// --- port/stub.c --- +// --- port/OS/libultra.c --- s32 osContSetCh(u8 ch); u32 __osGetSR(void); void osCreateThread(OSThread* thread, OSId id, void* entry, void* arg, void* sp, OSPri p); void osDestroyThread(OSThread* thread); -void osDpSetStatus(u32 data); void osSetThreadPri(OSThread* thread, OSPri p); void osSpTaskYield(void); void osStartThread(OSThread* thread); void osStopThread(OSThread* t); +u32 bkGetSR(void); +float gu_sqrtf(float val); +void osViExtendVStart(u32 arg0); +OSYieldResult osSpTaskYielded(OSTask* task); +void __osError(s16 error_code, s16 num_args, ...); +s32 eeprom_readBlocks(s32 file, s32 offset, void* buffer, s32 count); +s32 eeprom_writeBlocks(s32 file, s32 offset, void* buffer, s32 count); + +// --- port/OS/OS_RCP.cpp --- +u32 osDpGetStatus(void); +void osDpSetStatus(u32 data); + +// --- port/OS/OS_VI.cpp --- +void* osViGetCurrentFramebuffer(void); +void* osViGetNextFramebuffer(void); // --- provided by libultraship --- s32 osPiReadIo(u32, u32 *); @@ -3156,9 +3170,6 @@ void spawnQueue_defrag(void); void bkmemcpy64(void *dest, void *src, s32 size); void bkmemset64(void *dest, s32 value, s32 size); -// --- port/stub.c --- -u32 bkGetSR(void); - // --- RBB/ch/engineparts.c --- f32 func_8038A6B8(ActorMarker *); @@ -3460,9 +3471,6 @@ Struct70s *func_8034C528(s32); Struct70s *func_8034C5AC(s32); s16 func_8034C50C(Struct70s *arg0); -// --- port/stub.c --- -float gu_sqrtf(float val); - // --- GV/gv_helpers.c --- void rubeeEggPot_addedEggToPot(void); s32 rubeeEggPot_getEggGoal(void); diff --git a/lib/ultralib/include/PR/gbi.h b/lib/ultralib/include/PR/gbi.h index 4b21795f9..052fb33a8 100644 --- a/lib/ultralib/include/PR/gbi.h +++ b/lib/ultralib/include/PR/gbi.h @@ -4579,7 +4579,7 @@ typedef union { #endif -// [port] Function declarations for GBI overrides in stub.c +// [port] Function declarations for GBI overrides in libultra.c // The decomp macros above are inside #if 0, so callers need prototypes // to avoid implicit-declaration truncation of 64-bit pointer arguments. #if defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) diff --git a/libultraship b/libultraship index f57f4d255..2917d0f4f 160000 --- a/libultraship +++ b/libultraship @@ -1 +1 @@ -Subproject commit f57f4d2552453cf330fb48f2d6f780137f33c221 +Subproject commit 2917d0f4fe62c579174561dcd34f327c9410bb72 diff --git a/src/core1/audio_manager.c b/src/core1/audio_manager.c index 62ff19f63..dce5f581a 100644 --- a/src/core1/audio_manager.c +++ b/src/core1/audio_manager.c @@ -7,6 +7,7 @@ //#include "PR/sched.h" #include "n_audio/PR/n_libaudio.h" //#include "PR/os_system.h" +#include "port/DevTools/ThreadWatchdog.h" #include "port/ShipUtils.h" #define DMA_BLOCK_SIZE VER_SELECT(0x200, 0x270, 0x200, 0x200) @@ -355,6 +356,7 @@ void audioManagerThread_entry(void *arg) { while (true) { osRecvMesg(&audioManager.audioFrameMsgQ, NULL, OS_MESG_BLOCK); + ThreadWatchdog_Beat(WATCHDOG_AUDIO_MANAGER); // [port] one beat per audio frame if (audioManager_handleFrameMsg(audioManager.audio_info[sAudioInfoID % 3], sPrevFinishedAudioInfo)) { if (skip_handle_done_mesg == 0) { osRecvMesg(&audioManager.audioReplyMsgQ, (OSMesg *) &D_80275844, OS_MESG_BLOCK); @@ -384,6 +386,12 @@ bool audioManager_handleFrameMsg(AudioInfo *info, AudioInfo *prev_info){ ret = 0; #endif + // [port] On N64 nothing could run concurrently with this thread: one core, + // and the game brackets its audio writes with osSetIntMask, which blocks + // preemption. On PC those brackets map to a lock, and the engine advance + // here has to take the same one. + port_lockAudio(); + outbuffer = (s16 *) osVirtualToPhysical(info->data); audioManager_func_802403F0(); audioManager_func_8023FFAC(); @@ -425,10 +433,12 @@ bool audioManager_handleFrameMsg(AudioInfo *info, AudioInfo *prev_info){ #endif if (command_list_len == 0) { + port_unlockAudio(); // [port] return false; } else { core1_15B30_addAudioTaskData(audioManager.ACMDList[sCmdBufferIndex], command_list_end, &audioManager.audioReplyMsgQ, OS_MESG_PTR(&info->reply_mesg_data)); // [port] OSMesg is a union on PC func_80250650(); + port_unlockAudio(); // [port] sCmdBufferIndex ^= 1; return true; } @@ -590,10 +600,14 @@ void audioManager_stopThread(void) { void audioManager_startThread(void) { if (!sAudioManagerThreadStarted) { sAudioManagerThreadStarted = true; - port_audioStartThread(); + osStartThread(&audioManager.thread); } } +OSMesgQueue *audioManager_getReplyMesgQueue(void) { + return &audioManager.audioReplyMsgQ; +} + OSThread *audioManager_getThread(void) { return &audioManager.thread; } diff --git a/src/core1/graphics_thread.c b/src/core1/graphics_thread.c index a164333cc..ea7dae3d2 100644 --- a/src/core1/graphics_thread.c +++ b/src/core1/graphics_thread.c @@ -7,6 +7,8 @@ #include #include "core1/core1.h" #include "functions.h" +#include "port/DevTools/ThreadWatchdog.h" +#include "port/Patches/Patches.h" #include "libultraship/libultra/rcp.h" #include "libultraship/libultra/sptask.h" #include "libultraship/libultra/types.h" @@ -90,11 +92,24 @@ static OSTimer sControllerTimer; static bool sEnableControllerTimer; void thread5_startNextAudioTask(void); +void osSpTaskLoad(OSTask* task); +void osSpTaskStartGo(OSTask* task); /* .code */ + +// [port] The queues are static; Game.cpp opts them into blocking before +// thread5_create runs. +OSMesgQueue* thread5_getTaskQueue(void) { + return &sThread5MesgQueue; +} +OSMesgQueue* thread5_getSyncQueue(void) { + return &sThread5SyncMesgQueue; +} + void thread5_sendTaskToQueue(OSMesg arg0) { static bool clear_freeze = true; + port_thread5_onSubmit(arg0.ptr); // [port] carry the interpolation pair with the task osSendMesg(&sThread5MesgQueue, arg0, 1); // Lighthouse [port] Adjustment here to account for our OSMesg union definition if (arg0.data32 == THREAD5_MESSAGE_EVENT_SYNC) { @@ -125,28 +140,29 @@ void thread5_insertGfxTaskData(OSMesg arg0) { } void thread5_startAudioTask(struct ucode_task_data_s *task_data) { -#if 0 +#if 0 // [port] microcode boot pointers, there is no RSP to load them into ucode_getPtrAndSize(&sAudTask.t.ucode_boot, &sAudTask.t.ucode_boot_size); sAudTask.t.ucode = n_aspMainTextStart; sAudTask.t.ucode_data = n_aspMainDataStart; +#endif sAudTask.t.data_ptr = (void*) task_data->data_ptr; - sAudTask.t.data_size = (task_data->data_ptr_end - task_data->data_ptr) >> 3 << 3; + sAudTask.t.data_size = ((u8 *)task_data->data_ptr_end - (u8 *)task_data->data_ptr) >> 3 << 3; osWritebackDCache(sAudTask.t.data_ptr , sAudTask.t.data_size); osWritebackDCache(&sAudTask, sizeof(OSTask)); sActiveAudioTaskDataPtr = task_data; osSpTaskLoad(&sAudTask); osSpTaskStartGo(&sAudTask); sUnkFlag1 = UNKFLAG1_AUDIO_TASK; -#endif } void thread5_startF3DEXTask(struct ucode_task_data_s *task_data) { -#if 0 +#if 0 // [port] microcode boot pointers, there is no RSP to load them into ucode_getPtrAndSize(&sGfxTask.t.ucode_boot, &sGfxTask.t.ucode_boot_size); sGfxTask.t.ucode = gSPF3DEX_fifoTextStart; sGfxTask.t.ucode_data = gSPF3DEX_fifoDataStart; +#endif sGfxTask.t.data_ptr = (void*) task_data->data_ptr; - sGfxTask.t.data_size = (task_data->data_ptr_end - task_data->data_ptr) >> 3 << 3; + sGfxTask.t.data_size = ((u8 *)task_data->data_ptr_end - (u8 *)task_data->data_ptr) >> 3 << 3; osWritebackDCache(sGfxTask.t.data_ptr , sGfxTask.t.data_size); osWritebackDCache(&sGfxTask, sizeof(OSTask)); osSpTaskLoad(&sGfxTask); @@ -157,16 +173,16 @@ void thread5_startF3DEXTask(struct ucode_task_data_s *task_data) { sUnkFlag2_Saved = sUnkFlag2; sUnkCounter3 = 30; } -#endif } void thread5_startL3DEXTask(struct ucode_task_data_s *task_data) { -#if 0 +#if 0 // [port] microcode boot pointers, there is no RSP to load them into ucode_getPtrAndSize(&sGfxTask.t.ucode_boot, &sGfxTask.t.ucode_boot_size); sGfxTask.t.ucode = gSPL3DEX_fifoTextStart; sGfxTask.t.ucode_data = gSPL3DEX_fifoDataStart; +#endif sGfxTask.t.data_ptr = (void*) task_data->data_ptr; - sGfxTask.t.data_size = (task_data->data_ptr_end - task_data->data_ptr) >> 3 << 3; + sGfxTask.t.data_size = ((u8 *)task_data->data_ptr_end - (u8 *)task_data->data_ptr) >> 3 << 3; osWritebackDCache(sGfxTask.t.data_ptr , sGfxTask.t.data_size); osWritebackDCache(&sGfxTask, sizeof(OSTask)); osSpTaskLoad(&sGfxTask); @@ -177,11 +193,9 @@ void thread5_startL3DEXTask(struct ucode_task_data_s *task_data) { sUnkFlag2_Saved = sUnkFlag2; sUnkCounter3 = 30; } -#endif } void thread5_startGfxTask(struct ucode_task_data_s *task_data) { -#if 0 switch (task_data->task_type) { case 1: thread5_startF3DEXTask(task_data); @@ -191,7 +205,6 @@ void thread5_startGfxTask(struct ucode_task_data_s *task_data) { thread5_startL3DEXTask(task_data); break; } -#endif } void thread5_handleAudioTaskMesg(OSMesg msg) { @@ -215,7 +228,6 @@ void thread5_handleL3DEXTaskMesg(OSMesg msg) { } void thread5_handleSyncEvent(void) { -#if 0 if ((sUnkFlag1 == UNKFLAG1_NO_TASK) && (sUnkFlag2_Saved == 2) && (sActiveGfxTaskDataID == sSelectedGfxTaskDataID) @@ -226,13 +238,11 @@ void thread5_handleSyncEvent(void) { else { sSyncCounter++; } -#endif } extern u64 osClockRate; void thread5_handleDPEvent(void) { -#if 0 if ((sUnkFlag2 << 1) < 0) { osDpSetStatus(DPC_SET_FREEZE); sCurrentFramebuffer = osViGetCurrentFramebuffer(); @@ -250,12 +260,9 @@ void thread5_handleDPEvent(void) { sSyncCounter--; } } -#endif } void thread5_handleVIRetraceEvent(void) { -#if 0 - static s32 audiotimer_trigger = 0; s32 sp2C = (sSyncCounter != 0) && (sActiveGfxTaskDataID == sSelectedGfxTaskDataID) && (sUnkFlag2 == 2) && (sUnkFlag1 == UNKFLAG1_NO_TASK); volatile s32 sp30; @@ -265,7 +272,7 @@ void thread5_handleVIRetraceEvent(void) { osDpSetStatus(DPC_CLR_FREEZE); sUnkFlag2_Saved = sUnkFlag2; - dummy_func_8025AFB8(); + // dummy_func_8025AFB8(); if (sUnkFlag2_Saved & 1) { sUnkCounter3 = 30; @@ -295,6 +302,7 @@ void thread5_handleVIRetraceEvent(void) { } } sTask7Handled = false; + static s32 audiotimer_trigger = 0; audiotimer_trigger++; if (!(audiotimer_trigger & 1)) { osStopTimer(&sAudioTimer); @@ -306,14 +314,12 @@ void thread5_handleVIRetraceEvent(void) { #if VERSION == VERSION_USA_1_0 osSetTimer(&sControllerTimer, ((osClockRate / 60)* 2) / 3, 0, &sThread5MesgQueue, OS_MESG_32(THREAD5_MESSAGE_EVENT_CONT_TIMER)); #elif VERSION == VERSION_PAL - osSetTimer(&sControllerTimer, ((osClockRate / 60.0)* 2) / 3, 0, &sThread5MesgQueue, THREAD5_MESSAGE_EVENT_CONT_TIMER); + osSetTimer(&sControllerTimer, ((osClockRate / 60.0)* 2) / 3, 0, &sThread5MesgQueue, OS_MESG_32(THREAD5_MESSAGE_EVENT_CONT_TIMER)); #endif } -#endif } void thread5_handleSPEvent(void) { -#if 0 struct ucode_task_data_s *active_audio_task; s32 temp_v1; @@ -328,7 +334,10 @@ void thread5_handleSPEvent(void) { } if (sUnkFlag1 == UNKFLAG1_AUDIO_TASK) { - osSendMesg(&sActiveAudioTaskDataPtr->task_type, sActiveAudioTaskDataPtr->unk4, 0); + // [port] The raw decomp sends through the first two struct fields; + // with the struct typed, these are the reply queue and message set by + // core1_15B30_addAudioTaskData. + osSendMesg(sActiveAudioTaskDataPtr->audio_mesg_queue, sActiveAudioTaskDataPtr->audio_mesg, 0); } if ((sUnkFlag1 == UNKFLAG1_AUDIO_TASK) && (sGfxTaskYielded != 0)) { @@ -350,7 +359,6 @@ void thread5_handleSPEvent(void) { osSendMesgPtr(&sThread5SyncMesgQueue, NULL, 0); sSyncCounter--; } -#endif } void thread5_handleTask7Mesg(OSMesg arg0) { @@ -358,6 +366,11 @@ void thread5_handleTask7Mesg(OSMesg arg0) { } void thread5_handleAudioTimerEvent(void) { + // [port] While the demo audio hold is up, skip the frame message so the + // engine does not consume sfx cues queued for the demo's first frame. + if (port_audioHeld()) { + return; + } osSendMesgPtr(audioManager_getFrameMesgQueue(), NULL, OS_MESG_NOBLOCK); thread5_startNextAudioTask(); } @@ -466,40 +479,43 @@ void thread5_checkAndExecutePreNMI(void) { //thread5 entry void thread5_entry(void *arg) { -#if 0 - OSMesg msg = NULL; + // [port] Only adjustment: OSMesg is a union here, + // so event words read through .data32 and tasks through .ptr + OSMesg msg; + msg.ptr = NULL; do { osRecvMesg(&sThread5MesgQueue, &msg, OS_MESG_BLOCK); + ThreadWatchdog_Beat(WATCHDOG_THREAD5); // [port] one beat per serviced message thread5_checkAndExecutePreNMI(); - if ((s32)msg == THREAD5_MESSAGE_EVENT_SYNC) { thread5_handleSyncEvent(); } - else if ((u32)msg == THREAD5_MESSAGE_EVENT_VI_RETRACE) { thread5_handleVIRetraceEvent(); } - else if ((u32)msg == THREAD5_MESSAGE_EVENT_DP) { thread5_handleDPEvent(); } - else if ((u32)msg == THREAD5_MESSAGE_EVENT_SP) { thread5_handleSPEvent(); } - else if ((u32)msg == THREAD5_MESSAGE_EVENT_AUDIO_TIMER) { thread5_handleAudioTimerEvent(); } - else if ((u32)msg == THREAD5_MESSAGE_EVENT_FAULT) { do{}while(1); } - else if ((u32)msg == THREAD5_MESSAGE_EVENT_PRENMI) { thread5_handlePreNMIEvent(); } - else if ((u32)msg == THREAD5_MESSAGE_EVENT_DEBUG) { } - else if ((u32)msg == THREAD5_MESSAGE_EVENT_CONT_TIMER) { pfsManager_getStartReadData(); } - else if ((u32)msg >= 100) { - if (((struct ucode_task_data_s *)msg)->task_type == UCODE_TASK_TYPE_AUDIO) { thread5_handleAudioTaskMesg(msg); } - else if (((struct ucode_task_data_s *)msg)->task_type == UCODE_TASK_TYPE_F3DEX) { thread5_handleF3DEXTaskMesg(msg); } - else if (((struct ucode_task_data_s *)msg)->task_type == UCODE_TASK_TYPE_L3DEX) { thread5_handleL3DEXTaskMesg(msg); } - else if (((struct ucode_task_data_s *)msg)->task_type == UCODE_TASK_TYPE_FRAMEBUFFER_CHANGED) { thread5_handleTask7Mesg(msg); } + if ((uintptr_t)msg.ptr < 100) { + if (msg.data32 == THREAD5_MESSAGE_EVENT_SYNC) { thread5_handleSyncEvent(); } + else if (msg.data32 == THREAD5_MESSAGE_EVENT_VI_RETRACE) { thread5_handleVIRetraceEvent(); } + else if (msg.data32 == THREAD5_MESSAGE_EVENT_DP) { thread5_handleDPEvent(); } + else if (msg.data32 == THREAD5_MESSAGE_EVENT_SP) { thread5_handleSPEvent(); } + else if (msg.data32 == THREAD5_MESSAGE_EVENT_AUDIO_TIMER) { thread5_handleAudioTimerEvent(); } + else if (msg.data32 == THREAD5_MESSAGE_EVENT_FAULT) { do{}while(1); } + else if (msg.data32 == THREAD5_MESSAGE_EVENT_PRENMI) { thread5_handlePreNMIEvent(); } + else if (msg.data32 == THREAD5_MESSAGE_EVENT_DEBUG) { } + else if (msg.data32 == THREAD5_MESSAGE_EVENT_CONT_TIMER) { pfsManager_getStartReadData(); } + } + else { + if (((struct ucode_task_data_s *)msg.ptr)->task_type == UCODE_TASK_TYPE_AUDIO) { thread5_handleAudioTaskMesg(msg); } + else if (((struct ucode_task_data_s *)msg.ptr)->task_type == UCODE_TASK_TYPE_F3DEX) { thread5_handleF3DEXTaskMesg(msg); } + else if (((struct ucode_task_data_s *)msg.ptr)->task_type == UCODE_TASK_TYPE_L3DEX) { thread5_handleL3DEXTaskMesg(msg); } + else if (((struct ucode_task_data_s *)msg.ptr)->task_type == UCODE_TASK_TYPE_FRAMEBUFFER_CHANGED) { thread5_handleTask7Mesg(msg); } } } while (1); -#endif } //thread5 create void thread5_create(void) { -#if 0 u8 *yield_data_ptr; - osCreateMesgQueue(&sThread5MesgQueue, &sThread5MesgBuffer, 20); - osCreateMesgQueue(&sThread5SyncMesgQueue, &sThread5SyncMesgBufer, 10); - osSetEventMesg(OS_EVENT_DP, &sThread5MesgQueue, THREAD5_MESSAGE_EVENT_DP); - osSetEventMesg(OS_EVENT_SP, &sThread5MesgQueue, THREAD5_MESSAGE_EVENT_SP); - osSetEventMesg(OS_EVENT_FAULT, &sThread5MesgQueue, THREAD5_MESSAGE_EVENT_FAULT); - osSetEventMesg(OS_EVENT_PRENMI, &sThread5MesgQueue, THREAD5_MESSAGE_EVENT_PRENMI); + osCreateMesgQueue(&sThread5MesgQueue, sThread5MesgBuffer, 20); + osCreateMesgQueue(&sThread5SyncMesgQueue, sThread5SyncMesgBufer, 10); + osSetEventMesg(OS_EVENT_DP, &sThread5MesgQueue, OS_MESG_32(THREAD5_MESSAGE_EVENT_DP)); + osSetEventMesg(OS_EVENT_SP, &sThread5MesgQueue, OS_MESG_32(THREAD5_MESSAGE_EVENT_SP)); + osSetEventMesg(OS_EVENT_FAULT, &sThread5MesgQueue, OS_MESG_32(THREAD5_MESSAGE_EVENT_FAULT)); + osSetEventMesg(OS_EVENT_PRENMI, &sThread5MesgQueue, OS_MESG_32(THREAD5_MESSAGE_EVENT_PRENMI)); viMgr_registerSignalMesg(&sThread5MesgQueue, OS_MESG_32(THREAD5_MESSAGE_EVENT_VI_RETRACE)); sSyncCounter = 0; sTask7Handled = 0; @@ -516,7 +532,6 @@ void thread5_create(void) { sGfxTask.t.yield_data_ptr = (u64 *) yield_data_ptr; osCreateThread(&sThread5, THREAD5_ID, thread5_entry, NULL, &sThread5Stack[2048], THREAD5_PRI); osStartThread(&sThread5); -#endif } void thread5_enableControllerTimer(void) { @@ -539,3 +554,20 @@ OSMesgQueue *__thread5_getMessageQueue(void) { OSThread *__thread5_getThreadObject(void) { return &sThread5; } + +// [port] Watchdog diagnostics: unsynchronized snapshot of the pipeline state. +void thread5_getWatchdogState(Thread5WatchdogState *out) { + out->unkFlag1 = sUnkFlag1; + out->unkFlag2 = sUnkFlag2; + out->unkFlag2Saved = sUnkFlag2_Saved; + out->syncCounter = sSyncCounter; + out->task7Handled = sTask7Handled; + out->gfxActiveId = sActiveGfxTaskDataID; + out->gfxSelectedId = sSelectedGfxTaskDataID; + out->audioActiveId = sActiveAudioTaskDataID; + out->audioSelectedId = sSelectedAudioTaskDataID; + out->taskQueueCount = sThread5MesgQueue.validCount; + out->taskQueueCap = sThread5MesgQueue.msgCount; + out->syncQueueCount = sThread5SyncMesgQueue.validCount; + out->syncQueueCap = sThread5SyncMesgQueue.msgCount; +} diff --git a/src/core1/pfsmanager.c b/src/core1/pfsmanager.c index b91107670..a7f747c14 100644 --- a/src/core1/pfsmanager.c +++ b/src/core1/pfsmanager.c @@ -9,6 +9,7 @@ #include "version.h" #include "checksums.h" +#include "port/DevTools/ThreadWatchdog.h" #include "port/Patches/Patches.h" #define PFSMANAGER_THREAD_STACK_SIZE 0x200 @@ -165,10 +166,9 @@ void pfsManager_update(void) { osSetThreadPri(0, 0x29); - // [port] On N64, pfsManager_getStartReadData() is called from the RSP/GFX thread - // (code_8C50.c:490) which is #if 0'd on PC. Without it, pfsManagerBusy is never set, - // pfsManager_readData() never fires, and osContGetReadData() never fills the pad data. - // Poll LUS input directly here each frame instead. + // [port] Re-read the latched transaction so the pad data is stable for the + // whole tick; the SI completes reads at its own cadence, and the shaping + // below rewrites this buffer in place. osContGetReadData(pfsManagerContPadData); // [port] Control-scheme input shaping: right stick -> C-button conversion, @@ -301,14 +301,13 @@ void pfsManager_update(void) { void pfsManager_readData(){ func_8024F35C(0); - if(!pfsManagerContStatus.err_no) - osContGetReadData(pfsManagerContPadData); } void pfsManager_entry(void *arg) { do { osRecvMesg(&pfsManagerContPollingMsqQ, 0, 1); + ThreadWatchdog_Beat(WATCHDOG_PFSMANAGER); // [port] one beat per SI completion if(pfsManagerBusy == true){ pfsManager_readData(); } @@ -398,15 +397,24 @@ OSMesgQueue *pfsManager_getFrameMesgQ(void){ return &pfsManagerContPollingMsqQ; } +// [port] Watchdog diagnostics: the SI event-registration lock queue +// (func_8024F450 parks here), so blocked waits get a name. +OSMesgQueue *pfsManager_getSiLockQueue(void){ + return &D_802816E8; +} + void func_8024F35C(s32 arg0) { if(!arg0) func_8024F4AC(); else func_8024F450(); - +#if 0 if(arg0 || D_802816E8.validCount == 1){ pfsManagerBusy = arg0; } +#endif + // [port] Rumble safety, don't rely on the OSMesgQueue + pfsManagerBusy = arg0; } bool pfsManager_isBusy(void){ diff --git a/src/core1/vimgr.c b/src/core1/vimgr.c index 928ed8d2e..39ce4d322 100644 --- a/src/core1/vimgr.c +++ b/src/core1/vimgr.c @@ -6,7 +6,9 @@ #include "version.h" #include "libultraship/libultra/rcp.h" +#include "port/DevTools/ThreadWatchdog.h" #include "port/Patches/Patches.h" +#include "port/OS/OS.h" #define VIMANAGER_THREAD_STACK_SIZE 0x400 @@ -139,6 +141,9 @@ void viMgr_init(void) { osCreateMesgQueue(&sMesgQueue2, sMesgBuffer2, 1); osCreateMesgQueue(&sMesgQueue3, sMesgBuffer3, FRAMERATE); osViSetEvent(&sMesgQueue1, OS_MESG_PTR(NULL), 1); + OS_SetQueueBlocking(&sMesgQueue1, 1); // viMgr_entry parks here between retraces + OS_SetQueueBlocking(&sMesgQueue2, 1); // the tick parks here for the frame token + OS_SetQueueBlocking(&sMesgQueue3, 1); // and here for its retraces sActiveFramebuffer = 0; D_80280724 = 1; @@ -174,10 +179,9 @@ void viMgr_func_8024BFD8(s32 arg0){ // During demo playback, sDemoViCount includes the N64's original rendering lag // for maps that ran slow, which the zoombox dialog system needs to pace text. s32 demoVi = port_getDemoViCount(); - D_80280724 = (demoVi > 0) ? demoVi : time_getDeltaReal_frames(); -#if 0 static s32 D_80280E90; - + s32 viBudget = (!func_802E4A08() && demoVi > 2) ? demoVi : 2; + osSetThreadPri(NULL, 0x7f); defragManager_setPriority(DEFRAGMANAGER_THREAD_PRIORITY_HIGH); defragManager_resume(); @@ -185,26 +189,25 @@ void viMgr_func_8024BFD8(s32 arg0){ osRecvMesg(&sMesgQueue2, NULL, OS_MESG_BLOCK); } - while(D_802808D8 < viMgr_func_8024BFA0() - D_80280E90){ + while(D_802808D8 < viBudget - D_80280E90){ osRecvMesg(&sMesgQueue3, NULL, OS_MESG_BLOCK); } while(sMesgQueue3.validCount){ osRecvMesg(&sMesgQueue3, NULL, OS_MESG_NOBLOCK); } - + osViSwapBuffer(gFramebuffers[sActiveFramebuffer = getOtherFramebuffer()]); D_80280E90 = 0; while(!(osDpGetStatus() & 2) && osViGetCurrentFramebuffer() != osViGetNextFramebuffer()){ osRecvMesg(&sMesgQueue3, NULL, OS_MESG_BLOCK); D_80280E90++; }//L8024C178 - D_80280724 = D_802808D8; + D_80280724 = (demoVi > 0) ? demoVi : D_802808D8; D_802808D8 = 0; defragManager_pause(); osSetThreadPri(NULL, 0x14); defragManager_setPriority(DEFRAGMANAGER_THREAD_PRIORITY); -#endif } void viMgr_func_8024C1B4(void){ @@ -237,6 +240,7 @@ void viMgr_entry(void *arg0){ OSMesg sp48; do{ osRecvMesg(&sMesgQueue1, &sp48, OS_MESG_BLOCK); + ThreadWatchdog_Beat(WATCHDOG_VIMGR); // [port] one beat per retrace thread5_checkAndExecutePreNMI(); D_802808D8++; if(D_802808D8 == 420){ @@ -256,7 +260,6 @@ void viMgr_entry(void *arg0){ void viMgr_setScreenBlack(s32 active) { osViBlack(active); - port_setViBlack(active); } void viMgr_clearFramebuffers(void) { @@ -271,6 +274,25 @@ s32 viMgr_func_8024C4E8(void) { return D_802808D8; } +// [port] Watchdog diagnostics: unsynchronized snapshot of the pacing state. +void viMgr_getWatchdogState(ViMgrWatchdogState *out) { + out->retraceCount = D_802808D8; + out->q1Count = sMesgQueue1.validCount; + out->q2Count = sMesgQueue2.validCount; + out->q3Count = sMesgQueue3.validCount; +} + +// [port] Watchdog diagnostics: queue identities, so blocked waits get names. +OSMesgQueue *viMgr_getRetraceQueue(void) { + return &sMesgQueue1; +} +OSMesgQueue *viMgr_getFrameTokenQueue(void) { + return &sMesgQueue2; +} +OSMesgQueue *viMgr_getTickRetraceQueue(void) { + return &sMesgQueue3; +} + void viMgr_func_8024C4F8(s32 arg0) { D_802808D8 = arg0; } diff --git a/src/core2/actor_cubepropsystem.c b/src/core2/actor_cubepropsystem.c index 77c0c5bc1..46d95face 100644 --- a/src/core2/actor_cubepropsystem.c +++ b/src/core2/actor_cubepropsystem.c @@ -156,6 +156,9 @@ void __cube_sort(Cube *cube, bool global) { } //sort prop list + // [port] Cancelled by PerfPatches.cpp, which sorts the same distances + // with a stable insertion sort instead of this exchange sort. + if (EventSystem_Should(VB_CUBE_PROP_SORT, true, cube)) { start_prop = cube->prop2Ptr; var_t0 = cube->prop2Ptr + (cube->prop2Cnt - 1); do { @@ -194,6 +197,7 @@ void __cube_sort(Cube *cube, bool global) { i++; } } while (start_prop != NULL); + } code_A5BC0_initCubePropActorProp(cube); } } diff --git a/src/core2/frame/auxbuffer.c b/src/core2/frame/auxbuffer.c index 05e9808af..aa62a9546 100644 --- a/src/core2/frame/auxbuffer.c +++ b/src/core2/frame/auxbuffer.c @@ -8,13 +8,23 @@ int gfx_create_framebuffer(unsigned int width, unsigned int height, unsigned int native_width, unsigned int native_height, unsigned char resize, bool force_fixed_aspect); +#include "port/Patches/Patches.h" + s32 sAuxGpuFbId = -1; +// [port] Renderer call; runs on the render thread under thread5 mode. +static void __auxbuffer_createGpuFb(void* arg); + #define TILE_SIZE 32 #define TILE_COUNT_X 5 #define TILE_COUNT_Y 4 #define IMAGE_WIDTH (TILE_SIZE * TILE_COUNT_X) #define IMAGE_HEIGHT (TILE_SIZE * TILE_COUNT_Y) + +static void __auxbuffer_createGpuFb(void* arg) { + (void)arg; + sAuxGpuFbId = gfx_create_framebuffer(IMAGE_WIDTH, IMAGE_HEIGHT, IMAGE_WIDTH, IMAGE_HEIGHT, 0, 0); +} #define SCREEN_WIDTH 292 #define SCREEN_HEIGHT 216 #define HORIZONTAL_MARGIN (((SCREEN_WIDTH) - IMAGE_WIDTH) / 2) @@ -63,7 +73,7 @@ void picturebox_init(void) { } } if (sAuxGpuFbId < 0) { - sAuxGpuFbId = gfx_create_framebuffer(IMAGE_WIDTH, IMAGE_HEIGHT, IMAGE_WIDTH, IMAGE_HEIGHT, 0, 0); + port_runOnRenderThread(__auxbuffer_createGpuFb, NULL); } } diff --git a/src/core2/frame/texture_capture.c b/src/core2/frame/texture_capture.c index cd6140bd1..51b7c1070 100644 --- a/src/core2/frame/texture_capture.c +++ b/src/core2/frame/texture_capture.c @@ -4,8 +4,16 @@ #include "functions.h" #include "variables.h" +#include "port/Patches/Patches.h" + extern void gfx_texture_cache_clear(void); +// [port] The texture cache belongs to the renderer; marshal the clear. +static void __textureCacheClearFn(void* arg) { + (void)arg; + gfx_texture_cache_clear(); +} + u8 *textureList_getDataPtr(BKTextureList *texture_list); void model_copyFramebufferBlockToTexture(BKTextureList *texture_list, s32 indx, s32 x_offset, s32 y_offset){ @@ -35,6 +43,10 @@ void model_copyFramebufferToTextures(BKModelBin *model_bin){ s32 x, y; texture_list = modelbin_getTextureList(model_bin); + // [port] The blocks below read the rendered frame from the CPU-side + // buffer, so the frame this tick submitted has to be drawn first. One + // sync covers the whole capture. + port_pipelineSyncPoint(); osInvalDCache((void *)gFramebuffers[getActiveFramebuffer()], gFramebufferWidth * gFramebufferHeight*2); for(y = 0; y < 8; y++){ @@ -47,5 +59,5 @@ void model_copyFramebufferToTextures(BKModelBin *model_bin){ // [port] The CPU just modified texture data that LUS may have cached on the GPU. // Clear the texture cache so the next draw re-uploads from CPU memory. - gfx_texture_cache_clear(); + port_runOnRenderThread(__textureCacheClearFn, NULL); } diff --git a/src/core2/fx/weather_snow.c b/src/core2/fx/weather_snow.c index cf10f14db..7148b5046 100644 --- a/src/core2/fx/weather_snow.c +++ b/src/core2/fx/weather_snow.c @@ -240,8 +240,12 @@ bool func_802F989C(Gfx **gfx, Mtx **mtx, f32 arg2[3]) { mlMtxApply(*mtx); mlMtx_apply_vec3f_restricted(D_80381080, D_80381094->unkC); func_80251B5C(D_80381080[0], D_80381080[1], D_80381080[2]); - mlMtx_rotate_yaw_deg(D_80381060[1]); - mlMtx_rotate_pitch_deg(D_80381060[0]); + // [port] Cancelled by PerfPatches.cpp, which applies the same rotations + // with the trig cached across flakes. + if (EventSystem_Should(VB_SNOW_CAMERA_ROTATION, true, D_80381060)) { + mlMtx_rotate_yaw_deg(D_80381060[1]); + mlMtx_rotate_pitch_deg(D_80381060[0]); + } func_80252A38(-(D_80381094->unkC[0]), -(D_80381094->unkC[1]), -(D_80381094->unkC[2])); mlMtxApply(*mtx); gSPMatrix((*gfx)++, (*mtx)++, G_MTX_PUSH | G_MTX_LOAD | G_MTX_MODELVIEW); diff --git a/src/core2/gameSelect.c b/src/core2/gameSelect.c index 019afc1e4..98c6ae72f 100644 --- a/src/core2/gameSelect.c +++ b/src/core2/gameSelect.c @@ -617,7 +617,6 @@ void gameSelect_update(Actor *this){ ); if(this->marker->unk14_21) { osViBlack(0); - port_setViBlack(0); } }//L802C5734 } diff --git a/src/core2/model/modelRender.c b/src/core2/model/modelRender.c index dfd193f1f..8b25efc4c 100644 --- a/src/core2/model/modelRender.c +++ b/src/core2/model/modelRender.c @@ -959,8 +959,10 @@ void modelRender_geoCmd_DRAWDIST(Gfx ** gfx, Mtx ** mtx, struct bk_geo_cmd_s *ar sp20[2] = (f32)cmd->unkE[2] * modelRenderScale; // [port] The N64 bounding boxes in CmdD_DRAW_DISTANCE are too conservative // for the port's viewport (292x216 -> 320x240 at 4:3). Extend to all aspect - //ratios since the port always renders at a higher effective resolution. - modelRender_executeGeoCmds(gfx, mtx, (BKGeoCmd*)((u8*)cmd + cmd->unk14)); + // ratios since the port always renders at a higher effective resolution. + if (EventSystem_Should(VB_DRAWDIST_BOX_CULL, true, sp2C, sp20)) { + modelRender_executeGeoCmds(gfx, mtx, (BKGeoCmd*)((u8*)cmd + cmd->unk14)); + } } } diff --git a/src/core2/vla.c b/src/core2/vla.c index 5fc9ff726..d8c6e284a 100644 --- a/src/core2/vla.c +++ b/src/core2/vla.c @@ -81,7 +81,9 @@ void bk_vector_remove(VLA *this, u32 indx){ uintptr_t nextOffset = (uintptr_t)this->begin + (indx + 1) * this->elem_size;\ uintptr_t size = (uintptr_t)this->end - (uintptr_t)this->begin; - memcpy((void *)elemOffset, (void *)nextOffset, size - (indx + 1) * this->elem_size); + // [port] source and destination overlap when removing anywhere but the tail; + // memcpy on overlapping buffers is UB on PC toolchains. + memmove((void *)elemOffset, (void *)nextOffset, size - (indx + 1) * this->elem_size); this->end = (void *)((uintptr_t)this->end - this->elem_size); } diff --git a/src/core2/vtx/gclights.c b/src/core2/vtx/gclights.c index 4ec7b3eb3..67f3e0b65 100644 --- a/src/core2/vtx/gclights.c +++ b/src/core2/vtx/gclights.c @@ -233,6 +233,12 @@ void gclights_recolor_vertices(BKVertexList *vertex_list, f32 position[3], f32 r ref_ptr = vtxList_getVertices(ref_vertex_list); vtxList_getVtxRange(vertex_list, &i_ptr, &end_ptr); + // [port] Cancelled by PerfPatches.cpp, which runs this same loop with a + // squared-distance early-out so out-of-range lights never pay the sqrt. + if (!EventSystem_Should(VB_GCLIGHTS_RECOLOR, true, i_ptr, end_ptr, ref_ptr, &sLightingbk_vectorList.unk4[0], + sLightingbk_vectorList.unk44)) { + return; + } for(i_ptr = i_ptr; i_ptr < end_ptr; i_ptr++, ref_ptr++) { rgb_modifier[0] = rgb_modifier[1] = rgb_modifier[2] = 0.0f; TUPLE_COPY(vtx_position, ref_ptr->v.ob); diff --git a/src/port/Audio/mixer.h b/src/port/Audio/mixer.h index 4420a159a..c7358a110 100644 --- a/src/port/Audio/mixer.h +++ b/src/port/Audio/mixer.h @@ -36,20 +36,20 @@ void aSetVolumeImpl(uint8_t flags, int16_t v, int16_t t, int16_t r); void aPoleFilterImpl(uint8_t flags, uint16_t gain, uint8_t dmem_shift, void* state); void aDisableImpl(uint16_t outp, uint32_t b, uint32_t c); -#define aDisable(pkt, o, b, c) aDisableImpl(o, b, c) -#define aClearBuffer(pkt, d, c) aClearBufferImpl(d, c) -#define aLoadBuffer(pkt, c, d, s) aLoadBufferImpl((void*)(s), d, c) -#define aSaveBuffer(pkt, c, s, d) aSaveBufferImpl(s, (int16_t*)(d), c) -#define aLoadADPCM(pkt, c, d) aLoadADPCMImpl(c, (int16_t*)(d)) -#define aDMEMMove(pkt, i, o, c) aDMEMMoveImpl(i, o, c) -#define aSetLoop(pkt, a) aSetLoopImpl((void*)(a)) -#define aADPCMdec(pkt, s, f, c, i, o) aADPCMdecImpl(f, (void*)(s), c, i, o) -#define aResample(pkt, s, f, p, i, o) aResampleImpl(f, p, (void*)(s), i, o) -#define aInterleave(pkt) aInterleaveImpl() -#define aMix(pkt, f, g, i, o) aMixImpl(f, g, i, o) -#define aEnvMixer(pkt, f, t, s) aEnvMixerImpl(f, (void*)(s), t) -#define aSetVolume(pkt, f, v, t, r) aSetVolumeImpl(f, v, t, r) -#define aPoleFilter(pkt, f, g, t, s) aPoleFilterImpl(f, g, t, s) -#define aPlayMP3(pkt, a, b, c, r) aPlayMP3Impl((void*)(a), b, (void*)(c), r) +#define aDisable(pkt, o, b, c) ((void)(pkt), aDisableImpl(o, b, c)) +#define aClearBuffer(pkt, d, c) ((void)(pkt), aClearBufferImpl(d, c)) +#define aLoadBuffer(pkt, c, d, s) ((void)(pkt), aLoadBufferImpl((void*)(s), d, c)) +#define aSaveBuffer(pkt, c, s, d) ((void)(pkt), aSaveBufferImpl(s, (int16_t*)(d), c)) +#define aLoadADPCM(pkt, c, d) ((void)(pkt), aLoadADPCMImpl(c, (int16_t*)(d))) +#define aDMEMMove(pkt, i, o, c) ((void)(pkt), aDMEMMoveImpl(i, o, c)) +#define aSetLoop(pkt, a) ((void)(pkt), aSetLoopImpl((void*)(a))) +#define aADPCMdec(pkt, s, f, c, i, o) ((void)(pkt), aADPCMdecImpl(f, (void*)(s), c, i, o)) +#define aResample(pkt, s, f, p, i, o) ((void)(pkt), aResampleImpl(f, p, (void*)(s), i, o)) +#define aInterleave(pkt) ((void)(pkt), aInterleaveImpl()) +#define aMix(pkt, f, g, i, o) ((void)(pkt), aMixImpl(f, g, i, o)) +#define aEnvMixer(pkt, f, t, s) ((void)(pkt), aEnvMixerImpl(f, (void*)(s), t)) +#define aSetVolume(pkt, f, v, t, r) ((void)(pkt), aSetVolumeImpl(f, v, t, r)) +#define aPoleFilter(pkt, f, g, t, s) ((void)(pkt), aPoleFilterImpl(f, g, t, s)) +#define aPlayMP3(pkt, a, b, c, r) ((void)(pkt), aPlayMP3Impl((void*)(a), b, (void*)(c), r)) #endif diff --git a/src/port/DevTools/ThreadWatchdog.cpp b/src/port/DevTools/ThreadWatchdog.cpp new file mode 100644 index 000000000..e38c1b028 --- /dev/null +++ b/src/port/DevTools/ThreadWatchdog.cpp @@ -0,0 +1,545 @@ +#include "ThreadWatchdog.h" + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "port/OS/OS.h" + +#if defined(_WIN32) +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#ifndef NOMINMAX +#define NOMINMAX +#endif +#include +#include +#pragma comment(lib, "dbghelp.lib") +#define LH_WATCHDOG_STACKS 1 +#endif + +extern "C" { +#include "libultraship/libultra/types.h" +#include "libultraship/libultra/message.h" +u32 osDpGetStatus(void); +void* osViGetCurrentFramebuffer(void); +void* osViGetNextFramebuffer(void); +OSMesgQueue* thread5_getTaskQueue(void); +OSMesgQueue* thread5_getSyncQueue(void); +OSMesgQueue* pfsManager_getFrameMesgQ(void); +OSMesgQueue* pfsManager_getFrameReplyQ(void); +OSMesgQueue* pfsManager_getSiLockQueue(void); +int pfsManager_isBusy(void); +OSMesgQueue* audioManager_getFrameMesgQueue(void); +OSMesgQueue* audioManager_getReplyMesgQueue(void); +OSMesgQueue* viMgr_getRetraceQueue(void); +OSMesgQueue* viMgr_getFrameTokenQueue(void); +OSMesgQueue* viMgr_getTickRetraceQueue(void); +int port_audioHeld(void); +int port_renderServicePending(void); +// Repro context +int gsworld_getMap(void); +int gsworld_getExit(void); +int getGameMode(void); +extern char gBuildVersion[]; +extern char gGitBranch[]; +extern char gGitCommitHash[]; +} + +namespace { + +using Clock = std::chrono::steady_clock; + +constexpr const char* kThreadNames[WATCHDOG_NUM_THREADS] = { + "vi-ticker", "main-loop", "game-tick", "thread5", "vimgr", "pfsmanager", "audio-mgr", +}; + +// Blocking points in each loop that are not message-queue waits. A stall with +// no queue park is in one of these; naming them gives the reader somewhere to +// look when no symbols were available to resolve a stack. +constexpr const char* kThreadNonQueueWaits[WATCHDOG_NUM_THREADS] = { + "sleep_until; OS_SendEventMesg -> sMesgMutex", + "HandleEvents (SDL/window), ProcessGfxCommands (renderer present/DXGI wait), DrainRenderService callback, " + "OS_SiService -> ControlDeck", + "port_runOnRenderThread sSvcCv handoff; port_lockAudio (gAudioLock); ProcessGfxCommands std::async waits; " + "map-load I/O", + "sMesgMutex; a handler blocking in osSendMesg on a full queue", + "sMesgMutex", + "func_8024F450 -> D_802816E8 wait; port_shapeControllerInput; CALL_EVENT(OnControllerUpdate)", + "port_lockAudio (gAudioLock) in audioManager_handleFrameMsg", +}; + +// Entry point each heartbeat belongs to. +constexpr const char* kThreadLoops[WATCHDOG_NUM_THREADS] = { + "osCreateViManager ticker (OS_VI.cpp)", + "SDL_main service loop (Game.cpp)", + "push_frame -> mainLoop (Game.cpp)", + "thread5_entry (graphics_thread.c)", + "viMgr_entry (vimgr.c)", + "pfsManager_entry (pfsmanager.c)", + "audioManagerThread_entry (audio_manager.c)", +}; + +// The audio thread legitimately idles through demo audio holds, and the +// pfsmanager thread races the game tick for the same polling queue, so both +// get a longer leash than the frame-paced threads. +constexpr auto kStallAfter = std::chrono::seconds(5); +constexpr auto kRelaxedStallAfter = std::chrono::seconds(10); +constexpr auto kSampleEvery = std::chrono::milliseconds(500); +constexpr auto kRedumpEvery = std::chrono::seconds(10); + +struct Heartbeat { + std::atomic count{ 0 }; + std::atomic tid{ 0 }; // SDL thread id, recorded on first beat + // Real (non-pseudo) thread handle, so the watcher can walk this thread's + // stack when it stalls. Recorded on first beat alongside the tid. + std::atomic handle{ nullptr }; + // Watcher-thread state + uint64_t lastCount = 0; + Clock::time_point lastBeat{}; + bool started = false; +}; + +Heartbeat sBeats[WATCHDOG_NUM_THREADS]; +std::atomic sStalledFlags[WATCHDOG_NUM_THREADS] = {}; +std::thread sWatcher; +std::atomic sWatcherRun{ false }; + +std::string DescribeUnkFlag1(int32_t f) { + switch (f) { + case 0x04: + return "AUDIO_TASK"; + case 0x10: + return "NO_TASK"; + case 0x20: + return "TASK_YIELDED"; + default: + break; + } + if (f & 0x08) { + return fmt::format("GFX_TASK|{:#x}", f & ~0x08); + } + return fmt::format("{:#x}?", f); +} + +std::string HumanDuration(std::chrono::milliseconds ms) { + if (ms.count() < 1000) { + return fmt::format("{}ms", ms.count()); + } + return fmt::format("{:.1f}s", ms.count() / 1000.0); +} + +// A queue's name and its producers, so a blocked wait names the code to audit. +struct QueueInfo { + bool known; + const char* name; + const char* fedBy; +}; + +QueueInfo DescribeQueue(OSMesgQueue* mq) { + if (mq == thread5_getTaskQueue()) { + return { true, "sThread5MesgQueue (graphics_thread.c)", + "thread5_sendTaskToQueue, osSetTimer cbs, viMgr_entry retrace, OS_SendEventMesg(SP/DP) from " + "ServiceRcp" }; + } + if (mq == thread5_getSyncQueue()) { + return { true, "sThread5SyncMesgQueue (graphics_thread.c)", + "thread5_handleSyncEvent/handleDPEvent/handleSPEvent/handleVIRetraceEvent; all need " + "sUnkFlag1==NO_TASK + gfx ring drained" }; + } + if (mq == viMgr_getRetraceQueue()) { + return { true, "sMesgQueue1 (vimgr.c)", "OS_VI ticker via OS_EVENT_VI" }; + } + if (mq == viMgr_getFrameTokenQueue()) { + return { true, "sMesgQueue2 (vimgr.c)", + "viMgr_func_8024BFAC <- thread5_handleDPEvent (needs sUnkFlag2 bit30), func_80253FE8" }; + } + if (mq == viMgr_getTickRetraceQueue()) { + return { true, "sMesgQueue3 (vimgr.c)", "viMgr_entry" }; + } + if (mq == pfsManager_getFrameMesgQ()) { + return { true, "pfsManagerContPollingMsqQ (pfsmanager.c)", + "OS_EVENT_SI <- OS_SiService (window thread) after osContStartReadData" }; + } + if (mq == pfsManager_getFrameReplyQ()) { + return { true, "pfsManagerContReplyMsgQ (pfsmanager.c)", "pfsManager_entry when !pfsManagerBusy" }; + } + if (mq == pfsManager_getSiLockQueue()) { + return { true, "D_802816E8 (pfsmanager.c)", "func_8024F4AC via func_8024F35C(0)" }; + } + if (mq == audioManager_getFrameMesgQueue()) { + return { true, "audioFrameMsgQ (audio_manager.c)", + "thread5_handleAudioTimerEvent (skipped while port_audioHeld)" }; + } + if (mq == audioManager_getReplyMesgQueue()) { + return { true, "audioReplyMsgQ (audio_manager.c)", + "thread5_handleSPEvent when sUnkFlag1==UNKFLAG1_AUDIO_TASK" }; + } + return { false, "unmapped queue", "unknown" }; +} + +// Repo source root, derived from this file's own build-time path so the check +// holds wherever the repo was cloned. The PDB records paths from the same +// compiler invocation, so our translation units share this prefix while the +// CRT/STL ones (which also contain "\src\") do not. +const std::string& ProjectSourceRoot() { + static const std::string root = [] { + const std::string self = __FILE__; + const size_t pos = self.rfind("src"); + // Only usable if __FILE__ came through absolute; otherwise mark nothing + // rather than risk the false positives a looser match produces. + if (pos == std::string::npos || self.find(':') == std::string::npos) { + return std::string(); + } + return self.substr(0, pos); + }(); + return root; +} + +// Stack of the stalled thread, symbolized against the shipped PDB. Nothing else +// in the report can be reconstructed after the fact: by the time a maintainer +// reads the log the process is gone, so capture it here rather than asking for +// a debugger they cannot attach. +// +// Addresses are collected while the target is suspended and symbolized only +// after it resumes, to keep the window in which it is held as narrow as +// possible. See the caller for the hang risk this still carries. +std::string CaptureStalledStack(int threadIdx) { +#if defined(LH_WATCHDOG_STACKS) + HANDLE thread = (HANDLE)sBeats[threadIdx].handle.load(std::memory_order_relaxed); + if (thread == nullptr) { + return {}; + } + + HANDLE proc = GetCurrentProcess(); + static std::once_flag symOnce; + std::call_once(symOnce, [proc] { + SymSetOptions(SYMOPT_LOAD_LINES | SYMOPT_UNDNAME | SYMOPT_DEFERRED_LOADS); + SymInitialize(proc, nullptr, TRUE); + }); + + if (SuspendThread(thread) == (DWORD)-1) { + return {}; + } + + CONTEXT ctx = {}; + ctx.ContextFlags = CONTEXT_FULL; + DWORD64 frames[32]; + int numFrames = 0; + if (GetThreadContext(thread, &ctx)) { + STACKFRAME64 sf = {}; +#if defined(_M_X64) + const DWORD machine = IMAGE_FILE_MACHINE_AMD64; + sf.AddrPC.Offset = ctx.Rip; + sf.AddrFrame.Offset = ctx.Rbp; + sf.AddrStack.Offset = ctx.Rsp; +#elif defined(_M_ARM64) + const DWORD machine = IMAGE_FILE_MACHINE_ARM64; + sf.AddrPC.Offset = ctx.Pc; + sf.AddrFrame.Offset = ctx.Fp; + sf.AddrStack.Offset = ctx.Sp; +#else + const DWORD machine = IMAGE_FILE_MACHINE_I386; + sf.AddrPC.Offset = ctx.Eip; + sf.AddrFrame.Offset = ctx.Ebp; + sf.AddrStack.Offset = ctx.Esp; +#endif + sf.AddrPC.Mode = sf.AddrFrame.Mode = sf.AddrStack.Mode = AddrModeFlat; + // Addresses only while suspended; symbol lookup happens after resume. + while (numFrames < 32 && + StackWalk64(machine, proc, thread, &sf, &ctx, nullptr, SymFunctionTableAccess64, SymGetModuleBase64, + nullptr) && + sf.AddrPC.Offset != 0) { + frames[numFrames++] = sf.AddrPC.Offset; + } + } + ResumeThread(thread); + + if (numFrames == 0) { + return {}; + } + + const std::string& srcRoot = ProjectSourceRoot(); + std::string out = "Stack:\n"; + alignas(SYMBOL_INFO) char symBuf[sizeof(SYMBOL_INFO) + 256] = {}; + auto* sym = reinterpret_cast(symBuf); + sym->SizeOfStruct = sizeof(SYMBOL_INFO); + sym->MaxNameLen = 255; + for (int i = 0; i < numFrames; i++) { + DWORD64 symDisp = 0; + DWORD lineDisp = 0; + IMAGEHLP_LINE64 line = {}; + line.SizeOfStruct = sizeof(line); + if (SymFromAddr(proc, frames[i], &symDisp, sym)) { + if (SymGetLineFromAddr64(proc, frames[i], &lineDisp, &line)) { + // Only frames under this repo's source root are ours; CRT and + // STL paths contain "\src\" as well and must not match. + const bool ours = !srcRoot.empty() && + _strnicmp(line.FileName, srcRoot.c_str(), srcRoot.size()) == 0; + out += fmt::format("{} #{:02} {}+0x{:x} ({}:{})\n", ours ? ">" : " ", i, sym->Name, symDisp, + line.FileName, line.LineNumber); + } else { + out += fmt::format(" #{:02} {}+0x{:x}\n", i, sym->Name, symDisp); + } + } else { + // No symbols (plain Release with no PDB alongside): emit + // module+offset, which stays resolvable later against a matching + // build. A raw address is meaningless once ASLR is factored in. + DWORD64 base = SymGetModuleBase64(proc, frames[i]); + char modPath[MAX_PATH] = {}; + const char* modName = "?"; + if (base != 0 && GetModuleFileNameA((HMODULE)(uintptr_t)base, modPath, MAX_PATH) != 0) { + const char* slash = strrchr(modPath, '\\'); + modName = slash != nullptr ? slash + 1 : modPath; + } + if (base != 0) { + out += fmt::format(" #{:02} {}+0x{:x}\n", i, modName, frames[i] - base); + } else { + out += fmt::format(" #{:02} 0x{:x}\n", i, frames[i]); + } + } + } + return out; +#else + (void)threadIdx; + return {}; +#endif +} + +std::string BuildDump(const bool* stalled, Clock::time_point now, const std::string& stack) { + OS_BlockedWait waits[16]; + const int numWaits = OS_MesgSnapshotBlockedWaits(waits, 16); + auto waitFor = [&](int threadIdx) -> const OS_BlockedWait* { + unsigned long tid = sBeats[threadIdx].tid.load(std::memory_order_relaxed); + for (int i = 0; i < numWaits; i++) { + if (waits[i].tid == tid) { + return &waits[i]; + } + } + return nullptr; + }; + auto ageOf = [&](int threadIdx) { + return std::chrono::duration_cast(now - sBeats[threadIdx].lastBeat); + }; + + std::string out; + + // Downstream threads stall behind the one that actually broke, so the + // longest-stalled thread is the best root-cause guess. + int firstStalled = -1; + int numStalled = 0; + if (stalled != nullptr) { + for (int i = 0; i < WATCHDOG_NUM_THREADS; i++) { + if (!stalled[i]) { + continue; + } + numStalled++; + if (firstStalled < 0 || sBeats[i].lastBeat < sBeats[firstStalled].lastBeat) { + firstStalled = i; + } + } + } + + if (firstStalled < 0) { + out += "===== Thread Watchdog: snapshot, no stall =====\n"; + } else { + out += fmt::format("===== Thread Watchdog: STALL DETECTED =====\n" + "{} has not reported for {} (tid {}){}\n" + "In loop: {}\n", + kThreadNames[firstStalled], HumanDuration(ageOf(firstStalled)), + sBeats[firstStalled].tid.load(std::memory_order_relaxed), + numStalled > 1 ? fmt::format(", {} stalled total, this one first", numStalled) : "", + kThreadLoops[firstStalled]); + if (const OS_BlockedWait* w = waitFor(firstStalled)) { + QueueInfo qi = DescribeQueue(w->mq); + out += fmt::format("Parked at: {} on {} {}/{}\n", w->isSend ? "osSendMesg (full)" : "osRecvMesg (empty)", + qi.name, w->mq->validCount, w->mq->msgCount); + out += fmt::format("Producers: {}\n", qi.fedBy); + } else if (!stack.empty()) { + out += "Parked at: no queue wait; see Stack below\n"; + } else { + out += fmt::format("Parked at: no queue wait, so loop/mutex/condvar. Candidates: {}\n", + kThreadNonQueueWaits[firstStalled]); + if (firstStalled == WATCHDOG_GAME_TICK && port_renderServicePending()) { + out += "Note: port_runOnRenderThread call is pending, so sSvcCv is the prime suspect\n"; + } + } + } + + for (int i = 0; i < WATCHDOG_NUM_THREADS; i++) { + const Heartbeat& hb = sBeats[i]; + uint64_t count = hb.count.load(std::memory_order_relaxed); + if (count == 0) { + out += fmt::format(" {:<11} never started\n", kThreadNames[i]); + continue; + } + std::string age = (hb.lastBeat == Clock::time_point{}) ? std::string("?") : HumanDuration(ageOf(i)); + std::string park; + if (const OS_BlockedWait* w = waitFor(i)) { + QueueInfo qi = DescribeQueue(w->mq); + park = fmt::format(" {} {} {}/{}", w->isSend ? "send" : "recv", qi.name, w->mq->validCount, + w->mq->msgCount); + } + out += fmt::format(" {:<11} {:<7} {:>6} tid {:<6} {} beats{}\n", kThreadNames[i], + (stalled != nullptr && stalled[i]) ? "STALLED" : "ok", age, + hb.tid.load(std::memory_order_relaxed), count, park); + } + + Thread5WatchdogState t5; + thread5_getWatchdogState(&t5); + ViMgrWatchdogState vi; + viMgr_getWatchdogState(&vi); + const u32 dpStatus = osDpGetStatus(); + void* curFb = osViGetCurrentFramebuffer(); + void* nextFb = osViGetNextFramebuffer(); + + out += fmt::format("Pipeline: sUnkFlag1={} sUnkFlag2={:#x}/saved={:#x} sSyncCounter={} task7={} " + "gfxRing={}->{} audioRing={}->{} taskQ={}/{} syncQ={}/{} FREEZE={} pendingSpTask={} " + "fb cur{}next{}\n", + DescribeUnkFlag1(t5.unkFlag1), t5.unkFlag2, t5.unkFlag2Saved, t5.syncCounter, t5.task7Handled, + t5.gfxActiveId, t5.gfxSelectedId, t5.audioActiveId, t5.audioSelectedId, t5.taskQueueCount, + t5.taskQueueCap, t5.syncQueueCount, t5.syncQueueCap, (dpStatus & 0x2) ? 1 : 0, + OS_SpPeekPendingTask() != nullptr ? "yes" : "no", curFb == nextFb ? "==" : "!=", + OS_ViBlackActive() ? " viBlack" : ""); + out += fmt::format("Frame pacing: D_802808D8={}{} frameTokenQ={} tickRetraceQ={} retraceQ={}\n", vi.retraceCount, + vi.retraceCount > 10 ? " (accumulating)" : "", vi.q2Count, vi.q3Count, vi.q1Count); + + OSMesgQueue* pfsPoll = pfsManager_getFrameMesgQ(); + OSMesgQueue* audioFrame = audioManager_getFrameMesgQueue(); + OSMesgQueue* audioReply = audioManager_getReplyMesgQueue(); + out += fmt::format("SI/audio: pfsBusy={} pollingQ={} audioFrameQ={} audioReplyQ={} audioHeld={} svcPending={}\n", + pfsManager_isBusy(), pfsPoll->validCount, audioFrame->validCount, audioReply->validCount, + port_audioHeld(), port_renderServicePending()); + out += fmt::format("Context: map={:#x} exit={:#x} gameMode={} build={} {}@{}", gsworld_getMap(), + gsworld_getExit(), getGameMode(), (char*)gBuildVersion, (char*)gGitBranch, + (char*)gGitCommitHash); + + if (!stack.empty()) { + out += "\n" + stack; + } + return out; +} + +void Watcher() { + auto lastSample = Clock::now(); + auto lastReport = Clock::time_point{}; + bool wasStalled = false; + + while (sWatcherRun.load(std::memory_order_relaxed)) { + std::this_thread::sleep_for(kSampleEvery); + auto now = Clock::now(); + + // A debugger pause (or system sleep) suspends every thread including + // this one; a stale "last beat" then isn't a stall. Rebaseline. + const bool suspended = (now - lastSample) > kSampleEvery * 4; + lastSample = now; + + bool stalled[WATCHDOG_NUM_THREADS] = {}; + bool anyStalled = false; + for (int i = 0; i < WATCHDOG_NUM_THREADS; i++) { + Heartbeat& hb = sBeats[i]; + uint64_t cur = hb.count.load(std::memory_order_relaxed); + if (!hb.started) { + if (cur == 0) { + continue; // thread not running yet; don't judge it + } + hb.started = true; + } + if (cur != hb.lastCount || suspended) { + hb.lastCount = cur; + hb.lastBeat = now; + continue; + } + const auto limit = + (i == WATCHDOG_AUDIO_MANAGER || i == WATCHDOG_PFSMANAGER) ? kRelaxedStallAfter : kStallAfter; + if (now - hb.lastBeat > limit) { + stalled[i] = true; + anyStalled = true; + } + } + for (int i = 0; i < WATCHDOG_NUM_THREADS; i++) { + sStalledFlags[i].store(stalled[i], std::memory_order_relaxed); + } + + if (!anyStalled) { + wasStalled = false; + continue; + } + // One dump when a stall appears, then a refresher while it persists. + if (wasStalled && (now - lastReport) < kRedumpEvery) { + continue; + } + const bool firstReportOfEpisode = !wasStalled; + wasStalled = true; + lastReport = now; + + int root = -1; + for (int i = 0; i < WATCHDOG_NUM_THREADS; i++) { + if (stalled[i] && (root < 0 || sBeats[i].lastBeat < sBeats[root].lastBeat)) { + root = i; + } + } + + // The stack is folded into the report below so the diagnosis is one + // block, but walking a thread means suspending it, which can hang if it + // holds a DbgHelp or loader lock and would take this watcher with it. + // Leave a breadcrumb first so a hang still names the stalled thread. + std::string stack; + if (firstReportOfEpisode && root >= 0) { + SPDLOG_ERROR("[Watchdog] {} stalled, collecting state", kThreadNames[root]); + stack = CaptureStalledStack(root); + } + SPDLOG_ERROR("{}", BuildDump(stalled, now, stack)); + } +} + +} // namespace + +extern "C" void ThreadWatchdog_Beat(WatchdogThread id) { + Heartbeat& hb = sBeats[id]; + hb.count.fetch_add(1, std::memory_order_relaxed); + if (hb.tid.load(std::memory_order_relaxed) == 0) { +#if defined(LH_WATCHDOG_STACKS) + // GetCurrentThread is a pseudo-handle only valid on this thread, so + // duplicate it into one the watcher can use. Leaked by design: it must + // outlive the thread's own loop for the whole session. + HANDLE dup = nullptr; + DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), &dup, + THREAD_SUSPEND_RESUME | THREAD_GET_CONTEXT | THREAD_QUERY_INFORMATION, FALSE, 0); + hb.handle.store(dup, std::memory_order_relaxed); +#endif + hb.tid.store((unsigned long)SDL_ThreadID(), std::memory_order_relaxed); + } +} + +extern "C" void ThreadWatchdog_Start(void) { + if (sWatcherRun.exchange(true)) { + return; + } + sWatcher = std::thread(Watcher); +} + +extern "C" void ThreadWatchdog_Stop(void) { + if (!sWatcherRun.exchange(false)) { + return; + } + if (sWatcher.joinable()) { + sWatcher.join(); + } +} + +extern "C" void ThreadWatchdog_DumpNow(void) { + SPDLOG_INFO("{}", BuildDump(nullptr, Clock::now(), std::string())); +} + +extern "C" int ThreadWatchdog_IsStalled(WatchdogThread id) { + return sStalledFlags[id].load(std::memory_order_relaxed) ? 1 : 0; +} + diff --git a/src/port/DevTools/ThreadWatchdog.h b/src/port/DevTools/ThreadWatchdog.h new file mode 100644 index 000000000..4ac9600d7 --- /dev/null +++ b/src/port/DevTools/ThreadWatchdog.h @@ -0,0 +1,75 @@ +#ifndef PORT_THREAD_WATCHDOG_H +#define PORT_THREAD_WATCHDOG_H + +#include + +// Heartbeat watchdog over the revived decomp threads. +// +// Every serviced loop beats once per iteration and a watcher thread samples the +// counters. When a thread that has already proven alive stops beating while the +// wall clock keeps moving, the watcher logs the pipeline state: thread5's flag +// words and task rings, every queue depth, who is parked where, and the stalled +// thread's stack. + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum WatchdogThread { + WATCHDOG_VI_TICKER = 0, // retrace source (OS_VI.cpp); everything below is paced by it + WATCHDOG_MAIN_LOOP, // window thread: event pump + RCP service (Game.cpp) + WATCHDOG_GAME_TICK, // push_frame loop (Game.cpp) + WATCHDOG_THREAD5, // decomp graphics thread (graphics_thread.c) + WATCHDOG_VIMGR, // decomp VI manager thread (vimgr.c) + WATCHDOG_PFSMANAGER, // controller thread (pfsmanager.c) + WATCHDOG_AUDIO_MANAGER, // audio thread (audio_manager.c); idles during demo audio holds + WATCHDOG_NUM_THREADS +} WatchdogThread; + +// Called once per loop iteration; one relaxed atomic increment. +void ThreadWatchdog_Beat(WatchdogThread id); + +// Started once the decomp threads exist, stopped before shutdown teardown. +void ThreadWatchdog_Start(void); +void ThreadWatchdog_Stop(void); + +// Log the pipeline state immediately, stalled or not. +void ThreadWatchdog_DumpNow(void); + +// Whether the watcher currently considers this thread stalled. The gui only +// draws inside serviced frames, so the main loop uses this to keep drawing +// while the tick is down instead of freezing ImGui along with it. +int ThreadWatchdog_IsStalled(WatchdogThread id); + +// Diagnostic snapshots served by the decomp thread owners; plain structs so +// the C side fills them without knowing about the watchdog's internals. +typedef struct Thread5WatchdogState { + int32_t unkFlag1; // 0x04 audio task, 0x08 gfx task, 0x10 idle, 0x20 yielded + int32_t unkFlag2; + int32_t unkFlag2Saved; + int32_t syncCounter; + int32_t task7Handled; + int32_t gfxActiveId; + int32_t gfxSelectedId; + int32_t audioActiveId; + int32_t audioSelectedId; + int32_t taskQueueCount; + int32_t taskQueueCap; + int32_t syncQueueCount; + int32_t syncQueueCap; +} Thread5WatchdogState; +void thread5_getWatchdogState(Thread5WatchdogState* out); + +typedef struct ViMgrWatchdogState { + int32_t retraceCount; // D_802808D8: retraces seen since the tick last consumed them + int32_t q1Count; // retrace event queue (viMgr_entry parks here) + int32_t q2Count; // frame token queue (the tick parks here) + int32_t q3Count; // tick retrace queue +} ViMgrWatchdogState; +void viMgr_getWatchdogState(ViMgrWatchdogState* out); + +#ifdef __cplusplus +} +#endif + +#endif // PORT_THREAD_WATCHDOG_H diff --git a/src/port/Engine.cpp b/src/port/Engine.cpp index 91590aad7..7dad6ba56 100644 --- a/src/port/Engine.cpp +++ b/src/port/Engine.cpp @@ -33,8 +33,8 @@ #include "build.h" #include "Extractor/GameExtractor.h" #include "ship/window/gui/FileBrowserWindow.h" -#include "Interpolation/AdaptiveFps.h" #include "Interpolation/FrameInterpolation.h" +#include "OS/OS.h" #include "Network/Anchor/Anchor.h" #include "port/Enhancements/Events/PortEnhancements.h" #include "port/Patches/Patches.h" @@ -74,11 +74,6 @@ extern s32 D_80275610; bool prevAltAssets = false; // bool gEnableGammaBoost = true; -// Audio synthesis entry point (decomp n_synthesizer.c) -Acmd* n_alAudioFrame(Acmd* cmdList, s32* cmdLen, s16* outBuf, s32 outLen); -// DMA cache cleanup (decomp audio_manager.c) -void audioManager_func_802403F0(void); -void func_80250650(void); // Game mode helper bool func_802E4A08(void); @@ -394,6 +389,11 @@ void GameEngine::FinishInit() { lhFast3dWindow->SetMaximumFrameLatency(1); lhFast3dWindow->SetRendererUCode(ucode_f3d); + // Opt-in to memoization + if (auto interpreter = lhFast3dWindow->GetInterpreterWeak().lock()) { + interpreter->SetResolvedResourceCacheEnabled(true); + } + #ifdef USE_NETWORKING SDLNet_Init(); #endif @@ -412,7 +412,6 @@ void GameEngine::FinishInit() { // Likewise if it refused romhack overlays due to a non-v1.0 base. MaybeShowRomhackBaseMismatchPopup(); Instance->AudioInit(); - AdaptiveFps_Configure(30); // BK ticks at 30 Hz // Instance->LoadDictionary(); // Instance->LoadPlayerAnims(); #if defined(__SWITCH__) || defined(__WIIU__) @@ -1057,7 +1056,6 @@ void GameEngine::Destroy() { // Flush all resource refs so destructors run while spdlog is still active. // sResourceRefCache holds shared_ptrs that outlive the LUS cache otherwise. - AudioExit(); ResourceHelpers_ClearRefCache(); AudioDma_Clear(); ReleaseSoundfonts(); @@ -1139,33 +1137,19 @@ void GameEngine::RelaunchIfRequested(int argc, char* argv[]) { #endif } -#if 0 -// Values for 44100 hz -#define SAMPLES_HIGH 752 -#define SAMPLES_LOW 720 -#else -// Values for 32000 hz -#define SAMPLES_HIGH 560 -#define SAMPLES_LOW 528 +#define SAMPLES_PER_FRAME (560 * 2 * 2) -#endif -#define NUM_AUDIO_CHANNELS 2 -#define SAMPLES_PER_FRAME (SAMPLES_HIGH * NUM_AUDIO_CHANNELS * 2) +// 2 VIs per game frame (30fps) +#define gVIsPerFrame 2 extern "C" uint32_t GameEngine_GetSamplesPerFrame() { return SAMPLES_PER_FRAME; } -// 2 VIs per game frame (30fps) -#define gVIsPerFrame 2 - -// 736 samples per audio update (44000/60, aligned to 184-sample boundary) -#define AlFrameSize 736 - // Attract-demo audio hold static std::atomic sHoldAudio{ false }; -static constexpr int kDemoAudioHoldFrames = 2; // frames to stay held after the load -static int sHoldFramesRemaining = 0; // game-thread countdown +static constexpr int kDemoAudioHoldFrames = 2; // drawn ticks to stay held after the load +static int sHoldFramesRemaining = 0; // game thread only extern "C" void port_beginDemoAudioHold(void) { if (kDemoAudioHoldFrames <= 0) { @@ -1175,50 +1159,14 @@ extern "C" void port_beginDemoAudioHold(void) { sHoldAudio.store(true); } -void GameEngine::HandleAudioThread() { - int16_t audioBuffer[AlFrameSize * 2]; - Acmd cmdList[0x800]; - - // Free-run: continuously keep the backend queue topped up, real-time paced and - // decoupled from the game frame, so a long game frame can't starve the device. - while (audio.running) { - if (audio.ready) { - while (audio.running && AudioPlayerBuffered() < AudioPlayerGetDesiredBuffered()) { - int samplesToGen = AlFrameSize * 2 * sizeof(int16_t); - - memset(audioBuffer, 0, samplesToGen); - - // While held, leave the buffer as silence and do NOT advance the engine. - if (!sHoldAudio) { - int32_t cmdLen = 0; - // Lock only the engine work; the volume scale and backend submit touch - // worker-local / backend state, not the synth. - port_lockAudio(); - audioManager_func_802403F0(); - n_alAudioFrame(cmdList, &cmdLen, audioBuffer, AlFrameSize); - func_80250650(); - port_unlockAudio(); - - float master_vol = CVarGetInteger(CVAR_SETTING("Volume.Master"), 100) / 100.0f; - for (u32 i = 0; i < AlFrameSize * 2; i++) { - audioBuffer[i] = static_cast(audioBuffer[i] * master_vol); - } - } - AudioPlayerPlayFrame((uint8_t*)audioBuffer, samplesToGen); - } - } - std::this_thread::sleep_for(std::chrono::milliseconds(2)); +extern "C" void port_tickDemoAudioHold(void) { + if (sHoldAudio.load() && --sHoldFramesRemaining <= 0) { + sHoldAudio.store(false); } } -void GameEngine::StartAudioFrame() { - // Worker free-runs now; this only marks the engine initialized (first call is after - // audio init, once the game loop is running). - audio.ready = true; -} - -void GameEngine::EndAudioFrame() { - // No-op: audio generation is decoupled from the game frame. +extern "C" int port_audioHeld(void) { + return sHoldAudio.load() ? 1 : 0; } static std::vector> sSoundfontResources; @@ -1267,26 +1215,8 @@ void GameEngine::AudioInit() { LoadSoundfonts(); } -void GameEngine::AudioStartThread() { - if (!audio.running) { - audio.running = true; - audio.thread = std::thread(HandleAudioThread); -#ifdef _WIN32 - SetThreadPriority(audio.thread.native_handle(), THREAD_PRIORITY_TIME_CRITICAL); -#endif - } -} -void GameEngine::AudioExit() { - // Free-run worker checks `running` each loop (~every 2 ms), so just clear it and join. - audio.running = false; - if (audio.thread.joinable()) { - audio.thread.join(); - } -} - -// Local timer helper for the per-sub-frame measurement we feed into -// AdaptiveFps_Sample. +// Local timer helper for the per-sub-frame cost measurement. namespace { using Clock = std::chrono::steady_clock; inline long long NsSince(Clock::time_point t0) { @@ -1295,6 +1225,11 @@ inline long long NsSince(Clock::time_point t0) { // In-flight async builds of interpolated sub-frame replacement maps std::vector> sMapBuildFutures; + +// Cost of the most recent sub-frame, and the wall time this pass may spend: +// subframes/paceFps is exactly the game time one task represents. +long long sLastSubFrameNs = 0; +long long sPassBudgetNs = 0; } // namespace void GameEngine::RunCommands(Gfx* Commands, const std::vector>& mtx_replacements, @@ -1316,14 +1251,18 @@ void GameEngine::RunCommands(Gfx* Commands, const std::vectorGetWindow(); + const auto passT0 = Clock::now(); for (size_t frameIdx = 0; frameIdx < frameCount; frameIdx++) { if (frameIdx >= 1 && frameIdx - 1 < sMapBuildFutures.size()) { sMapBuildFutures[frameIdx - 1].wait(); } + // Stop once another sub-frame no longer fits in what the tick's worth + // of wall time has left. + if (frameIdx > 0 && sLastSubFrameNs > 0 && (sPassBudgetNs - NsSince(passT0)) < sLastSubFrameNs) { + break; + } const auto& m = mtx_replacements[frameIdx]; bool isFinalFrame = (frameIdx == frameCount - 1); - // Bypass IsFrameReady() when interpolation is active — render all - // frames per tick and let vsync pace them. if (frameCount > 1 || wndBase->IsFrameReady()) { // Sample the full CPU cost of producing this sub-frame. auto runT0 = Clock::now(); @@ -1332,16 +1271,14 @@ void GameEngine::RunCommands(Gfx* Commands, const std::vectorStartDraw(); interpreter->StartFrame(); interpreter->Run(Commands, m); - // Emulate N64 osViBlack to prevent a flicker when the scene is drawn - // for the falling jiggy transition framebuffer capture. - if (port_isViBlack()) { + if (OS_ViBlackActive()) { interpreter->mGfxFrameBuffer = 0; auto rapi = interpreter->GetCurrentRenderingAPI(); rapi->StartDrawToFramebuffer(0, 1.0f); rapi->ClearFramebuffer(true, false); } gui->EndDraw(); - AdaptiveFps_Sample(NsSince(runT0)); + sLastSubFrameNs = NsSince(runT0); interpreter->EndFrame(); CALL_EVENT(FrameDrawEnd); } @@ -1375,10 +1312,6 @@ SubframePacing ComputeSubframePacing() { // Demo/replay modes render at the native rate const bool replayMode = func_802E4A08(); if (!replayMode) { - if (CVarGetInteger(CVAR_SETTING("AdaptiveFPS"), 1)) { - target_fps = (int)AdaptiveFps_Cap((uint32_t)target_fps); - } - // Some music-synced cutscenes cap interpolation at native 30 int fpsCap = port_getInterpolationFpsCap(); if (fpsCap > 0 && target_fps > fpsCap) { @@ -1469,6 +1402,8 @@ void GameEngine::ProcessGfxCommands(Gfx* commands) { activeFrames++; } + sPassBudgetNs = 1000000000LL * subframesPerTick / fps; + if (wnd != nullptr) { wnd->SetTargetFps(fps); // Hardcoded: CVarGetInteger crashes due to heap corruption in debug builds. @@ -1493,11 +1428,6 @@ void GameEngine::ProcessGfxCommands(Gfx* commands) { } } sMapBuildFutures.clear(); - - // [port] Release the demo audio hold after kDemoAudioHoldFrames rendered frames. - if (sHoldAudio.load() && --sHoldFramesRemaining <= 0) { - sHoldAudio.store(false); - } } uint32_t GameEngine::GetInterpolationFPS() { diff --git a/src/port/Engine.h b/src/port/Engine.h index 477a785e9..c6e1b9a34 100644 --- a/src/port/Engine.h +++ b/src/port/Engine.h @@ -42,12 +42,7 @@ class GameEngine { GameEngine(); void StartFrame() const; static void Create(int argc, char* argv[]); - static void HandleAudioThread(); - static void StartAudioFrame(); - static void EndAudioFrame(); static void AudioInit(); - static void AudioStartThread(); - static void AudioExit(); void FinishInit(); void RunExtract(int argc, char* argv[]); // Render a GUI-only frame (no game tick). Used to keep the ImGui progress diff --git a/src/port/Enhancements/Events/Hooks/Events.h b/src/port/Enhancements/Events/Hooks/Events.h index 641f2f740..7a3a8b581 100644 --- a/src/port/Enhancements/Events/Hooks/Events.h +++ b/src/port/Enhancements/Events/Hooks/Events.h @@ -100,6 +100,10 @@ typedef enum VBehaviorID { VB_WARP_DISPATCH, VB_XMAS_TREE_ICE_UPDATE, VB_BOGGY_HOME_VISIBLE, + VB_CUBE_PROP_SORT, + VB_GCLIGHTS_RECOLOR, + VB_SNOW_CAMERA_ROTATION, + VB_DRAWDIST_BOX_CULL, } VBehaviorID; typedef enum DoorCameraId { diff --git a/src/port/Game.cpp b/src/port/Game.cpp index 3189e791a..fcc8de0e6 100644 --- a/src/port/Game.cpp +++ b/src/port/Game.cpp @@ -1,8 +1,13 @@ #include "Engine.h" +#include +#include #include #include #include #include +#include +#include +#include #include #include @@ -13,12 +18,14 @@ #endif #include +#include "DevTools/ThreadWatchdog.h" #include "GameStatus.h" -#include "Interpolation/AdaptiveFps.h" #include "Interpolation/FrameInterpolation.h" #include "Network/Anchor/Anchor.h" +#include "OS/OS.h" #include "Patches/Patches.h" #include "ShipUtils.h" +#include "ShipInit.hpp" #include "src/port/Enhancements/Events/Hooks/Events.h" #include "UI/LighthouseModMenuWindow.h" @@ -26,44 +33,186 @@ extern "C" { #include "enums.h" #include "core1/core1.h" #include "core1/main.h" +#include "core1/thread5.h" +void viMgr_entry(void* arg); +void thread5_entry(void* arg); +void audioManagerThread_entry(void* arg); +void core1_15B30_sendMesg3ToRenderThread(void); +OSMesgQueue* thread5_getTaskQueue(void); +OSMesgQueue* thread5_getSyncQueue(void); // Non-interactive demo/playback modes (attract demo, file playback, etc.) -- decomp gameloop.c bool func_802E4A08(void); } +// The game tick runs on its own thread and submits display lists through the +// decomp's thread5 queue; this thread stays behind as the RCP and event pump. +namespace { +std::atomic sGameThreadDone{ false }; +std::thread sGameThread; +thread_local bool tIsGameThread = false; + +// The interpolation pair a submitted list was built from, carried to whoever +// renders it. At most a couple are live at once. +struct InterpPair { + int prev = -1; + int curr = -1; + bool should = false; +}; +std::mutex sInterpMutex; +std::map sTaskInterp; + +// Renderer calls made from tick code, run by the main loop between services. +std::mutex sSvcMutex; +std::condition_variable sSvcCv; +void (*sSvcFn)(void*) = nullptr; +void* sSvcArg = nullptr; + +int sTitleMap = 0; + +void DrainRenderService() { + std::unique_lock lock(sSvcMutex); + if (sSvcFn != nullptr) { + auto* fn = sSvcFn; + void* arg = sSvcArg; + lock.unlock(); + fn(arg); + lock.lock(); + sSvcFn = nullptr; + sSvcCv.notify_all(); + } +} + +// False on the window thread, including everything that runs during init +// before the tick thread exists. +bool OnGameThread() { + return tIsGameThread; +} +} // namespace + +// A list is submitted while its tick is still recording, so the pair is +// captured here and travels with the task. +extern "C" void port_thread5_onSubmit(void* taskData) { + if (!OnGameThread() || (uintptr_t)taskData < 100) { + return; + } + struct ucode_task_data_s* task = (struct ucode_task_data_s*)taskData; + if (task->task_type != UCODE_TASK_TYPE_F3DEX && task->task_type != UCODE_TASK_TYPE_L3DEX) { + return; + } + InterpPair pair; + FrameInterpolation_GetRecordingPair(&pair.prev, &pair.curr, &pair.should); + FrameInterpolation_ClaimPair(pair.prev, pair.curr); + FrameInterpolation_StopRecord(); + std::lock_guard lock(sInterpMutex); + sTaskInterp[task->data_ptr] = pair; +} + +namespace { +void RenderTask(void* dlStart) { + InterpPair pair; + { + std::lock_guard lock(sInterpMutex); + auto it = sTaskInterp.find(dlStart); + if (it != sTaskInterp.end()) { + pair = it->second; + sTaskInterp.erase(it); + } + } + FrameInterpolation_BeginRenderPass(pair.prev, pair.curr, pair.should); + GameEngine::ProcessGfxCommands((Gfx*)dlStart); + FrameInterpolation_ReleasePair(pair.prev, pair.curr); +} + +// This thread plays the RCP: thread5 hands over a task, +// we run it and raise SP then DP. +int ServiceRcp() { + OSTask* task = OS_SpTakePendingTask(); + if (task == nullptr) { + return 0; + } + RenderTask(task->t.data_ptr); + OS_SendEventMesg(OS_EVENT_SP); + OS_SendEventMesg(OS_EVENT_DP); + return 1; +} + +// Called before core1_init, which is where these threads are created. +void EnableThread5() { + OS_EnableThreadEntry((void*)thread5_entry); + OS_SetQueueBlocking(thread5_getTaskQueue(), 1); + OS_SetQueueBlocking(thread5_getSyncQueue(), 1); + // The controller manager parks on its polling queue waiting for OS_EVENT_SI. + OS_EnableThreadEntry((void*)pfsManager_entry); + OS_SetQueueBlocking(pfsManager_getFrameMesgQ(), 1); + OS_EnableThreadEntry((void*)audioManagerThread_entry); + OS_SetQueueBlocking(audioManager_getFrameMesgQueue(), 1); + OS_SetQueueBlocking(audioManager_getReplyMesgQueue(), 1); +} +} // namespace + + +// Drain submitted lists for safety. +static void RegisterThread5MapSync_Init() { + COND_HOOK(OnMapLoad, EVENT_PRIORITY_HIGH, true, [](IEvent* event) { + (void)event; + port_pipelineSyncPoint(); + }); +} + +static RegisterShipInitFunc sThread5MapSyncInit(RegisterThread5MapSync_Init); + +// Whether a tick-side renderer call is waiting on the window thread. The +// handshake below is a condvar rather than a message queue, so it is the one +// park the watchdog's blocked-wait registry cannot see. +extern "C" int port_renderServicePending(void) { + return sSvcFn != nullptr; +} + +// Renderer calls from tick code come through here; D3D11 hangs if they run +// off the window thread. Inline when there is no separate tick thread. +extern "C" void port_runOnRenderThread(void (*fn)(void*), void* arg) { + if (!OnGameThread()) { + fn(arg); + return; + } + std::unique_lock lock(sSvcMutex); + sSvcCv.wait(lock, [] { return sSvcFn == nullptr; }); + sSvcFn = fn; + sSvcArg = arg; + sSvcCv.wait(lock, [] { return sSvcFn == nullptr; }); +} + +// Barrier before the tick frees or reads memory an in-flight list references. +// The game's own EVENT_SYNC handshake is the RDP-done wait. +extern "C" void port_pipelineSyncPoint(void) { + if (OnGameThread()) { + core1_15B30_sendMesg3ToRenderThread(); + } +} + // Tracks whether mainLoop actually fed the renderer this iteration. // BK's gameloop conditionally skips game_draw during scene transitions. static bool sFrameRendered = false; -// Start of this tick. The gap until drawing begins is how long the game spent -// updating; Adaptive FPS uses it to budget how many interpolated frames fit. -static std::chrono::steady_clock::time_point sTickStart; - +// The list itself reaches the renderer through thread5's task queue, submitted +// by core1_15B30_addF3DEXTaskData right after this call; all that is left here +// is noting that the tick drew. extern "C" void Graphics_PushFrame(Gfx* data) { - // Only measure the first draw of the tick. - if (!sFrameRendered) { - auto logicNs = - std::chrono::duration_cast(std::chrono::steady_clock::now() - sTickStart).count(); - AdaptiveFps_SampleTick((long long)logicNs); - } + (void)data; sFrameRendered = true; - GameEngine::ProcessGfxCommands(data); } void push_frame() { static int sTitleCounter = 0; sFrameRendered = false; - // While an inline mod extraction runs on its worker thread, freeze the game - // and render only the GUI so the progress modal stays live and the extractor - // gets the machine instead of fighting a full-speed game loop. The delay - // keeps the otherwise-idle main thread from busy-spinning a core. + // The window thread keeps the progress modal alive while an inline mod + // extraction runs; the tick just idles so the extractor gets the machine. if (IsInlineModExtractionBusy()) { - GameEngine::Instance->RenderGuiFrame(); SDL_Delay(16); return; } - sTickStart = std::chrono::steady_clock::now(); GameEngine::Instance->StartFrame(); // Demo/playback modes render at native rate with no interpolation, so skip recording it. const bool recordInterpolation = GameEngine::IsInterpolationEnabled() && !func_802E4A08(); @@ -74,13 +223,16 @@ void push_frame() { if (recordInterpolation) { FrameInterpolation_StopRecord(); } - GameEngine::StartAudioFrame(); - GameEngine::EndAudioFrame(); + if (sFrameRendered) { + port_tickDemoAudioHold(); + } - // Refresh window title stats once per second (every 30 game ticks) + // Refresh window title stats once per second (every 30 game ticks). The + // window belongs to the other thread, so hand the call over. if (++sTitleCounter >= 30) { sTitleCounter = 0; - port_setWindowTitle(gsworld_getMap()); + sTitleMap = gsworld_getMap(); + port_runOnRenderThread([](void*) { port_setWindowTitle(sTitleMap); }, nullptr); } if (!sFrameRendered) { @@ -117,11 +269,49 @@ int SDL_main(int argc, char* argv[]) { } GameEngine::Create(argc, argv); + // Both threads are created during core1_init, so allowlist them first. + OS_EnableThreadEntry((void*)viMgr_entry); + EnableThread5(); core1_init(); + ThreadWatchdog_Start(); - while (WindowIsRunning()) { - push_frame(); + sGameThread = std::thread([] { + tIsGameThread = true; + while (WindowIsRunning()) { + ThreadWatchdog_Beat(WATCHDOG_GAME_TICK); + push_frame(); + } + sGameThreadDone.store(true); + }); + while (WindowIsRunning() || !sGameThreadDone.load()) { + ThreadWatchdog_Beat(WATCHDOG_MAIN_LOOP); + // Pump events every iteration: a task-starved pass must not starve + // input and window messages. + Ship::Context::GetRawInstance()->GetWindow()->HandleEvents(); + OS_SiService(); + if (IsInlineModExtractionBusy()) { + GameEngine::Instance->RenderGuiFrame(); + SDL_Delay(16); + continue; + } + DrainRenderService(); + if (!ServiceRcp()) { + // The gui only draws inside serviced frames, so a stalled game + // thread would freeze ImGui with it. Render gui-only frames during + // a stall so the menu (and the watchdog dump) stays reachable. + if (ThreadWatchdog_IsStalled(WATCHDOG_GAME_TICK)) { + GameEngine::Instance->RenderGuiFrame(); + SDL_Delay(16); + continue; + } + SDL_Delay(1); + } + } + if (sGameThread.joinable()) { + sGameThread.join(); } + ThreadWatchdog_Stop(); + OS_StopViTicker(); #ifdef USE_NETWORKING Anchor::GetInstance()->Disable(); SDLNet_Quit(); diff --git a/src/port/Interpolation/AdaptiveFps.cpp b/src/port/Interpolation/AdaptiveFps.cpp deleted file mode 100644 index 085cdcdce..000000000 --- a/src/port/Interpolation/AdaptiveFps.cpp +++ /dev/null @@ -1,200 +0,0 @@ -#include "AdaptiveFps.h" - -#include -#include - -namespace { - -using Clock = std::chrono::steady_clock; - -// Tuning knobs - -// How much of each update's time we'll spend drawing once things are steady. -// Raise toward 1.0 if FPS dips in scenes that look fine; lower if it stutters. -constexpr double kSafetySteady = 0.95; - -// Same, but used the moment a scene gets busier (more cautious). Lower if busy -// scenes still hitch; raise if FPS drops more than needed when they start. -constexpr double kSafetyRising = 0.75; - -// How much busier a scene must get to count as "getting busy". Lower reacts -// sooner but trips on normal noise; raise to ignore small bumps. -constexpr double kRisingThreshold = 1.20; - -// How long to stay cautious after a scene gets busy. Raise if FPS wobbles in -// steady scenes; lower if it feels slow to speed back up. -constexpr int kRisingHoldWindows = 3; - -// How often measurements are averaged. Shorter reacts quicker but is jumpier; -// longer is steadier but slower to react. -constexpr auto kSampleWindow = std::chrono::milliseconds(200); - -// How much each new measurement counts vs. past ones when averaging. -// 1.0 = only the latest; 0.0 = never changes. -constexpr double kEmaAlpha = 0.5; - -// How much busier one frame must be than usual to count as a spike. Lower -// reacts harder to one-off heavy frames; raise to ignore them. -constexpr double kSpikeFactor = 1.25; - -// How strongly a spike pulls the estimate up. 1.0 = snap to it instantly; -// 0.0 = ignore spikes. 0.5 lets a sustained busy scene ramp up over a few frames. -constexpr double kSpikeBlend = 0.5; - -// How quickly the busy estimate eases back down each averaging period. 0 = -// never; 1 = drop to the latest right away. Higher recovers FPS faster. -constexpr double kPeakDecay = 0.40; - -// How fast the reserved game-update time follows the latest tick: jump up -// quickly when a scene gets busy, ease back down slowly when it calms. -constexpr double kLogicRiseAlpha = 0.5; -constexpr double kLogicFallAlpha = 0.1; - -// How much estimated spare capacity (in sub-frames) is needed beyond the next -// tier before the cap steps up. -constexpr double kStepUpHeadroom = 0.25; - -// Default game update rate (times per second) if none is given. -constexpr uint32_t kDefaultTickHz = 30; - -struct State { - uint32_t tickHz = kDefaultTickHz; - double tickBudgetUs = 1'000'000.0 / kDefaultTickHz; - double emaPerSubFrameUs = 0.0; // Average time to draw one frame. - double peakPerSubFrameUs = 0.0; // Busiest recent frame; the cap is based on this. - double envLogicUs = 0.0; // Reserved game-update time per tick. - long long winRunNs = 0; // Totals for the current measurement period. - int winSubFrames = 0; - double winMaxUs = 0.0; - Clock::time_point winStart = Clock::now(); - double safety = kSafetySteady; - int risingHoldRemaining = 0; - int grantedSub = 0; -}; - -State& state() { - static State s; - return s; -} - -} // namespace - -extern "C" { - -void AdaptiveFps_Configure(uint32_t tickHz) { - if (tickHz == 0) { - tickHz = kDefaultTickHz; - } - auto& s = state(); - s.tickHz = tickHz; - s.tickBudgetUs = 1'000'000.0 / tickHz; - s.emaPerSubFrameUs = 0.0; - s.peakPerSubFrameUs = 0.0; - s.envLogicUs = 0.0; - s.winRunNs = 0; - s.winSubFrames = 0; - s.winMaxUs = 0.0; - s.winStart = Clock::now(); - s.safety = kSafetySteady; - s.risingHoldRemaining = 0; - s.grantedSub = 0; -} - -uint32_t AdaptiveFps_Cap(uint32_t userTarget) { - auto& s = state(); - // Base the cap on the busiest recent frame, not the average: every frame we - // promise gets drawn, so the time has to fit the worst one. - double costUs = std::max(s.peakPerSubFrameUs, s.emaPerSubFrameUs); - if (costUs <= 0.0) { - return userTarget; - } - int userSub = (int)(userTarget / s.tickHz); - if (userSub < 1) { - userSub = 1; - } - // Set aside the time the game spent updating, then share what's left among - // interpolated frames so a busy scene can't overshoot the tick's budget. - double renderBudgetUs = s.tickBudgetUs - s.envLogicUs; - double maxSubPerTick = renderBudgetUs <= 0.0 ? 1.0 : (renderBudgetUs * s.safety) / costUs; - int desired = maxSubPerTick < 1.0 ? 1 : (int)maxSubPerTick; - if (desired > userSub) { - desired = userSub; - } - - if (s.grantedSub == 0 || desired < s.grantedSub) { - // First measurement, or capacity dropped (or the user lowered the - // target): apply immediately, don't promise frames that can't be drawn. - s.grantedSub = desired; - } else if (desired > s.grantedSub && s.risingHoldRemaining == 0 && - maxSubPerTick >= (double)(s.grantedSub + 1) + kStepUpHeadroom) { - // Recover one tier at a time, only in steady state and with headroom. - s.grantedSub++; - } - - return std::min(userTarget, (uint32_t)s.grantedSub * s.tickHz); -} - -void AdaptiveFps_SampleTick(long long logicNs) { - auto& s = state(); - double us = (double)logicNs / 1000.0; - if (us < 0.0) { - return; - } - if (s.envLogicUs == 0.0) { - s.envLogicUs = us; - } else { - // Rise fast when the scene gets busier, fall slow when it calms. - double alpha = us > s.envLogicUs ? kLogicRiseAlpha : kLogicFallAlpha; - s.envLogicUs = alpha * us + (1.0 - alpha) * s.envLogicUs; - } -} - -void AdaptiveFps_Sample(long long runNs) { - auto& s = state(); - double sampleUs = (double)runNs / 1000.0; - - s.winRunNs += runNs; - s.winSubFrames++; - if (sampleUs > s.winMaxUs) { - s.winMaxUs = sampleUs; - } - - // If one frame is suddenly much busier than usual, bump the estimate up - // right away and stay cautious, so the next cap already reflects it. - if (s.peakPerSubFrameUs == 0.0) { - s.peakPerSubFrameUs = sampleUs; - s.safety = kSafetyRising; - s.risingHoldRemaining = kRisingHoldWindows; - } else if (sampleUs > s.peakPerSubFrameUs * kSpikeFactor) { - s.peakPerSubFrameUs = kSpikeBlend * sampleUs + (1.0 - kSpikeBlend) * s.peakPerSubFrameUs; - s.safety = kSafetyRising; - s.risingHoldRemaining = kRisingHoldWindows; - } - - auto now = Clock::now(); - if (now - s.winStart < kSampleWindow) { - return; - } - - // End of a measurement period: refresh the average, decide whether the - // scene is still getting busier, and ease the busy estimate back down. - double mean = (double)s.winRunNs / s.winSubFrames / 1000.0; - s.emaPerSubFrameUs = s.emaPerSubFrameUs == 0.0 ? mean : kEmaAlpha * mean + (1.0 - kEmaAlpha) * s.emaPerSubFrameUs; - - bool rising = s.peakPerSubFrameUs > 0.0 && s.winMaxUs > s.peakPerSubFrameUs * kRisingThreshold; - if (rising) { - s.risingHoldRemaining = kRisingHoldWindows; - } else if (s.risingHoldRemaining > 0) { - s.risingHoldRemaining--; - } - s.safety = s.risingHoldRemaining > 0 ? kSafetyRising : kSafetySteady; - - s.peakPerSubFrameUs = std::max(s.winMaxUs, s.peakPerSubFrameUs * (1.0 - kPeakDecay) + s.winMaxUs * kPeakDecay); - - s.winRunNs = 0; - s.winSubFrames = 0; - s.winMaxUs = 0.0; - s.winStart = now; -} - -} // extern "C" diff --git a/src/port/Interpolation/AdaptiveFps.h b/src/port/Interpolation/AdaptiveFps.h deleted file mode 100644 index c2422b545..000000000 --- a/src/port/Interpolation/AdaptiveFps.h +++ /dev/null @@ -1,46 +0,0 @@ -#pragma once - -#include - -// Adaptive interpolation FPS cap. -// -// Drawing each extra interpolated frame is expensive, so asking for too many -// in a busy scene can starve the game and make it stutter. This times how long -// drawing takes and lowers the FPS just enough to keep the game smooth, then -// raises it again once the scene clears. -// -// Call order (from the gfx pipeline): -// AdaptiveFps_Configure(tickHz) // once at startup -// AdaptiveFps_SampleTick(logicNs) // each tick, before Cap -// AdaptiveFps_Cap(userTarget) // pick the allowed FPS -// AdaptiveFps_Sample(runNs) // after each frame is drawn -// -// Defaults assume the game runs at 30 fps native; pass a different rate to -// Configure() if not. On a 60 Hz display the result is either 60 or 30 with -// nothing in between (no whole number of frames fits), so it switches directly. - -#ifdef __cplusplus -extern "C" { -#endif - -// Set how many times per second the game updates. Also clears past -// measurements so a freshly loaded game starts fresh. Safe to call repeatedly. -void AdaptiveFps_Configure(uint32_t tickHz); - -// Returns the highest FPS the current scene can sustain, never above what the -// user asked for nor below the game's update rate. Returns the user's value -// until it has measured at least once. -uint32_t AdaptiveFps_Cap(uint32_t userTarget); - -// Report how long it took to draw one frame (nanoseconds), so the module can -// gauge how heavy the scene is. -void AdaptiveFps_Sample(long long runNs); - -// Report how long the game spent updating this tick before drawing started. -// Adaptive FPS reserves that time so a busy scene can't make it schedule too -// many interpolated frames. Call once per tick, before Cap(). -void AdaptiveFps_SampleTick(long long logicNs); - -#ifdef __cplusplus -} -#endif diff --git a/src/port/Interpolation/FrameInterpolation.cpp b/src/port/Interpolation/FrameInterpolation.cpp index 0d06f03b9..e56a641b5 100644 --- a/src/port/Interpolation/FrameInterpolation.cpp +++ b/src/port/Interpolation/FrameInterpolation.cpp @@ -1,5 +1,7 @@ #include "FrameInterpolation.h" +#include +#include #include #include #include @@ -71,8 +73,10 @@ struct FrameTree { float cameraPos[3] = { 0.0f, 0.0f, 0.0f }; bool hasCameraPos = false; bool valid = false; + std::atomic generation{ 0 }; void reset() { + generation.fetch_add(1, std::memory_order_release); toMtxs.clear(); projRots.clear(); sprites.clear(); @@ -85,10 +89,18 @@ struct FrameTree { } }; -FrameTree gTreeA; -FrameTree gTreeB; -FrameTree* gCurrent = &gTreeA; -FrameTree* gPrevious = &gTreeB; +// Ring of trees: the render side reads a (prev, curr) pair while the tick +// records the next one. Reuse is ownership-based; a submitted pair claims +// its two slots until that render finishes, and recording skips claimed slots. +constexpr int kRingSlots = 4; +FrameTree gRing[kRingSlots]; +std::atomic gSlotClaims[kRingSlots] = {}; +int gRecordSlot = 0; +int gLastRecordedSlot = -1; +FrameTree* gRecord = &gRing[0]; +FrameTree* gRenderPrev = nullptr; +FrameTree* gRenderCurr = nullptr; +bool gRenderShould = false; bool gRecording = false; bool gShouldInterpolate = true; @@ -134,25 +146,82 @@ InterpolationCache gCache; extern "C" { void FrameInterpolation_StartRecord(void) { - gCurrent->reset(); - gCurrent->toMtxs.reserve(512); - gCurrent->projRots.reserve(4); - gCurrent->sprites.reserve(256); - gCurrent->sigToToMtx.reserve(512); - gCurrent->sigToSprite.reserve(64); - gCurrent->scopeStack.push_back({ kFnvSeed, 0, 0 }); + for (int i = 0; i < kRingSlots; i++) { + gRecordSlot = (gRecordSlot + 1) % kRingSlots; + if (gSlotClaims[gRecordSlot].load(std::memory_order_acquire) == 0 && gRecordSlot != gLastRecordedSlot) { + break; + } + } + if (gSlotClaims[gRecordSlot].load(std::memory_order_acquire) != 0) { + // Should be impossible, but if it ever prints, a claim leaked. + SPDLOG_WARN("interp record forced into claimed slot {} claims=[{},{},{},{}]", gRecordSlot, + gSlotClaims[0].load(), gSlotClaims[1].load(), gSlotClaims[2].load(), gSlotClaims[3].load()); + } + gRecord = &gRing[gRecordSlot]; + gRecord->reset(); + gRecord->toMtxs.reserve(512); + gRecord->projRots.reserve(4); + gRecord->sprites.reserve(256); + gRecord->sigToToMtx.reserve(512); + gRecord->sigToSprite.reserve(64); + gRecord->scopeStack.push_back({ kFnvSeed, 0, 0 }); gShouldInterpolate = true; gNoInterpolateDepth = 0; gRecording = true; - // The old cache indexes into the tree this tick is about to overwrite. - gCache.built = false; - gCache.valid = false; } +// Idempotent: a threaded submitter has to close the session early, before the +// tree goes to another thread, so the tick's own call then finds it closed. void FrameInterpolation_StopRecord(void) { + if (!gRecording) { + return; + } gRecording = false; - gCurrent->valid = gShouldInterpolate; - std::swap(gCurrent, gPrevious); + gRecord->valid = gShouldInterpolate; + gLastRecordedSlot = gRecordSlot; +} + +// The pair for the tick being recorded right now, grabbed when a display list +// is handed off so it renders against the trees it was built from. +void FrameInterpolation_GetRecordingPair(int* prevSlot, int* currSlot, bool* shouldInterpolate) { + if (!gRecording) { + *prevSlot = -1; + *currSlot = -1; + *shouldInterpolate = false; + return; + } + *prevSlot = gLastRecordedSlot; + *currSlot = gRecordSlot; + *shouldInterpolate = gShouldInterpolate; +} + +// Claim and release bracket a pair's render lifetime: claimed on the tick side +// at submission, released once the render (and its workers) are done reading. +void FrameInterpolation_ClaimPair(int prevSlot, int currSlot) { + if (prevSlot >= 0 && prevSlot < kRingSlots) { + gSlotClaims[prevSlot].fetch_add(1, std::memory_order_release); + } + if (currSlot >= 0 && currSlot < kRingSlots) { + gSlotClaims[currSlot].fetch_add(1, std::memory_order_release); + } +} + +void FrameInterpolation_ReleasePair(int prevSlot, int currSlot) { + if (prevSlot >= 0 && prevSlot < kRingSlots) { + gSlotClaims[prevSlot].fetch_sub(1, std::memory_order_release); + } + if (currSlot >= 0 && currSlot < kRingSlots) { + gSlotClaims[currSlot].fetch_sub(1, std::memory_order_release); + } +} + +// Pins the trees this pass blends and drops the previous pass's pairing cache. +void FrameInterpolation_BeginRenderPass(int prevSlot, int currSlot, bool shouldInterpolate) { + gRenderPrev = (prevSlot >= 0 && prevSlot < kRingSlots) ? &gRing[prevSlot] : nullptr; + gRenderCurr = (currSlot >= 0 && currSlot < kRingSlots) ? &gRing[currSlot] : nullptr; + gRenderShould = shouldInterpolate && gRenderCurr != nullptr && gRenderPrev != nullptr; + gCache.built = false; + gCache.valid = false; } void FrameInterpolation_ShouldInterpolateFrame(bool shouldInterpolate) { @@ -163,18 +232,18 @@ void FrameInterpolation_RecordOpenChild(const void* key, uintptr_t id) { if (!gRecording) { return; } - uint64_t h = gCurrent->scopeStack.back().pathHash; + uint64_t h = gRecord->scopeStack.back().pathHash; h = fnvMix(h, reinterpret_cast(key)); h = fnvMix(h, static_cast(id)); - gCurrent->scopeStack.push_back({ h, 0, 0 }); + gRecord->scopeStack.push_back({ h, 0, 0 }); } void FrameInterpolation_RecordCloseChild(void) { if (!gRecording) { return; } - if (gCurrent->scopeStack.size() > 1) { - gCurrent->scopeStack.pop_back(); + if (gRecord->scopeStack.size() > 1) { + gRecord->scopeStack.pop_back(); } } @@ -193,18 +262,18 @@ void FrameInterpolation_RecordMatrixToMtx(void* dst, const float src[4][4]) { if (!gRecording) { return; } - ScopeFrame& scope = gCurrent->scopeStack.back(); + ScopeFrame& scope = gRecord->scopeStack.back(); uint64_t sig = fnvMix(fnvMix(scope.pathHash, kSigKindToMtx), scope.toMtxIdx); scope.toMtxIdx++; - uint32_t idx = static_cast(gCurrent->toMtxs.size()); - gCurrent->toMtxs.emplace_back(); - ToMtxData& d = gCurrent->toMtxs.back(); + uint32_t idx = static_cast(gRecord->toMtxs.size()); + gRecord->toMtxs.emplace_back(); + ToMtxData& d = gRecord->toMtxs.back(); d.dst = dst; std::memcpy(d.src, src, sizeof(float) * 16); d.pathSig = sig; d.noInterpolate = (gNoInterpolateDepth > 0); - gCurrent->sigToToMtx.emplace(sig, idx); + gRecord->sigToToMtx.emplace(sig, idx); } void FrameInterpolation_RecordCameraProjectionRotation(void* rollMtx, float rollDeg, void* pitchMtx, float pitchDeg, @@ -212,8 +281,8 @@ void FrameInterpolation_RecordCameraProjectionRotation(void* rollMtx, float roll if (!gRecording) { return; } - gCurrent->projRots.emplace_back(); - CameraProjRotData& d = gCurrent->projRots.back(); + gRecord->projRots.emplace_back(); + CameraProjRotData& d = gRecord->projRots.back(); d.rollMtx = rollMtx; d.pitchMtx = pitchMtx; d.yawMtx = yawMtx; @@ -226,10 +295,10 @@ void FrameInterpolation_RecordCameraPosition(const float pos[3]) { if (!gRecording || pos == nullptr) { return; } - gCurrent->cameraPos[0] = pos[0]; - gCurrent->cameraPos[1] = pos[1]; - gCurrent->cameraPos[2] = pos[2]; - gCurrent->hasCameraPos = true; + gRecord->cameraPos[0] = pos[0]; + gRecord->cameraPos[1] = pos[1]; + gRecord->cameraPos[2] = pos[2]; + gRecord->hasCameraPos = true; } void FrameInterpolation_NoInterpolatePush(void) { @@ -248,13 +317,13 @@ void FrameInterpolation_RecordSpriteDraw(int kind, void* dst, const float camRel if (!gRecording) { return; } - ScopeFrame& scope = gCurrent->scopeStack.back(); + ScopeFrame& scope = gRecord->scopeStack.back(); uint64_t sig = fnvMix(fnvMix(scope.pathHash, kSigKindSprite), scope.spriteIdx); scope.spriteIdx++; - uint32_t idx = static_cast(gCurrent->sprites.size()); - gCurrent->sprites.emplace_back(); - SpriteDrawData& d = gCurrent->sprites.back(); + uint32_t idx = static_cast(gRecord->sprites.size()); + gRecord->sprites.emplace_back(); + SpriteDrawData& d = gRecord->sprites.back(); d.dst = dst; std::memcpy(d.camRelPos, camRelPos, sizeof(float) * 3); std::memcpy(d.scale, scale, sizeof(float) * 3); @@ -269,12 +338,12 @@ void FrameInterpolation_RecordSpriteDraw(int kind, void* dst, const float camRel d.pathSig = sig; d.kind = static_cast(kind); d.mirrored = (mirrored != 0); - gCurrent->sigToSprite.emplace(sig, idx); + gRecord->sigToSprite.emplace(sig, idx); } void FrameInterpolation_DontInterpolateCamera(void) { - if (gPrevious != nullptr) { - gPrevious->valid = false; + if (gLastRecordedSlot >= 0) { + gRing[gLastRecordedSlot].valid = false; } } @@ -326,23 +395,25 @@ inline float lerpAngleDegSP(float a, float b, float tt) { void BuildInterpolationCache() { gCache.reset(); gCache.built = true; - if (!gPrevious->valid) { + if (gRenderPrev == nullptr || gRenderCurr == nullptr || !gRenderPrev->valid) { return; } + const uint32_t prevGen = gRenderPrev->generation.load(std::memory_order_acquire); + const uint32_t currGen = gRenderCurr->generation.load(std::memory_order_acquire); - gCache.prevHasCameraPos = gPrevious->hasCameraPos; + gCache.prevHasCameraPos = gRenderPrev->hasCameraPos; if (gCache.prevHasCameraPos) { - gCache.prevCameraPos[0] = gPrevious->cameraPos[0]; - gCache.prevCameraPos[1] = gPrevious->cameraPos[1]; - gCache.prevCameraPos[2] = gPrevious->cameraPos[2]; + gCache.prevCameraPos[0] = gRenderPrev->cameraPos[0]; + gCache.prevCameraPos[1] = gRenderPrev->cameraPos[1]; + gCache.prevCameraPos[2] = gRenderPrev->cameraPos[2]; } - const std::vector& currToMtxs = gCurrent->toMtxs; - const std::vector& prevToMtxs = gPrevious->toMtxs; - const std::vector& currSprites = gCurrent->sprites; - const std::vector& prevSprites = gPrevious->sprites; - const std::unordered_map& prevSigMap = gPrevious->sigToToMtx; - const std::unordered_map& prevSpriteMap = gPrevious->sigToSprite; + const std::vector& currToMtxs = gRenderCurr->toMtxs; + const std::vector& prevToMtxs = gRenderPrev->toMtxs; + const std::vector& currSprites = gRenderCurr->sprites; + const std::vector& prevSprites = gRenderPrev->sprites; + const std::unordered_map& prevSigMap = gRenderPrev->sigToToMtx; + const std::unordered_map& prevSpriteMap = gRenderPrev->sigToSprite; gCache.pairedToMtxs.reserve(currToMtxs.size()); gCache.pairedSprites.reserve(currSprites.size()); @@ -357,7 +428,7 @@ void BuildInterpolationCache() { continue; } auto it = prevSigMap.find(c.pathSig); - if (it == prevSigMap.end()) { + if (it == prevSigMap.end() || it->second >= prevToMtxs.size()) { continue; } const ToMtxData& p = prevToMtxs[it->second]; @@ -373,7 +444,7 @@ void BuildInterpolationCache() { for (uint32_t i = 0; i < currSprites.size(); i++) { const SpriteDrawData& c = currSprites[i]; auto it = prevSpriteMap.find(c.pathSig); - if (it == prevSpriteMap.end() || prevSprites[it->second].kind != c.kind) { + if (it == prevSpriteMap.end() || it->second >= prevSprites.size() || prevSprites[it->second].kind != c.kind) { gCache.pairedSprites.push_back({ i, UINT32_MAX }); continue; } @@ -387,6 +458,17 @@ void BuildInterpolationCache() { gCache.pairedSprites.push_back({ i, it->second }); } + // A tree recycled while we walked it means every index above is suspect. + // Drop the pass to uninterpolated and say which slot collided. + if (gRenderPrev->generation.load(std::memory_order_acquire) != prevGen || + gRenderCurr->generation.load(std::memory_order_acquire) != currGen) { + SPDLOG_WARN("interp tree recycled mid-pass: prev={} curr={} record={} last={} claims=[{},{},{},{}]", + (int)(gRenderPrev - gRing), (int)(gRenderCurr - gRing), gRecordSlot, gLastRecordedSlot, + gSlotClaims[0].load(), gSlotClaims[1].load(), gSlotClaims[2].load(), gSlotClaims[3].load()); + gCache.reset(); + gCache.built = true; + return; + } gCache.valid = true; } @@ -470,7 +552,7 @@ void emitSprite(const SpriteDrawData& L, std::unordered_map& replace void FrameInterpolation_Interpolate(float t, std::unordered_map& replacements) { replacements.clear(); - if (!gShouldInterpolate) { + if (!gRenderShould) { return; } if (!gCache.built) { @@ -482,22 +564,22 @@ void FrameInterpolation_Interpolate(float t, std::unordered_map& rep // A large camera jump means a warp or camera cut; blending across it // would draw the world halfway between two scenes for a frame. - if (gCache.prevHasCameraPos && gCurrent->hasCameraPos) { - float dx = gCurrent->cameraPos[0] - gCache.prevCameraPos[0]; - float dy = gCurrent->cameraPos[1] - gCache.prevCameraPos[1]; - float dz = gCurrent->cameraPos[2] - gCache.prevCameraPos[2]; + if (gCache.prevHasCameraPos && gRenderCurr->hasCameraPos) { + float dx = gRenderCurr->cameraPos[0] - gCache.prevCameraPos[0]; + float dy = gRenderCurr->cameraPos[1] - gCache.prevCameraPos[1]; + float dz = gRenderCurr->cameraPos[2] - gCache.prevCameraPos[2]; constexpr float kCutDistSq = 1000.0f * 1000.0f; if (dx * dx + dy * dy + dz * dz > kCutDistSq) { return; } } - const std::vector& prevToMtxs = gPrevious->toMtxs; - const std::vector& currToMtxs = gCurrent->toMtxs; - const std::vector& prevSpritesData = gPrevious->sprites; - const std::vector& currSpritesData = gCurrent->sprites; + const std::vector& prevToMtxs = gRenderPrev->toMtxs; + const std::vector& currToMtxs = gRenderCurr->toMtxs; + const std::vector& prevSpritesData = gRenderPrev->sprites; + const std::vector& currSpritesData = gRenderCurr->sprites; - replacements.reserve(gCache.pairedToMtxs.size() + gCache.pairedSprites.size() + gCurrent->projRots.size() * 3); + replacements.reserve(gCache.pairedToMtxs.size() + gCache.pairedSprites.size() + gRenderCurr->projRots.size() * 3); const float w = 1.0f - t; for (const PairedToMtx& pair : gCache.pairedToMtxs) { @@ -534,8 +616,8 @@ void FrameInterpolation_Interpolate(float t, std::unordered_map& rep emitSprite(L, replacements); } - const std::vector& prevProj = gPrevious->projRots; - const std::vector& currProj = gCurrent->projRots; + const std::vector& prevProj = gRenderPrev->projRots; + const std::vector& currProj = gRenderCurr->projRots; if (prevProj.size() == currProj.size()) { for (size_t i = 0; i < currProj.size(); i++) { const CameraProjRotData& p = prevProj[i]; diff --git a/src/port/Interpolation/FrameInterpolation.h b/src/port/Interpolation/FrameInterpolation.h index 25b3e32aa..441384ff9 100644 --- a/src/port/Interpolation/FrameInterpolation.h +++ b/src/port/Interpolation/FrameInterpolation.h @@ -21,6 +21,14 @@ void FrameInterpolation_StartRecord(void); void FrameInterpolation_StopRecord(void); void FrameInterpolation_ShouldInterpolateFrame(bool shouldInterpolate); +// Which pair of recorded ticks a render pass blends between. The threaded +// path captures the pair when a display list is submitted and applies it when +// that list renders; the single-threaded path uses the live variant. +void FrameInterpolation_GetRecordingPair(int* prevSlot, int* currSlot, bool* shouldInterpolate); +void FrameInterpolation_ClaimPair(int prevSlot, int currSlot); +void FrameInterpolation_ReleasePair(int prevSlot, int currSlot); +void FrameInterpolation_BeginRenderPass(int prevSlot, int currSlot, bool shouldInterpolate); + // Hierarchical scope (cross-tick pairing identity). void FrameInterpolation_RecordOpenChild(const void* key, uintptr_t id); void FrameInterpolation_RecordCloseChild(void); diff --git a/src/port/OS/OS.h b/src/port/OS/OS.h new file mode 100644 index 000000000..f57911328 --- /dev/null +++ b/src/port/OS/OS.h @@ -0,0 +1,73 @@ +#ifndef PORT_OS_H +#define PORT_OS_H + +// N64 OS SDK +// +// libultraship already implements most of the libultra surface, and where its +// version is correct for a PC port we use it as-is. This layer exists only for +// the calls libultraship cannot serve, so that the decomp's own threading code +// can run instead of being replaced by port stand-ins. + +#ifdef __cplusplus +extern "C" { +#endif + +#include "libultraship/libultra/thread.h" + +void OS_CreateThread(OSThread* thread, OSId id, void* entry, void* arg, void* sp, OSPri p); +void OS_StartThread(OSThread* thread); +void OS_StopThread(OSThread* thread); +void OS_DestroyThread(OSThread* thread); +void OS_SetThreadPri(OSThread* thread, OSPri p); + +// Allowlist one decomp thread entry point. Until its entry is passed here, an +// osCreateThread/osStartThread pair is recorded but never launched, so threads +// are revived deliberately, one consumer at a time. +void OS_EnableThreadEntry(void* entry); + +#include "libultraship/libultra/message.h" + +// OS_MESG_BLOCK only blocks on queues opted in here. +void OS_SetQueueBlocking(OSMesgQueue* mq, int enabled); + +// Watchdog diagnostics: threads currently parked inside a blocking +// osSendMesg/osRecvMesg, so a stall dump can say where each one waits. +typedef struct OS_BlockedWait { + unsigned long tid; // SDL thread id + OSMesgQueue* mq; + int isSend; // 0 = recv, 1 = send/jam +} OS_BlockedWait; +int OS_MesgSnapshotBlockedWaits(OS_BlockedWait* out, int max); + +// Raise a registered hardware event (VI retrace, SI done, RDP done). +void OS_SendEventMesg(OSEvent event); + +// Raise an event ahead of whatever the recipient already has queued, the way +// an interrupt preempts. Used for completions that must not be reordered +// behind pending messages. +void OS_JamEventMesg(OSEvent event); + +// The VI ticker starts with osCreateViManager; this stops it at shutdown. +void OS_StopViTicker(void); + +// Complete one pending controller read: poll the pads and raise OS_EVENT_SI. +// Called by the thread that owns SDL input. +int OS_SiService(void); + +// Whether osViBlack has the display blanked. The renderer blacks the presented +// frame while the world keeps rendering underneath. +int OS_ViBlackActive(void); + +#include "libultraship/libultra/sptask.h" + +// Take the task osSpTaskStartGo handed over, or NULL if none is pending. +OSTask* OS_SpTakePendingTask(void); + +// Same, but without consuming it; the watchdog reports what is in flight. +OSTask* OS_SpPeekPendingTask(void); + +#ifdef __cplusplus +} +#endif + +#endif // PORT_OS_H diff --git a/src/port/OS/OS_AI.cpp b/src/port/OS/OS_AI.cpp new file mode 100644 index 000000000..3c4e89a99 --- /dev/null +++ b/src/port/OS/OS_AI.cpp @@ -0,0 +1,48 @@ +// This file should eventually go to LUS as the AI api. +// +// The audio interface, backed by the libultraship audio player. The decomp's +// audio manager runs its original path and this is the DAC at the end of it. + +#include "OS.h" + +#include + +#include "port/UI/cvar_prefixes.h" + +extern "C" { +#include "libultraship/libultra/types.h" +#include "libultraship/libultra/os.h" +int32_t AudioPlayerBuffered(void); +int32_t AudioPlayerGetDesiredBuffered(void); +void AudioPlayerPlayFrame(const uint8_t* buf, size_t len); +} + +#include +#include + +extern "C" u32 osAiGetLength(void) { + int32_t excess = AudioPlayerBuffered() - AudioPlayerGetDesiredBuffered(); + return excess > 0 ? (u32)excess * 4 : 0; +} + +extern "C" s32 osAiSetNextBuffer(void* buff, size_t len) { + static bool sPrimed = false; + if (!sPrimed) { + sPrimed = true; + std::vector silence((size_t)AudioPlayerGetDesiredBuffered() * 4, 0); + AudioPlayerPlayFrame(silence.data(), silence.size()); + } + + float masterVol = CVarGetInteger(CVAR_SETTING("Volume.Master"), 100) / 100.0f; + if (masterVol >= 1.0f) { + AudioPlayerPlayFrame((const uint8_t*)buff, len); + return 0; + } + std::vector scaled(len / 2); + const int16_t* src = (const int16_t*)buff; + for (size_t i = 0; i < scaled.size(); i++) { + scaled[i] = (int16_t)(src[i] * masterVol); + } + AudioPlayerPlayFrame((const uint8_t*)scaled.data(), len); + return 0; +} diff --git a/src/port/OS/OS_Cont.cpp b/src/port/OS/OS_Cont.cpp new file mode 100644 index 000000000..15ebdba1f --- /dev/null +++ b/src/port/OS/OS_Cont.cpp @@ -0,0 +1,89 @@ +// This file should eventually go to LUS as the SI api. The controller init and +// motor pieces are unchanged from libultra/os.cpp and only live here because +// taking osSetTimer port-side meant taking that whole object with it. + +#include "OS.h" + +#include + +#include +#include +#include + +extern "C" { + +uint8_t __osMaxControllers = MAXCONTROLLERS; + +int32_t osContInit(OSMesgQueue* mq, uint8_t* controllerBits, OSContStatus* status) { + *controllerBits = 0; + status->status |= 1; + + // The SDL game-controller subsystem and mappings are brought up earlier, in + // Context::InitControlDeck, so controllers work in pre-game UI. ControlDeck::Init + // stays here as it needs the game's controllerBits. + Ship::Context::GetRawInstance()->GetControlDeck()->Init(controllerBits); + + return 0; +} + +// The SI, as a request and a completion rather than an inline poll. +// +// LUS's StartReadData does nothing and GetReadData polls the control deck on +// whichever thread asked, which cannot work once the tick is off the window +// thread: SDL input belongs to the thread pumping its events. A read is +// posted here, completed by that thread in OS_SiService, and answered with +// OS_EVENT_SI, which is what pfsManager_init already registered for and what +// its thread has been waiting on all along. +namespace { +std::atomic sReadPending{ false }; +std::mutex sLatchMutex; +OSContPad sLatch[MAXCONTROLLERS]; +std::atomic sLatchValid{ false }; +} // namespace + +int32_t osContStartReadData(OSMesgQueue* mesg) { + (void)mesg; // completion goes to whoever registered for OS_EVENT_SI + sReadPending.store(true, std::memory_order_release); + return 0; +} + +extern "C" int OS_SiService(void) { + if (!sReadPending.exchange(false, std::memory_order_acq_rel)) { + return 0; + } + { + std::lock_guard lock(sLatchMutex); + memset(sLatch, 0, sizeof(sLatch)); + Ship::Context::GetRawInstance()->GetControlDeck()->WriteToPad(sLatch); + } + sLatchValid.store(true, std::memory_order_release); + OS_SendEventMesg(OS_EVENT_SI); + return 1; +} + +void osContGetReadData(OSContPad* pad) { + if (sLatchValid.load(std::memory_order_acquire)) { + std::lock_guard lock(sLatchMutex); + memcpy(pad, sLatch, sizeof(sLatch)); + return; + } + memset(pad, 0, sizeof(OSContPad) * __osMaxControllers); +} + +int32_t __osMotorAccess(OSPfs* pfs, uint32_t vibrate) { + auto io = Ship::Context::GetRawInstance()->GetControlDeck()->GetControllerByPort(pfs->channel)->GetRumble(); + if (vibrate) { + io->StartRumble(); + } else { + io->StopRumble(); + } + + return 0; +} + +int32_t osMotorInit(OSMesgQueue* ctrlrqueue, OSPfs* pfs, int32_t channel) { + pfs->channel = channel; + return 0; +} + +} // extern "C" diff --git a/src/port/OS/OS_Mesg.cpp b/src/port/OS/OS_Mesg.cpp new file mode 100644 index 000000000..a14c85482 --- /dev/null +++ b/src/port/OS/OS_Mesg.cpp @@ -0,0 +1,228 @@ +// This file should eventually replace libultraship's os_mesg.cpp + +#include +#include +#include +#include + +#include + +#include "OS.h" + +extern "C" { +#include "libultraship/libultra/message.h" +#include "libultraship/libultra/internal.h" + +// Event -> (queue, message) routing table. +// Override from lus os_vi.cpp. +__OSEventState __osEventStateTab[OS_NUM_EVENTS] = { 0 }; +} + +// Message queues that can actually block. +// +// LUS's queues never do: osRecvMesg on an empty queue just returns -1. Every +// decomp thread is a loop parked on a queue, so they'd spin instead of sleeping +// and nobody would ever get woken. +// +// The queue fields themselves stay as they were, since decomp code reads them +// directly (pfsmanager watches validCount); only the waiting is ours, a +// condvar pair per queue where libultra used priority-ordered thread lists. +// Blocking is opt-in per queue. + +namespace { + +struct QueueSync { + std::condition_variable notEmpty; + std::condition_variable notFull; + bool blockingEnabled = false; +}; + +std::mutex sMesgMutex; +std::map sQueueSync; + +QueueSync& SyncFor(OSMesgQueue* mq) { + return sQueueSync[mq]; +} + +// Blocked-wait registry for the watchdog. Slots are atomics so a stall dump +// can read them without taking sMesgMutex (which a deadlocked thread may +// implicate); marking and clearing happen under sMesgMutex on the wait path. +constexpr int kMaxBlockedWaits = 16; +struct BlockedWaitSlot { + std::atomic tid{ 0 }; + std::atomic mq{ nullptr }; + std::atomic isSend{ 0 }; +}; +BlockedWaitSlot sBlockedWaits[kMaxBlockedWaits]; + +int MarkBlockedWait(OSMesgQueue* mq, int isSend) { + unsigned long tid = (unsigned long)SDL_ThreadID(); + for (int i = 0; i < kMaxBlockedWaits; i++) { + unsigned long expected = 0; + if (sBlockedWaits[i].tid.compare_exchange_strong(expected, tid, std::memory_order_acq_rel)) { + sBlockedWaits[i].mq.store(mq, std::memory_order_release); + sBlockedWaits[i].isSend.store(isSend, std::memory_order_release); + return i; + } + } + return -1; +} + +void ClearBlockedWait(int slot) { + if (slot >= 0) { + sBlockedWaits[slot].mq.store(nullptr, std::memory_order_release); + sBlockedWaits[slot].tid.store(0, std::memory_order_release); + } +} + +} // namespace + +extern "C" { + +void osCreateMesgQueue(OSMesgQueue* mq, OSMesg* msgBuf, int32_t count) { + std::lock_guard lock(sMesgMutex); + mq->mtqueue = nullptr; + mq->fullqueue = nullptr; + mq->validCount = 0; + mq->first = 0; + mq->msgCount = count; + mq->msg = msgBuf; + sQueueSync[mq]; +} + +int32_t osSendMesg(OSMesgQueue* mq, OSMesg msg, int32_t flag) { + std::unique_lock lock(sMesgMutex); + QueueSync& sync = SyncFor(mq); + int waitSlot = -1; + while (mq->validCount >= mq->msgCount) { + if (flag != OS_MESG_BLOCK || !sync.blockingEnabled) { + ClearBlockedWait(waitSlot); + return -1; + } + if (waitSlot < 0) { + waitSlot = MarkBlockedWait(mq, 1); + } + sync.notFull.wait(lock); + } + ClearBlockedWait(waitSlot); + s32 last = (mq->first + mq->validCount) % mq->msgCount; + mq->msg[last] = msg; + mq->validCount++; + sync.notEmpty.notify_one(); + return 0; +} + +// LUS bails when the queue is empty, which has it backwards. +// A jam should fail when there's no room, same as a send. +int32_t osJamMesg(OSMesgQueue* mq, OSMesg msg, int32_t flag) { + std::unique_lock lock(sMesgMutex); + QueueSync& sync = SyncFor(mq); + int waitSlot = -1; + while (mq->validCount >= mq->msgCount) { + if (flag != OS_MESG_BLOCK || !sync.blockingEnabled) { + ClearBlockedWait(waitSlot); + return -1; + } + if (waitSlot < 0) { + waitSlot = MarkBlockedWait(mq, 1); + } + sync.notFull.wait(lock); + } + ClearBlockedWait(waitSlot); + mq->first = (mq->first + mq->msgCount - 1) % mq->msgCount; + mq->msg[mq->first] = msg; + mq->validCount++; + sync.notEmpty.notify_one(); + return 0; +} + +int32_t osRecvMesg(OSMesgQueue* mq, OSMesg* msg, int32_t flag) { + std::unique_lock lock(sMesgMutex); + QueueSync& sync = SyncFor(mq); + int waitSlot = -1; + while (mq->validCount == 0) { + if (flag != OS_MESG_BLOCK || !sync.blockingEnabled) { + ClearBlockedWait(waitSlot); + return -1; + } + if (waitSlot < 0) { + waitSlot = MarkBlockedWait(mq, 0); + } + sync.notEmpty.wait(lock); + } + ClearBlockedWait(waitSlot); + if (msg != nullptr) { + *msg = mq->msg[mq->first]; + } + mq->first = (mq->first + 1) % mq->msgCount; + mq->validCount--; + sync.notFull.notify_one(); + return 0; +} + +void osSetEventMesg(OSEvent event, OSMesgQueue* mq, OSMesg msg) { + std::lock_guard lock(sMesgMutex); + if (event < OS_NUM_EVENTS) { + __osEventStateTab[event].queue = mq; + __osEventStateTab[event].msg = msg; + } +} + +void OS_SetQueueBlocking(OSMesgQueue* mq, int enabled) { + std::lock_guard lock(sMesgMutex); + SyncFor(mq).blockingEnabled = (enabled != 0); +} + +// Lock-free on purpose: the caller is a watchdog inspecting a possible +// deadlock, so it must not touch sMesgMutex. Entries can be mid-update; +// they are diagnostics, not decisions. +int OS_MesgSnapshotBlockedWaits(OS_BlockedWait* out, int max) { + int n = 0; + for (int i = 0; i < kMaxBlockedWaits && n < max; i++) { + unsigned long tid = sBlockedWaits[i].tid.load(std::memory_order_acquire); + OSMesgQueue* mq = sBlockedWaits[i].mq.load(std::memory_order_acquire); + if (tid == 0 || mq == nullptr) { + continue; + } + out[n].tid = tid; + out[n].mq = mq; + out[n].isSend = sBlockedWaits[i].isSend.load(std::memory_order_acquire); + n++; + } + return n; +} + +// Raise a hardware event. Nothing interrupts on PC, so whoever stands in for a +// piece of hardware calls this when the real one would have fired. +void OS_SendEventMesg(OSEvent event) { + OSMesgQueue* mq = nullptr; + OSMesg msg = {}; + { + std::lock_guard lock(sMesgMutex); + if (event >= OS_NUM_EVENTS || __osEventStateTab[event].queue == nullptr) { + return; + } + mq = __osEventStateTab[event].queue; + msg = __osEventStateTab[event].msg; + } + osSendMesg(mq, msg, OS_MESG_NOBLOCK); +} + +// Same, but the message goes to the front of the queue. An interrupt landed +// ahead of whatever the recipient had queued; a hardware stand-in whose event +// must be seen before pending messages jams instead of sending. +void OS_JamEventMesg(OSEvent event) { + OSMesgQueue* mq = nullptr; + OSMesg msg = {}; + { + std::lock_guard lock(sMesgMutex); + if (event >= OS_NUM_EVENTS || __osEventStateTab[event].queue == nullptr) { + return; + } + mq = __osEventStateTab[event].queue; + msg = __osEventStateTab[event].msg; + } + osJamMesg(mq, msg, OS_MESG_NOBLOCK); +} + +} // extern "C" diff --git a/src/port/OS/OS_RCP.cpp b/src/port/OS/OS_RCP.cpp new file mode 100644 index 000000000..c2433a4fe --- /dev/null +++ b/src/port/OS/OS_RCP.cpp @@ -0,0 +1,102 @@ +// This file should eventually go to LUS as the RCP api + +#include "OS.h" + +#include + +extern "C" { +#include +#include "libultraship/libultra/types.h" +#include "libultraship/libultra/sptask.h" +} + +// The RDP command unit's status register. +// +// Nothing on PC obeys FREEZE, since there is no RDP to stall, but thread5 runs +// its pipeline off that bit: it freezes after handing a frame over and clears +// it on the next retrace, which is what keeps one frame in flight. Holding the +// bit as real state lets that code run as written instead of being replaced. + +namespace { +std::atomic sStatus{ 0 }; +} + +extern "C" u32 osDpGetStatus(void) { + return sStatus.load(std::memory_order_acquire); +} + +// Writes are set/clear command pairs, mirrored into the bits reads return. +extern "C" void osDpSetStatus(u32 data) { + uint32_t set = 0; + uint32_t clr = 0; + if (data & DPC_SET_FREEZE) { + set |= DPC_STATUS_FREEZE; + } + if (data & DPC_CLR_FREEZE) { + clr |= DPC_STATUS_FREEZE; + } + if (data & DPC_SET_FLUSH) { + set |= DPC_STATUS_FLUSH; + } + if (data & DPC_CLR_FLUSH) { + clr |= DPC_STATUS_FLUSH; + } + if (set != 0) { + sStatus.fetch_or(set, std::memory_order_acq_rel); + } + if (clr != 0) { + sStatus.fetch_and(~clr, std::memory_order_acq_rel); + } +} + +// Task submission. +// +// There is no RSP, so this only hands the task over; whoever drains it decides +// what running one means. For the graphics task that has to be the window +// thread, since it ends up in the renderer. +// +// One slot is enough: the decomp starts a task and waits for its SP event +// before starting the next, so a second can never be pending. +namespace { +std::atomic sPendingTask{ nullptr }; +std::atomic sYieldPending{ false }; // yield requested, not yet observed +std::atomic sResumePending{ false }; // next gfx StartGo is the resume +} + +extern "C" void osSpTaskYield(void) { + sYieldPending.store(true, std::memory_order_release); + OS_JamEventMesg(OS_EVENT_SP); +} + +extern "C" OSYieldResult osSpTaskYielded(OSTask* task) { + (void)task; + if (sYieldPending.exchange(false, std::memory_order_acq_rel)) { + sResumePending.store(true, std::memory_order_release); + return 1; + } + return 0; +} + +extern "C" void osSpTaskLoad(OSTask* task) { + (void)task; // no DMEM to load; StartGo carries the pointer +} + +extern "C" void osSpTaskStartGo(OSTask* task) { + if (task->t.type == M_AUDTASK) { + OS_JamEventMesg(OS_EVENT_SP); + return; + } + + if (sResumePending.exchange(false, std::memory_order_acq_rel)) { + return; + } + sPendingTask.store(task, std::memory_order_release); +} + +extern "C" OSTask* OS_SpTakePendingTask(void) { + return sPendingTask.exchange(nullptr, std::memory_order_acq_rel); +} + +extern "C" OSTask* OS_SpPeekPendingTask(void) { + return sPendingTask.load(std::memory_order_acquire); +} diff --git a/src/port/OS/OS_Threads.cpp b/src/port/OS/OS_Threads.cpp new file mode 100644 index 000000000..d94fd7a34 --- /dev/null +++ b/src/port/OS/OS_Threads.cpp @@ -0,0 +1,93 @@ +// This file should eventually go to LUS as the threading api + +#include "OS.h" + +#include +#include +#include +#include + +namespace { + +struct OsThreadState { + void (*entry)(void*) = nullptr; + void* arg = nullptr; + OSPri pri = 0; + OSId id = 0; + std::thread worker; + bool started = false; +}; + +std::mutex sTableMutex; +std::map sThreads; +std::set sEnabledEntries; + +bool ThreadEnabled(void* entry) { + return sEnabledEntries.count(entry) != 0; +} + +} // namespace + +extern "C" void OS_EnableThreadEntry(void* entry) { + std::lock_guard lock(sTableMutex); + sEnabledEntries.insert(entry); +} + +extern "C" void OS_CreateThread(OSThread* thread, OSId id, void* entry, void* arg, void* sp, OSPri p) { + (void)sp; // N64 stack pointers are meaningless here + std::lock_guard lock(sTableMutex); + OsThreadState& st = sThreads[thread]; + st.entry = (void (*)(void*))entry; + st.arg = arg; + st.pri = p; + st.id = id; + st.started = false; +} + +extern "C" void OS_StartThread(OSThread* thread) { + std::lock_guard lock(sTableMutex); + auto it = sThreads.find(thread); + if (it == sThreads.end() || it->second.started || it->second.entry == nullptr) { + return; + } + if (!ThreadEnabled((void*)it->second.entry)) { + return; + } + it->second.started = true; + it->second.worker = std::thread(it->second.entry, it->second.arg); + it->second.worker.detach(); +} + +extern "C" void OS_StopThread(OSThread* thread) { + // N64 semantics are preemptive suspension, which std::thread cannot do. + // Revived consumers must exit cooperatively; Stop just joins if running. + OS_DestroyThread(thread); +} + +extern "C" void OS_DestroyThread(OSThread* thread) { + std::thread worker; + { + std::lock_guard lock(sTableMutex); + auto it = sThreads.find(thread); + if (it == sThreads.end()) { + return; + } + worker = std::move(it->second.worker); + sThreads.erase(it); + } + if (worker.joinable()) { + worker.join(); + } +} + +// Priority is recorded but not applied: the N64 scheduler was cooperative and +// priority-ordered, while these are preemptive OS threads. What the game needs +// from priority is queue ordering and blocking behavior, which the queues +// provide; mapping it onto OS thread priorities would only add scheduler noise. +extern "C" void OS_SetThreadPri(OSThread* thread, OSPri p) { + std::lock_guard lock(sTableMutex); + auto it = sThreads.find(thread); + if (it != sThreads.end()) { + it->second.pri = p; + } +} diff --git a/src/port/OS/OS_Time.cpp b/src/port/OS/OS_Time.cpp new file mode 100644 index 000000000..b068836d7 --- /dev/null +++ b/src/port/OS/OS_Time.cpp @@ -0,0 +1,39 @@ +// This file should eventually go back to LUS; it is unchanged from its +// libultra/os.cpp original, and only lives here because taking osSetTimer +// port-side means taking that whole object with it. + +#include +#include + +extern "C" { +#include "libultraship/libultra/types.h" +#include "libultraship/libultra/os.h" +} + +// A chrono duration matching the N64's 46.875MHz clock rate. +typedef std::ratio<3000, 64> n64ClockRatio; +typedef std::ratio_divide n64CycleRate; +typedef std::chrono::duration n64CycleRateDuration; + +extern "C" { + +uint64_t __osCurrentTime = 0; + +void osSetTime(OSTime time) { + __osCurrentTime = + std::chrono::duration_cast(std::chrono::steady_clock::now().time_since_epoch()).count() + + time; +} + +uint64_t osGetTime() { + return std::chrono::duration_cast(std::chrono::steady_clock::now().time_since_epoch()) + .count() - + __osCurrentTime; +} + +uint32_t osGetCount() { + return std::chrono::duration_cast(std::chrono::steady_clock::now().time_since_epoch()) + .count(); +} + +} // extern "C" diff --git a/src/port/OS/OS_Timer.cpp b/src/port/OS/OS_Timer.cpp new file mode 100644 index 000000000..342e7f8cf --- /dev/null +++ b/src/port/OS/OS_Timer.cpp @@ -0,0 +1,95 @@ +// This file should eventually go to LUS as the timer api + +#include "OS.h" + +#include +#include +#include +#include +#include + +extern "C" { +#include "libultraship/libultra/time.h" +} + +// Deadline timers. LUS's osSetTimer returns 0 without arming anything and it +// has no osStopTimer at all, so a decomp timer never fired. Thread5 uses one +// to pace controller reads. +// +// Countdowns are in 46.875MHz ticks; 1e9/46875000 is exactly 64/3, so +// nanoseconds are ticks * 64 / 3 with no rounding. +namespace { + +struct Armed { + std::chrono::steady_clock::time_point deadline; + std::chrono::nanoseconds interval; + OSMesgQueue* mq = nullptr; + OSMesg msg = {}; +}; + +std::mutex sMutex; +std::map sTimers; +std::condition_variable sCv; +bool sWorkerStarted = false; + +// One worker serves every timer, waking for whichever is due first and +// recomputing whenever the set changes under it. +void Worker() { + std::unique_lock lock(sMutex); + for (;;) { + OSTimer* key = nullptr; + std::chrono::steady_clock::time_point deadline{}; + for (auto& [t, armed] : sTimers) { + if (key == nullptr || armed.deadline < deadline) { + key = t; + deadline = armed.deadline; + } + } + if (key == nullptr) { + sCv.wait(lock); + continue; + } + if (sCv.wait_until(lock, deadline) != std::cv_status::timeout) { + continue; // re-armed or stopped while waiting + } + auto it = sTimers.find(key); + if (it == sTimers.end() || it->second.deadline != deadline) { + continue; // this one changed under the wait + } + OSMesgQueue* mq = it->second.mq; + OSMesg msg = it->second.msg; + if (it->second.interval.count() > 0) { + it->second.deadline += it->second.interval; + } else { + sTimers.erase(it); + } + lock.unlock(); + osSendMesg(mq, msg, OS_MESG_NOBLOCK); + lock.lock(); + } +} + +} // namespace + +extern "C" int osSetTimer(OSTimer* t, OSTime countdown, OSTime interval, OSMesgQueue* mq, OSMesg msg) { + std::lock_guard lock(sMutex); + if (!sWorkerStarted) { + sWorkerStarted = true; + std::thread(Worker).detach(); + } + Armed armed; + armed.deadline = std::chrono::steady_clock::now() + std::chrono::nanoseconds(countdown * 64 / 3); + armed.interval = std::chrono::nanoseconds(interval * 64 / 3); + armed.mq = mq; + armed.msg = msg; + sTimers[t] = armed; + sCv.notify_all(); + return 0; +} + +extern "C" int osStopTimer(OSTimer* t) { + std::lock_guard lock(sMutex); + sTimers.erase(t); + sCv.notify_all(); + return 0; +} diff --git a/src/port/OS/OS_VI.cpp b/src/port/OS/OS_VI.cpp new file mode 100644 index 000000000..744eb1cf3 --- /dev/null +++ b/src/port/OS/OS_VI.cpp @@ -0,0 +1,111 @@ +// This file should eventually replace libultraship's os_vi.cpp + +#include "OS.h" + +#include +#include +#include + +#include "port/DevTools/ThreadWatchdog.h" + +extern "C" { +#include "libultraship/libultra/types.h" +#include "libultraship/libultra/vi.h" +} + +// The VI: retrace source and framebuffer registers. +// +// LUS drives retraces off an SDL timer at 16ms, which is 62.5Hz rather than 60, +// and only if SDL_INIT_TIMER were up. It never is, so retraces never fire at +// all. Game speed is meant to come off this cadence, so it needs to be a real +// 60Hz on an absolute schedule instead of an interval that drifts. +// +// The framebuffer registers are no-ops in LUS: swap does nothing and the +// getters return null. The decomp waits for a swap to latch and compares the +// current buffer against what it last saw, so they have to hold real values. + +namespace { + +std::thread sTicker; +std::atomic sTickerRun{ false }; + +std::atomic sNextFramebuffer{ nullptr }; +std::atomic sCurrentFramebuffer{ nullptr }; +std::atomic sBlack{ false }; + +} // namespace + +extern "C" void osCreateViManager(OSPri pri) { + (void)pri; + if (sTickerRun.exchange(true)) { + return; + } + sTicker = std::thread([] { + constexpr std::chrono::nanoseconds kVi(16666667); // NTSC 60Hz + auto next = std::chrono::steady_clock::now() + kVi; + while (sTickerRun.load(std::memory_order_relaxed)) { + std::this_thread::sleep_until(next); + next += kVi; + // If the process was suspended (debugger, sleep), resync rather + // than firing a burst of catch-up retraces. + auto now = std::chrono::steady_clock::now(); + if (now - next > std::chrono::milliseconds(100)) { + next = now + kVi; + } + // A retrace latches whatever swap armed, then raises VI. + sCurrentFramebuffer.store(sNextFramebuffer.load(std::memory_order_acquire), std::memory_order_release); + ThreadWatchdog_Beat(WATCHDOG_VI_TICKER); + OS_SendEventMesg(OS_EVENT_VI); + } + }); +} + +extern "C" void OS_StopViTicker(void) { + if (!sTickerRun.exchange(false)) { + return; + } + if (sTicker.joinable()) { + sTicker.join(); + } +} + +extern "C" void osViSetEvent(OSMesgQueue* queue, OSMesg mesg, u32 retraceCount) { + (void)retraceCount; + osSetEventMesg(OS_EVENT_VI, queue, mesg); +} + +extern "C" void osViSwapBuffer(void* framebuffer) { + sNextFramebuffer.store(framebuffer, std::memory_order_release); +} + +extern "C" void* osViGetNextFramebuffer(void) { + return sNextFramebuffer.load(std::memory_order_acquire); +} + +extern "C" void* osViGetCurrentFramebuffer(void) { + return sCurrentFramebuffer.load(std::memory_order_acquire); +} + +extern "C" void osViSetMode(OSViMode* mode) { + (void)mode; +} + +extern "C" void osViSetSpecialFeatures(u32 features) { + (void)features; +} + +extern "C" void osViBlack(u8 active) { + sBlack.store(active != 0, std::memory_order_release); +} + +extern "C" int OS_ViBlackActive(void) { + return sBlack.load(std::memory_order_acquire) ? 1 : 0; +} + +extern "C" void osViSetXScale(f32 scale) { + (void)scale; +} + +extern "C" void osViSetYScale(f32 scale) { + (void)scale; +} diff --git a/src/port/stub.c b/src/port/OS/libultra.c similarity index 62% rename from src/port/stub.c rename to src/port/OS/libultra.c index 20cf8c57f..b651a0bdc 100644 --- a/src/port/stub.c +++ b/src/port/OS/libultra.c @@ -1,7 +1,14 @@ +// BanjoDecomp: This file no longer exists upstream, +// but we do wrap its functions with our own. + +// Include the headers that declare what this file defines, so the compiler +// checks the definitions against them. #include "libultraship/libultra/types.h" #include "libultraship/libultra/interrupt.h" #include "libultraship/libultra/sptask.h" #include "libultraship/libultra/thread.h" +#include "libultraship/libultra/os.h" +#include "functions.h" #include "bk_string.h" #include @@ -16,29 +23,35 @@ s32 osViClock = VI_NTSC_CLOCK; u32 __osShutdown = 0; u32 __OSGlobalIntMask = OS_IM_ALL; s32 osCicId = 6103; -// [port] On N64 this was a fixed-address depth buffer at 0x8000E800 (naturally 0x40-aligned). +// On N64 this was a fixed-address depth buffer at 0x8000E800 (naturally 0x40-aligned). // On PC we need a properly sized and aligned buffer to avoid the alignment loop in func_80253428. _Alignas(0x40) u8 D_8000E800[DEFAULT_FRAMEBUFFER_WIDTH * DEFAULT_FRAMEBUFFER_HEIGHT * sizeof(u16)]; u16 gFramebuffers[2][DEFAULT_FRAMEBUFFER_WIDTH * DEFAULT_FRAMEBUFFER_HEIGHT]; +// Threads are in src/port/OS/OS.cpp. +void OS_CreateThread(OSThread* thread, OSId id, void* entry, void* arg, void* sp, OSPri p); +void OS_StartThread(OSThread* thread); +void OS_StopThread(OSThread* thread); +void OS_DestroyThread(OSThread* thread); +void OS_SetThreadPri(OSThread* thread, OSPri p); + void osCreateThread(OSThread* thread, OSId id, void* entry, void* arg, void* sp, OSPri p) { + OS_CreateThread(thread, id, entry, arg, sp, p); } void osStartThread(OSThread* thread) { + OS_StartThread(thread); } void osStopThread(OSThread* t) { + OS_StopThread(t); } void osDestroyThread(OSThread* thread) { -} -void osSpTaskYield(void) { -} -void osSpTaskLoad(OSTask* task) { -} -void osSpTaskStartGo(OSTask* task) { + OS_DestroyThread(thread); } void osViExtendVStart(u32 arg0) { } void osSetThreadPri(OSThread* thread, OSPri p) { + OS_SetThreadPri(thread, p); } s32 osContSetCh(u8 ch) { return 0; @@ -48,23 +61,12 @@ u32 __osGetSR(void) { } void __osSetSR(u32 value) { } +// All interrupt-enable bits set. thread5_checkAndExecutePreNMI reads SR_IBIT5 +// and treats a clear bit as "reset pressed"; with retraces running, returning +// 0 fires the PreNMI handler 60 times a second. u32 bkGetSR(void) { - return 0; -} -OSYieldResult osSpTaskYielded(OSTask* task) { - return 0; + return 0xFFFFFFFFu; } -// Lighthouse TODO these need to be implemented in LUS -int osStartTimer(void* t) { - return 0; -} -int osStopTimer(void* t) { - return 0; -} - -void osDpSetStatus(u32 data) { -} - void __osError(s16 error_code, s16 num_args, ...) { } diff --git a/src/port/Patches/FramebufferPatches.cpp b/src/port/Patches/FramebufferPatches.cpp index 5f9fb533c..9eafbb586 100644 --- a/src/port/Patches/FramebufferPatches.cpp +++ b/src/port/Patches/FramebufferPatches.cpp @@ -7,6 +7,10 @@ #include "port/Engine.h" +// From Patches.h; declared here because this file's definitions use concrete +// Gfx/model types where the header declares void*. +extern "C" void port_runOnRenderThread(void (*fn)(void*), void* arg); + extern "C" { #include "core1/core1.h" @@ -63,10 +67,17 @@ static void currentRenderSize(int* w, int* h) { } } +// Framebuffer creation talks to the renderer, so under thread5 mode it has to +// happen on the render thread rather than the game tick. +static void createPauseFb(void* arg) { + (void)arg; + s_pauseFbId = gfx_create_framebuffer(s_pauseFbW, s_pauseFbH, s_pauseFbW, s_pauseFbH, 0, 0); +} + int port_getPauseFramebufferId(void) { if (s_pauseFbId < 0) { currentRenderSize(&s_pauseFbW, &s_pauseFbH); - s_pauseFbId = gfx_create_framebuffer(s_pauseFbW, s_pauseFbH, s_pauseFbW, s_pauseFbH, 0, 0); + port_runOnRenderThread(createPauseFb, NULL); } return s_pauseFbId; } @@ -82,7 +93,7 @@ int port_capturePauseFramebuffer(void) { if (s_pauseFbId < 0 || w != s_pauseFbW || h != s_pauseFbH) { s_pauseFbW = w; s_pauseFbH = h; - s_pauseFbId = gfx_create_framebuffer(w, h, w, h, 0, 0); + port_runOnRenderThread(createPauseFb, NULL); } return s_pauseFbId; } @@ -236,11 +247,16 @@ void port_patchPictureModel(BKModelBin* model_bin, s32 min_xy, s32 max_xy, s32 m static u16 sTransitionFbDummy[1]; static s32 sTransitionGpuFbId = -1; +static void createTransitionFb(void* arg) { + (void)arg; + sTransitionGpuFbId = gfx_create_framebuffer(DEFAULT_FRAMEBUFFER_WIDTH, DEFAULT_FRAMEBUFFER_HEIGHT, + DEFAULT_FRAMEBUFFER_WIDTH, DEFAULT_FRAMEBUFFER_HEIGHT, 1, 0); + gfx_register_fb_texture(sTransitionFbDummy, sTransitionGpuFbId); +} + s32 port_getTransitionGpuFbId(void) { if (sTransitionGpuFbId < 0) { - sTransitionGpuFbId = gfx_create_framebuffer(DEFAULT_FRAMEBUFFER_WIDTH, DEFAULT_FRAMEBUFFER_HEIGHT, - DEFAULT_FRAMEBUFFER_WIDTH, DEFAULT_FRAMEBUFFER_HEIGHT, 1, 0); - gfx_register_fb_texture(sTransitionFbDummy, sTransitionGpuFbId); + port_runOnRenderThread(createTransitionFb, NULL); } return sTransitionGpuFbId; } diff --git a/src/port/Patches/Patches.h b/src/port/Patches/Patches.h index 5ea045f61..cc1e7384d 100644 --- a/src/port/Patches/Patches.h +++ b/src/port/Patches/Patches.h @@ -7,6 +7,15 @@ extern "C" { #endif +// Threaded rendering (Game.cpp) + +// Carries the interpolation pair with a submitted display list. +void port_thread5_onSubmit(void* taskData); +// Runs fn on the window thread when the tick is on its own thread. +void port_runOnRenderThread(void (*fn)(void*), void* arg); +// Waits for in-flight display lists before freeing or reading what they use. +void port_pipelineSyncPoint(void); + // Frame Pacing (FramePacingPatches.cpp) int port_getDemoViCount(void); @@ -28,8 +37,6 @@ void port_refreshDialogFontGlyphCount(void); // re-read the reachable glyph coun // Framebuffer (FramebufferPatches.cpp) -void port_setViBlack(int active); -int port_isViBlack(void); void port_freezeReadback(int freeze); void port_requestReadback(void); int port_consumeReadbackRequest(void); @@ -113,6 +120,8 @@ void romhack_RewriteActorSpawn(void* actorInfo, u32* flags); // Attract-demo audio hold void port_beginDemoAudioHold(void); +void port_tickDemoAudioHold(void); +int port_audioHeld(void); void port_notedoor_remoteOpen(int32_t progressFlag); diff --git a/src/port/Patches/PerfPatches.cpp b/src/port/Patches/PerfPatches.cpp new file mode 100644 index 000000000..fc569df81 --- /dev/null +++ b/src/port/Patches/PerfPatches.cpp @@ -0,0 +1,230 @@ +#include +#include +#include + +#include "port/Enhancements/Events/Hooks/Events.h" +#include "port/ShipInit.hpp" + +extern "C" { +#include +#include "functions.h" +#include "core2/lighting.h" + +extern s32 D_80383450[0x40]; + +// core1 helpers not exposed through functions.h. +extern void func_80256E24(f32 dst[3], f32 theta, f32 phi, f32 x, f32 y, f32 z); +extern void ml_vec3f_normalize(f32 vec[3]); +extern void viewport_getPosition_vec3f(f32 dst[3]); +extern void viewport_getRotation_vec3f(f32 dst[3]); +} + +static const f32 kFrustumZX = 45.168514251708984f; // must match viewport.c +static const f32 kFrustumZY = 34.20201110839844f; +static constexpr float kDrawDistCullPadDeg = 25.0f; +static f32 sPadFrustumX = 89.21774f; +static f32 sPadFrustumY = 93.9692611694336f; +static f32 sPadPlanes[4][4]; +static bool sPadPlanesDirty = true; + +// __cube_sort re-sorts every visible cube's props each tick, but only the camera +// moves, so the order rarely changes. A stable insertion sort skims an already +// sorted array in one pass and produces the same ordering as the vanilla sort. +static void RegisterCubeSort_Init() { + COND_VB_SHOULD(VB_CUBE_PROP_SORT, EVENT_PRIORITY_NORMAL, true, { + Cube* cube = va_arg(args, Cube*); + s32 n = cube->prop2Cnt; + for (s32 i = 1; i < n; i++) { + if (D_80383450[i] <= D_80383450[i - 1]) { + continue; + } + s32 key = D_80383450[i]; + Prop tmp; + std::memcpy(&tmp, &cube->prop2Ptr[i], sizeof(Prop)); + s32 j = i - 1; + while (j >= 0 && D_80383450[j] < key) { + D_80383450[j + 1] = D_80383450[j]; + std::memcpy(&cube->prop2Ptr[j + 1], &cube->prop2Ptr[j], sizeof(Prop)); + j--; + } + D_80383450[j + 1] = key; + std::memcpy(&cube->prop2Ptr[j + 1], &tmp, sizeof(Prop)); + } + *should = false; + }); +} + +// Same vertex recolor loop as gclights_recolor_vertices, but out-of-range lights +// are rejected with squared distances so only vertices inside a fade band pay a sqrt. +static void RegisterGcLights_Init() { + COND_VB_SHOULD(VB_GCLIGHTS_RECOLOR, EVENT_PRIORITY_NORMAL, true, { + Vtx* vtx = va_arg(args, Vtx*); + Vtx* vtxEnd = va_arg(args, Vtx*); + Vtx* refVtx = va_arg(args, Vtx*); + Lighting** lightsBegin = va_arg(args, Lighting**); + Lighting** lightsEnd = va_arg(args, Lighting**); + + // Active-light list caps at 16 entries (NUM_LIGHTING_ELEM). + f32 minSq[16]; + f32 maxSq[16]; + s32 nLights = (s32)(lightsEnd - lightsBegin); + for (s32 li = 0; li < nLights; li++) { + minSq[li] = lightsBegin[li]->fade_radius_min * lightsBegin[li]->fade_radius_min; + maxSq[li] = lightsBegin[li]->fade_radius_max * lightsBegin[li]->fade_radius_max; + } + + for (; vtx < vtxEnd; vtx++, refVtx++) { + f32 mod[3]; + mod[0] = mod[1] = mod[2] = 0.0f; + for (s32 li = 0; li < nLights; li++) { + const Lighting* light = lightsBegin[li]; + f32 dx = light->positionCopy[0] - (f32)refVtx->v.ob[0]; + f32 dy = light->positionCopy[1] - (f32)refVtx->v.ob[1]; + f32 dz = light->positionCopy[2] - (f32)refVtx->v.ob[2]; + f32 distSq = dx * dx + dy * dy + dz * dz; + if (maxSq[li] <= distSq) { + continue; + } + if (distSq <= minSq[li]) { + mod[0] += light->red; + mod[1] += light->green; + mod[2] += light->blue; + } else { + f32 dist = sqrtf(distSq); + f32 fade = + 1.0f - ((dist - light->fade_radius_min) / (light->fade_radius_max - light->fade_radius_min)); + mod[0] += fade * light->red; + mod[1] += fade * light->green; + mod[2] += fade * light->blue; + } + } + vtx->v.cn[0] = (s8)((refVtx->v.cn[0] * mod[0]) / 256.0) & 0xFF; + vtx->v.cn[1] = (s8)((refVtx->v.cn[1] * mod[1]) / 256.0) & 0xFF; + vtx->v.cn[2] = (s8)((refVtx->v.cn[2] * mod[2]) / 256.0) & 0xFF; + } + *should = false; + }); +} + +// Same rotations as mlMtx_rotate_yaw_deg/mlMtx_rotate_pitch_deg, but every +// snowflake shares one camera rotation, so cache the sin/cos instead of +// recomputing four of them per flake. +static void ApplySnowCameraRotation(const f32 camRot[3]) { + constexpr double kBadDtor = 3.141592654 / 180.0; + static f32 sYawDeg; + static f32 sPitchDeg; + static f32 sSinYaw, sCosYaw; + static f32 sSinPitch, sCosPitch; + static bool sHaveTrig = false; + + f32 pitchDeg = camRot[0]; + f32 yawDeg = camRot[1]; + if (!sHaveTrig || yawDeg != sYawDeg || pitchDeg != sPitchDeg) { + f32 yawRad = (f32)(yawDeg * kBadDtor); + f32 pitchRad = (f32)(pitchDeg * kBadDtor); + sSinYaw = sinf(yawRad); + sCosYaw = cosf(yawRad); + sSinPitch = sinf(pitchRad); + sCosPitch = cosf(pitchRad); + sYawDeg = yawDeg; + sPitchDeg = pitchDeg; + sHaveTrig = true; + } + + MtxF* m = mlMtx_get_stack_pointer(); + if (yawDeg != 0.0f) { + for (s32 i = 0; i < 3; i++) { + f32 r0 = m->mf[0][i]; + f32 r2 = m->mf[2][i]; + m->mf[0][i] = r0 * sCosYaw - r2 * sSinYaw; + m->mf[2][i] = r0 * sSinYaw + r2 * sCosYaw; + } + } + if (pitchDeg != 0.0f) { + for (s32 i = 0; i < 3; i++) { + f32 r1 = m->mf[1][i]; + f32 r2 = m->mf[2][i]; + m->mf[1][i] = r1 * sCosPitch + r2 * sSinPitch; + m->mf[2][i] = r1 * -sSinPitch + r2 * sCosPitch; + } + } +} + +static void RegisterSnowTrig_Init() { + COND_VB_SHOULD(VB_SNOW_CAMERA_ROTATION, EVENT_PRIORITY_NORMAL, true, { + ApplySnowCameraRotation(va_arg(args, f32*)); + *should = false; + }); +} + + +static void RebuildPaddedPlanes() { + f32 rot[3]; + f32 pos[3]; + viewport_getRotation_vec3f(rot); + viewport_getPosition_vec3f(pos); + + // Components are cotangent-form (component/Z = cot(half angle)), so + // widening the frustum means shrinking the lateral component. + const f32 kDegToRad = 3.14159265f / 180.0f; + const f32 kMaxHalfAngle = 88.0f * kDegToRad; + f32 halfX = atanf(kFrustumZX / sPadFrustumX) + kDrawDistCullPadDeg * kDegToRad; + f32 halfY = atanf(kFrustumZY / sPadFrustumY) + kDrawDistCullPadDeg * kDegToRad; + halfX = std::min(halfX, kMaxHalfAngle); + halfY = std::min(halfY, kMaxHalfAngle); + f32 px = kFrustumZX / tanf(halfX); + f32 py = kFrustumZY / tanf(halfY); + + func_80256E24(sPadPlanes[0], rot[0], rot[1], -px, 0.0f, kFrustumZX); + func_80256E24(sPadPlanes[1], rot[0], rot[1], px, 0.0f, kFrustumZX); + func_80256E24(sPadPlanes[2], rot[0], rot[1], 0.0f, py, kFrustumZY); + func_80256E24(sPadPlanes[3], rot[0], rot[1], 0.0f, -py, kFrustumZY); + for (int i = 0; i < 4; i++) { + ml_vec3f_normalize(sPadPlanes[i]); + sPadPlanes[i][3] = -(pos[0] * sPadPlanes[i][0] + pos[1] * sPadPlanes[i][1] + pos[2] * sPadPlanes[i][2]); + } + sPadPlanesDirty = false; +} + +// Culled when all 8 corners are outside one plane. +static bool PaddedBoxCulled(const f32 boxMin[3], const f32 boxMax[3]) { + for (int p = 0; p < 4; p++) { + bool allOutside = true; + for (int c = 0; c < 8 && allOutside; c++) { + f32 x = (c & 1) ? boxMax[0] : boxMin[0]; + f32 y = (c & 2) ? boxMax[1] : boxMin[1]; + f32 z = (c & 4) ? boxMax[2] : boxMin[2]; + if (sPadPlanes[p][0] * x + sPadPlanes[p][1] * y + sPadPlanes[p][2] * z + sPadPlanes[p][3] < 0.0f) { + allOutside = false; + } + } + if (allOutside) { + return true; + } + } + return false; +} + +static void RegisterDrawDistCull_Init() { + COND_HOOK(ViewportFrustumUpdate, EVENT_PRIORITY_LOW, true, [](IEvent* event) { + auto* ev = (ViewportFrustumUpdate*)event; + sPadFrustumX = *ev->frustumX; + sPadFrustumY = *ev->frustumY; + sPadPlanesDirty = true; + }); + COND_VB_SHOULD(VB_DRAWDIST_BOX_CULL, EVENT_PRIORITY_NORMAL, true, { + f32* boxMin = va_arg(args, f32*); + f32* boxMax = va_arg(args, f32*); + if (sPadPlanesDirty) { + RebuildPaddedPlanes(); + } + if (PaddedBoxCulled(boxMin, boxMax)) { + *should = false; + } + }); +} + +static RegisterShipInitFunc sCubeSortInit(RegisterCubeSort_Init); +static RegisterShipInitFunc sGcLightsInit(RegisterGcLights_Init); +static RegisterShipInitFunc sSnowTrigInit(RegisterSnowTrig_Init); +static RegisterShipInitFunc sDrawDistCullInit(RegisterDrawDistCull_Init); \ No newline at end of file diff --git a/src/port/Patches/TransitionPatches.cpp b/src/port/Patches/TransitionPatches.cpp index 116931cbe..041e9e44e 100644 --- a/src/port/Patches/TransitionPatches.cpp +++ b/src/port/Patches/TransitionPatches.cpp @@ -19,20 +19,6 @@ static int32_t sTransitionModelId = 0; static int32_t sTransitionUid = 0; static int32_t sTransitionSubstate = 0; -// Emulate N64's osViBlack on PC. On N64, osViBlack(1) blanked the TV output but -// the RDP still rendered to framebuffers. On PC we render normally (so the capture -// sees the world), then Engine.cpp clears the backbuffer to black before present -// while this flag is set. -static bool s_viBlack = false; - -extern "C" void port_setViBlack(int active) { - s_viBlack = (active != 0); -} - -extern "C" int port_isViBlack(void) { - return s_viBlack ? 1 : 0; -} - extern "C" int port_shouldCaptureTransition(void) { if (sTransitionModelId != ASSET_467_MODEL_TRANSITION_FALLING_JIGGIES) { return 0; @@ -52,7 +38,6 @@ void RegisterTransitionPatches_Init() { sTransitionModelId = ev->modelId; sTransitionUid = ev->uid; sTransitionSubstate = ev->substate; - port_setViBlack(ev->uid == TRANSITION_FALLING_PIECES_IN && ev->substate <= 4 ? 1 : 0); }); // Widescreen transition scaling. For the falling jiggy pieces, X-scale the diff --git a/src/port/Resource/Alt/AltBoldFont.cpp b/src/port/Resource/Alt/AltBoldFont.cpp index df9c8524e..c5ec43030 100644 --- a/src/port/Resource/Alt/AltBoldFont.cpp +++ b/src/port/Resource/Alt/AltBoldFont.cpp @@ -23,6 +23,7 @@ #include #include +#include "AltPathPool.h" #include "AltSprites.h" #include "port/Enhancements/Events/Hooks/Events.h" #include "port/ShipInit.hpp" @@ -41,7 +42,11 @@ struct ChunkHeader { int16_t x, y, w, h; }; -std::unordered_map sByOutput; +// resolveHd hands these strings' addresses into display lists, and texture +// binds may be memoized on that address downstream: the strings must be +// immutable and immortal, so they live in the shared alt-path pool. +// reset() clears the output mapping, never the pool. +std::unordered_map sByOutput; std::unordered_set sBuilt; std::mutex sMutex; @@ -135,7 +140,7 @@ void buildHd(const void* output, const void* maskChunk, const void* sphereChunk) std::unique_lock lock(sMutex); if (sBuilt.count(cachePath)) { - sByOutput[output] = "__OTR__" + cachePath; + sByOutput[output] = InternAltPath("__OTR__" + cachePath); return; } @@ -143,7 +148,7 @@ void buildHd(const void* output, const void* maskChunk, const void* sphereChunk) // the identity path. Serve it directly and skip compositing. if (Ship::Context::GetRawInstance()->GetResourceManager()->GetArchiveManager()->HasFile("alt/" + cachePath)) { sBuilt.insert(cachePath); - sByOutput[output] = "__OTR__" + cachePath; + sByOutput[output] = InternAltPath("__OTR__" + cachePath); return; } lock.unlock(); @@ -211,7 +216,7 @@ void buildHd(const void* output, const void* maskChunk, const void* sphereChunk) lock.lock(); sBuilt.insert(cachePath); - sByOutput[output] = "__OTR__" + cachePath; + sByOutput[output] = InternAltPath("__OTR__" + cachePath); } void resolveHd(const void* output, const char** path) { @@ -221,7 +226,7 @@ void resolveHd(const void* output, const char** path) { std::lock_guard lock(sMutex); auto it = sByOutput.find(output); if (it != sByOutput.end()) { - *path = it->second.c_str(); + *path = it->second; } } diff --git a/src/port/ShipUtils.cpp b/src/port/ShipUtils.cpp index d1df32c95..a9ee2e27d 100644 --- a/src/port/ShipUtils.cpp +++ b/src/port/ShipUtils.cpp @@ -95,10 +95,6 @@ bool Ship_IsCStringEmpty(const char* str) { return str == NULL || str[0] == '\0'; } -void port_audioStartThread(void) { - GameEngine::AudioStartThread(); -} - int port_checkHeap(const char* label) { #if defined(_DEBUG) && defined(_MSC_VER) if (!_CrtCheckMemory()) { diff --git a/src/port/ShipUtils.h b/src/port/ShipUtils.h index cacdcb5eb..e669191bf 100644 --- a/src/port/ShipUtils.h +++ b/src/port/ShipUtils.h @@ -34,9 +34,6 @@ void BK_LOG_INFO(const char* fmt, ...); void BK_LOG_WARN(const char* fmt, ...); void BK_LOG_ERROR(const char* fmt, ...); -// Start the audio processing thread (called from audioManager_startThread after soundfont patching) -void port_audioStartThread(void); - // Flag: when true, audio spin-waits should force-stop immediately. extern int gPortResetPending; diff --git a/src/port/UI/LighthouseGui.cpp b/src/port/UI/LighthouseGui.cpp index 425ca0d62..217ba35de 100644 --- a/src/port/UI/LighthouseGui.cpp +++ b/src/port/UI/LighthouseGui.cpp @@ -109,10 +109,10 @@ void SetupGuiElements() { SPDLOG_ERROR("Could not find console window"); } - mGfxDebuggerWindow = gui->GetGuiWindow("GfxDebuggerWindow"); - if (mGfxDebuggerWindow == nullptr) { - SPDLOG_ERROR("Could not find input GfxDebuggerWindow"); - } + // mGfxDebuggerWindow = gui->GetGuiWindow("GfxDebuggerWindow"); + // if (mGfxDebuggerWindow == nullptr) { + // SPDLOG_ERROR("Could not find input GfxDebuggerWindow"); + // } mInputEditorWindow = std::make_shared(CVAR_WINDOW("ControllerConfiguration"), "Configure Controller"); diff --git a/src/port/UI/LighthouseMenuDevTools.cpp b/src/port/UI/LighthouseMenuDevTools.cpp index 7b4318cfc..a9fc84772 100644 --- a/src/port/UI/LighthouseMenuDevTools.cpp +++ b/src/port/UI/LighthouseMenuDevTools.cpp @@ -6,6 +6,7 @@ //#include #include "port/ResourceHelpers.h" #include "port/DevTools/DevSequences.h" +#include "port/DevTools/ThreadWatchdog.h" #include "UIWidgets.hpp" #include @@ -74,6 +75,11 @@ void LighthouseMenu::AddMenuDevTools() { AddWidget(path, "Nametag Distance", WIDGET_CVAR_SLIDER_FLOAT) .CVar(CVAR_DEVELOPER_TOOLS("NametagDist")) .Options(FloatSliderOptions().DefaultValue(3000.0f).Min(1000.0f).Max(10000.0f).Step(10.0f)); + AddWidget(path, "Dump Thread State", WIDGET_BUTTON) + .Callback([](WidgetInfo&) { ThreadWatchdog_DumpNow(); }) + .Options(ButtonOptions().Size(Sizes::Inline).Tooltip( + "Log a snapshot of the decomp thread heartbeats and pipeline queue state. The watchdog also logs " + "this automatically when a thread stops beating.")); /*AddWidget(path, "Debug Mode", WIDGET_CVAR_CHECKBOX) .CVar(CVAR_DEVELOPER_TOOLS("DebugMode")) .Options(CheckboxOptions().Tooltip("Various debug features, including a level selector from the main menu."));*/ @@ -139,14 +145,6 @@ void LighthouseMenu::AddMenuDevTools() { .HideInSearch(true) .Options(WindowButtonOptions().Tooltip( "Shows the stats window, with your FPS and frametimes, and the OS you're playing on.")); - AddWidget(path, "Adaptive FPS", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_SETTING("AdaptiveFPS")) - .RaceDisable(false) - .Options(CheckboxOptions() - .Tooltip("Automatically lowers interpolation FPS in demanding scenes so the game logic never " - "stalls, then restores it when the scene clears. Disable to always target your " - "requested FPS, which may stutter on heavy scenes or weaker hardware.") - .DefaultValue(true)); // Console // path.sidebarName = "Console"; From da4c699bdd6b020693159e01ee12512835519d31 Mon Sep 17 00:00:00 2001 From: Jeod <47716344+JeodC@users.noreply.github.com> Date: Wed, 29 Jul 2026 18:22:09 -0400 Subject: [PATCH 039/131] os: swap rumble thread bypass for real rumble thread (#281) * os: swap rumble thread bypass for real rumble thread * Linux compile fix --- src/core1/audio_manager.c | 1 + src/core1/bamotor.c | 52 ++++++++-------------------- src/core1/graphics_thread.c | 4 +-- src/core1/pfsmanager.c | 9 +++-- src/port/DevTools/ThreadWatchdog.cpp | 9 ++++- src/port/DevTools/ThreadWatchdog.h | 1 + src/port/OS/OS.h | 18 +++++++--- src/port/OS/OS_Cont.cpp | 14 ++++++++ 8 files changed, 58 insertions(+), 50 deletions(-) diff --git a/src/core1/audio_manager.c b/src/core1/audio_manager.c index dce5f581a..61225f6a9 100644 --- a/src/core1/audio_manager.c +++ b/src/core1/audio_manager.c @@ -8,6 +8,7 @@ #include "n_audio/PR/n_libaudio.h" //#include "PR/os_system.h" #include "port/DevTools/ThreadWatchdog.h" +#include "port/Patches/Patches.h" #include "port/ShipUtils.h" #define DMA_BLOCK_SIZE VER_SELECT(0x200, 0x270, 0x200, 0x200) diff --git a/src/core1/bamotor.c b/src/core1/bamotor.c index 8d5a23acc..ce82afa9b 100644 --- a/src/core1/bamotor.c +++ b/src/core1/bamotor.c @@ -5,10 +5,10 @@ #include "variables.h" #include "version.h" +#include "port/DevTools/ThreadWatchdog.h" +#include "port/OS/OS.h" #include "port/Patches/Patches.h" -//#include - #define RUMBLE_THREAD_STACK_SIZE 0x200 void func_8024F35C(s32); @@ -75,6 +75,7 @@ void rumbleThread_entry(void *arg) { do{ osRecvMesg(&D_80282390, NULL, 1); + ThreadWatchdog_Beat(WATCHDOG_RUMBLE); // [port] one beat per retrace signal D_802827E0++; if (!D_802823B0 && ((D_802827E0 % FRAMERATE) == 0)) { func_80250930(); @@ -109,43 +110,12 @@ void __baMotor_80250BA4(s32 arg0, s32 arg1, s32 arg2){ } void baMotor_80250C08(void) { - // [port] Rumble thread logic inlined — N64 thread/VBlank model replaced by per-frame update - static s32 sFrameCounter; - static s32 sRumbleState; - if (D_802823AC != 0) { - s32 prev_state; - D_80282424 = MIN(D_80282420, D_80282424 + time_getDelta()); - - prev_state = sRumbleState; - sFrameCounter++; - - if (D_80282424 != D_80282420) { - f32 temp_f2 = D_80282428 + ((D_8028242C - D_80282428) * D_80282424 / D_80282420); - s32 var_v0 = (s32)(((1.0 - temp_f2) * 8.0) + 1); - if (var_v0 < 2) { - sRumbleState = var_v0; - } else { - sRumbleState = (sFrameCounter % var_v0) == 0; - } - } else { - sRumbleState = 0; - } - - if (sRumbleState != prev_state) { - if (sRumbleState) { - __baMotor_startRumble(); - } else { - __baMotor_stopRumble(); - } - } } } void baMotor_init(void) { - // [port] Bypass N64 PFS probing and rumble thread — LUS handles motor directly. -#if 0 s32 pfs_status; func_8024F35C(4); @@ -159,14 +129,20 @@ void baMotor_init(void) { D_802823B0 = D_802823AC; if(D_802823AC){ osCreateMesgQueue(&D_80282390, &D_802823A8, 1); + // [port] The thread parks on that queue between retraces, so it has to + // block on it, and its entry needs allowlisting before osStartThread + // will really launch it. + OS_SetQueueBlocking(&D_80282390, 1); + OS_EnableThreadEntry((void*)rumbleThread_entry); osCreateThread(&sRumbleThread, 8, rumbleThread_entry, NULL, sRumbleThreadStack + RUMBLE_THREAD_STACK_SIZE, 25); osStartThread(&sRumbleThread); - viMgr_registerSignalMesg(&D_80282390, OS_MESG_32(NULL)); + viMgr_registerSignalMesg(&D_80282390, OS_MESG_32(0)); } -#endif - osMotorInit(NULL, &D_802823B8, 0); - D_802823AC = 1; - D_802823B0 = 1; +} + +// [port] Watchdog diagnostics +OSMesgQueue *baMotor_getRetraceQueue(void){ + return &D_80282390; } void __baMotor_80250D8C(void){} diff --git a/src/core1/graphics_thread.c b/src/core1/graphics_thread.c index ea7dae3d2..35306d638 100644 --- a/src/core1/graphics_thread.c +++ b/src/core1/graphics_thread.c @@ -8,6 +8,7 @@ #include "core1/core1.h" #include "functions.h" #include "port/DevTools/ThreadWatchdog.h" +#include "port/OS/OS.h" #include "port/Patches/Patches.h" #include "libultraship/libultra/rcp.h" #include "libultraship/libultra/sptask.h" @@ -308,8 +309,7 @@ void thread5_handleVIRetraceEvent(void) { osStopTimer(&sAudioTimer); osSetTimer(&sAudioTimer, 280000, 0, &sThread5MesgQueue, OS_MESG_32(THREAD5_MESSAGE_EVENT_AUDIO_TIMER)); } - - if (sEnableControllerTimer) { + if (sEnableControllerTimer && OS_SiPumpLive()) { osStopTimer(&sControllerTimer); #if VERSION == VERSION_USA_1_0 osSetTimer(&sControllerTimer, ((osClockRate / 60)* 2) / 3, 0, &sThread5MesgQueue, OS_MESG_32(THREAD5_MESSAGE_EVENT_CONT_TIMER)); diff --git a/src/core1/pfsmanager.c b/src/core1/pfsmanager.c index a7f747c14..61aed416c 100644 --- a/src/core1/pfsmanager.c +++ b/src/core1/pfsmanager.c @@ -10,6 +10,7 @@ #include "checksums.h" #include "port/DevTools/ThreadWatchdog.h" +#include "port/OS/OS.h" #include "port/Patches/Patches.h" #define PFSMANAGER_THREAD_STACK_SIZE 0x200 @@ -408,13 +409,10 @@ void func_8024F35C(s32 arg0) { func_8024F4AC(); else func_8024F450(); -#if 0 + if(arg0 || D_802816E8.validCount == 1){ - pfsManagerBusy = arg0; + pfsManagerBusy = arg0; } -#endif - // [port] Rumble safety, don't rely on the OSMesgQueue - pfsManagerBusy = arg0; } bool pfsManager_isBusy(void){ @@ -433,6 +431,7 @@ OSContPad *func_8024F3F4(void){ void func_8024F400(void) { D_80275D38 = true; osCreateMesgQueue(&D_802816E8, D_80281700, 5); + OS_SetQueueBlocking(&D_802816E8, 1); osSendMesgPtr(&D_802816E8, NULL, OS_MESG_NOBLOCK); } diff --git a/src/port/DevTools/ThreadWatchdog.cpp b/src/port/DevTools/ThreadWatchdog.cpp index e38c1b028..945e94e75 100644 --- a/src/port/DevTools/ThreadWatchdog.cpp +++ b/src/port/DevTools/ThreadWatchdog.cpp @@ -39,6 +39,7 @@ OSMesgQueue* pfsManager_getSiLockQueue(void); int pfsManager_isBusy(void); OSMesgQueue* audioManager_getFrameMesgQueue(void); OSMesgQueue* audioManager_getReplyMesgQueue(void); +OSMesgQueue* baMotor_getRetraceQueue(void); OSMesgQueue* viMgr_getRetraceQueue(void); OSMesgQueue* viMgr_getFrameTokenQueue(void); OSMesgQueue* viMgr_getTickRetraceQueue(void); @@ -58,7 +59,7 @@ namespace { using Clock = std::chrono::steady_clock; constexpr const char* kThreadNames[WATCHDOG_NUM_THREADS] = { - "vi-ticker", "main-loop", "game-tick", "thread5", "vimgr", "pfsmanager", "audio-mgr", + "vi-ticker", "main-loop", "game-tick", "thread5", "vimgr", "pfsmanager", "audio-mgr", "rumble", }; // Blocking points in each loop that are not message-queue waits. A stall with @@ -74,6 +75,8 @@ constexpr const char* kThreadNonQueueWaits[WATCHDOG_NUM_THREADS] = { "sMesgMutex", "func_8024F450 -> D_802816E8 wait; port_shapeControllerInput; CALL_EVENT(OnControllerUpdate)", "port_lockAudio (gAudioLock) in audioManager_handleFrameMsg", + "func_8024F450 -> D_802816E8 wait via __baMotor_startRumble/stopRumble/func_80250930; __osMotorAccess -> " + "ControlDeck rumble", }; // Entry point each heartbeat belongs to. @@ -85,6 +88,7 @@ constexpr const char* kThreadLoops[WATCHDOG_NUM_THREADS] = { "viMgr_entry (vimgr.c)", "pfsManager_entry (pfsmanager.c)", "audioManagerThread_entry (audio_manager.c)", + "rumbleThread_entry (bamotor.c)", }; // The audio thread legitimately idles through demo audio holds, and the @@ -174,6 +178,9 @@ QueueInfo DescribeQueue(OSMesgQueue* mq) { if (mq == pfsManager_getSiLockQueue()) { return { true, "D_802816E8 (pfsmanager.c)", "func_8024F4AC via func_8024F35C(0)" }; } + if (mq == baMotor_getRetraceQueue()) { + return { true, "D_80282390 (bamotor.c)", "viMgr_entry retrace signal (NOBLOCK, so extras drop)" }; + } if (mq == audioManager_getFrameMesgQueue()) { return { true, "audioFrameMsgQ (audio_manager.c)", "thread5_handleAudioTimerEvent (skipped while port_audioHeld)" }; diff --git a/src/port/DevTools/ThreadWatchdog.h b/src/port/DevTools/ThreadWatchdog.h index 4ac9600d7..34ae17199 100644 --- a/src/port/DevTools/ThreadWatchdog.h +++ b/src/port/DevTools/ThreadWatchdog.h @@ -23,6 +23,7 @@ typedef enum WatchdogThread { WATCHDOG_VIMGR, // decomp VI manager thread (vimgr.c) WATCHDOG_PFSMANAGER, // controller thread (pfsmanager.c) WATCHDOG_AUDIO_MANAGER, // audio thread (audio_manager.c); idles during demo audio holds + WATCHDOG_RUMBLE, // motor thread (bamotor.c); one beat per retrace signal WATCHDOG_NUM_THREADS } WatchdogThread; diff --git a/src/port/OS/OS.h b/src/port/OS/OS.h index f57911328..f58696356 100644 --- a/src/port/OS/OS.h +++ b/src/port/OS/OS.h @@ -12,7 +12,11 @@ extern "C" { #endif +#include "libultraship/libultra/message.h" #include "libultraship/libultra/thread.h" +#include "libultraship/libultra/pfs.h" +#include "libultraship/libultra/sptask.h" +#include "libultraship/libultra/time.h" void OS_CreateThread(OSThread* thread, OSId id, void* entry, void* arg, void* sp, OSPri p); void OS_StartThread(OSThread* thread); @@ -25,8 +29,6 @@ void OS_SetThreadPri(OSThread* thread, OSPri p); // are revived deliberately, one consumer at a time. void OS_EnableThreadEntry(void* entry); -#include "libultraship/libultra/message.h" - // OS_MESG_BLOCK only blocks on queues opted in here. void OS_SetQueueBlocking(OSMesgQueue* mq, int enabled); @@ -54,12 +56,20 @@ void OS_StopViTicker(void); // Called by the thread that owns SDL input. int OS_SiService(void); +// Whether that thread has begun servicing SI at all. +int OS_SiPumpLive(void); + +// Cancel a pending timer. Both halves of the pair are ours (OS_Timer.cpp), but +// only osSetTimer has a prototype in LUS to be found through, so a decomp caller +// needs this one declared here. +int osStopTimer(OSTimer* t); + +s32 osPfsInit(OSMesgQueue* mq, OSPfs* pfs, s32 channel); + // Whether osViBlack has the display blanked. The renderer blacks the presented // frame while the world keeps rendering underneath. int OS_ViBlackActive(void); -#include "libultraship/libultra/sptask.h" - // Take the task osSpTaskStartGo handed over, or NULL if none is pending. OSTask* OS_SpTakePendingTask(void); diff --git a/src/port/OS/OS_Cont.cpp b/src/port/OS/OS_Cont.cpp index 15ebdba1f..b7369c77d 100644 --- a/src/port/OS/OS_Cont.cpp +++ b/src/port/OS/OS_Cont.cpp @@ -39,6 +39,7 @@ std::atomic sReadPending{ false }; std::mutex sLatchMutex; OSContPad sLatch[MAXCONTROLLERS]; std::atomic sLatchValid{ false }; +std::atomic sPumpLive{ false }; } // namespace int32_t osContStartReadData(OSMesgQueue* mesg) { @@ -47,7 +48,12 @@ int32_t osContStartReadData(OSMesgQueue* mesg) { return 0; } +extern "C" int OS_SiPumpLive(void) { + return sPumpLive.load(std::memory_order_acquire) ? 1 : 0; +} + extern "C" int OS_SiService(void) { + sPumpLive.store(true, std::memory_order_release); if (!sReadPending.exchange(false, std::memory_order_acq_rel)) { return 0; } @@ -86,4 +92,12 @@ int32_t osMotorInit(OSMesgQueue* ctrlrqueue, OSPfs* pfs, int32_t channel) { return 0; } +// Controller Pak gets probed first, the return kickstarts rumble +int32_t osPfsInit(OSMesgQueue* mq, OSPfs* pfs, int32_t channel) { + (void)mq; + (void)pfs; + (void)channel; + return PFS_ERR_DEVICE; +} + } // extern "C" From ee8bef6566a7f59f645d101a162e408e6ac09f32 Mon Sep 17 00:00:00 2001 From: Jeod <47716344+JeodC@users.noreply.github.com> Date: Wed, 29 Jul 2026 18:59:45 -0400 Subject: [PATCH 040/131] Fix a rare crash with the tooie jiggy animation (#282) --- src/port/Enhancements/Backports/TooieJiggyDance.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/port/Enhancements/Backports/TooieJiggyDance.cpp b/src/port/Enhancements/Backports/TooieJiggyDance.cpp index 6a1539c6d..c8ae5d1e1 100644 --- a/src/port/Enhancements/Backports/TooieJiggyDance.cpp +++ b/src/port/Enhancements/Backports/TooieJiggyDance.cpp @@ -136,6 +136,7 @@ void spawnOrbit() { } actor->state = 0; actor_collisionOff(actor); + actor->unk44_2 = 1; sfxsource_playHighPriority(SFX_3E9_UNKNOWN); sMarker = (void*)actor->marker; } From 4d503a45ea1e2c4a5401e8d8852b5ffc426b56f0 Mon Sep 17 00:00:00 2001 From: Jeod <47716344+JeodC@users.noreply.github.com> Date: Wed, 29 Jul 2026 20:51:39 -0400 Subject: [PATCH 041/131] Fix rando softlock in SM jump tutorial (#284) --- src/port/Rando/ObjectBehavior/Molehill.cpp | 28 +++++++++++++--------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/src/port/Rando/ObjectBehavior/Molehill.cpp b/src/port/Rando/ObjectBehavior/Molehill.cpp index e54b87563..c85003134 100644 --- a/src/port/Rando/ObjectBehavior/Molehill.cpp +++ b/src/port/Rando/ObjectBehavior/Molehill.cpp @@ -55,7 +55,9 @@ ChMoleDescription result; #define OPTION_ENABLED RANDO_SAVE_OPTIONS[RO_SHUFFLE_MOLEHILLS].optionValue ChMoleDescription GetMoleDescriptionByAbility(int16_t abilityId) { - result.ability = -1; + // Reset every field, not just ability: result is file-scope, so a miss used to + // return the previous hit's dialog ids alongside ability == -1. + result = { -1, -1, -1, -1 }; for (int i = 0; i < MOLETABLE_SIZE; i++) { if (moleDialogTable[i].ability == abilityId) { result = moleDialogTable[i]; @@ -112,13 +114,12 @@ void Rando::ObjectBehavior::InitMolehillBehavior() { RandoSaveCheck shuffledMolehill = Rando::Logic::GetShuffledObject(randoCheckId); ChMoleDescription moleInfo = GetMoleDescriptionByAbility(shuffledMolehill.randoCollectionId); + *should = true; - if (moleInfo.ability >= ABILITY_0_BARGE) { - *should = true; - - func_80347A14(0); - molehillActor->has_met_before = true; + func_80347A14(0); + molehillActor->has_met_before = true; + if (moleInfo.ability >= ABILITY_0_BARGE) { switch (moleInfo.ability) { case ABILITY_4_CLAW_SWIPE: *textId = (s32)moleInfo.refresher_text_id; @@ -152,13 +153,18 @@ void Rando::ObjectBehavior::InitMolehillBehavior() { ability_unlock((ability_e)moleInfo.ability); break; } + } else { + // Nothing in the table to say for whatever landed here, so hand the item to the shared + // dispatch every other check type grants through and keep Bottles on a generic line. + *textId = (s32)ASSET_E08_DIALOG_BOTTLES_FIND_ANOTHER_MOLEHILL; + CustomObject::ResolveCustomActorCollisionEX(randoCheckId); + } - CustomObject::CheckObtainedEX(shuffledMolehill.randoCheckId); + CustomObject::CheckObtainedEX(shuffledMolehill.randoCheckId); - if (map_getLevel(gsworld_getMap()) == LEVEL_B_SPIRAL_MOUNTAIN) { - if (CheckBridgeState()) { - SetSpiralMountainFlags(); - } + if (map_getLevel(gsworld_getMap()) == LEVEL_B_SPIRAL_MOUNTAIN) { + if (CheckBridgeState()) { + SetSpiralMountainFlags(); } } }) From 9c03d1d2972887d7ebf5be929eac46da49f2333f Mon Sep 17 00:00:00 2001 From: Jeod <47716344+JeodC@users.noreply.github.com> Date: Wed, 29 Jul 2026 20:51:46 -0400 Subject: [PATCH 042/131] Fix a few issues with note retention (#283) --- src/port/Enhancements/Retention/NoteRetention.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/port/Enhancements/Retention/NoteRetention.cpp b/src/port/Enhancements/Retention/NoteRetention.cpp index a928ff7c1..23c816046 100644 --- a/src/port/Enhancements/Retention/NoteRetention.cpp +++ b/src/port/Enhancements/Retention/NoteRetention.cpp @@ -366,7 +366,7 @@ void RegisterNoteRetention_Init() { if (!systemActive() || !applyEnabled()) { return; } - item_set(ITEM_C_NOTE, countCollectedForLevel(ev->levelId)); + item_adjustByDiffWithoutHud(ITEM_C_NOTE, countCollectedForLevel(ev->levelId) - item_getCount(ITEM_C_NOTE)); }); // Seeding ITEM_C_NOTE re-triggers vanilla high-score dialogs; suppress them. @@ -378,8 +378,9 @@ void RegisterNoteRetention_Init() { switch (textId) { case 0xD9C: // Bottles' first-note text: "you can't take notes with you" case 0xF76: // "you just beat your high score" - case 0xF74: // milestone: 50 notes (Mumbo's Mountain) - case 0xF78: // milestone: collected every note in the level + // Milestones...maybe they should not be suppressed? They're aides for new players. + //case 0xF74: // milestone: 50 notes (Mumbo's Mountain) + //case 0xF78: // milestone: collected every note in the level *should = true; break; default: From 64ae13f47343bdfff08b2ba114780920fdf35ceb Mon Sep 17 00:00:00 2001 From: Malkierian Date: Wed, 29 Jul 2026 18:32:26 -0700 Subject: [PATCH 043/131] Restore molehill rando functionality. Update readme and building docs. Add 50-note-door ability to FFM start. --- README.md | 55 +++++++++---------- docs/BUILDING.md | 12 ++-- src/core2/ch/mole.c | 45 ++++++++------- .../Enhancements/Gameplay/FurnaceFunMoves.cpp | 5 ++ 4 files changed, 62 insertions(+), 55 deletions(-) diff --git a/README.md b/README.md index c52561e5c..424325d8d 100644 --- a/README.md +++ b/README.md @@ -3,21 +3,24 @@ # Lighthouse -Lead Developers: +Lead Developer: * Malkierian -## Discord +Developers: +* JeodC +* Caladius +## Discord Official Discord: https://discord.com/invite/shipofharkinian -If you're having any trouble after reading through this `README`, feel free ask for help in the Lighthouse Support text channels. Please keep in mind that we do not condone piracy. +If you're having any trouble after reading through this `README`, feel free ask for help in the Lighthouse text channels. Please keep in mind that we do not condone piracy. # Quick Start Lighthouse does not include any copyrighted assets. You are required to provide a supported copy of the game. ### 1. Verify your ROM dump -The supported ROMs are US 1.0 and US 1.1 Rev A versions. You can verify you have dumped a supported copy of the game by using the SHA-1 File Checksum Online at https://www.romhacking.net/hash/. +Any retail version listed below is supported. You can verify you have dumped a supported copy of the game by using the SHA-1 File Checksum Online at https://www.romhacking.net/hash/. * `baserom.us.v10.z64`: `1fe1632098865f639e22c11b9a81ee8f29c75d7a` * `baserom.us.v11.z64`: `ded6ee166e740ad1bc810fd678a84b48e245ab80` @@ -29,9 +32,10 @@ If you have multiple regions of the game and want to use them as language packs, ### 2. Verify your ROM is in .z64 format Your ROM needs to be in .z64 format. If it's in .n64 format, use the following to convert it to a .z64: https://hack64.net/tools/swapper.php -### 2. Download Lighthouse from [Releases](https://github.com/HarbourMasters/Lighthouse/releases) +### 3. Download Lighthouse from [Releases](https://github.com/HarbourMasters/Lighthouse/releases) + +### 4. Generating the OTR from the ROM and Play! -### 3. Generating the OTR from the ROM and Play! #### Windows * Extract every file from the zip into a folder of your choosing. * Run lighthouse.exe and select your compatible ROM. @@ -44,12 +48,10 @@ Your ROM needs to be in .z64 format. If it's in .n64 format, use the following t * Extract every file from the zip into a folder of your choosing. * Run lighthouse and select your compatible ROM. -#### Nintendo Switch -* Run one of the PC releases to generate an `lighthouse.o2r` file. After launching the game on PC, you will be able to find these files in the same directory as `lighthouse.exe` or `lighthouse.appimage`. -* Copy the files to your sd card - # Configuration +Lighthouse ships with a file with many standard controller mappings that can be used as-is with most controllers. If your controller isn't recognized by Lighthouse, or isn't working properly, you can create your own custom mapping using the built-in mapper in the Settings menu. + ### Default keyboard configuration | N64 | A | B | Z | Start | Analog stick | C buttons | D-Pad | | - | - | - | - | - | - | - | - | @@ -59,45 +61,42 @@ Your ROM needs to be in .z64 format. If it's in .n64 format, use the following t | Keys | Action | | - | - | | ESC | Toggle menubar | -| F4 | Reset | +| Ctrl+R | Reset | | F11 | Fullscreen | | Tab | Toggle Alternate assets | ### Graphics Backends - -TODO: verify this info - -Currently, there are three rendering APIs supported: DirectX11 (Windows), OpenGL (all platforms), and Metal (macOS). You can change which API to use in the `Settings` menu of the menubar, which requires a restart. If you're having an issue with crashing, you can change the API in the `lighthouse.cfg.json` file by finding the line `"Backend":{`... and changing the `id` value to `3` and set the `Name` to `OpenGL`. `DirectX 11` with id `2` is the default on Windows. `Metal` with id `4` is the default on macOS. +Currently, there are three rendering APIs supported: DirectX11 (Windows), OpenGL (all platforms), and Metal (macOS). You can change which API to use in the `Settings` menu of the menubar, which requires a restart. If you're having an issue with crashing, you can change the API in the `lighthouse.cfg.json` file by finding the line `"Backend":{`... and changing the `id` value to `2` and set the `Name` to `OpenGL`. `DirectX 11` with id `1` is the default on Windows. `Metal` with id `3` is the default on macOS. # Language Packs Lighthouse supports using multiple regions of Banjo-Kazooie as language packs. Generate your base `bk.o2r` file and once Lighthouse has started, open the imgui menu. Under General -> Languages, you will be able to select another ROM to extract as a language pack. PAL supports UK, French, and German, and Japanese adds Japanese support. After the language pack is generated, the language it brings will be added to the dropdown menu. -When using romhacks, only US v1.0 is supported, inherited from Banjo's Backpack. Therefore, it is recommended to use **US v1.0** as your base `bk.o2r` file. +# Romhacks + +Many romhacks can be extracted from patched ROMs and used as mods with Lighthouse. This can be done in-game using the Romhacks menu in the Settings section. If any hack isn't fully supported, the menu should inform you when extracting the mod. Most supported romhacks currently haven't been fully tested, so there may still be some issues. + +_NOTE: When using romhacks, only US v1.0 is supported, inherited from Banjo's Backpack. Therefore, it is recommended to use **US v1.0** as your base `bk.o2r` file. # Custom Assets + Custom assets are packed in `.o2r` or `.otr` files. To use custom assets, place them in the `mods` folder. If you're interested in creating and/or packing your own custom asset `.o2r`/`.otr` files, check out the following tools: * [**retro - OTR and O2R generator**](https://github.com/HarbourMasters64/retro) -* [**fast64 - Blender plugin (Note that SF64 is not supported at this time)**](https://github.com/HarbourMasters/fast64) +* [**fast64 - Blender plugin (Note that BK64 is not supported at this time)**](https://github.com/HarbourMasters/fast64) # Development -### Building - -TODO: add a main branch +### Building If you want to manually compile Lighthouse, please consult the [building instructions](https://github.com/HarbourMasters/Lighthouse/blob/main/docs/BUILDING.md). ### Playtesting -If you want to playtest a continuous integration build, you can find them at the links below. Keep in mind that these are for playtesting only, and you will likely encounter bugs and possibly crashes. - -TODO: replace these with lighthouse builds +If you want to playtest a continuous integration build, you can find them at the links below. Keep in mind that these are for playtesting only, and you will likely encounter bugs and possibly crashes. -* [Windows](https://nightly.link/HarbourMasters/Starship/workflows/main/main/starship-windows.zip) -* [macOS](https://nightly.link/HarbourMasters/Starship/workflows/main/main/starship-mac-x64.zip) -* [Linux](https://nightly.link/HarbourMasters/Starship/workflows/main/main/Starship-linux.zip) -* [Switch](https://nightly.link/HarbourMasters/Starship/workflows/main/main/Starship-switch.zip) +* [Windows](https://nightly.link/HarbourMasters/Lighthouse/workflows/main/main/Lighthouse-windows.zip) +* [macOS](https://nightly.link/HarbourMasters/Lighthouse/workflows/main/main/Lighthouse-mac.zip) +* [Linux](https://nightly.link/HarbourMasters/Lighthouse/workflows/main/main/Lighthouse-linux.zip) @@ -109,4 +108,4 @@ TODO: replace these with lighthouse builds # Special Thanks: * GiantJigglypuff3 for their extensive and continued Banjo Decomp documentation -TODO: fill in +* Fredomato, scorched11 for work on rando diff --git a/docs/BUILDING.md b/docs/BUILDING.md index 96037377e..65d0ee921 100644 --- a/docs/BUILDING.md +++ b/docs/BUILDING.md @@ -9,7 +9,7 @@ Requires: * The `MSVC v143 - VS 2022 C++ build tools` component of Visual Studio * Python 3 (can be installed manually or as part of Visual Studio) * Git (can be installed manually or as part of Visual Studio) - * Cmake (can be installed via chocolatey or manually) + * Cmake version <= 3.3 (can be installed via chocolatey or manually) During installation, check the "Desktop development with C++" feature set: @@ -22,10 +22,10 @@ It is recommended that you install Python and Git standalone, the install proces _Note: Be sure to either clone with the ``--recursive`` flag or do ``git submodule update --init`` after cloning to pull in the libultraship submodule!_ -2. Place a Banjo-Kazooie `.z64` ROM in the `baseroms/` directory. -3. Build and generate the `bk.o2r` asset archive. +2. Build and generate the `lighthouse.o2r` port assets archive. +3. Generate the `bk.o2r` ROM asset archive. -_Note: Instructions assume using powershell_ +_Note: Instructions assume using powershell, however, it's recommended to use the GeneratePortO2R project in VS and the built-in extraction flow to create the asset archives ```powershell # Navigate to the lighthouse repo within powershell. ie: cd "C:\yourpath\lighthouse" cd lighthouse @@ -216,13 +216,13 @@ cmake --build build-cmake --target clean ``` # Compatible Roms -See [`supportedHashes.json`](supportedHashes.json) +Any retail version. See [the readme](https://github.com/HarbourMasters/Lighthouse/blob/develop/README.md#1-verify-your-rom-dump) ## Getting CI to work on your fork The CI works via [Github Actions](https://github.com/features/actions) where we mostly make use of machines hosted by Github; except for the very first step of the CI process called "Extract assets". This step extracts assets from the ROM and generates the `bk.o2r` archive. -To get this step working on your fork, you'll need to add a machine to your own repository as a self-hosted runner via "Settings > Actions > Runners" in your repository settings. Make sure to add the 'asset-builder' tag to your newly added runner to assign it to run this step. To setup your runner as a service read the docs [here](https://docs.github.com/en/actions/hosting-your-own-runners/configuring-the-self-hosted-runner-application-as-a-service?platform=linux). +To get this step working on your fork, you'll need to enable actions for all sources in the Actions tab on GitHub. You can also add your own local runner on GitHub. ### Runner on Windows You'll have to enable the ability to run unsigned scripts through PowerShell. To do this, open Powershell as administrator and run `set-executionpolicy remotesigned`. Most dependencies get installed as part of the CI process. You will also need to separately install 7z and add it to the PATH so `7z` can be run as a command. [Chocolatey](https://chocolatey.org/) or other package managers can be used to install it easily. diff --git a/src/core2/ch/mole.c b/src/core2/ch/mole.c index 67f90ae1b..1e06bc5c0 100644 --- a/src/core2/ch/mole.c +++ b/src/core2/ch/mole.c @@ -239,27 +239,30 @@ void chmole_additionalAbilityLearnActions(ActorMarker *marker, enum asset_e arg1 int chmole_learnAbility(Actor *this){ s32 teach_text_id; s32 sp28 = 0xe; - // Known Ability: Refresher Dialog - if(ability_isUnlocked(moleTable[this->actorTypeSpecificField - MOLE_ID_TO_TABLE_SHIFT].ability)){ - sp28 = 0xf; - teach_text_id = moleTable[this->actorTypeSpecificField - MOLE_ID_TO_TABLE_SHIFT].refresher_text_id; - }//L802D99EC - // New Ability: Learn Dialog & Misc Actions - else{ - func_80347A14(0); - this->has_met_before = TRUE; - teach_text_id = moleTable[this->actorTypeSpecificField - MOLE_ID_TO_TABLE_SHIFT].teach_text_id; - ability_unlock(moleTable[this->actorTypeSpecificField - MOLE_ID_TO_TABLE_SHIFT].ability); - switch(moleTable[this->actorTypeSpecificField - MOLE_ID_TO_TABLE_SHIFT].ability){ - case ABILITY_9_FLIGHT: - case ABILITY_D_SHOCK_JUMP: - gcsfx_playWithPitch(SFX_113_PAD_APPEARS, 0.9f, 32000); - break; - case ABILITY_13_1ST_NOTEDOOR: - func_802FAD64(ITEM_C_NOTE); - break; - } - }//L802D9A9C + // [port] Rando hands out its own item here, whether or not the vanilla move is known. + if (!EventSystem_Should(VB_OVERRIDE_MOLEHILL_ABILITY, false, this, &teach_text_id, &sp28)) { + // Known Ability: Refresher Dialog + if(ability_isUnlocked(moleTable[this->actorTypeSpecificField - MOLE_ID_TO_TABLE_SHIFT].ability)){ + sp28 = 0xf; + teach_text_id = moleTable[this->actorTypeSpecificField - MOLE_ID_TO_TABLE_SHIFT].refresher_text_id; + }//L802D99EC + // New Ability: Learn Dialog & Misc Actions + else{ + func_80347A14(0); + this->has_met_before = TRUE; + teach_text_id = moleTable[this->actorTypeSpecificField - MOLE_ID_TO_TABLE_SHIFT].teach_text_id; + ability_unlock(moleTable[this->actorTypeSpecificField - MOLE_ID_TO_TABLE_SHIFT].ability); + switch(moleTable[this->actorTypeSpecificField - MOLE_ID_TO_TABLE_SHIFT].ability){ + case ABILITY_9_FLIGHT: + case ABILITY_D_SHOCK_JUMP: + gcsfx_playWithPitch(SFX_113_PAD_APPEARS, 0.9f, 32000); + break; + case ABILITY_13_1ST_NOTEDOOR: + func_802FAD64(ITEM_C_NOTE); + break; + } + }//L802D9A9C + } gcdialog_showDialog(teach_text_id, sp28, this->position, this->marker, chmole_healthRefill, chmole_additionalAbilityLearnActions); return TRUE; } diff --git a/src/port/Enhancements/Gameplay/FurnaceFunMoves.cpp b/src/port/Enhancements/Gameplay/FurnaceFunMoves.cpp index 38e09a8c5..f76860273 100644 --- a/src/port/Enhancements/Gameplay/FurnaceFunMoves.cpp +++ b/src/port/Enhancements/Gameplay/FurnaceFunMoves.cpp @@ -21,7 +21,12 @@ void RegisterFurnaceFunMoves_Init() { continue; } ability_unlock(static_cast(ability)); + ability_setHasUsed(static_cast(ability)); } + // Outside the loop's range. Without it the note doors never open and Bottles + // force-triggers his tutorial on approach to the 50-note door. + ability_unlock(ABILITY_13_1ST_NOTEDOOR); + ability_setHasUsed(ABILITY_13_1ST_NOTEDOOR); }); } From 4cc0828efa1ebb7b61f32128cad5cebabfaddee5 Mon Sep 17 00:00:00 2001 From: Jeod <47716344+JeodC@users.noreply.github.com> Date: Wed, 29 Jul 2026 21:38:24 -0400 Subject: [PATCH 044/131] Fix interpolation bug introduced by rings (#285) --- src/port/Game.cpp | 25 +++++++++- src/port/Interpolation/FrameInterpolation.cpp | 49 +++++++++++++++++-- 2 files changed, 70 insertions(+), 4 deletions(-) diff --git a/src/port/Game.cpp b/src/port/Game.cpp index fcc8de0e6..c2e4a5e7d 100644 --- a/src/port/Game.cpp +++ b/src/port/Game.cpp @@ -57,9 +57,14 @@ struct InterpPair { int prev = -1; int curr = -1; bool should = false; + uint64_t serial = 0; }; std::mutex sInterpMutex; std::map sTaskInterp; +uint64_t sInterpSerial = 0; +// Submissions of slack before an unrendered pair is assumed dropped. The ring is +// 4 slots, so by then its trees have been recycled regardless. +constexpr uint64_t kInterpStaleAfter = 4; // Renderer calls made from tick code, run by the main loop between services. std::mutex sSvcMutex; @@ -104,7 +109,25 @@ extern "C" void port_thread5_onSubmit(void* taskData) { FrameInterpolation_ClaimPair(pair.prev, pair.curr); FrameInterpolation_StopRecord(); std::lock_guard lock(sInterpMutex); - sTaskInterp[task->data_ptr] = pair; + pair.serial = ++sInterpSerial; + auto [it, inserted] = sTaskInterp.emplace(task->data_ptr, pair); + if (!inserted) { + FrameInterpolation_ReleasePair(it->second.prev, it->second.curr); + it->second = pair; + } + + // Anything still here after a full trip round the ring can no longer be + // blended against a live tree, so its claim is only holding a slot hostage. + // Dropping the entry leaves RenderTask with a -1 pair, which renders + // uninterpolated rather than against a recycled tree. + for (auto stale = sTaskInterp.begin(); stale != sTaskInterp.end();) { + if (stale->second.serial + kInterpStaleAfter < pair.serial) { + FrameInterpolation_ReleasePair(stale->second.prev, stale->second.curr); + stale = sTaskInterp.erase(stale); + } else { + ++stale; + } + } } namespace { diff --git a/src/port/Interpolation/FrameInterpolation.cpp b/src/port/Interpolation/FrameInterpolation.cpp index e56a641b5..e94e7e7d0 100644 --- a/src/port/Interpolation/FrameInterpolation.cpp +++ b/src/port/Interpolation/FrameInterpolation.cpp @@ -17,6 +17,9 @@ struct ToMtxData { float src[4][4]; uint64_t pathSig; bool noInterpolate; + // Another entry this tick claimed the same scope identity, so which one a + // cross-tick partner refers to is a guess. See recordSigCollision. + bool ambiguousSig; }; // Sprites keep their raw inputs instead of the finished matrix so replay can @@ -33,6 +36,7 @@ struct SpriteDrawData { uint64_t pathSig; uint8_t kind; bool mirrored; + bool ambiguousSig; }; struct CameraProjRotData { @@ -73,6 +77,7 @@ struct FrameTree { float cameraPos[3] = { 0.0f, 0.0f, 0.0f }; bool hasCameraPos = false; bool valid = false; + uint32_t sigCollisions = 0; std::atomic generation{ 0 }; void reset() { @@ -86,9 +91,31 @@ struct FrameTree { cameraPos[0] = cameraPos[1] = cameraPos[2] = 0.0f; hasCameraPos = false; valid = false; + sigCollisions = 0; } }; +// A scope identity is only useful if one entry owns it. When two do, the +// sig->index maps cannot say which, and emplace keeps whichever arrived first +// -- so the second entry silently pairs against the first one's transform and +// gets dragged across the screen for a sub-frame. Mark every claimant instead +// and point the map at a sentinel, which leaves all of them uninterpolated. +constexpr uint32_t kAmbiguousSig = UINT32_MAX; + +template +void recordSigCollision(Map& sigMap, Vec& entries, uint64_t sig, uint32_t idx, uint32_t& collisionCount) { + auto [it, inserted] = sigMap.emplace(sig, idx); + if (inserted) { + return; + } + if (it->second < entries.size()) { + entries[it->second].ambiguousSig = true; + } + entries[idx].ambiguousSig = true; + it->second = kAmbiguousSig; + collisionCount++; +} + // Ring of trees: the render side reads a (prev, curr) pair while the tick // records the next one. Reuse is ownership-based; a submitted pair claims // its two slots until that render finishes, and recording skips claimed slots. @@ -179,6 +206,17 @@ void FrameInterpolation_StopRecord(void) { gRecording = false; gRecord->valid = gShouldInterpolate; gLastRecordedSlot = gRecordSlot; + + // One line per affected tick, not per collision: a scope whose id repeats + // usually repeats for every instance behind it. + if (gRecord->sigCollisions != 0) { + static uint32_t sReported = 0; + if (sReported < 20) { + sReported++; + SPDLOG_WARN("interp scope id collided {}x this tick ({} matrices, {} sprites)", + gRecord->sigCollisions, gRecord->toMtxs.size(), gRecord->sprites.size()); + } + } } // The pair for the tick being recorded right now, grabbed when a display list @@ -273,7 +311,8 @@ void FrameInterpolation_RecordMatrixToMtx(void* dst, const float src[4][4]) { std::memcpy(d.src, src, sizeof(float) * 16); d.pathSig = sig; d.noInterpolate = (gNoInterpolateDepth > 0); - gRecord->sigToToMtx.emplace(sig, idx); + d.ambiguousSig = false; + recordSigCollision(gRecord->sigToToMtx, gRecord->toMtxs, sig, idx, gRecord->sigCollisions); } void FrameInterpolation_RecordCameraProjectionRotation(void* rollMtx, float rollDeg, void* pitchMtx, float pitchDeg, @@ -338,7 +377,8 @@ void FrameInterpolation_RecordSpriteDraw(int kind, void* dst, const float camRel d.pathSig = sig; d.kind = static_cast(kind); d.mirrored = (mirrored != 0); - gRecord->sigToSprite.emplace(sig, idx); + d.ambiguousSig = false; + recordSigCollision(gRecord->sigToSprite, gRecord->sprites, sig, idx, gRecord->sigCollisions); } void FrameInterpolation_DontInterpolateCamera(void) { @@ -424,7 +464,7 @@ void BuildInterpolationCache() { // matrix didn't change, can simply be dropped here. for (uint32_t i = 0; i < currToMtxs.size(); i++) { const ToMtxData& c = currToMtxs[i]; - if (c.dst == nullptr || c.noInterpolate) { + if (c.dst == nullptr || c.noInterpolate || c.ambiguousSig) { continue; } auto it = prevSigMap.find(c.pathSig); @@ -443,6 +483,9 @@ void BuildInterpolationCache() { // keep facing the blended camera. for (uint32_t i = 0; i < currSprites.size(); i++) { const SpriteDrawData& c = currSprites[i]; + if (c.ambiguousSig) { + continue; + } auto it = prevSpriteMap.find(c.pathSig); if (it == prevSpriteMap.end() || it->second >= prevSprites.size() || prevSprites[it->second].kind != c.kind) { gCache.pairedSprites.push_back({ i, UINT32_MAX }); From 67d05f6f985b2b2a8c668e412f2aa76eee71b725 Mon Sep 17 00:00:00 2001 From: Jeod <47716344+JeodC@users.noreply.github.com> Date: Wed, 29 Jul 2026 21:38:39 -0400 Subject: [PATCH 045/131] Resolve a crash when searching in imgui (#286) --- src/port/UI/Menu.cpp | 5 +++-- src/port/UI/UIWidgets.cpp | 24 ++++++++++++------------ 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/src/port/UI/Menu.cpp b/src/port/UI/Menu.cpp index 187bdd140..d04ecdd02 100644 --- a/src/port/UI/Menu.cpp +++ b/src/port/UI/Menu.cpp @@ -248,8 +248,9 @@ uint32_t Menu::DrawSearchResults(std::string& menuSearchText) { entry.info.type == WIDGET_SEPARATOR_TEXT || entry.info.isHidden || entry.info.hideInSearch) { continue; } - std::string widgetStr = - entry.info.name + entry.info.options->tooltip + entry.extraTerms + entry.sidebarName; + const char* extraTooltip = entry.info.options->tooltip; + std::string widgetStr = entry.info.name + std::string(extraTooltip != nullptr ? extraTooltip : "") + + entry.extraTerms + entry.sidebarName; std::transform(widgetStr.begin(), widgetStr.end(), widgetStr.begin(), ::tolower); widgetStr.erase(std::remove(widgetStr.begin(), widgetStr.end(), ' '), widgetStr.end()); if (widgetStr.find(menuSearchText) != std::string::npos) { diff --git a/src/port/UI/UIWidgets.cpp b/src/port/UI/UIWidgets.cpp index e2b670a1f..518e051f8 100644 --- a/src/port/UI/UIWidgets.cpp +++ b/src/port/UI/UIWidgets.cpp @@ -529,7 +529,7 @@ bool SliderInt(const char* label, int32_t* value, const IntSliderOptions& option } ImGui::AlignTextToFramePadding(); if (options.alignment == ComponentAlignments::Right && options.labelPosition != LabelPositions::None) { - ImGui::Text(label, *value); + ImGui::Text("%s", label); if (options.labelPosition == LabelPositions::Above) { ImGui::NewLine(); ImGui::SameLine(ImGui::GetContentRegionAvail().x - width); @@ -540,7 +540,7 @@ bool SliderInt(const char* label, int32_t* value, const IntSliderOptions& option } } else if (options.alignment == ComponentAlignments::Left) { if (options.labelPosition == LabelPositions::Above) { - ImGui::Text(label, *value); + ImGui::Text("%s", label); } } if (options.showButtons) { @@ -585,11 +585,11 @@ bool SliderInt(const char* label, int32_t* value, const IntSliderOptions& option if (options.alignment == ComponentAlignments::Left && options.labelPosition != LabelPositions::None) { if (options.labelPosition == LabelPositions::Near) { ImGui::SameLine(); - ImGui::Text(label, *value); + ImGui::Text("%s", label); } else if (options.labelPosition == LabelPositions::Far) { ImGui::SameLine(ImGui::GetContentRegionAvail().x - ImGui::CalcTextSize(label).x + ImGui::GetStyle().ItemSpacing.x); - ImGui::Text(label, *value); + ImGui::Text("%s", label); } } PopStyleSlider(); @@ -665,7 +665,7 @@ bool SliderFloat(const char* label, float* value, const FloatSliderOptions& opti } ImGui::AlignTextToFramePadding(); if (options.alignment == ComponentAlignments::Right) { - ImGui::Text(label, *value); + ImGui::Text("%s", label); if (options.labelPosition == LabelPositions::Above) { ImGui::NewLine(); ImGui::SameLine(ImGui::GetContentRegionAvail().x - width); @@ -678,7 +678,7 @@ bool SliderFloat(const char* label, float* value, const FloatSliderOptions& opti } } else if (options.alignment == ComponentAlignments::Left) { if (options.labelPosition == LabelPositions::Above) { - ImGui::Text(label, *value); + ImGui::Text("%s", label); } } if (options.showButtons) { @@ -717,10 +717,10 @@ bool SliderFloat(const char* label, float* value, const FloatSliderOptions& opti if (options.alignment == ComponentAlignments::Left) { if (options.labelPosition == LabelPositions::Near) { ImGui::SameLine(); - ImGui::Text(label, *value); + ImGui::Text("%s", label); } else if (options.labelPosition == LabelPositions::Far || options.labelPosition == LabelPositions::None) { ImGui::SameLine(ImGui::GetContentRegionAvail().x - labelSpacing); - ImGui::Text(label, *value); + ImGui::Text("%s", label); } } PopStyleSlider(); @@ -771,13 +771,13 @@ bool InputString(const char* label, std::string* value, const InputOptions& opti if (labelSize.x != 0) { if (options.alignment == ComponentAlignments::Left) { if (options.labelPosition == LabelPositions::Above) { - ImGui::Text(label, *value->c_str()); + ImGui::Text("%s", label); } } else if (options.alignment == ComponentAlignments::Right) { if (options.labelPosition == LabelPositions::Above) { ImGui::NewLine(); ImGui::SameLine(width - ImGui::CalcTextSize(label).x); - ImGui::Text(label, *value->c_str()); + ImGui::Text("%s", label); } } } @@ -834,13 +834,13 @@ bool InputInt(const char* label, int32_t* value, const InputOptions& options) { float width = (options.size == ImVec2(0, 0)) ? ImGui::GetContentRegionAvail().x : options.size.x; if (options.alignment == ComponentAlignments::Left) { if (options.labelPosition == LabelPositions::Above) { - ImGui::Text(label, *value); + ImGui::Text("%s", label); } } else if (options.alignment == ComponentAlignments::Right) { if (options.labelPosition == LabelPositions::Above) { ImGui::NewLine(); ImGui::SameLine(width - ImGui::CalcTextSize(label).x); - ImGui::Text(label, *value); + ImGui::Text("%s", label); } } ImGui::SetNextItemWidth(width); From e5cc9400ef085c47634fbc3154b7c04fd6a10c39 Mon Sep 17 00:00:00 2001 From: Jeod <47716344+JeodC@users.noreply.github.com> Date: Wed, 29 Jul 2026 22:32:07 -0400 Subject: [PATCH 046/131] Fix CC rando mapstates (#287) --- src/port/Rando/MiscBehavior/WorldState.cpp | 9 ++++++++- src/port/Rando/ObjectBehavior/Jiggy.cpp | 23 ++++++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/src/port/Rando/MiscBehavior/WorldState.cpp b/src/port/Rando/MiscBehavior/WorldState.cpp index e6916053e..4cb72f0b0 100644 --- a/src/port/Rando/MiscBehavior/WorldState.cpp +++ b/src/port/Rando/MiscBehavior/WorldState.cpp @@ -195,7 +195,14 @@ void Rando::MiscBehavior::InitWorldStateBehavior() { if (randoCheckId == RC_MMM_JIGGY_TUMBLARS_PUZZLE) { ev->result = mapSpecificFlags_get(MMM_SPECIFIC_FLAG_TUMBLAR_BROKEN); } else if (randoCheckId == RC_CC_JIGGY_CLANKER_RAISED) { - ev->result = RANDO_SAVE_FLAGS[RANDO_INF_CLANKER_RAISED].flagState; + // Clanker's height and his rings' water level are both recalled from + // this query, so it has to answer for the world event and not just + // for a reward still sitting in the level. + ev->result = RANDO_SAVE_FLAGS[RANDO_INF_CLANKER_RAISED].flagState || + CustomObject::CheckSpawnedIdList(randoCheckId); + } else if (randoCheckId == RC_CC_JIGGY_RINGS) { + ev->result = RANDO_SAVE_FLAGS[RANDO_INF_MINIGAME_RINGS_COMPLETED].flagState || + CustomObject::CheckSpawnedIdList(randoCheckId); } else { ev->result = CustomObject::CheckSpawnedIdList(randoCheckId); } diff --git a/src/port/Rando/ObjectBehavior/Jiggy.cpp b/src/port/Rando/ObjectBehavior/Jiggy.cpp index cc4fc67f8..5084aed7a 100644 --- a/src/port/Rando/ObjectBehavior/Jiggy.cpp +++ b/src/port/Rando/ObjectBehavior/Jiggy.cpp @@ -7,6 +7,26 @@ #define OPTION_ENABLED RANDO_SAVE_OPTIONS[RO_SHUFFLE_JIGGIES].optionValue +// Some jiggies double as the world's only memory of what opened them up: raising +// Clanker and finishing his rings are both recalled purely from +// jiggyscore_isSpawned on the jiggy that appeared. Vanilla records that in +// jiggy_spawn via jiggyscore_setSpawned, which the override below never reaches, +// and the check-obtained path only fires once the reward is actually picked up. +static void MarkWorldStateFromJiggySpawn(RandoCheckId randoCheckId) { + RandoInf randoInfFlag = RANDO_INF_UNKNOWN; + switch (randoCheckId) { + case RC_CC_JIGGY_CLANKER_RAISED: + randoInfFlag = RANDO_INF_CLANKER_RAISED; + break; + case RC_CC_JIGGY_RINGS: + randoInfFlag = RANDO_INF_MINIGAME_RINGS_COMPLETED; + break; + default: + return; + } + CALL_EVENT(SetRandoInfFlag, randoInfFlag, 1); +} + void Rando::ObjectBehavior::InitJiggyBehavior() { COND_VB_SHOULD(VB_NAPPER_SET_JIGGY_POSITION, EVENT_PRIORITY_NORMAL, true, { if (!IS_RANDO && !OPTION_ENABLED) { @@ -51,6 +71,9 @@ void Rando::ObjectBehavior::InitJiggyBehavior() { if (jiggyId != JIGGY_17_CC_CLANKER_RAISED && jiggyId != JIGGY_1B_CC_TOOTH) { ApplyCustomActorPhysics(randoCheckId, randoCustomActor, false); } + // Stand in for the jiggyscore_setSpawned this override skips, for the + // jiggies the world reads back as state rather than as a collectable. + MarkWorldStateFromJiggySpawn(randoCheckId); *should = true; }) } From 01a0ab4110eebfdd1f2e2d98aed623aaa38253bb Mon Sep 17 00:00:00 2001 From: Malkierian Date: Wed, 29 Jul 2026 19:38:57 -0700 Subject: [PATCH 047/131] Restore event call in `chmole_learnedAllSpiralMountainAbilities` (#288) --- src/core2/ch/mole.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/core2/ch/mole.c b/src/core2/ch/mole.c index 1e06bc5c0..ca9a701a5 100644 --- a/src/core2/ch/mole.c +++ b/src/core2/ch/mole.c @@ -491,14 +491,16 @@ void chmole_update(Actor *this){ int chmole_learnedAllSpiralMountainAbilities(void){ // Checks if the player has learned all of the Spiral Mountain abilities. - return ability_isUnlocked(ABILITY_F_DIVE) - && ability_isUnlocked(ABILITY_4_CLAW_SWIPE) - && ability_isUnlocked(ABILITY_C_ROLL) - && ability_isUnlocked(ABILITY_B_RATATAT_RAP) - && ability_isUnlocked(ABILITY_0_BARGE) - && ability_isUnlocked(ABILITY_A_HOLD_A_JUMP_HIGHER) - && ability_isUnlocked(ABILITY_7_FEATHERY_FLAP) - && ability_isUnlocked(ABILITY_8_FLAP_FLIP) - && ability_isUnlocked(ABILITY_5_CLIMB) - ; + CALL_CANCELLABLE_RETURN_EVENT(OnCheckSpiralMountainAbilities) { + return ability_isUnlocked(ABILITY_F_DIVE) + && ability_isUnlocked(ABILITY_4_CLAW_SWIPE) + && ability_isUnlocked(ABILITY_C_ROLL) + && ability_isUnlocked(ABILITY_B_RATATAT_RAP) + && ability_isUnlocked(ABILITY_0_BARGE) + && ability_isUnlocked(ABILITY_A_HOLD_A_JUMP_HIGHER) + && ability_isUnlocked(ABILITY_7_FEATHERY_FLAP) + && ability_isUnlocked(ABILITY_8_FLAP_FLIP) + && ability_isUnlocked(ABILITY_5_CLIMB) + ; + } } From 414032a4532cba2f043efb6c735803b58c505dcf Mon Sep 17 00:00:00 2001 From: Jeod <47716344+JeodC@users.noreply.github.com> Date: Wed, 29 Jul 2026 23:10:59 -0400 Subject: [PATCH 048/131] Rando: don't require pumpkin for shuffled MMM honeycomb (#289) --- src/port/Rando/MiscBehavior/WorldState.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/port/Rando/MiscBehavior/WorldState.cpp b/src/port/Rando/MiscBehavior/WorldState.cpp index 4cb72f0b0..5a851f09f 100644 --- a/src/port/Rando/MiscBehavior/WorldState.cpp +++ b/src/port/Rando/MiscBehavior/WorldState.cpp @@ -209,6 +209,15 @@ void Rando::MiscBehavior::InitWorldStateBehavior() { } }) + // Drop the id-keyed requirement for the MMM floorboard honeycomb (marker.c) + COND_VB_SHOULD(VB_HONEYCOMB_PUMPKIN_REQUIREMENT, EVENT_PRIORITY_NORMAL, true, { + (void)args; + if (!IS_RANDO || !EMPTY_HONEYCOMB_OPTION_ENABLED) { + return; + } + *should = false; + }) + REGISTER_LISTENER(OnIsHoneycombScoreCollected, EVENT_PRIORITY_NORMAL, [](IEvent* event) { OnIsHoneycombScoreCollected* ev = (OnIsHoneycombScoreCollected*)event; From 92a6716b65c474765759d73d08e740dfe4912b6f Mon Sep 17 00:00:00 2001 From: Malkierian Date: Wed, 29 Jul 2026 22:06:43 -0700 Subject: [PATCH 049/131] Fix rando events (#290) * Make InitRandoEvents call only once per real save load (instead of only on rando OnSaveLoad). Fix actor save state restorations in rando. * full-project clang --- src/core2/gameSelect.c | 1 + src/port/Controller/Mapper.h | 10 +++++----- src/port/DevTools/ThreadWatchdog.cpp | 17 +++++++---------- src/port/DevTools/ThreadWatchdog.h | 16 ++++++++-------- src/port/Engine.cpp | 1 - .../Enhancements/Events/Hooks/List/GameEvent.h | 3 +++ .../Enhancements/Events/PortEnhancements.cpp | 1 + .../Enhancements/Retention/NoteRetention.cpp | 6 +++--- src/port/Game.cpp | 1 - src/port/Interpolation/FrameInterpolation.cpp | 4 ++-- src/port/OS/OS_Mesg.cpp | 2 +- src/port/OS/OS_RCP.cpp | 2 +- src/port/Patches/PerfPatches.cpp | 1 - src/port/Rando/MiscBehavior/OnFileLoad.cpp | 9 +++------ .../Rando/ObjectBehavior/ObjectBehavior.cpp | 7 ++++--- src/port/UI/LighthouseMenuDevTools.cpp | 9 ++++++--- 16 files changed, 45 insertions(+), 45 deletions(-) diff --git a/src/core2/gameSelect.c b/src/core2/gameSelect.c index 98c6ae72f..7f2dc02cb 100644 --- a/src/core2/gameSelect.c +++ b/src/core2/gameSelect.c @@ -452,6 +452,7 @@ void gameSelect_update(Actor *this){ chBottlesBonus_resetCompleted(); gameFile_load(gSelectedGameNum); port_syncBottlesBonusIndex(); + CALL_EVENT(OnGameStart); if(EventSystem_Should(VB_GAMESELECT_START_NEW_GAME, !gameFile_isNotEmpty(sp84), sp84)){ s32 skipIntro = 0; CALL_EVENT(OnNewGame, &skipIntro); diff --git a/src/port/Controller/Mapper.h b/src/port/Controller/Mapper.h index d8f72376c..0d0d41bb3 100644 --- a/src/port/Controller/Mapper.h +++ b/src/port/Controller/Mapper.h @@ -62,7 +62,7 @@ struct AxisState { }; class MappingSession { - public: +public: static constexpr int32_t AXIS_COMMIT_DISTANCE = 16000; static constexpr int32_t AXIS_RETURN_DISTANCE = 10000; static constexpr uint32_t PENDING_ADVANCE_DELAY_MS = 100; @@ -93,7 +93,7 @@ class MappingSession { void SetBindings(const ExtendedBind (&bindings)[BINDING_COUNT]); void CopyBindingsTo(ExtendedBind (&out)[BINDING_COUNT]) const; - private: +private: void ConfigureBinding(const ExtendedBind& binding); bool BindingContainsBinding(const ExtendedBind& a, const ExtendedBind& b) const; @@ -121,16 +121,16 @@ bool SaveUserMapping(const std::string& mapping); bool DeleteUserMapping(const std::string& guid); class MapperWindow final : public Ship::GuiWindow { - public: +public: using GuiWindow::GuiWindow; ~MapperWindow(); - protected: +protected: void InitElement() override; void UpdateElement() override; void DrawElement() override; - private: +private: struct DeviceInfo { int32_t deviceIndex; SDL_JoystickID instanceId; diff --git a/src/port/DevTools/ThreadWatchdog.cpp b/src/port/DevTools/ThreadWatchdog.cpp index 945e94e75..aaac15e7c 100644 --- a/src/port/DevTools/ThreadWatchdog.cpp +++ b/src/port/DevTools/ThreadWatchdog.cpp @@ -288,8 +288,7 @@ std::string CaptureStalledStack(int threadIdx) { if (SymGetLineFromAddr64(proc, frames[i], &lineDisp, &line)) { // Only frames under this repo's source root are ours; CRT and // STL paths contain "\src\" as well and must not match. - const bool ours = !srcRoot.empty() && - _strnicmp(line.FileName, srcRoot.c_str(), srcRoot.size()) == 0; + const bool ours = !srcRoot.empty() && _strnicmp(line.FileName, srcRoot.c_str(), srcRoot.size()) == 0; out += fmt::format("{} #{:02} {}+0x{:x} ({}:{})\n", ours ? ">" : " ", i, sym->Name, symDisp, line.FileName, line.LineNumber); } else { @@ -391,8 +390,8 @@ std::string BuildDump(const bool* stalled, Clock::time_point now, const std::str std::string park; if (const OS_BlockedWait* w = waitFor(i)) { QueueInfo qi = DescribeQueue(w->mq); - park = fmt::format(" {} {} {}/{}", w->isSend ? "send" : "recv", qi.name, w->mq->validCount, - w->mq->msgCount); + park = + fmt::format(" {} {} {}/{}", w->isSend ? "send" : "recv", qi.name, w->mq->validCount, w->mq->msgCount); } out += fmt::format(" {:<11} {:<7} {:>6} tid {:<6} {} beats{}\n", kThreadNames[i], (stalled != nullptr && stalled[i]) ? "STALLED" : "ok", age, @@ -413,8 +412,8 @@ std::string BuildDump(const bool* stalled, Clock::time_point now, const std::str DescribeUnkFlag1(t5.unkFlag1), t5.unkFlag2, t5.unkFlag2Saved, t5.syncCounter, t5.task7Handled, t5.gfxActiveId, t5.gfxSelectedId, t5.audioActiveId, t5.audioSelectedId, t5.taskQueueCount, t5.taskQueueCap, t5.syncQueueCount, t5.syncQueueCap, (dpStatus & 0x2) ? 1 : 0, - OS_SpPeekPendingTask() != nullptr ? "yes" : "no", curFb == nextFb ? "==" : "!=", - OS_ViBlackActive() ? " viBlack" : ""); + OS_SpPeekPendingTask() != nullptr ? "yes" : "no", + curFb == nextFb ? "==" : "!=", OS_ViBlackActive() ? " viBlack" : ""); out += fmt::format("Frame pacing: D_802808D8={}{} frameTokenQ={} tickRetraceQ={} retraceQ={}\n", vi.retraceCount, vi.retraceCount > 10 ? " (accumulating)" : "", vi.q2Count, vi.q3Count, vi.q1Count); @@ -424,9 +423,8 @@ std::string BuildDump(const bool* stalled, Clock::time_point now, const std::str out += fmt::format("SI/audio: pfsBusy={} pollingQ={} audioFrameQ={} audioReplyQ={} audioHeld={} svcPending={}\n", pfsManager_isBusy(), pfsPoll->validCount, audioFrame->validCount, audioReply->validCount, port_audioHeld(), port_renderServicePending()); - out += fmt::format("Context: map={:#x} exit={:#x} gameMode={} build={} {}@{}", gsworld_getMap(), - gsworld_getExit(), getGameMode(), (char*)gBuildVersion, (char*)gGitBranch, - (char*)gGitCommitHash); + out += fmt::format("Context: map={:#x} exit={:#x} gameMode={} build={} {}@{}", gsworld_getMap(), gsworld_getExit(), + getGameMode(), (char*)gBuildVersion, (char*)gGitBranch, (char*)gGitCommitHash); if (!stack.empty()) { out += "\n" + stack; @@ -549,4 +547,3 @@ extern "C" void ThreadWatchdog_DumpNow(void) { extern "C" int ThreadWatchdog_IsStalled(WatchdogThread id) { return sStalledFlags[id].load(std::memory_order_relaxed) ? 1 : 0; } - diff --git a/src/port/DevTools/ThreadWatchdog.h b/src/port/DevTools/ThreadWatchdog.h index 34ae17199..5b63da21a 100644 --- a/src/port/DevTools/ThreadWatchdog.h +++ b/src/port/DevTools/ThreadWatchdog.h @@ -16,14 +16,14 @@ extern "C" { #endif typedef enum WatchdogThread { - WATCHDOG_VI_TICKER = 0, // retrace source (OS_VI.cpp); everything below is paced by it - WATCHDOG_MAIN_LOOP, // window thread: event pump + RCP service (Game.cpp) - WATCHDOG_GAME_TICK, // push_frame loop (Game.cpp) - WATCHDOG_THREAD5, // decomp graphics thread (graphics_thread.c) - WATCHDOG_VIMGR, // decomp VI manager thread (vimgr.c) - WATCHDOG_PFSMANAGER, // controller thread (pfsmanager.c) - WATCHDOG_AUDIO_MANAGER, // audio thread (audio_manager.c); idles during demo audio holds - WATCHDOG_RUMBLE, // motor thread (bamotor.c); one beat per retrace signal + WATCHDOG_VI_TICKER = 0, // retrace source (OS_VI.cpp); everything below is paced by it + WATCHDOG_MAIN_LOOP, // window thread: event pump + RCP service (Game.cpp) + WATCHDOG_GAME_TICK, // push_frame loop (Game.cpp) + WATCHDOG_THREAD5, // decomp graphics thread (graphics_thread.c) + WATCHDOG_VIMGR, // decomp VI manager thread (vimgr.c) + WATCHDOG_PFSMANAGER, // controller thread (pfsmanager.c) + WATCHDOG_AUDIO_MANAGER, // audio thread (audio_manager.c); idles during demo audio holds + WATCHDOG_RUMBLE, // motor thread (bamotor.c); one beat per retrace signal WATCHDOG_NUM_THREADS } WatchdogThread; diff --git a/src/port/Engine.cpp b/src/port/Engine.cpp index 7dad6ba56..746048a50 100644 --- a/src/port/Engine.cpp +++ b/src/port/Engine.cpp @@ -1215,7 +1215,6 @@ void GameEngine::AudioInit() { LoadSoundfonts(); } - // Local timer helper for the per-sub-frame cost measurement. namespace { using Clock = std::chrono::steady_clock; diff --git a/src/port/Enhancements/Events/Hooks/List/GameEvent.h b/src/port/Enhancements/Events/Hooks/List/GameEvent.h index 79a1fa13c..37af7a155 100644 --- a/src/port/Enhancements/Events/Hooks/List/GameEvent.h +++ b/src/port/Enhancements/Events/Hooks/List/GameEvent.h @@ -32,6 +32,9 @@ typedef enum WarpId { DEFINE_EVENT(OnWarpResolveDest, int32_t warpId; int32_t defaultDest; int32_t bkcfOverride; int32_t * dest;) DEFINE_EVENT(OnNewGame, int32_t* skipIntro;) +// The file-select commit, for both new game and continue. Unlike OnGameLoad this +// does not fire for the zoombox preview. +DEFINE_EVENT(OnGameStart) DEFINE_EVENT(EggHeadSpawn, float* pitch; float* spawnHeight; float* minVerticalVelocity; float* yawBias; int32_t * flattenTrajectory;) diff --git a/src/port/Enhancements/Events/PortEnhancements.cpp b/src/port/Enhancements/Events/PortEnhancements.cpp index 83e983972..c8978ce36 100644 --- a/src/port/Enhancements/Events/PortEnhancements.cpp +++ b/src/port/Enhancements/Events/PortEnhancements.cpp @@ -93,6 +93,7 @@ void PortEnhancements_Register() { REGISTER_EVENT(OnPropInit); REGISTER_EVENT(OnWarpResolveDest); REGISTER_EVENT(OnNewGame); + REGISTER_EVENT(OnGameStart); REGISTER_EVENT(EggHeadSpawn); REGISTER_EVENT(OnActorDestroy); REGISTER_EVENT(OnCheckSpiralMountainAbilities); diff --git a/src/port/Enhancements/Retention/NoteRetention.cpp b/src/port/Enhancements/Retention/NoteRetention.cpp index 23c816046..1baf8b806 100644 --- a/src/port/Enhancements/Retention/NoteRetention.cpp +++ b/src/port/Enhancements/Retention/NoteRetention.cpp @@ -378,9 +378,9 @@ void RegisterNoteRetention_Init() { switch (textId) { case 0xD9C: // Bottles' first-note text: "you can't take notes with you" case 0xF76: // "you just beat your high score" - // Milestones...maybe they should not be suppressed? They're aides for new players. - //case 0xF74: // milestone: 50 notes (Mumbo's Mountain) - //case 0xF78: // milestone: collected every note in the level + // Milestones...maybe they should not be suppressed? They're aides for new players. + /* case 0xF74: // milestone: 50 notes (Mumbo's Mountain) + case 0xF78: // milestone: collected every note in the level*/ *should = true; break; default: diff --git a/src/port/Game.cpp b/src/port/Game.cpp index c2e4a5e7d..6d4cc7461 100644 --- a/src/port/Game.cpp +++ b/src/port/Game.cpp @@ -173,7 +173,6 @@ void EnableThread5() { } } // namespace - // Drain submitted lists for safety. static void RegisterThread5MapSync_Init() { COND_HOOK(OnMapLoad, EVENT_PRIORITY_HIGH, true, [](IEvent* event) { diff --git a/src/port/Interpolation/FrameInterpolation.cpp b/src/port/Interpolation/FrameInterpolation.cpp index e94e7e7d0..9da37c63c 100644 --- a/src/port/Interpolation/FrameInterpolation.cpp +++ b/src/port/Interpolation/FrameInterpolation.cpp @@ -213,8 +213,8 @@ void FrameInterpolation_StopRecord(void) { static uint32_t sReported = 0; if (sReported < 20) { sReported++; - SPDLOG_WARN("interp scope id collided {}x this tick ({} matrices, {} sprites)", - gRecord->sigCollisions, gRecord->toMtxs.size(), gRecord->sprites.size()); + SPDLOG_WARN("interp scope id collided {}x this tick ({} matrices, {} sprites)", gRecord->sigCollisions, + gRecord->toMtxs.size(), gRecord->sprites.size()); } } } diff --git a/src/port/OS/OS_Mesg.cpp b/src/port/OS/OS_Mesg.cpp index a14c85482..56d02fb29 100644 --- a/src/port/OS/OS_Mesg.cpp +++ b/src/port/OS/OS_Mesg.cpp @@ -27,7 +27,7 @@ __OSEventState __osEventStateTab[OS_NUM_EVENTS] = { 0 }; // The queue fields themselves stay as they were, since decomp code reads them // directly (pfsmanager watches validCount); only the waiting is ours, a // condvar pair per queue where libultra used priority-ordered thread lists. -// Blocking is opt-in per queue. +// Blocking is opt-in per queue. namespace { diff --git a/src/port/OS/OS_RCP.cpp b/src/port/OS/OS_RCP.cpp index c2433a4fe..8a1c06e12 100644 --- a/src/port/OS/OS_RCP.cpp +++ b/src/port/OS/OS_RCP.cpp @@ -61,7 +61,7 @@ namespace { std::atomic sPendingTask{ nullptr }; std::atomic sYieldPending{ false }; // yield requested, not yet observed std::atomic sResumePending{ false }; // next gfx StartGo is the resume -} +} // namespace extern "C" void osSpTaskYield(void) { sYieldPending.store(true, std::memory_order_release); diff --git a/src/port/Patches/PerfPatches.cpp b/src/port/Patches/PerfPatches.cpp index fc569df81..12c8c169f 100644 --- a/src/port/Patches/PerfPatches.cpp +++ b/src/port/Patches/PerfPatches.cpp @@ -157,7 +157,6 @@ static void RegisterSnowTrig_Init() { }); } - static void RebuildPaddedPlanes() { f32 rot[3]; f32 pos[3]; diff --git a/src/port/Rando/MiscBehavior/OnFileLoad.cpp b/src/port/Rando/MiscBehavior/OnFileLoad.cpp index ef1247193..f10df31fd 100644 --- a/src/port/Rando/MiscBehavior/OnFileLoad.cpp +++ b/src/port/Rando/MiscBehavior/OnFileLoad.cpp @@ -24,21 +24,18 @@ void Rando::MiscBehavior::OnFileLoad() { if (saveData->magic != 0) { if (saveData->shipSaveData.fileType == FILE_TYPE_SAVE_RANDO) { Rando::Logic::GeneratePoolFromSaveData(saveData); - CALL_EVENT(InitRandoEvents); } - return; - } - - if (CVarGetInteger("gRandoSettings.Enable", 0)) { + } else if (CVarGetInteger("gRandoSettings.Enable", 0)) { Rando::Logic::InitializeSaveData(saveData); Rando::Logic::GenerateShufflePool(saveData); Rando::Logic::GrantStartingLoadout(); saveData->shipSaveData.fileType = FILE_TYPE_SAVE_RANDO; saveData->shipSaveData.fileCreatedAt = GetUnixTimestamp(); - CALL_EVENT(InitRandoEvents); } }); + REGISTER_LISTENER(OnGameStart, EVENT_PRIORITY_NORMAL, [](IEvent* event) { CALL_EVENT(InitRandoEvents); }); + REGISTER_LISTENER(OnLoadFileSelect, EVENT_PRIORITY_NORMAL, [](IEvent* event) { OnLoadFileSelect* ev = (OnLoadFileSelect*)event; diff --git a/src/port/Rando/ObjectBehavior/ObjectBehavior.cpp b/src/port/Rando/ObjectBehavior/ObjectBehavior.cpp index a86462f6e..753db4c3b 100644 --- a/src/port/Rando/ObjectBehavior/ObjectBehavior.cpp +++ b/src/port/Rando/ObjectBehavior/ObjectBehavior.cpp @@ -316,12 +316,13 @@ void Rando::ObjectBehavior::Init() { COND_HOOK(OnLoadActorSaveState, EVENT_PRIORITY_NORMAL, IS_RANDO, [](IEvent* event) { OnLoadActorSaveState* ev = (OnLoadActorSaveState*)event; + // Junk doesn't count as rando-managed while restoring; only real checks do. isSaveState = true; - if (!IsActorWhitelisted((actor_e)ev->actor->modelCacheIndex)) { - event->Cancelled = true; + bool randoManaged = IsActorWhitelisted((actor_e)ev->actor->modelCacheIndex); + isSaveState = false; + if (!randoManaged) { return; } - isSaveState = false; if (randoSaveState.empty()) { return; diff --git a/src/port/UI/LighthouseMenuDevTools.cpp b/src/port/UI/LighthouseMenuDevTools.cpp index a9fc84772..e36c7ae71 100644 --- a/src/port/UI/LighthouseMenuDevTools.cpp +++ b/src/port/UI/LighthouseMenuDevTools.cpp @@ -77,9 +77,12 @@ void LighthouseMenu::AddMenuDevTools() { .Options(FloatSliderOptions().DefaultValue(3000.0f).Min(1000.0f).Max(10000.0f).Step(10.0f)); AddWidget(path, "Dump Thread State", WIDGET_BUTTON) .Callback([](WidgetInfo&) { ThreadWatchdog_DumpNow(); }) - .Options(ButtonOptions().Size(Sizes::Inline).Tooltip( - "Log a snapshot of the decomp thread heartbeats and pipeline queue state. The watchdog also logs " - "this automatically when a thread stops beating.")); + .Options( + ButtonOptions() + .Size(Sizes::Inline) + .Tooltip( + "Log a snapshot of the decomp thread heartbeats and pipeline queue state. The watchdog also logs " + "this automatically when a thread stops beating.")); /*AddWidget(path, "Debug Mode", WIDGET_CVAR_CHECKBOX) .CVar(CVAR_DEVELOPER_TOOLS("DebugMode")) .Options(CheckboxOptions().Tooltip("Various debug features, including a level selector from the main menu."));*/ From 87f5f9f00dd20608b210d4b2276641dde1b714a5 Mon Sep 17 00:00:00 2001 From: Jeod <47716344+JeodC@users.noreply.github.com> Date: Thu, 30 Jul 2026 13:16:21 -0400 Subject: [PATCH 050/131] RC Patches 4 (#291) * Thread safety in teardown + imgui safety * Interpolation adjustments * Optimize initial rom scans * Mute Chimpy stump's rumble on reentry to MM * Anchor: BGS catchup bug with tanktup and yellow flibbit initializer * Clang format * RBB: fix lfieboat culling by disabling the DIAG check, fix whistle switch interpolation * GV: gate ancient ones catch-up behind anchor being connected * Interpolation: particles adjustments * Add another fix for tooie jiggy dance * Fix Lair water level taking the wrong path when player exits RBB * Convert imgui text to ascii so it renders properly --- src/BGS/ch/tanktup.c | 9 +- src/BGS/ch/yellowflibbit.c | 1 + src/GV/ch/ancientone.c | 8 +- src/MM/ch/chimpystump.c | 4 +- src/RBB/ch/whistleswitch.c | 38 +++- src/RBB/rbbspawnqueue.c | 4 +- src/core1/audio_manager.c | 3 + src/core1/bamotor.c | 3 + src/core1/graphics_thread.c | 5 + src/core1/pfsmanager.c | 3 + src/core1/vimgr.c | 3 + src/core2/actor_cubepropsystem.c | 75 ++++---- src/core2/model/modelRender.c | 7 +- src/core2/particle/particle.c | 26 ++- src/core2/quiz/game.c | 5 +- src/port/DevTools/OcclusionDebug.cpp | 2 +- src/port/Engine.cpp | 12 +- .../Backports/TooieJiggyDance.cpp | 3 +- src/port/Extractor/GameExtractor.cpp | 25 +-- src/port/Game.cpp | 25 ++- src/port/GameStatus.cpp | 63 ++++++- src/port/Interpolation/FrameInterpolation.cpp | 167 ++++++++++-------- src/port/Network/Anchor/Anchor.cpp | 6 + src/port/Network/Anchor/Menu.cpp | 2 +- .../Anchor/Packets/UpdateRoomState.cpp | 2 +- src/port/OS/OS.h | 9 + src/port/OS/OS_Mesg.cpp | 11 ++ src/port/OS/OS_Threads.cpp | 66 ++++++- src/port/Save/SaveManager.cpp | 46 +++-- src/port/UI/DeveloperTools/SaveEditor.cpp | 31 +++- src/port/UI/LighthouseMenuEnhancements.cpp | 8 +- src/port/UI/LighthouseMenuSettings.cpp | 4 +- 32 files changed, 482 insertions(+), 194 deletions(-) diff --git a/src/BGS/ch/tanktup.c b/src/BGS/ch/tanktup.c index 86943b2fa..457de1af0 100644 --- a/src/BGS/ch/tanktup.c +++ b/src/BGS/ch/tanktup.c @@ -100,6 +100,7 @@ void func_8028F918(s32); // Anchor: set when state 2 took the head-raise look-at/freeze push; state 3 releases it. static s32 sTanktupCameraPushed = 0; +static s32 sTanktupPoseCatchUp = 0; void chTanktup_update(Actor *this) { @@ -157,6 +158,7 @@ void chTanktup_update(Actor *this) // Anchor: team completed Tanktup but our body is still idle (state 1) — raise the head to match. if (this->state == CH_TANKTUP_STATE_1_UNK && jiggyscore_isSpawned(JIGGY_26_BGS_TANKTUP)) { + sTanktupPoseCatchUp = 1; // [port] pose only, no presentation subaddie_set_state_with_direction(this, CH_TANKTUP_STATE_3_UNK, 0.0f, -1); actor_playAnimationOnce(this); } @@ -214,6 +216,7 @@ void chTanktup_update(Actor *this) } else { + sTanktupPoseCatchUp = 0; // [port] solved for real: keep the presentation subaddie_set_state_with_direction(this, CH_TANKTUP_STATE_3_UNK, 0.0f, -1); actor_playAnimationOnce(this); } @@ -226,13 +229,13 @@ void chTanktup_update(Actor *this) s32 near; player_getPosition(pp); near = ml_vec3f_distance(local->unk18, pp) < 700.0f; - if (actor_animationIsAt(this, 0.1f) != 0 && near) + if (actor_animationIsAt(this, 0.1f) != 0 && near && !sTanktupPoseCatchUp) { timed_setStaticCameraToNode(0.0f, 0xD); } - if (actor_animationIsAt(this, 0.55f) != 0) + if (actor_animationIsAt(this, 0.55f) != 0 && !sTanktupPoseCatchUp) { - func_8030E624(0x797FF885U); + func_8030E624(0x797FF885U); // SFX_85_ROUGH_COUGH } if (actor_animationIsAt(this, 0.4f) != 0 && jiggyscore_isSpawned(JIGGY_26_BGS_TANKTUP) == 0) { diff --git a/src/BGS/ch/yellowflibbit.c b/src/BGS/ch/yellowflibbit.c index d167e5f95..bc30286b9 100644 --- a/src/BGS/ch/yellowflibbit.c +++ b/src/BGS/ch/yellowflibbit.c @@ -360,6 +360,7 @@ void gChYellowFlibbit_update(Actor *this) { local->unk10[0] = (s16) (s32) this->position[0]; local->unk10[1] = (s16) (s32) this->position[1]; local->unk10[2] = (s16) (s32) this->position[2]; + this->state = 0; // [port] Zero-init, which vanilla did not need because of draw distance gChYellowFlibbit_setState(this, 1); if (jiggyscore_isSpawned(JIGGY_24_BGS_FLIBBITS) != 0) { marker_despawn(this->marker); diff --git a/src/GV/ch/ancientone.c b/src/GV/ch/ancientone.c index 59ddf6117..b4d535f77 100644 --- a/src/GV/ch/ancientone.c +++ b/src/GV/ch/ancientone.c @@ -4,6 +4,7 @@ #include "variables.h" extern void core1_7090_initSfxSource(s32, s32, s32, f32); +extern s32 port_anchor_isConnected(void); typedef struct { f32 unk0[3]; @@ -132,6 +133,11 @@ void chAncientOne_update(Actor *this){ func_80386620(this); return; } + // Anchor only. A statue that has not been drawn yet still has to run the + // body below so it can catch up to flags another client set. + if(!port_anchor_isConnected()){ + return; + } { s32 fc = 0, fi; for(fi = 7; fi < 0xC && mapSpecificFlags_get(fi); fi++) fc++; @@ -146,7 +152,7 @@ void chAncientOne_update(Actor *this){ return; } // Anchor: ring order is randomized per-client; advance by synced-flag count. - { + if(port_anchor_isConnected()){ s32 fc = 0, fi; for(fi = 7; fi < 0xC && mapSpecificFlags_get(fi); fi++) fc++; if(this->state == 1 && this->actorTypeSpecificField <= fc){ diff --git a/src/MM/ch/chimpystump.c b/src/MM/ch/chimpystump.c index 43c85bec8..951a3a6a9 100644 --- a/src/MM/ch/chimpystump.c +++ b/src/MM/ch/chimpystump.c @@ -33,10 +33,10 @@ void __chchimpystump_updateShaking(Actor *this) { if (mapSpecificFlags_get(MM_SPECIFIC_FLAG_4_SHAKE)) { if (this->unk10_12 == 0) { this->unk10_12 = 1; - func_802BB3DC(1, 3.0f, 1.0f); // [port] Vanilla replays Chimpy's walk-off, and with it this rise, on every entry to MM - // once his jiggy has spawned. The rumble can be muted for those replays. + // once his jiggy has spawned. Both halves are muted for those replays. if (EventSystem_Should(VB_MM_CHIMPY_STUMP_RUMBLE, true)) { + func_802BB3DC(1, 3.0f, 1.0f); core1_7090_initSfxSource(0, 0x6A, 0x7FF8, 0.2f); } }//L80386D0C diff --git a/src/RBB/ch/whistleswitch.c b/src/RBB/ch/whistleswitch.c index 37134cce5..0305f4fdc 100644 --- a/src/RBB/ch/whistleswitch.c +++ b/src/RBB/ch/whistleswitch.c @@ -3,6 +3,8 @@ #include "functions.h" #include "variables.h" +#include "port/Patches/Patches.h" + void vtxList_tintColorsFrom(BKVertexList *dst, s32 target_color[3], f32 amount, BKVertexList *src); BKVertexList *vtxList_clone(BKVertexList *); @@ -19,6 +21,8 @@ typedef struct { Struct_ChWhistleSwitchInfo *whistleSwitchInfo; f32 unk8; BKVertexList *unkC; + // [port] Back buffer for unkC. See chRBBWhistleSwitch_draw. + BKVertexList *portVtxBack; } ActorLocal_RBB_47D0; Actor *chRBBWhistleSwitch_draw(ActorMarker *marker, Gfx** gdl, Mtx** mptr, Vtx **arg3); @@ -80,7 +84,14 @@ void chRBBWhistleSwitch_setState(Actor *this, s32 new_state){ local->unk8 = 0.0f; if(new_state == CH_RBB_WHISTLE_SWITCH_STATE_2_UNK){ func_8030E6D4(SFX_90_SWITCH_PRESS); - local->unkC = vtxList_clone(modelbin_getVtxList(marker_loadModelBin(this->marker))); + // [port] Clone once and keep it. Freeing on release hands the buffer back + // while a display list built from this tick may still be queued for the + // render thread. + if(local->unkC == NULL){ + BKVertexList *src = modelbin_getVtxList(marker_loadModelBin(this->marker)); + local->unkC = vtxList_clone(src); + local->portVtxBack = vtxList_clone(src); + } mapSpecificFlags_set(local->whistleSwitchInfo->mapSpecificFlag, true); this->position_y -= 30.0f; @@ -95,7 +106,6 @@ void chRBBWhistleSwitch_setState(Actor *this, s32 new_state){ this->position_x = local->whistleSwitchInfo->position[0]; this->position_y = local->whistleSwitchInfo->position[1]; this->position_z = local->whistleSwitchInfo->position[2]; - vtxList_free(local->unkC); } this->state = new_state; } @@ -107,7 +117,17 @@ void chRBBWhistleSwitch_press(ActorMarker *marker, ActorMarker *arg1){ } void chRBBWhistleSwitch_free(Actor *this){ + ActorLocal_RBB_47D0 *local = (ActorLocal_RBB_47D0 *)&this->local; chRBBWhistleSwitch_setState(this, CH_RBB_WHISTLE_SWITCH_STATE_0_NOT_INIT); + if(local->unkC != NULL){ + // [port] No queued display list may still reference these vertices once + // they are handed back to the heap. + port_pipelineSyncPoint(); + vtxList_free(local->unkC); + vtxList_free(local->portVtxBack); + local->unkC = NULL; + local->portVtxBack = NULL; + } } Actor *chRBBWhistleSwitch_draw(ActorMarker *marker, Gfx **gdl, Mtx **mptr, Vtx **arg3){ @@ -123,14 +143,23 @@ Actor *chRBBWhistleSwitch_draw(ActorMarker *marker, Gfx **gdl, Mtx **mptr, Vtx * if( actor->state == 2 && local->unk0 != 0 ){ + BKVertexList *swap; + temp_v0 = marker_loadModelBin(marker); sp1C = (local->unk0 == 2) ? D_80390938 : D_8039092C; + + // [port] Alternate between two clones. + swap = local->unkC; + local->unkC = local->portVtxBack; + local->portVtxBack = swap; + vtxList_tintColorsFrom(local->unkC, sp1C, (local->whistleSwitchInfo->position[1] - actor->position_y) / 30.0, modelbin_getVtxList(temp_v0) ); modelRender_setVertexList(local->unkC); } + return actor_draw(marker, gdl, mptr, arg3); } @@ -141,6 +170,11 @@ void chRBBWhistleSwitch_update(Actor *this){ if(!this->volatile_initialized){ this->volatile_initialized = true; + // [port] The map savestate memcpys `local` wholesale and only nulls the + // Actor's own heap pointers, so these two come back pointing at freed + // vertices. Drop them before anything can reuse or free them again. + local->unkC = NULL; + local->portVtxBack = NULL; this->marker->propPtr->unk8_3 = 1; this->marker->actorFreeFunc = chRBBWhistleSwitch_free; marker_setCollisionScripts(this->marker, NULL, chRBBWhistleSwitch_press, NULL); diff --git a/src/RBB/rbbspawnqueue.c b/src/RBB/rbbspawnqueue.c index 770a7fd51..211b30172 100644 --- a/src/RBB/rbbspawnqueue.c +++ b/src/RBB/rbbspawnqueue.c @@ -160,12 +160,14 @@ void func_80386A7C(Actor *this){ f32 cull = 8000.0f * port_drawDistanceMul(); if(viewport[0] + cull < this->position_x || this->position_x < viewport[0] - cull) return; - + if( !( (sp28 ^ temp_v0) & 2 && (-5000.0f < viewport[0] && viewport[0] < 6000.0f) && (viewport[2] < -600.0f || 600.0f < viewport[2]) ) +#if 0 && ( sp28 ^ temp_v0) != 3 +#endif ){ this->unk38_0 = 1; } diff --git a/src/core1/audio_manager.c b/src/core1/audio_manager.c index 61225f6a9..2489cefd5 100644 --- a/src/core1/audio_manager.c +++ b/src/core1/audio_manager.c @@ -357,6 +357,9 @@ void audioManagerThread_entry(void *arg) { while (true) { osRecvMesg(&audioManager.audioFrameMsgQ, NULL, OS_MESG_BLOCK); + if (OS_ThreadShouldExit()) { // [port] cooperative shutdown + return; + } ThreadWatchdog_Beat(WATCHDOG_AUDIO_MANAGER); // [port] one beat per audio frame if (audioManager_handleFrameMsg(audioManager.audio_info[sAudioInfoID % 3], sPrevFinishedAudioInfo)) { if (skip_handle_done_mesg == 0) { diff --git a/src/core1/bamotor.c b/src/core1/bamotor.c index ce82afa9b..7101e75bd 100644 --- a/src/core1/bamotor.c +++ b/src/core1/bamotor.c @@ -75,6 +75,9 @@ void rumbleThread_entry(void *arg) { do{ osRecvMesg(&D_80282390, NULL, 1); + if (OS_ThreadShouldExit()) { // [port] cooperative shutdown + return; + } ThreadWatchdog_Beat(WATCHDOG_RUMBLE); // [port] one beat per retrace signal D_802827E0++; if (!D_802823B0 && ((D_802827E0 % FRAMERATE) == 0)) { diff --git a/src/core1/graphics_thread.c b/src/core1/graphics_thread.c index 35306d638..4df502bf2 100644 --- a/src/core1/graphics_thread.c +++ b/src/core1/graphics_thread.c @@ -485,6 +485,11 @@ void thread5_entry(void *arg) { msg.ptr = NULL; do { osRecvMesg(&sThread5MesgQueue, &msg, OS_MESG_BLOCK); + // [port] Shutdown released the queue rather than delivering anything, so msg + // holds nothing worth dispatching. Leave before the engine goes away. + if (OS_ThreadShouldExit()) { + return; + } ThreadWatchdog_Beat(WATCHDOG_THREAD5); // [port] one beat per serviced message thread5_checkAndExecutePreNMI(); if ((uintptr_t)msg.ptr < 100) { diff --git a/src/core1/pfsmanager.c b/src/core1/pfsmanager.c index 61aed416c..8d87bdebb 100644 --- a/src/core1/pfsmanager.c +++ b/src/core1/pfsmanager.c @@ -308,6 +308,9 @@ void pfsManager_readData(){ void pfsManager_entry(void *arg) { do { osRecvMesg(&pfsManagerContPollingMsqQ, 0, 1); + if (OS_ThreadShouldExit()) { // [port] cooperative shutdown + return; + } ThreadWatchdog_Beat(WATCHDOG_PFSMANAGER); // [port] one beat per SI completion if(pfsManagerBusy == true){ pfsManager_readData(); diff --git a/src/core1/vimgr.c b/src/core1/vimgr.c index 39ce4d322..27b71403b 100644 --- a/src/core1/vimgr.c +++ b/src/core1/vimgr.c @@ -240,6 +240,9 @@ void viMgr_entry(void *arg0){ OSMesg sp48; do{ osRecvMesg(&sMesgQueue1, &sp48, OS_MESG_BLOCK); + if (OS_ThreadShouldExit()) { // [port] cooperative shutdown + return; + } ThreadWatchdog_Beat(WATCHDOG_VIMGR); // [port] one beat per retrace thread5_checkAndExecutePreNMI(); D_802808D8++; diff --git a/src/core2/actor_cubepropsystem.c b/src/core2/actor_cubepropsystem.c index 46d95face..b8a9375fe 100644 --- a/src/core2/actor_cubepropsystem.c +++ b/src/core2/actor_cubepropsystem.c @@ -318,7 +318,7 @@ static void __marker_draw(ActorMarker *this, Gfx **gfx, Mtx **mtx, Vtx **vtx){ f32 draw_dist_f; f32 percentage; - FrameInterpolation_RecordOpenChild(this, this->actrArrayIdx); + FrameInterpolation_RecordOpenChildHash3("marker", (uintptr_t)this, (uintptr_t)this->actrArrayIdx, 0); if(!this->unk3E_0){ this->drawFunc(this, gfx, mtx, vtx); @@ -1005,6 +1005,9 @@ void code7AF80_initCubeFromFile(File *file_ptr, Cube *cube) { // bitfield structs across endianness boundaries. if (file_isNextByteExpected(file_ptr, CUBE_PROP_2_LIST_START_INDICATOR)) { s32 i; + // [port] A vetoed prop must not keep its slot. Compact + // instead, writing only the props we keep. + s32 writeIdx = 0; memset(cube->prop2Ptr, 0, sp47 * sizeof(Prop)); for (i = 0; i < sp47; i++) { u8 raw[12]; @@ -1035,58 +1038,60 @@ void code7AF80_initCubeFromFile(File *file_ptr, Cube *cube) { bool b4 = (flags >> 4) & 1; // unk8_4 bool b5 = (flags >> 5) & 1; // unk8_5 // Set position and flags via anonymous struct - cube->prop2Ptr[i].unk4[0] = pos[0]; - cube->prop2Ptr[i].unk4[1] = pos[1]; - cube->prop2Ptr[i].unk4[2] = pos[2]; - cube->prop2Ptr[i].markerFlag = mf; - cube->prop2Ptr[i].unk8_1 = b1; - cube->prop2Ptr[i].unk8_2 = b2; - cube->prop2Ptr[i].unk8_3 = b3; - cube->prop2Ptr[i].unk8_4 = b4; - cube->prop2Ptr[i].unk8_5 = b5; + cube->prop2Ptr[writeIdx].unk4[0] = pos[0]; + cube->prop2Ptr[writeIdx].unk4[1] = pos[1]; + cube->prop2Ptr[writeIdx].unk4[2] = pos[2]; + cube->prop2Ptr[writeIdx].markerFlag = mf; + cube->prop2Ptr[writeIdx].unk8_1 = b1; + cube->prop2Ptr[writeIdx].unk8_2 = b2; + cube->prop2Ptr[writeIdx].unk8_3 = b3; + cube->prop2Ptr[writeIdx].unk8_4 = b4; + cube->prop2Ptr[writeIdx].unk8_5 = b5; if (mf) { // ActorProp: marker=NULL (set at actor spawn), position - cube->prop2Ptr[i].actorProp.marker = NULL; - cube->prop2Ptr[i].actorProp.x = pos[0]; - cube->prop2Ptr[i].actorProp.y = pos[1]; - cube->prop2Ptr[i].actorProp.z = pos[2]; + cube->prop2Ptr[writeIdx].actorProp.marker = NULL; + cube->prop2Ptr[writeIdx].actorProp.x = pos[0]; + cube->prop2Ptr[writeIdx].actorProp.y = pos[1]; + cube->prop2Ptr[writeIdx].actorProp.z = pos[2]; // SpriteProp unk8_10/unk8_15 overlap anonymous pad8_15 - cube->prop2Ptr[i].actorProp.frame = (flags >> 11) & 0x1F; - cube->prop2Ptr[i].actorProp.unk8_10 = (flags >> 6) & 0x1F; + cube->prop2Ptr[writeIdx].actorProp.frame = (flags >> 11) & 0x1F; + cube->prop2Ptr[writeIdx].actorProp.unk8_10 = (flags >> 6) & 0x1F; } else if (b1) { // ModelProp: word0 = { u16 unk0, u8 unk0_15, u8 unk0_7 } // [port] Set through bitfield accessor, not raw u16, for LE correctness - cube->prop2Ptr[i].modelProp.modelId = (word0 >> 20) & 0xFFF; - cube->prop2Ptr[i].modelProp.pad0_19 = (word0 >> 16) & 0xF; - cube->prop2Ptr[i].modelProp.yaw = (u8)(word0 >> 8); - cube->prop2Ptr[i].modelProp.roll = (u8)(word0); + cube->prop2Ptr[writeIdx].modelProp.modelId = (word0 >> 20) & 0xFFF; + cube->prop2Ptr[writeIdx].modelProp.pad0_19 = (word0 >> 16) & 0xF; + cube->prop2Ptr[writeIdx].modelProp.yaw = (u8)(word0 >> 8); + cube->prop2Ptr[writeIdx].modelProp.roll = (u8)(word0); // ModelProp flags at offset 10-11 - cube->prop2Ptr[i].modelProp.scale = (u8)(flags >> 8); - cube->prop2Ptr[i].modelProp.unkB_5 = (flags >> 5) & 1; - cube->prop2Ptr[i].modelProp.unkB_4 = (flags >> 4) & 1; + cube->prop2Ptr[writeIdx].modelProp.scale = (u8)(flags >> 8); + cube->prop2Ptr[writeIdx].modelProp.unkB_5 = (flags >> 5) & 1; + cube->prop2Ptr[writeIdx].modelProp.unkB_4 = (flags >> 4) & 1; } else { // SpriteProp: word0 is a u32 with bitfields - cube->prop2Ptr[i].spriteProp.spriteId = (word0 >> 20) & 0xFFF; - cube->prop2Ptr[i].spriteProp.unk0_19 = (word0 >> 19) & 1; - cube->prop2Ptr[i].spriteProp.rgb_remove_red = (word0 >> 16) & 7; - cube->prop2Ptr[i].spriteProp.rgb_remove_green = (word0 >> 13) & 7; - cube->prop2Ptr[i].spriteProp.rgb_remove_blue = (word0 >> 10) & 7; - cube->prop2Ptr[i].spriteProp.scale = (word0 >> 2) & 0xFF; - cube->prop2Ptr[i].spriteProp.isMirrored = (word0 >> 1) & 1; - cube->prop2Ptr[i].spriteProp.pad0_0 = word0 & 1; + cube->prop2Ptr[writeIdx].spriteProp.spriteId = (word0 >> 20) & 0xFFF; + cube->prop2Ptr[writeIdx].spriteProp.unk0_19 = (word0 >> 19) & 1; + cube->prop2Ptr[writeIdx].spriteProp.rgb_remove_red = (word0 >> 16) & 7; + cube->prop2Ptr[writeIdx].spriteProp.rgb_remove_green = (word0 >> 13) & 7; + cube->prop2Ptr[writeIdx].spriteProp.rgb_remove_blue = (word0 >> 10) & 7; + cube->prop2Ptr[writeIdx].spriteProp.scale = (word0 >> 2) & 0xFF; + cube->prop2Ptr[writeIdx].spriteProp.isMirrored = (word0 >> 1) & 1; + cube->prop2Ptr[writeIdx].spriteProp.pad0_0 = word0 & 1; // SpriteProp flags - cube->prop2Ptr[i].spriteProp.frame = (flags >> 11) & 0x1F; - cube->prop2Ptr[i].spriteProp.unk8_10 = (flags >> 6) & 0x1F; + cube->prop2Ptr[writeIdx].spriteProp.frame = (flags >> 11) & 0x1F; + cube->prop2Ptr[writeIdx].spriteProp.unk8_10 = (flags >> 6) & 0x1F; } } //Prop* ptr = cube->prop2Ptr + i * sizeof(Prop); - CALL_EVENT(OnPropInit, &cube->prop2Ptr[i]); + CALL_EVENT(OnPropInit, &cube->prop2Ptr[writeIdx]); + writeIdx++; } } + cube->prop2Cnt = writeIdx; } - for(var_v1_2 = cube->prop2Ptr; var_v1_2 < cube->prop2Ptr + sp47; var_v1_2++){ + for(var_v1_2 = cube->prop2Ptr; var_v1_2 < cube->prop2Ptr + cube->prop2Cnt; var_v1_2++){ var_v1_2->unk8_4 = 1; if (var_v1_2->unk8_1) { var_v1_2->unk8_5 = 0; diff --git a/src/core2/model/modelRender.c b/src/core2/model/modelRender.c index 8b25efc4c..715d072c0 100644 --- a/src/core2/model/modelRender.c +++ b/src/core2/model/modelRender.c @@ -792,11 +792,8 @@ void modelRender_geoCmd_TEXWRAP(Gfx **gfx, Mtx **mtx, struct bk_geo_cmd_s *arg2) void modelRender_geoCmd_BONE(Gfx **gfx, Mtx **mtx, struct bk_geo_cmd_s *arg2){ GeoCmd2 *cmd = (GeoCmd2 *)arg2; - // [port] Stable per-bone scope. Without it, any op-count shift in the - // geo walk mis-pairs every subsequent bone — Banjo ends up half in - // one pose and half in another on the affected sub-frame. Nested - // bones nest their scopes via the recursive walk below. - FrameInterpolation_RecordOpenChild("bone", (uintptr_t)(u8)cmd->unk9); + // [port] Stable per-bone scope. + FrameInterpolation_RecordOpenChildHash3("bone", (uintptr_t)(u8)cmd->unk9, (uintptr_t)cmd, 0); if(D_8038371C){ mlMtx_push_multiplied_2(&D_80383BF8, animMtxList_get(D_8038371C, cmd->unk9)); if(D_80370990){ diff --git a/src/core2/particle/particle.c b/src/core2/particle/particle.c index 731152222..27b0c0c04 100644 --- a/src/core2/particle/particle.c +++ b/src/core2/particle/particle.c @@ -52,12 +52,17 @@ typedef struct particle{ f32 velocity_50[3]; u8 unk5C; //u8 pad5D[3]; + // [port] Spawn serial; see the identity comment in __particleEmitter_drawOnPass. + u32 portSerial; } Particle; /* .bss */ f32 particleSfxTimer; u8 partEmitMgrEnable; +// [port] Monotonic source for Particle::portSerial. +static u32 sPortParticleSerial = 0; + /* .code */ void func_802EE930(ParticleEmitter *this){ func_8033B388(&this->sprite_1C, &this->unk34); @@ -121,6 +126,7 @@ void __particleEmitter_initParticle(ParticleEmitter *this, Particle *particle){ particle->angluar_velocity[1] = randf2(this->unkBC[1], this->unkC8[1]); particle->angluar_velocity[2] = randf2(this->unkBC[2], this->unkC8[2]); + particle->portSerial = ++sPortParticleSerial; // [port] interpolation identity particle->age_48 = 0.0f; particle->lifetime_4C = randf2(this->particleLifeTimeRange[0], this->particleLifeTimeRange[1]) + 0.001; if(!this->sphericalParticleVelocity_48){ @@ -165,19 +171,10 @@ void __particleEmitter_drawOnPass(ParticleEmitter *this, Gfx **gfx, Mtx **mtx, V return; if(this->model_20 != NULL){ - // [port] Stable scope per emitter + per particle. Slot index plus - // a coarse age bucket: two consecutive frames of the same particle - // land in the same bucket, so they pair. When expiry swaps a new - // particle into the slot its age resets to ~0 — different bucket, - // no false pair with the dead particle. Spawn-field hashing alone - // failed for sparkles (shared emitter, zero-width scale/lifetime - // ranges → every particle had the same hash → visible flashing). + // [port] Stable scope per emitter + per particle, keyed on a spawn serial. FrameInterpolation_RecordOpenChild("part_emit", FrameInterpolation_GetId(this)); for(iPtr = this->pList_start_124; iPtr < this->pList_end_128; iPtr++){ - FrameInterpolation_RecordOpenChildHash3("part", - (uint64_t)(uintptr_t)(iPtr - this->pList_start_124), - (uint64_t)(iPtr->age_48 * 2.0f), - 0); + FrameInterpolation_RecordOpenChildHash3("part", (uint64_t)iPtr->portSerial, 0, 0); position[0] = iPtr->position[0] + this->unk4[0]; position[1] = iPtr->position[1] + this->unk4[1]; position[2] = iPtr->position[2] + this->unk4[2]; @@ -218,13 +215,10 @@ void __particleEmitter_drawOnPass(ParticleEmitter *this, Gfx **gfx, Mtx **mtx, V flat_rotation[0] = 90.0f; flat_rotation[1] = 0.0f; flat_rotation[2] = 0.0f; - // [port] Same slot+age-bucket identity as the model branch above. + // [port] Same spawn-serial identity as the model branch above. FrameInterpolation_RecordOpenChild("part_emit", FrameInterpolation_GetId(this)); for(iPtr = this->pList_start_124; iPtr < this->pList_end_128; iPtr++){ - FrameInterpolation_RecordOpenChildHash3("part", - (uint64_t)(uintptr_t)(iPtr - this->pList_start_124), - (uint64_t)(iPtr->age_48 * 2.0f), - 0); + FrameInterpolation_RecordOpenChildHash3("part", (uint64_t)iPtr->portSerial, 0, 0); gDPSetPrimColor((*gfx)++, 0, 0, this->rgb[0], this->rgb[1], this->rgb[2], iPtr->fade*this->alpha); position[0] = iPtr->position[0] + this->unk4[0]; position[1] = iPtr->position[1] + this->unk4[1]; diff --git a/src/core2/quiz/game.c b/src/core2/quiz/game.c index 3a45fd3a1..29024bf74 100644 --- a/src/core2/quiz/game.c +++ b/src/core2/quiz/game.c @@ -985,6 +985,9 @@ void func_802D520C(Gfx **gfx, Mtx **mtx, Vtx **vtx){ } } +// [port] Map the lair water was last levelled for, so re-entry snaps instead of ramping. +static s32 sLairWaterMap = -1; + void func_802D5260(void) { s32 sp3C; Struct70s *sp38; @@ -997,6 +1000,7 @@ void func_802D5260(void) { : -1; if (sp3C == -1) { + sLairWaterMap = -1; // [port] see above levelSpecificFlags_set(LEVEL_FLAG_3C_LAIR_UNKNOWN, false); fileProgressFlag_set(FILEPROG_26_WATER_SWITCH_3_PRESSED, false); fileProgressFlag_set(FILEPROG_27_LAIR_WATER_LEVEL_3, false); @@ -1050,7 +1054,6 @@ void func_802D5260(void) { lvl = port_lairWater_targetLevel(gsworld_getMap(), lvl); sp34 = ((s16 *)&D_803679C8[sp3C])[lvl]; } - static s32 sLairWaterMap = -1; s32 curMap = gsworld_getMap(); if (sLairWaterMap != curMap || levelSpecificFlags_get(LEVEL_FLAG_3C_LAIR_UNKNOWN)) { sLairWaterMap = curMap; diff --git a/src/port/DevTools/OcclusionDebug.cpp b/src/port/DevTools/OcclusionDebug.cpp index 0c96f60ec..17e93e3ad 100644 --- a/src/port/DevTools/OcclusionDebug.cpp +++ b/src/port/DevTools/OcclusionDebug.cpp @@ -155,7 +155,7 @@ void OcclusionDebugWindow::DrawElement() { } ImGui::TextWrapped( "Flip 'Force draw all' on for a moment to walk every cull command and populate the list (the " - "screen will look broken — that is expected), then turn it off and tick 'Force Draw' on " + "screen will look broken - that is expected), then turn it off and tick 'Force Draw' on " "individual rows to find the chunk(s) that reveal the target scenery. Offsets are stable, so the " "list never shifts. Dump the chosen set to the log when done."); diff --git a/src/port/Engine.cpp b/src/port/Engine.cpp index 746048a50..099dd855e 100644 --- a/src/port/Engine.cpp +++ b/src/port/Engine.cpp @@ -1,4 +1,5 @@ #include "Engine.h" +#include #include #include #include @@ -734,10 +735,17 @@ void GameEngine::RunExtract(int argc, char* argv[]) { } case PS_LOCAL: { extract = GameExtractor(); + const std::string appDir = Ship::Context::GetAppDirectoryPath("bk"); + std::error_code sameDirEc; + const bool sameDir = std::filesystem::equivalent(installPath, appDir, sameDirEc); extract.SetSearchPath(installPath); extract.GetRoms(args); - extract.SetSearchPath(Ship::Context::GetAppDirectoryPath("bk")); - extract.GetRoms(args); + if (sameDirEc || !sameDir) { + extract.SetSearchPath(appDir); + extract.GetRoms(args); + } + std::sort(args.begin(), args.end()); + args.erase(std::unique(args.begin(), args.end()), args.end()); if (!args.empty()) { promptStep = PS_WAIT; LighthouseGui::RegisterPopup( diff --git a/src/port/Enhancements/Backports/TooieJiggyDance.cpp b/src/port/Enhancements/Backports/TooieJiggyDance.cpp index c8ae5d1e1..cc5510808 100644 --- a/src/port/Enhancements/Backports/TooieJiggyDance.cpp +++ b/src/port/Enhancements/Backports/TooieJiggyDance.cpp @@ -136,7 +136,8 @@ void spawnOrbit() { } actor->state = 0; actor_collisionOff(actor); - actor->unk44_2 = 1; + actor->unk44_2 = 1; // Keep this jiggy out of jiggylist_map_actors + actor->unk10_1 = 0; // Keep this jiggy out of map savestate sfxsource_playHighPriority(SFX_3E9_UNKNOWN); sMarker = (void*)actor->marker; } diff --git a/src/port/Extractor/GameExtractor.cpp b/src/port/Extractor/GameExtractor.cpp index 2b6b6eec8..d20911f0e 100644 --- a/src/port/Extractor/GameExtractor.cpp +++ b/src/port/Extractor/GameExtractor.cpp @@ -134,7 +134,7 @@ void GameExtractor::GetRoms(std::vector& roms) { // Check for any standard N64 rom file extensions. if (ext != NULL && (strcmp(ext, ".z64") == 0) /* || (strcmp(ext, ".n64") == 0) || (strcmp(ext, ".v64") == 0)*/) - roms.push_back(ffd.cFileName); + roms.push_back(mSearchPath + "/" + ffd.cFileName); } } while (FindNextFileA(h, &ffd) != 0); FindClose(h); @@ -148,20 +148,23 @@ void GameExtractor::GetRoms(std::vector& roms) { while ((dir = readdir(d)) != NULL) { struct stat path; - // Check if current entry is not folder - stat(dir->d_name, &path); - if (S_ISREG(path.st_mode)) { + // Against the full path: a bare name would be resolved relative to the + // working directory, so searching anywhere else stat'd the wrong file (or + // nothing) and left path uninitialised for the S_ISREG test below. + const std::string fullPath = mSearchPath + "/" + dir->d_name; + if (stat(fullPath.c_str(), &path) != 0 || !S_ISREG(path.st_mode)) { + continue; + } - // Get the position of the extension character. - char* ext = strrchr(dir->d_name, '.'); - if (ext != NULL && - (strcmp(ext, ".z64") == 0 /* || strcmp(ext, ".n64") == 0 || strcmp(ext, ".v64") == 0*/)) { - roms.push_back(dir->d_name); - } + // Get the position of the extension character. + char* ext = strrchr(dir->d_name, '.'); + if (ext != NULL && + (strcmp(ext, ".z64") == 0 /* || strcmp(ext, ".n64") == 0 || strcmp(ext, ".v64") == 0*/)) { + roms.push_back(fullPath); } } + closedir(d); } - closedir(d); #else for (const auto& file : std::filesystem::directory_iterator(mSearchPath)) { if (file.is_directory()) { diff --git a/src/port/Game.cpp b/src/port/Game.cpp index 6d4cc7461..ad2fbde83 100644 --- a/src/port/Game.cpp +++ b/src/port/Game.cpp @@ -71,6 +71,7 @@ std::mutex sSvcMutex; std::condition_variable sSvcCv; void (*sSvcFn)(void*) = nullptr; void* sSvcArg = nullptr; +std::atomic sShutdownRequested{ false }; int sTitleMap = 0; @@ -198,10 +199,17 @@ extern "C" void port_runOnRenderThread(void (*fn)(void*), void* arg) { return; } std::unique_lock lock(sSvcMutex); - sSvcCv.wait(lock, [] { return sSvcFn == nullptr; }); + auto done = [] { return sSvcFn == nullptr || sShutdownRequested.load(std::memory_order_acquire); }; + if (sShutdownRequested.load(std::memory_order_acquire)) { + return; + } + sSvcCv.wait(lock, done); + if (sShutdownRequested.load(std::memory_order_acquire)) { + return; + } sSvcFn = fn; sSvcArg = arg; - sSvcCv.wait(lock, [] { return sSvcFn == nullptr; }); + sSvcCv.wait(lock, done); } // Barrier before the tick frees or reads memory an in-flight list references. @@ -329,9 +337,22 @@ int SDL_main(int argc, char* argv[]) { SDL_Delay(1); } } + // Ask first, then release: a thread woken before the request is set would just + // park again. + OS_RequestThreadExit(); + { + std::lock_guard lock(sSvcMutex); + sShutdownRequested.store(true, std::memory_order_release); + sSvcFn = nullptr; + } + sSvcCv.notify_all(); + OS_BeginShutdown(); + if (sGameThread.joinable()) { sGameThread.join(); } + // Before Destroy: these threads draw and play audio through the engine. + OS_JoinDecompThreads(); ThreadWatchdog_Stop(); OS_StopViTicker(); #ifdef USE_NETWORKING diff --git a/src/port/GameStatus.cpp b/src/port/GameStatus.cpp index 5b8287c94..b316614da 100644 --- a/src/port/GameStatus.cpp +++ b/src/port/GameStatus.cpp @@ -2,14 +2,70 @@ #include "ShipUtils.h" #include #include +#include #ifdef _WIN32 #include +#include +#include #endif #include "port/Enhancements/Events/Hooks/Events.h" +#include "port/Patches/Patches.h" #include "port/Romhack/RomhackConfig.h" #include "port/ShipInit.hpp" +#ifdef _WIN32 +namespace { +HWND ResolveGameWindow() { + static HWND sCached = nullptr; + if (sCached != nullptr && IsWindow(sCached)) { + return sCached; + } + for (Uint32 id = 1; id <= 16 && sCached == nullptr; id++) { + SDL_Window* window = SDL_GetWindowFromID(id); + if (window == nullptr) { + continue; + } + SDL_SysWMinfo info; + SDL_VERSION(&info.version); + if (SDL_GetWindowWMInfo(window, &info) == SDL_TRUE && info.subsystem == SDL_SYSWM_WINDOWS) { + sCached = info.info.win.window; + } + } + if (sCached == nullptr) { + struct Search { + DWORD pid; + HWND gameWindow; + HWND fallback; + }; + Search search{ GetCurrentProcessId(), nullptr, nullptr }; + EnumWindows( + [](HWND hwnd, LPARAM param) -> BOOL { + Search* s = reinterpret_cast(param); + DWORD pid = 0; + GetWindowThreadProcessId(hwnd, &pid); + if (pid != s->pid || GetWindow(hwnd, GW_OWNER) != nullptr || !IsWindowVisible(hwnd)) { + return TRUE; + } + char cls[64] = { 0 }; + GetClassNameA(hwnd, cls, (int)sizeof(cls)); + if (strcmp(cls, "N64GAME") == 0) { + s->gameWindow = hwnd; + return FALSE; + } + if (s->fallback == nullptr && strcmp(cls, "ConsoleWindowClass") != 0) { + s->fallback = hwnd; + } + return TRUE; + }, + reinterpret_cast(&search)); + sCached = (search.gameWindow != nullptr) ? search.gameWindow : search.fallback; + } + return sCached; +} +} // namespace +#endif + #include "functions.h" extern "C" { #include "enums.h" @@ -140,17 +196,20 @@ extern "C" void port_setWindowTitle(int map_id) { noteStr, jiggyStr, hcStr, timeStr); #ifdef _WIN32 - HWND hwnd = GetActiveWindow(); + HWND hwnd = ResolveGameWindow(); if (hwnd) { SetWindowTextA(hwnd, title); } #endif } +static int sPendingTitleMap = 0; + void RegisterGameStatus_Init() { COND_HOOK(OnMapLoad, EVENT_PRIORITY_LOW, true, [](IEvent* event) { OnMapLoad* ev = (OnMapLoad*)event; - port_setWindowTitle(ev->nextMap); + sPendingTitleMap = ev->nextMap; + port_runOnRenderThread([](void*) { port_setWindowTitle(sPendingTitleMap); }, nullptr); }); } diff --git a/src/port/Interpolation/FrameInterpolation.cpp b/src/port/Interpolation/FrameInterpolation.cpp index 9da37c63c..e87cf8a0a 100644 --- a/src/port/Interpolation/FrameInterpolation.cpp +++ b/src/port/Interpolation/FrameInterpolation.cpp @@ -12,19 +12,21 @@ namespace { +constexpr uint64_t kFnvSeed = 0xcbf29ce484222325ULL; +constexpr uint64_t kSigKindToMtx = 0x1ULL; +constexpr uint64_t kSigKindSprite = 0x2ULL; +constexpr float kSpriteSnapDistSq = 300.0f * 300.0f; +constexpr int kRingSlots = 4; +constexpr uint32_t kAmbiguousSig = UINT32_MAX; + struct ToMtxData { void* dst; float src[4][4]; uint64_t pathSig; bool noInterpolate; - // Another entry this tick claimed the same scope identity, so which one a - // cross-tick partner refers to is a guess. See recordSigCollision. bool ambiguousSig; }; -// Sprites keep their raw inputs instead of the finished matrix so replay can -// blend angles as angles; blending the matrix itself makes billboards shear -// while the camera swings around them. struct SpriteDrawData { void* dst; float camRelPos[3]; @@ -48,25 +50,14 @@ struct CameraProjRotData { float yawDeg; }; -// Two entries pair up across ticks when they were recorded under the same -// scope path at the same index; that identity is hashed into pathSig as the -// game draws. struct ScopeFrame { uint64_t pathHash; uint32_t toMtxIdx; uint32_t spriteIdx; + const char* key; + uintptr_t id; }; -constexpr uint64_t kFnvSeed = 0xcbf29ce484222325ULL; -constexpr uint64_t kSigKindToMtx = 0x1ULL; -constexpr uint64_t kSigKindSprite = 0x2ULL; - -inline uint64_t fnvMix(uint64_t h, uint64_t v) { - h ^= v; - h *= 0x100000001b3ULL; - return h; -} - struct FrameTree { std::vector toMtxs; std::vector projRots; @@ -95,61 +86,18 @@ struct FrameTree { } }; -// A scope identity is only useful if one entry owns it. When two do, the -// sig->index maps cannot say which, and emplace keeps whichever arrived first -// -- so the second entry silently pairs against the first one's transform and -// gets dragged across the screen for a sub-frame. Mark every claimant instead -// and point the map at a sentinel, which leaves all of them uninterpolated. -constexpr uint32_t kAmbiguousSig = UINT32_MAX; - -template -void recordSigCollision(Map& sigMap, Vec& entries, uint64_t sig, uint32_t idx, uint32_t& collisionCount) { - auto [it, inserted] = sigMap.emplace(sig, idx); - if (inserted) { - return; - } - if (it->second < entries.size()) { - entries[it->second].ambiguousSig = true; - } - entries[idx].ambiguousSig = true; - it->second = kAmbiguousSig; - collisionCount++; -} - -// Ring of trees: the render side reads a (prev, curr) pair while the tick -// records the next one. Reuse is ownership-based; a submitted pair claims -// its two slots until that render finishes, and recording skips claimed slots. -constexpr int kRingSlots = 4; -FrameTree gRing[kRingSlots]; -std::atomic gSlotClaims[kRingSlots] = {}; -int gRecordSlot = 0; -int gLastRecordedSlot = -1; -FrameTree* gRecord = &gRing[0]; -FrameTree* gRenderPrev = nullptr; -FrameTree* gRenderCurr = nullptr; -bool gRenderShould = false; - -bool gRecording = false; -bool gShouldInterpolate = true; -int gNoInterpolateDepth = 0; - -std::unordered_map gIdMap; -uint64_t gNextId = 1; - struct PairedToMtx { uint32_t currIdx; uint32_t prevIdx; bool snap; }; + struct PairedSprite { uint32_t currIdx; uint32_t prevIdx; + bool snap; }; -// Pairing happens once per tick, on the first Interpolate() call; later -// sub-frames only read the result. Engine.cpp builds those on worker threads, -// so after `built` goes true nothing in here may be mutated until the next -// StartRecord. struct InterpolationCache { bool built = false; bool valid = false; @@ -166,8 +114,65 @@ struct InterpolationCache { prevHasCameraPos = false; } }; + +// Ring of trees +FrameTree gRing[kRingSlots]; +std::atomic gSlotClaims[kRingSlots] = {}; +int gRecordSlot = 0; +int gLastRecordedSlot = -1; +FrameTree* gRecord = &gRing[0]; +FrameTree* gRenderPrev = nullptr; +FrameTree* gRenderCurr = nullptr; +bool gRenderShould = false; + +bool gRecording = false; +bool gShouldInterpolate = true; +int gNoInterpolateDepth = 0; + +std::unordered_map gIdMap; +uint64_t gNextId = 1; + InterpolationCache gCache; +// First scope identity to collide this tick, reported once by StopRecord so a +// busy frame cannot flood the log. Cleared per tick in StartRecord; nullptr +// means nothing has collided yet. +const char* gCollidedScopeKey = nullptr; +uintptr_t gCollidedScopeId = 0; +const char* gCollidedParentKey = nullptr; +uintptr_t gCollidedParentId = 0; + +inline uint64_t fnvMix(uint64_t h, uint64_t v) { + h ^= v; + h *= 0x100000001b3ULL; + return h; +} + +template +void recordSigCollision(Map& sigMap, Vec& entries, uint64_t sig, uint32_t idx, uint32_t& collisionCount, + const std::vector& stack) { + const ScopeFrame& scope = stack.back(); + auto [it, inserted] = sigMap.emplace(sig, idx); + if (inserted) { + return; + } + if (it->second < entries.size()) { + entries[it->second].ambiguousSig = true; + } + entries[idx].ambiguousSig = true; + it->second = kAmbiguousSig; + collisionCount++; + if (gCollidedScopeKey == nullptr) { + gCollidedScopeKey = scope.key; + gCollidedScopeId = scope.id; + if (stack.size() >= 2) { + const ScopeFrame& parent = stack[stack.size() - 2]; + gCollidedParentKey = parent.key; + gCollidedParentId = parent.id; + } + } +} + } // namespace extern "C" { @@ -185,13 +190,17 @@ void FrameInterpolation_StartRecord(void) { gSlotClaims[0].load(), gSlotClaims[1].load(), gSlotClaims[2].load(), gSlotClaims[3].load()); } gRecord = &gRing[gRecordSlot]; + gCollidedScopeKey = nullptr; + gCollidedScopeId = 0; + gCollidedParentKey = nullptr; + gCollidedParentId = 0; gRecord->reset(); gRecord->toMtxs.reserve(512); gRecord->projRots.reserve(4); gRecord->sprites.reserve(256); gRecord->sigToToMtx.reserve(512); gRecord->sigToSprite.reserve(64); - gRecord->scopeStack.push_back({ kFnvSeed, 0, 0 }); + gRecord->scopeStack.push_back({ kFnvSeed, 0, 0, "root", 0 }); gShouldInterpolate = true; gNoInterpolateDepth = 0; gRecording = true; @@ -213,7 +222,10 @@ void FrameInterpolation_StopRecord(void) { static uint32_t sReported = 0; if (sReported < 20) { sReported++; - SPDLOG_WARN("interp scope id collided {}x this tick ({} matrices, {} sprites)", gRecord->sigCollisions, + SPDLOG_WARN("interp scope id collided {}x this tick under \"{}\" id={:#x} > \"{}\" id={:#x} " + "({} matrices, {} sprites)", + gRecord->sigCollisions, gCollidedParentKey != nullptr ? gCollidedParentKey : "?", + gCollidedParentId, gCollidedScopeKey != nullptr ? gCollidedScopeKey : "?", gCollidedScopeId, gRecord->toMtxs.size(), gRecord->sprites.size()); } } @@ -273,7 +285,7 @@ void FrameInterpolation_RecordOpenChild(const void* key, uintptr_t id) { uint64_t h = gRecord->scopeStack.back().pathHash; h = fnvMix(h, reinterpret_cast(key)); h = fnvMix(h, static_cast(id)); - gRecord->scopeStack.push_back({ h, 0, 0 }); + gRecord->scopeStack.push_back({ h, 0, 0, static_cast(key), id }); } void FrameInterpolation_RecordCloseChild(void) { @@ -312,7 +324,7 @@ void FrameInterpolation_RecordMatrixToMtx(void* dst, const float src[4][4]) { d.pathSig = sig; d.noInterpolate = (gNoInterpolateDepth > 0); d.ambiguousSig = false; - recordSigCollision(gRecord->sigToToMtx, gRecord->toMtxs, sig, idx, gRecord->sigCollisions); + recordSigCollision(gRecord->sigToToMtx, gRecord->toMtxs, sig, idx, gRecord->sigCollisions, gRecord->scopeStack); } void FrameInterpolation_RecordCameraProjectionRotation(void* rollMtx, float rollDeg, void* pitchMtx, float pitchDeg, @@ -378,7 +390,7 @@ void FrameInterpolation_RecordSpriteDraw(int kind, void* dst, const float camRel d.kind = static_cast(kind); d.mirrored = (mirrored != 0); d.ambiguousSig = false; - recordSigCollision(gRecord->sigToSprite, gRecord->sprites, sig, idx, gRecord->sigCollisions); + recordSigCollision(gRecord->sigToSprite, gRecord->sprites, sig, idx, gRecord->sigCollisions, gRecord->scopeStack); } void FrameInterpolation_DontInterpolateCamera(void) { @@ -488,7 +500,7 @@ void BuildInterpolationCache() { } auto it = prevSpriteMap.find(c.pathSig); if (it == prevSpriteMap.end() || it->second >= prevSprites.size() || prevSprites[it->second].kind != c.kind) { - gCache.pairedSprites.push_back({ i, UINT32_MAX }); + gCache.pairedSprites.push_back({ i, UINT32_MAX, false }); continue; } const SpriteDrawData& p = prevSprites[it->second]; @@ -498,7 +510,15 @@ void BuildInterpolationCache() { p.mirrored == c.mirrored) { continue; } - gCache.pairedSprites.push_back({ i, it->second }); + bool snap = false; + if (gRenderPrev->hasCameraPos && gRenderCurr->hasCameraPos) { + float d[3]; + for (int k = 0; k < 3; k++) { + d[k] = (c.camRelPos[k] + gRenderCurr->cameraPos[k]) - (p.camRelPos[k] + gRenderPrev->cameraPos[k]); + } + snap = (d[0] * d[0] + d[1] * d[1] + d[2] * d[2]) > kSpriteSnapDistSq; + } + gCache.pairedSprites.push_back({ i, it->second, snap }); } // A tree recycled while we walked it means every index above is suspect. @@ -559,8 +579,6 @@ void emitSprite(const SpriteDrawData& L, std::unordered_map& replace } }; - // The rotation lambdas only touch rows 0-2, which is why FULL can - // translate first while billboards translate last. if (L.kind == FI_SPRITE_KIND_FULL) { m[3][0] = L.camRelPos[0]; m[3][1] = L.camRelPos[1]; @@ -605,8 +623,7 @@ void FrameInterpolation_Interpolate(float t, std::unordered_map& rep return; } - // A large camera jump means a warp or camera cut; blending across it - // would draw the world halfway between two scenes for a frame. + // A large camera jump means a warp or camera cut. if (gCache.prevHasCameraPos && gRenderCurr->hasCameraPos) { float dx = gRenderCurr->cameraPos[0] - gCache.prevCameraPos[0]; float dy = gRenderCurr->cameraPos[1] - gCache.prevCameraPos[1]; @@ -643,7 +660,7 @@ void FrameInterpolation_Interpolate(float t, std::unordered_map& rep for (const PairedSprite& pair : gCache.pairedSprites) { const SpriteDrawData& c = currSpritesData[pair.currIdx]; SpriteDrawData L = c; - if (pair.prevIdx != UINT32_MAX) { + if (pair.prevIdx != UINT32_MAX && !pair.snap) { const SpriteDrawData& p = prevSpritesData[pair.prevIdx]; for (int k = 0; k < 3; k++) { L.camRelPos[k] = w * p.camRelPos[k] + t * c.camRelPos[k]; diff --git a/src/port/Network/Anchor/Anchor.cpp b/src/port/Network/Anchor/Anchor.cpp index f19e6bd24..063649fab 100644 --- a/src/port/Network/Anchor/Anchor.cpp +++ b/src/port/Network/Anchor/Anchor.cpp @@ -301,6 +301,12 @@ void Anchor::ClearDummies() { dummies.clear(); } +// Lets decomp gate Anchor-only catch-up paths so single player keeps vanilla behaviour. +extern "C" s32 port_anchor_isConnected(void) { + Anchor* anchor = Anchor::GetInstance(); + return (anchor != nullptr && anchor->isConnected) ? 1 : 0; +} + // actorArray_free tears down actors/markers without firing OnActorDestroy; forget them all. extern "C" void port_anchorDummies_onActorsFreed(void) { Anchor* anchor = Anchor::GetInstance(); diff --git a/src/port/Network/Anchor/Menu.cpp b/src/port/Network/Anchor/Menu.cpp index 347e6d15b..e5d543fb2 100644 --- a/src/port/Network/Anchor/Menu.cpp +++ b/src/port/Network/Anchor/Menu.cpp @@ -88,7 +88,7 @@ void AnchorMainMenu(WidgetInfo& info) { if (UIWidgets::Button("Global Room", UIWidgets::ButtonOptions() .Color(UIWidgets::Colors::Blue) .Tooltip("Always-online public room so you don't have to explore alone. " - "You'll see other players' characters, but nothing is synced — " + "You'll see other players' characters, but nothing is synced - " "no items, flags, PvP, or teleporting."))) { CVarSetString(CVAR_REMOTE_ANCHOR("Host"), "anchor.hm64.org"); CVarSetInteger(CVAR_REMOTE_ANCHOR("Port"), 43383); diff --git a/src/port/Network/Anchor/Packets/UpdateRoomState.cpp b/src/port/Network/Anchor/Packets/UpdateRoomState.cpp index bd8495ab0..e8e98a539 100644 --- a/src/port/Network/Anchor/Packets/UpdateRoomState.cpp +++ b/src/port/Network/Anchor/Packets/UpdateRoomState.cpp @@ -110,7 +110,7 @@ void Anchor::CheckRandoRoomCompatibility() { std::string msg; if (roomState.isRando && !localRando) { msg = "This is a randomizer room, but the save you loaded is not a randomizer file.\n\n" - "Items, flags, and checks will not line up — you'll receive progress you can't use\n" + "Items, flags, and checks will not line up - you'll receive progress you can't use\n" "and may corrupt the shared session. Load the matching randomizer file, or\n" "disconnect before continuing."; } else if (!roomState.isRando && localRando) { diff --git a/src/port/OS/OS.h b/src/port/OS/OS.h index f58696356..66f24b5f5 100644 --- a/src/port/OS/OS.h +++ b/src/port/OS/OS.h @@ -32,6 +32,15 @@ void OS_EnableThreadEntry(void* entry); // OS_MESG_BLOCK only blocks on queues opted in here. void OS_SetQueueBlocking(OSMesgQueue* mq, int enabled); +// Cooperative exit for threads. +void OS_RequestThreadExit(void); +int OS_ThreadShouldExit(void); +void OS_JoinDecompThreads(void); + +// Stop every queue blocking and wake all waiters, so the tick can unwind and be +// joined. Call once the window has closed and before joining it. +void OS_BeginShutdown(void); + // Watchdog diagnostics: threads currently parked inside a blocking // osSendMesg/osRecvMesg, so a stall dump can say where each one waits. typedef struct OS_BlockedWait { diff --git a/src/port/OS/OS_Mesg.cpp b/src/port/OS/OS_Mesg.cpp index 56d02fb29..d0e2885a5 100644 --- a/src/port/OS/OS_Mesg.cpp +++ b/src/port/OS/OS_Mesg.cpp @@ -173,6 +173,17 @@ void OS_SetQueueBlocking(OSMesgQueue* mq, int enabled) { SyncFor(mq).blockingEnabled = (enabled != 0); } +// Called once the window closes, before the tick is joined. +void OS_BeginShutdown(void) { + std::lock_guard lock(sMesgMutex); + for (auto& [mq, sync] : sQueueSync) { + (void)mq; + sync.blockingEnabled = false; + sync.notEmpty.notify_all(); + sync.notFull.notify_all(); + } +} + // Lock-free on purpose: the caller is a watchdog inspecting a possible // deadlock, so it must not touch sMesgMutex. Entries can be mid-update; // they are diagnostics, not decisions. diff --git a/src/port/OS/OS_Threads.cpp b/src/port/OS/OS_Threads.cpp index d94fd7a34..250514944 100644 --- a/src/port/OS/OS_Threads.cpp +++ b/src/port/OS/OS_Threads.cpp @@ -2,9 +2,13 @@ #include "OS.h" +#include +#include +#include #include #include #include +#include #include namespace { @@ -26,8 +30,52 @@ bool ThreadEnabled(void* entry) { return sEnabledEntries.count(entry) != 0; } +std::atomic sExitRequested{ false }; + +// Counted rather than joined blind: a thread stuck somewhere other than its queue +// wait would never see the request, and join() cannot time out. Waiting on the +// count lets us give up on a straggler instead of hanging the process on it. +std::mutex sExitMutex; +std::condition_variable sExitCv; +int sLiveThreads = 0; + } // namespace +extern "C" void OS_RequestThreadExit(void) { + sExitRequested.store(true, std::memory_order_release); +} + +extern "C" int OS_ThreadShouldExit(void) { + return sExitRequested.load(std::memory_order_acquire) ? 1 : 0; +} + +extern "C" void OS_JoinDecompThreads(void) { + bool allReturned; + { + std::unique_lock lock(sExitMutex); + allReturned = sExitCv.wait_for(lock, std::chrono::seconds(2), [] { return sLiveThreads == 0; }); + } + + std::lock_guard lock(sTableMutex); + for (auto& [thread, st] : sThreads) { + (void)thread; + if (!st.worker.joinable()) { + continue; + } + if (allReturned) { + st.worker.join(); + } else { + // Nothing safe left to do: it is still inside game code, so it cannot be + // joined without hanging and cannot be killed without leaving locks held. + // Detaching restores the pre-existing behaviour for that one thread. + st.worker.detach(); + } + } + if (!allReturned) { + SPDLOG_WARN("{} decomp thread(s) did not reach their exit check; detaching", sLiveThreads); + } +} + extern "C" void OS_EnableThreadEntry(void* entry) { std::lock_guard lock(sTableMutex); sEnabledEntries.insert(entry); @@ -54,8 +102,22 @@ extern "C" void OS_StartThread(OSThread* thread) { return; } it->second.started = true; - it->second.worker = std::thread(it->second.entry, it->second.arg); - it->second.worker.detach(); + void (*entry)(void*) = it->second.entry; + void* arg = it->second.arg; + { + std::lock_guard exitLock(sExitMutex); + sLiveThreads++; + } + // Kept joinable: shutdown waits for these to leave their loops before the + // engine they draw and play audio through is destroyed. + it->second.worker = std::thread([entry, arg]() { + entry(arg); + { + std::lock_guard exitLock(sExitMutex); + sLiveThreads--; + } + sExitCv.notify_all(); + }); } extern "C" void OS_StopThread(OSThread* thread) { diff --git a/src/port/Save/SaveManager.cpp b/src/port/Save/SaveManager.cpp index fda108d9f..839a167f5 100644 --- a/src/port/Save/SaveManager.cpp +++ b/src/port/Save/SaveManager.cpp @@ -666,6 +666,34 @@ static void LoadGlobalData() { } } +static bool WriteFileAtomically(const std::filesystem::path& path, const std::string& contents) { + const std::filesystem::path tempPath = path.parent_path() / (path.filename().string() + ".tmp"); + std::error_code ec; + { + std::ofstream ofs(tempPath, std::ios::binary | std::ios::trunc); + if (!ofs.is_open()) { + SPDLOG_ERROR("SaveManager: failed to open \"{}\" for writing", tempPath.string()); + return false; + } + ofs << contents; + ofs.flush(); + if (!ofs.good()) { + SPDLOG_ERROR("SaveManager: failed writing \"{}\"; leaving the existing file alone", tempPath.string()); + ofs.close(); + std::filesystem::remove(tempPath, ec); + return false; + } + } + std::filesystem::rename(tempPath, path, ec); + if (ec) { + SPDLOG_ERROR("SaveManager: failed to replace \"{}\": {}", path.string(), ec.message()); + std::error_code removeEc; + std::filesystem::remove(tempPath, removeEc); + return false; + } + return true; +} + static void SaveGlobalData() { ordered_json j = ordered_json::object(); @@ -687,13 +715,7 @@ static void SaveGlobalData() { j["bottlesBonusCompleted"] = bb; std::string globalPath = SaveManager_GetSavePath("global.json"); - std::ofstream ofs(globalPath); - if (ofs.is_open()) { - ofs << CollapsedJSONArray(j); - ofs.close(); - } else { - SPDLOG_ERROR("SaveManager: failed to open global save file \"{}\" for writing", globalPath); - } + WriteFileAtomically(globalPath, CollapsedJSONArray(j)); } void SaveManager_MoveInvalidSaveFile(const std::filesystem::path& fileName, const std::string& message) { @@ -764,15 +786,7 @@ void SaveManager_Init() { ordered_json saveFile = Convert_SaveDataToJSON((SaveData*)ev->saveBuffer, ev->fileNum); if (!saveFile.empty()) { - std::string collapsedString = CollapsedJSONArray(saveFile); - - std::ofstream outputFile(filePath); - if (outputFile.is_open()) { - outputFile << collapsedString; - outputFile.close(); - } else { - SPDLOG_ERROR("SaveManager: failed to open save file \"{}\" for writing", filePath); - } + WriteFileAtomically(filePath, CollapsedJSONArray(saveFile)); } SaveGlobalData(); diff --git a/src/port/UI/DeveloperTools/SaveEditor.cpp b/src/port/UI/DeveloperTools/SaveEditor.cpp index 0207a1fbb..c13d8b29c 100644 --- a/src/port/UI/DeveloperTools/SaveEditor.cpp +++ b/src/port/UI/DeveloperTools/SaveEditor.cpp @@ -356,6 +356,10 @@ void SaveEditor_DrawProgressTab() { void DrawRandoFlagEditor() { ImGui::SeparatorText("Rando INF Flags"); + if (selectedFileNum == DEFAULT_FILE_NUM) { + ImGui::Text("No Save File Loaded"); + return; + } if (ImGui::BeginChild("RandoFlagChild")) { for (int f = RANDO_INF_UNKNOWN; f < RANDO_INF_MAX; f++) { ImGui::PushID(f); @@ -370,7 +374,7 @@ void DrawRandoFlagEditor() { } void DrawRandoCheckEditor() { - if (Rando::Logic::shuffledPool.empty()) { + if (selectedFileNum == DEFAULT_FILE_NUM || Rando::Logic::shuffledPool.empty()) { ImGui::Text("No Rando Save Data"); } else { static ImGuiTextFilter rcFilter; @@ -393,8 +397,17 @@ void DrawRandoCheckEditor() { ImGui::TableNextColumn(); for (auto& check : RANDO_SAVE_CHECKS) { - if (!rcFilter.PassFilter(check.name) && - !rcFilter.PassFilter(Rando::StaticData::Items[check.randoItemId].name)) { + auto checkEntry = Rando::StaticData::Checks.find(check.randoCheckId); + if (checkEntry == Rando::StaticData::Checks.end()) { + continue; + } + const char* checkName = checkEntry->second.name; + + auto itemEntry = Rando::StaticData::Items.find(check.randoItemId); + const char* itemName = + (itemEntry != Rando::StaticData::Items.end()) ? itemEntry->second.name : nullptr; + + if (!rcFilter.PassFilter(checkName) && !rcFilter.PassFilter(itemName)) { continue; } @@ -430,19 +443,21 @@ void DrawRandoCheckEditor() { } ImGui::TableNextColumn(); - std::string checkName = Rando::StaticData::Checks[check.randoCheckId].name; - ImGui::TextWrapped(checkName.c_str()); + ImGui::TextWrapped("%s", checkName); ImGui::TableNextColumn(); if (check.randoItemId == RI_MOLEHILL) { TableCellCenteredText(abilityNameList[check.randoCollectionId].c_str()); } else { - TableCellCenteredText(Rando::StaticData::Items[check.randoItemId].name); + TableCellCenteredText(itemName != nullptr ? itemName : ""); } ImGui::TableNextColumn(); - if (Rando::StaticData::Checks[check.shuffledCheckId].randoCheckType != RCTYPE_JINJO && - Rando::StaticData::Checks[check.shuffledCheckId].randoCheckType != RCTYPE_MUSIC_NOTE) { + auto shuffledEntry = Rando::StaticData::Checks.find(check.shuffledCheckId); + const RandoCheckType shuffledType = (shuffledEntry != Rando::StaticData::Checks.end()) + ? shuffledEntry->second.randoCheckType + : RCTYPE_UNKNOWN; + if (shuffledType != RCTYPE_JINJO && shuffledType != RCTYPE_MUSIC_NOTE) { TableCellCenteredText(std::to_string(check.randoCollectionId).c_str()); } ImGui::TableNextColumn(); diff --git a/src/port/UI/LighthouseMenuEnhancements.cpp b/src/port/UI/LighthouseMenuEnhancements.cpp index 8a558d380..8e3e17677 100644 --- a/src/port/UI/LighthouseMenuEnhancements.cpp +++ b/src/port/UI/LighthouseMenuEnhancements.cpp @@ -154,10 +154,10 @@ void LighthouseMenu::AddMenuEnhancements() { path.column = SECTION_COLUMN_1; - AddWidget(path, "Extended Draw Distance: %dx", WIDGET_CVAR_SLIDER_INT) + AddWidget(path, "Extended Draw Distance", WIDGET_CVAR_SLIDER_INT) .CVar(CVAR_ENHANCEMENT("Graphics.DrawDistance")) .RaceDisable(false) - .Options(IntSliderOptions().Min(1).Max(6).DefaultValue(1).ShowButtons(true).Format("").Tooltip( + .Options(IntSliderOptions().Min(1).Max(6).DefaultValue(1).ShowButtons(true).Format("%dx").Tooltip( "Multiplies the draw distance for objects.\n" "Higher values render more but cost performance.")); @@ -647,7 +647,7 @@ void LighthouseMenu::AddMenuEnhancements() { .CVar(CVAR_ENHANCEMENT("Cheats.TalonTrotCycle")) .RaceDisable(false) .Options(CheckboxOptions().Tooltip( - "While in Talon Trot: D-pad Right cycles forward (Normal→Boots→Sneakers), D-pad Left cycles backward.")); + "While in Talon Trot: D-pad Right cycles forward (Normal->Boots->Sneakers), D-pad Left cycles backward.")); // Transformations Section AddWidget(path, "Transformations", WIDGET_SEPARATOR_TEXT); @@ -666,7 +666,7 @@ void LighthouseMenu::AddMenuEnhancements() { .CVar(CVAR_ENHANCEMENT("Cheats.CycleTransform")) .RaceDisable(false) .Options(CheckboxOptions().Tooltip("Press D-pad Up/Down to cycle through transformation forms.\nUp: Forward " - "(Banjo→Termite→...→Bee→Banjo), Down: Backward.")); + "(Banjo->Termite->...->Bee->Banjo), Down: Backward.")); AddWidget(path, "No Mumbo Untransform", WIDGET_CVAR_CHECKBOX) .CVar(CVAR_ENHANCEMENT("Cheats.NoMumboUntransform")) diff --git a/src/port/UI/LighthouseMenuSettings.cpp b/src/port/UI/LighthouseMenuSettings.cpp index 89d2d0b61..08336cc00 100644 --- a/src/port/UI/LighthouseMenuSettings.cpp +++ b/src/port/UI/LighthouseMenuSettings.cpp @@ -293,10 +293,10 @@ void LighthouseMenu::AddMenuSettings() { path.column = SECTION_COLUMN_1; AddSidebarEntry("Settings", "Audio", 3); - AddWidget(path, "Master Volume: %d %%", WIDGET_CVAR_SLIDER_INT) + AddWidget(path, "Master Volume", WIDGET_CVAR_SLIDER_INT) .CVar(CVAR_SETTING("Volume.Master")) .RaceDisable(false) - .Options(IntSliderOptions().Min(0).Max(100).DefaultValue(40).ShowButtons(true).Format("")); + .Options(IntSliderOptions().Min(0).Max(100).DefaultValue(40).ShowButtons(true).Format("%d%%")); // AddWidget(path, "Main Music Volume: %d %%", WIDGET_CVAR_SLIDER_INT) // .CVar(CVAR_SETTING("Volume.MainMusic")) // .RaceDisable(false) From de98057abc0370ef199d5fee393332d7b2cc095d Mon Sep 17 00:00:00 2001 From: Malkierian Date: Fri, 31 Jul 2026 10:41:01 -0700 Subject: [PATCH 051/131] Extend prop count (#292) * Restore event call in `chmole_learnedAllSpiralMountainAbilities` * Extend propCnt1/propCnt2 to avoid overflow while creating particles. Add guards surrounding these structures to inform if a prop clear is attempted that isn't part of a given cube. * Widen unk0_4 as well (not really a vanilla issue, but could present problems with hacks and such). * More and better guards. * Fix flowered pots in MMM not surviving transitions. * Add comment to find better place for warn functions in PerfPatches later. Fix memory footprint of Cube. Fix guard placements and return values in `func_8032D9C0`. --- include/prop.h | 13 ++++++++--- src/core2/actor_cubepropsystem.c | 22 ++++++++++++++++--- src/core2/fx/commonParticle.c | 12 +++++++++-- src/core2/quiz/game.c | 13 +++++++++++ src/port/Patches/Patches.h | 6 ++++++ src/port/Patches/PerfPatches.cpp | 25 +++++++++++++++++++++- src/port/Resource/Importers/MapFactory.cpp | 15 ++++++++----- 7 files changed, 92 insertions(+), 14 deletions(-) diff --git a/include/prop.h b/include/prop.h index d61bfbe0f..564b2f560 100644 --- a/include/prop.h +++ b/include/prop.h @@ -398,13 +398,20 @@ typedef struct { u32 pad10_0:1; } OtherNode; //can be inplace of NodeProp (see code7AF80_initCubeFromFile) size: 12 (0xC) bytes +// Distance scratch __cube_sort fills, one entry per prop. Cubes past this are +// left unsorted rather than overrunning it. +#define CUBE_SORT_SCRATCH_SIZE 0x400 + typedef struct cude_s{ s32 x:5; s32 y:5; s32 z:5; - u32 prop1Cnt:6; - u32 prop2Cnt:6; - u32 unk0_4:5; //node_prop_count + // [port] were bitfields (:5/:6/:6). The 64th prop wrapped a count to 0, which + // realloc'd the prop array to nothing while live markers still pointed into it; + // unk0_4 is the front index of the node-prop partition and wrapped at 32. + u32 unk0_4:16; //node_prop_count + u16 prop1Cnt; + u16 prop2Cnt; NodeProp *prop1Ptr; Prop *prop2Ptr; }Cube; diff --git a/src/core2/actor_cubepropsystem.c b/src/core2/actor_cubepropsystem.c index b8a9375fe..9a5dfdc9b 100644 --- a/src/core2/actor_cubepropsystem.c +++ b/src/core2/actor_cubepropsystem.c @@ -119,7 +119,7 @@ BKCollisionTriangle *D_80383420; u8 D_80383428[MARKER_BITMAP_BYTES]; s32 D_80383444; int D_80383448; -s32 D_80383450[0x40]; +s32 D_80383450[CUBE_SORT_SCRATCH_SIZE]; bk_vector(ActorMarker *) *D_80383550; bk_vector(ActorMarker *) *D_80383554; Method_Core2_A5BC0 D_80383558; @@ -138,6 +138,11 @@ void __cube_sort(Cube *cube, bool global) { s32 i; Prop *new_var; + // [port] Sorting is only draw order; skip rather than overrun the scratch. + if (cube->prop2Cnt > CUBE_SORT_SCRATCH_SIZE) { + return; + } + if (cube->prop2Cnt >= 2) { if (global == 0) { viewport_getPosition_vec3w(ref_position); //distance from viewport @@ -515,14 +520,20 @@ s32 func_8032D9C0(Cube *cube, Prop* prop){ s32 tmp; sp24 = 0; - if(cube->prop2Cnt != 0){ + if(cube != NULL && cube->prop2Cnt != 0 && prop != NULL && cube->prop2Ptr != NULL){ + ptrdiff_t index = prop - cube->prop2Ptr; + // [port] A stale propPtr makes elementsAfter enormous; drop the removal instead. + if (index < 0 || index >= (ptrdiff_t)cube->prop2Cnt) { + port_warnPropNotInCube((s32)index, (s32)cube->prop2Cnt); + return sp24; + } + sp24 = prop->unk8_1; if(func_80305D14()){ func_80305CD8(func_803058C0(prop->unk4[1]), -1); } // port - Rando manipulation of prop2Ptr results in mismatched data, this corrects that. - ptrdiff_t index = prop - cube->prop2Ptr; ptrdiff_t elementsAfter = (cube->prop2Cnt - 1) - index; if (elementsAfter > 0) { memmove(prop, prop + 1, elementsAfter * sizeof(Prop)); @@ -945,6 +956,11 @@ static void __codeA5BC0_initPropPointerForCube(NodeProp *node, Cube *cube, s32 c } } + // [port] unk0_4 is the front index of this partition; :5 wrapped it here. + if(cube->unk0_4 > 31){ + port_warnNodePropSplit(cube->unk0_4, cnt); + } + bk_free(node); for(i = 0; i < cnt; i++){ diff --git a/src/core2/fx/commonParticle.c b/src/core2/fx/commonParticle.c index d4f534162..9f93abca2 100644 --- a/src/core2/fx/commonParticle.c +++ b/src/core2/fx/commonParticle.c @@ -183,14 +183,18 @@ s32 commonParticle_findFree(void){ int commonParticle_new(enum common_particle_e particle_id, int arg1){ f32 sp34[3]; uintptr_t a0; + s32 slot; if(arg1 == 0) return -1; ml_vec3f_clear(sp34); - D_80384FD0 = commonParticle_findFree(); - if(D_80384FD0 < 0) + // [port] Don't publish -1 to the global; every D_80384490[D_80384FD0] access + // downstream (accessors, commonParticle_update) would read out of bounds. + slot = commonParticle_findFree(); + if(slot < 0) return -1; + D_80384FD0 = slot; D_80384490[D_80384FD0].projectileIndex = func_8033FA84(); @@ -249,6 +253,10 @@ void freeParticleByIndex(s32 arg0){ void commonParticle_add(ActorMarker *arg0, s32 arg1, FuncUnk40 arg2){ s32 tmp_v0 = commonParticle_findFree(); + // [port] Pool full returns -1; writing D_80384490[-1] corrupts whatever precedes it. + if(tmp_v0 < 0){ + return; + } D_80384490[tmp_v0].isInUse--; D_80384490[tmp_v0].unk38 = arg0; D_80384490[tmp_v0].unk3C = arg1; diff --git a/src/core2/quiz/game.c b/src/core2/quiz/game.c index 29024bf74..4ebc2dfeb 100644 --- a/src/core2/quiz/game.c +++ b/src/core2/quiz/game.c @@ -502,6 +502,16 @@ void port_breakable_remoteBreakAt(s32 markerId, s32 x, s32 y, s32 z) { } } +static bool port_breakable_survivesBreak(s32 markerId) { + switch (markerId) { + case MARKER_34_CEMETARY_POT: // flowers + case MARKER_66_ORANGE_PAD: // stays, marked hit + return TRUE; + default: + return FALSE; + } +} + // [port] Iterates backward: despawn swap-removes from the end. void port_breakable_despawnBrokenRestores(s32 map) { s32 i; @@ -514,6 +524,9 @@ void port_breakable_despawnBrokenRestores(s32 map) { if (actor->marker == NULL || actor->despawn_flag) { continue; } + if (port_breakable_survivesBreak(actor->marker->id)) { + continue; + } if (port_breakable_isBroken(map, actor->marker->id, (s32)actor->position[0], (s32)actor->position[1], (s32)actor->position[2])) { marker_despawn(actor->marker); diff --git a/src/port/Patches/Patches.h b/src/port/Patches/Patches.h index cc1e7384d..3bb5a3872 100644 --- a/src/port/Patches/Patches.h +++ b/src/port/Patches/Patches.h @@ -194,6 +194,12 @@ int32_t port_hutSmash_countForCurrentLevel(void); void port_jiggyCrane_broadcast(int32_t stage); void port_jiggyCrane_remoteApply(int32_t stage); +// Rate-limited: a marker reached cube_removeProp with a propPtr outside its cube. +void port_warnPropNotInCube(int32_t index, int32_t propCnt); + +// Rate-limited: a cube's node-prop split index passed 31, where the old :5 field wrapped. +void port_warnNodePropSplit(int32_t splitIndex, int32_t nodeCnt); + #ifdef __cplusplus } #endif diff --git a/src/port/Patches/PerfPatches.cpp b/src/port/Patches/PerfPatches.cpp index 12c8c169f..037a48567 100644 --- a/src/port/Patches/PerfPatches.cpp +++ b/src/port/Patches/PerfPatches.cpp @@ -2,7 +2,10 @@ #include #include +#include + #include "port/Enhancements/Events/Hooks/Events.h" +#include "port/Patches/Patches.h" #include "port/ShipInit.hpp" extern "C" { @@ -10,7 +13,7 @@ extern "C" { #include "functions.h" #include "core2/lighting.h" -extern s32 D_80383450[0x40]; +extern s32 D_80383450[CUBE_SORT_SCRATCH_SIZE]; // core1 helpers not exposed through functions.h. extern void func_80256E24(f32 dst[3], f32 theta, f32 phi, f32 x, f32 y, f32 z); @@ -27,6 +30,26 @@ static f32 sPadFrustumY = 93.9692611694336f; static f32 sPadPlanes[4][4]; static bool sPadPlanesDirty = true; +// TODO: Find better place for these two warn functions +// Capped so a bad frame can't flood the log; one print is enough to investigate. +extern "C" void port_warnPropNotInCube(int32_t index, int32_t propCnt) { + static int32_t sReported = 0; + if (sReported < 20) { + sReported++; + SPDLOG_WARN("cube_removeProp: prop not in cube (index {}, cnt {})", index, propCnt); + } +} + +// Fires only for a cube the old :5 unk0_4 would have silently corrupted, so if this +// never prints, no shipped map reaches the limit and the widening is forward-looking. +extern "C" void port_warnNodePropSplit(int32_t splitIndex, int32_t nodeCnt) { + static int32_t sReported = 0; + if (sReported < 20) { + sReported++; + SPDLOG_WARN("cube node-prop split {} of {} exceeds the old 31 limit", splitIndex, nodeCnt); + } +} + // __cube_sort re-sorts every visible cube's props each tick, but only the camera // moves, so the order rarely changes. A stable insertion sort skims an already // sorted array in one pass and produces the same ordering as the vanilla sort. diff --git a/src/port/Resource/Importers/MapFactory.cpp b/src/port/Resource/Importers/MapFactory.cpp index 68f90b4de..d7a19d22a 100644 --- a/src/port/Resource/Importers/MapFactory.cpp +++ b/src/port/Resource/Importers/MapFactory.cpp @@ -128,19 +128,24 @@ void SerializeLegacyMapData(std::vector& out, const std::vector(cube.nodeProps.size(), 0xFF); out.push_back(0x0A); - out.push_back(static_cast(std::min(cube.nodeProps.size(), 0xFF))); + out.push_back(static_cast(nodeCnt)); out.push_back(0x0B); - for (const auto& node : cube.nodeProps) { - WriteNodeProp(out, node); + for (size_t n = 0; n < nodeCnt; n++) { + WriteNodeProp(out, cube.nodeProps[n]); } } if (!cube.props.empty()) { + const size_t propCnt = std::min(cube.props.size(), 0xFF); out.push_back(0x08); - out.push_back(static_cast(std::min(cube.props.size(), 0xFF))); + out.push_back(static_cast(propCnt)); out.push_back(0x09); - for (const auto& prop : cube.props) { + for (size_t pi = 0; pi < propCnt; pi++) { + const auto& prop = cube.props[pi]; // [port] Props are raw 12-byte N64 big-endian structs from the ROM. // Layout: u32(4) + s16(2) + s16(2) + s16(2) + u16(2) = 12 bytes. // Byte-swap each multi-byte field to native (little-endian) order From 95c6a66823e25c1bca95488ddaadbcac2d6a9504 Mon Sep 17 00:00:00 2001 From: Jeod <47716344+JeodC@users.noreply.github.com> Date: Fri, 31 Jul 2026 13:51:55 -0400 Subject: [PATCH 052/131] Final adjustments to RC (#293) * Defer the note retention seed out of demo playback * Adjust modern controls * Bottles bonus demo sync and picture rendering * Fix missing topper enemy in SM ending demo * Sort the VBehaviorID enum * Clang format * Serialize jiggy puzzle counters through the active layout * Don't pop the thread watchdog during expected stalls like the native file dialog --- src/SM/ch/attacktutorial.c | 7 +- src/core1/display_list.c | 8 +- src/core1/vimgr.c | 7 +- src/core2/demo.c | 7 +- src/core2/frame/auxbuffer.c | 19 ---- src/core2/gameloop.c | 9 +- src/core2/gamestate.c | 7 +- src/core2/gc/pictureframe.c | 1 - src/core2/gc/zoombox.c | 19 +++- src/core2/mumboshandwithpicture.c | 1 - src/port/Controller/ControlSchemes.cpp | 60 +++------- src/port/DevTools/ThreadWatchdog.cpp | 33 +++++- src/port/DevTools/ThreadWatchdog.h | 18 +++ src/port/Enhancements/Events/Hooks/Events.h | 99 ++++++++-------- src/port/Enhancements/Fixes/GameFixes.cpp | 17 +++ .../Enhancements/Retention/NoteRetention.cpp | 22 +++- src/port/Enhancements/Retention/Retention.cpp | 10 +- src/port/Enhancements/Retention/WormSync.cpp | 10 +- src/port/FilePicker.cpp | 24 ++-- src/port/Patches/FramebufferPatches.cpp | 77 +++++++++++-- src/port/Patches/Patches.h | 2 - src/port/Rando/Logic/Logic.h | 4 +- src/port/Save/SaveManager.cpp | 107 +++++++++++++++--- src/port/ShipUtils.cpp | 6 +- 24 files changed, 378 insertions(+), 196 deletions(-) diff --git a/src/SM/ch/attacktutorial.c b/src/SM/ch/attacktutorial.c index 10b7ef264..79911a42c 100644 --- a/src/SM/ch/attacktutorial.c +++ b/src/SM/ch/attacktutorial.c @@ -137,6 +137,8 @@ static bool __chAttackTutorial_areLearnableAbilitiesUnlocked() { } // [port] A local tutorial opt-out unlocks every move mid-session; re-arm the spawn latch. +bool func_802E4A08(void); // non-interactive demo/playback modes + void chAttackTutorial_onTutorialSkipped(void) { Actor *tutorial = actorArray_findActorFromActorId(ACTOR_167_ATTACK_TUTORIAL); if (tutorial != NULL) { @@ -175,8 +177,9 @@ static void __chAttackTutorial_update(Actor *this) { case CH_ATTACK_TUTORIAL_STATE_1_UNKNOWN: if (mapSpecificFlags_get(SM_SPECIFIC_FLAG_4)) __chAttackTutorial_setState(this, CH_ATTACK_TUTORIAL_STATE_5_SHOW_LEARN_MOVE_DIALOG); - - if (this->movesKnownAtSpawn || volatileFlag_get(VOLATILE_FLAG_C1_IN_FINAL_CHARACTER_PARADE)) + if (this->movesKnownAtSpawn + || (func_802E4A08() && __chAttackTutorial_areLearnableAbilitiesUnlocked()) + || volatileFlag_get(VOLATILE_FLAG_C1_IN_FINAL_CHARACTER_PARADE)) __chAttackTutorial_setState(this, CH_ATTACK_TUTORIAL_STATE_4_TUTORIAL_COMPLETED); break; diff --git a/src/core1/display_list.c b/src/core1/display_list.c index fcf24b490..49d18e32e 100644 --- a/src/core1/display_list.c +++ b/src/core1/display_list.c @@ -84,13 +84,7 @@ void setupFramebuffer(Gfx **gfx, void *color_buffer) { void setupFramebufferForGamemode(Gfx **gdl, s32 framebuffer_idx) { if(getGameMode() == GAME_MODE_8_BOTTLES_BONUS || getGameMode() == GAME_MODE_A_SNS_PICTURE) { - // [port] Redirect rendering to GPU-side aux FB via gsSPSetFB. - // On N64, gDPSetColorImage pointed to D_80382450 (CPU buffer). - // gsSPResetFB is emitted in func_802E39D0 after the scene draw. - s32 auxFb = port_getAuxGpuFbId(); - if (auxFb >= 0) { - gsSPSetFB((*gdl)++, auxFb); - } + EventSystem_Should(VB_PICTUREBOX_TARGET_FB, true, gdl); picturebox_setScissorBox(); setupFramebuffer(gdl, picturebox_getColorBuffer()); } diff --git a/src/core1/vimgr.c b/src/core1/vimgr.c index 27b71403b..257477efd 100644 --- a/src/core1/vimgr.c +++ b/src/core1/vimgr.c @@ -174,13 +174,10 @@ void viMgr_func_8024BFAC(void){ void viMgr_func_8024BFD8(s32 arg0){ // [port] Set D_80280724 to the actual VI count so time_func_8033DDB8() returns - // the correct delta for demo/playback zoomboxes. On N64 this was set from the - // VI wait loop counter which reflected real rendering time (including lag). - // During demo playback, sDemoViCount includes the N64's original rendering lag - // for maps that ran slow, which the zoombox dialog system needs to pace text. + // the correct delta for demo/playback zoomboxes. s32 demoVi = port_getDemoViCount(); static s32 D_80280E90; - s32 viBudget = (!func_802E4A08() && demoVi > 2) ? demoVi : 2; + s32 viBudget = (demoVi > 2) ? demoVi : 2; osSetThreadPri(NULL, 0x7f); defragManager_setPriority(DEFRAGMANAGER_THREAD_PRIORITY_HIGH); diff --git a/src/core2/demo.c b/src/core2/demo.c index 3f687c49c..c03c7dbd7 100644 --- a/src/core2/demo.c +++ b/src/core2/demo.c @@ -42,8 +42,11 @@ s32 func_80349EC0(s32 arg0){ } int demo_readInput(OSContPad* arg0, s32* arg1){ - int not_eof = D_803860D8 < D_803860DC; - DemoInput *input_ptr = not_eof ? &D_803860D0[D_803860D8++] : &D_80371EF0; + s32 idx = D_803860D8; + int not_eof = (idx + 1) < D_803860DC; + DemoInput *input_ptr = not_eof ? &D_803860D0[idx] : &D_80371EF0; + if (idx < D_803860DC) + D_803860D8 = idx + 1; #if 0 DemoInput *input_ptr = &D_803860D0[D_803860D8++]; int not_eof = D_803860D8 < D_803860DC; diff --git a/src/core2/frame/auxbuffer.c b/src/core2/frame/auxbuffer.c index aa62a9546..2578da188 100644 --- a/src/core2/frame/auxbuffer.c +++ b/src/core2/frame/auxbuffer.c @@ -4,27 +4,11 @@ #include "functions.h" #include "variables.h" -// [port] GPU-side aux framebuffer for the picture box -int gfx_create_framebuffer(unsigned int width, unsigned int height, unsigned int native_width, - unsigned int native_height, unsigned char resize, bool force_fixed_aspect); - -#include "port/Patches/Patches.h" - -s32 sAuxGpuFbId = -1; - -// [port] Renderer call; runs on the render thread under thread5 mode. -static void __auxbuffer_createGpuFb(void* arg); - #define TILE_SIZE 32 #define TILE_COUNT_X 5 #define TILE_COUNT_Y 4 #define IMAGE_WIDTH (TILE_SIZE * TILE_COUNT_X) #define IMAGE_HEIGHT (TILE_SIZE * TILE_COUNT_Y) - -static void __auxbuffer_createGpuFb(void* arg) { - (void)arg; - sAuxGpuFbId = gfx_create_framebuffer(IMAGE_WIDTH, IMAGE_HEIGHT, IMAGE_WIDTH, IMAGE_HEIGHT, 0, 0); -} #define SCREEN_WIDTH 292 #define SCREEN_HEIGHT 216 #define HORIZONTAL_MARGIN (((SCREEN_WIDTH) - IMAGE_WIDTH) / 2) @@ -72,9 +56,6 @@ void picturebox_init(void) { sPictureBoxColorBuffer++; } } - if (sAuxGpuFbId < 0) { - port_runOnRenderThread(__auxbuffer_createGpuFb, NULL); - } } void picturebox_free(void) { diff --git a/src/core2/gameloop.c b/src/core2/gameloop.c index 8d3fcdc3b..0b3f74e4b 100644 --- a/src/core2/gameloop.c +++ b/src/core2/gameloop.c @@ -288,6 +288,7 @@ void func_802E3E7C(enum game_mode_e mode){ s32 sp28; s32 prev_mode; s32 prev_map; + s32 outgoing_mode = D_8037E8E0.game_mode; // [port] game_setMode below overwrites it core1_15B30_sendMesg3ToRenderThread(); sp34 = D_8037E8E0.unk18; @@ -297,13 +298,16 @@ void func_802E3E7C(enum game_mode_e mode){ prev_mode = D_8037E8E0.unk0; game_setMode(GAME_MODE_2_UNKNOWN, 0); if(!volatileFlag_getAndSet(VOLATILE_FLAG_21, 0) || map_getLevel(gsworld_getMap()) == map_getLevel(D_8037E8E0.map)){ - if(!volatileFlag_get(VOLATILE_FLAG_1F_IN_CHARACTER_PARADE)) + if(!volatileFlag_get(VOLATILE_FLAG_1F_IN_CHARACTER_PARADE) + && EventSystem_Should(VB_MAP_SAVESTATE_USE, true, outgoing_mode)) mapSavestate_save(gsworld_getMap()); } func_802E398C(1); prev_map = gsworld_getMap(); func_802E38E8(map, sp28, sp34); - mapSavestate_apply(map); + if(EventSystem_Should(VB_MAP_SAVESTATE_USE, true, mode)){ + mapSavestate_apply(map); + } D_8037E8E0.unk0 = prev_mode; game_setMode(mode, sp30); jiggylist_map_actors(); @@ -557,6 +561,7 @@ bool func_802E4424(void) { return false; case 7: /* switch 1 */ + port_beginDemoAudioHold(); func_8034B8C0(D_8037E8E0.map, D_8037E8E0.exit); func_802E3E7C(GAME_MODE_8_BOTTLES_BONUS); return false; diff --git a/src/core2/gamestate.c b/src/core2/gamestate.c index 4baef7311..b8534231b 100644 --- a/src/core2/gamestate.c +++ b/src/core2/gamestate.c @@ -30,7 +30,12 @@ bool func_80347A4C(void); /* .code */ void func_80345EB0(enum item_e item){ if(func_802FAFE8(item)){ - item_adjustByDiffWithHud(item, (s32)(-time_getDelta()*(float)(FRAMERATE) * 1.1)); + // [port] Pin the Bottles Bonus hourglass for timer consistency + f32 dt = time_getDelta(); + if(item == ITEM_0_HOURGLASS_TIMER && getGameMode() == GAME_MODE_8_BOTTLES_BONUS){ + dt = 1.0f / 30.0f; + } + item_adjustByDiffWithHud(item, (s32)(-dt*(float)(FRAMERATE) * 1.1)); }else{ code_73640_printItemCount(item); } diff --git a/src/core2/gc/pictureframe.c b/src/core2/gc/pictureframe.c index 57a7486c3..4697b14a5 100644 --- a/src/core2/gc/pictureframe.c +++ b/src/core2/gc/pictureframe.c @@ -35,7 +35,6 @@ Actor *func_802DF160(Gfx **gfx, Mtx **mtx, Vtx **vtx) { sp38 = picturebox_getColorBuffer(); modelRender_setDepthMode(MODEL_RENDER_DEPTH_FULL); gDPSetTextureFilter((*gfx)++, G_TF_BILERP); - port_readAuxFbToCpu(gfx); gSPSegment((*gfx)++, 0x04, osVirtualToPhysical(sp38)); modelRender_setPreDrawCallback((model_render_pre_draw_callback_f)actor_predrawMethod, (void *)this); modelRender_setPostDrawCallback((model_render_post_draw_callback_f)actor_postdrawMethod, (void *)D_8037E000); diff --git a/src/core2/gc/zoombox.c b/src/core2/gc/zoombox.c index 114913a89..6a59d9769 100644 --- a/src/core2/gc/zoombox.c +++ b/src/core2/gc/zoombox.c @@ -614,7 +614,9 @@ void func_8031594C(GcZoombox * this, u8 *str, s32 arg2, s32 arg3){ s1 = 0; f22 = (this->portrait_id == ZOOMBOX_SPRITE_5F_TOOTY_4) ? 0.4 : 0.8; - if(getGameMode() == GAME_MODE_9_BANJO_AND_KAZOOIE){ + // [port] The zoombox draws from the shared gameplay RNG, and these two calls are a + // save/restore of the whole state around that. + if(func_802E4A08()){ sfx_rand_sync_to_rand(); } for(s2 = arg2; s2 <= arg3; s2++){ @@ -667,7 +669,7 @@ void func_8031594C(GcZoombox * this, u8 *str, s32 arg2, s32 arg3){ }//L80315B6C this->unk189 = s1; this->unk187 = 0; - if(getGameMode() == GAME_MODE_9_BANJO_AND_KAZOOIE){ + if(func_802E4A08()){ rand_sync_to_sfx_rand(); } } @@ -995,7 +997,7 @@ void gczoombox_draw(GcZoombox *this, Gfx **gdl, Mtx ** mptr, void *vptr){ if(!this) return; - if(getGameMode() == GAME_MODE_9_BANJO_AND_KAZOOIE) + if(func_802E4A08()) sfx_rand_sync_to_rand(); //L80316BCC // [port] Stable scope. The crossfade branch below toggles 1↔2 sprite @@ -1046,7 +1048,7 @@ void gczoombox_draw(GcZoombox *this, Gfx **gdl, Mtx ** mptr, void *vptr){ } }//L80316DD8 FrameInterpolation_RecordCloseChild(); - if(getGameMode() == GAME_MODE_9_BANJO_AND_KAZOOIE){ + if(func_802E4A08()){ rand_sync_to_sfx_rand(); } @@ -1401,9 +1403,14 @@ void __gczoombox_load_sfx(GcZoombox *this, GcZoomboxSprite portrait_id){ } //L80317E48 } + // [port] Balanced bracket. Vanilla restores below without a matching save, + // which rewinds the shared stream to whenever the last snapshot was taken; + // taking one here means the restore only undoes this randi2. + if(func_802E4A08()){ + sfx_rand_sync_to_rand(); + } this->prev_sfx = randi2(0,this->sfx_count); - // [port] This mode needs a rand sync like many other places - if(getGameMode() == GAME_MODE_9_BANJO_AND_KAZOOIE){ + if(func_802E4A08()){ rand_sync_to_sfx_rand(); } } diff --git a/src/core2/mumboshandwithpicture.c b/src/core2/mumboshandwithpicture.c index 7a6f3bb94..5c4b044fe 100644 --- a/src/core2/mumboshandwithpicture.c +++ b/src/core2/mumboshandwithpicture.c @@ -69,7 +69,6 @@ Actor *chMumbosHandWithPicture_draw(ActorMarker *marker, Gfx **gfx, Mtx **mtx, V modelRender_draw(gfx, mtx, sp58, NULL, 1.0f, sp4C, D_8037DFE8); gDPSetColorDither((*gfx)++, G_CD_DISABLE); depthbuffer_clear(gfx); - port_readAuxFbToCpu(gfx); gDPSetTextureFilter((*gfx)++, G_TF_BILERP); gSPSegment((*gfx)++, 0x04, osVirtualToPhysical(sp48)); modelRender_setPreDrawCallback((model_render_pre_draw_callback_f)actor_predrawMethod, (void *)this); diff --git a/src/port/Controller/ControlSchemes.cpp b/src/port/Controller/ControlSchemes.cpp index dbe2a2ecf..53639908a 100644 --- a/src/port/Controller/ControlSchemes.cpp +++ b/src/port/Controller/ControlSchemes.cpp @@ -31,6 +31,7 @@ extern "C" { #include "enums.h" int bs_getState(void); int bsbtrot_inSet(int state); // nonzero if `state` is one of the Talon Trot states +s32 getGameMode(void); } using namespace Ship; @@ -130,6 +131,8 @@ void ControlSchemes_Apply(int scheme) { ClearButtonSDL(controller, BTN_CUP); BindButton(controller, BTN_CUP, SDL_CONTROLLER_BUTTON_Y); BindButton(controller, BTN_CDOWN, SDL_CONTROLLER_BUTTON_B); + BindAxisToButton(controller, BTN_CLEFT, SDL_CONTROLLER_AXIS_RIGHTX, -1); + BindAxisToButton(controller, BTN_CRIGHT, SDL_CONTROLLER_AXIS_RIGHTX, 1); // Recenter camera ClearButtonSDL(controller, BTN_R); @@ -228,50 +231,21 @@ extern "C" void port_shapeControllerInput(void* contPad) { pad->button &= ~BTN_CDOWN; } - // Read the raw right stick straight from SDL - int32_t sdlX = 0; - int32_t sdlY = 0; - { - auto ctx = Ship::Context::GetRawInstance(); - auto controlDeck = ctx != nullptr ? ctx->GetControlDeck() : nullptr; - auto deviceManager = controlDeck != nullptr ? controlDeck->GetConnectedPhysicalDeviceManager() : nullptr; - if (deviceManager != nullptr) { - for (auto& [instanceId, gamepad] : deviceManager->GetConnectedSDLGamepadsForPort(0)) { - if (gamepad == nullptr) { - continue; - } - int32_t x = SDL_GameControllerGetAxis(gamepad, SDL_CONTROLLER_AXIS_RIGHTX); - int32_t y = SDL_GameControllerGetAxis(gamepad, SDL_CONTROLLER_AXIS_RIGHTY); - if ((x < 0 ? -x : x) > (sdlX < 0 ? -sdlX : sdlX)) { - sdlX = x; - } - if ((y < 0 ? -y : y) > (sdlY < 0 ? -sdlY : sdlY)) { - sdlY = y; - } - } + const s32 mode = getGameMode(); + const bool picturePuzzle = (mode == GAME_MODE_8_BOTTLES_BONUS || mode == GAME_MODE_A_SNS_PICTURE); + if (!picturePuzzle) { + const uint16_t stickC = pad->button & (BTN_CLEFT | BTN_CRIGHT); + uint16_t allow = 0; + + // One action per push, so holding the stick cannot repeat Wonderwing. + static bool sStickArmed = true; + if (stickC == 0) { + sStickArmed = true; + } else if (crouched && (stickC & BTN_CRIGHT) && arx >= ary && sStickArmed) { + allow = BTN_CRIGHT; + sStickArmed = false; } - } - int32_t asx = (sdlX < 0) ? -sdlX : sdlX; - int32_t asy = (sdlY < 0) ? -sdlY : sdlY; - - // Edge press with hysteresis - static bool sStickArmed = true; - const int32_t onThreshold = 12000; - const int32_t offThreshold = 6000; - - // Standing, the camera owns the right stick - // Crouched, it yields one action - uint16_t want = 0; - if (crouched && sdlX > onThreshold && asx >= asy) { - want = BTN_CRIGHT; // stick-right -> Wonderwing - } - - if (want != 0 && sStickArmed) { - pad->button |= want; - sStickArmed = false; - } - if ((crouched ? asx : asy) < offThreshold) { - sStickArmed = true; + pad->button = (pad->button & ~(BTN_CLEFT | BTN_CRIGHT)) | allow; } } else { uint16_t axisMask = 0; diff --git a/src/port/DevTools/ThreadWatchdog.cpp b/src/port/DevTools/ThreadWatchdog.cpp index aaac15e7c..6a0bf17be 100644 --- a/src/port/DevTools/ThreadWatchdog.cpp +++ b/src/port/DevTools/ThreadWatchdog.cpp @@ -116,6 +116,10 @@ std::atomic sStalledFlags[WATCHDOG_NUM_THREADS] = {}; std::thread sWatcher; std::atomic sWatcherRun{ false }; +// Non-zero while a serviced thread is blocked on purpose. +std::atomic sExpectedStallDepth{ 0 }; +std::atomic sExpectedStallReason{ nullptr }; + std::string DescribeUnkFlag1(int32_t f) { switch (f) { case 0x04: @@ -436,6 +440,7 @@ void Watcher() { auto lastSample = Clock::now(); auto lastReport = Clock::time_point{}; bool wasStalled = false; + bool wasExpected = false; while (sWatcherRun.load(std::memory_order_relaxed)) { std::this_thread::sleep_for(kSampleEvery); @@ -445,6 +450,9 @@ void Watcher() { // this one; a stale "last beat" then isn't a stall. Rebaseline. const bool suspended = (now - lastSample) > kSampleEvery * 4; lastSample = now; + const bool expected = sExpectedStallDepth.load(std::memory_order_acquire) > 0; + const bool rebaseline = suspended || expected || wasExpected; + wasExpected = expected; bool stalled[WATCHDOG_NUM_THREADS] = {}; bool anyStalled = false; @@ -457,7 +465,7 @@ void Watcher() { } hb.started = true; } - if (cur != hb.lastCount || suspended) { + if (cur != hb.lastCount || rebaseline) { hb.lastCount = cur; hb.lastBeat = now; continue; @@ -547,3 +555,26 @@ extern "C" void ThreadWatchdog_DumpNow(void) { extern "C" int ThreadWatchdog_IsStalled(WatchdogThread id) { return sStalledFlags[id].load(std::memory_order_relaxed) ? 1 : 0; } + +extern "C" void ThreadWatchdog_BeginExpectedStall(const char* reason) { + if (sExpectedStallDepth.fetch_add(1, std::memory_order_acq_rel) == 0) { + sExpectedStallReason.store(reason, std::memory_order_relaxed); + SPDLOG_DEBUG("[Watchdog] stall reporting suppressed: {}", reason ? reason : "?"); + } +} + +extern "C" void ThreadWatchdog_EndExpectedStall(void) { + const int prev = sExpectedStallDepth.fetch_sub(1, std::memory_order_acq_rel); + if (prev <= 0) { + // Unbalanced release would leave the counter negative and suppress + // every future stall, which is worse than the false positive. + sExpectedStallDepth.store(0, std::memory_order_release); + SPDLOG_WARN("[Watchdog] ThreadWatchdog_EndExpectedStall without a matching Begin"); + return; + } + if (prev == 1) { + const char* reason = sExpectedStallReason.load(std::memory_order_relaxed); + SPDLOG_DEBUG("[Watchdog] stall reporting resumed: {}", reason ? reason : "?"); + sExpectedStallReason.store(nullptr, std::memory_order_relaxed); + } +} diff --git a/src/port/DevTools/ThreadWatchdog.h b/src/port/DevTools/ThreadWatchdog.h index 5b63da21a..62d0aec34 100644 --- a/src/port/DevTools/ThreadWatchdog.h +++ b/src/port/DevTools/ThreadWatchdog.h @@ -37,6 +37,10 @@ void ThreadWatchdog_Stop(void); // Log the pipeline state immediately, stalled or not. void ThreadWatchdog_DumpNow(void); +// Bracket a section that blocks a serviced thread on purpose. +void ThreadWatchdog_BeginExpectedStall(const char* reason); +void ThreadWatchdog_EndExpectedStall(void); + // Whether the watcher currently considers this thread stalled. The gui only // draws inside serviced frames, so the main loop uses this to keep drawing // while the tick is down instead of freezing ImGui along with it. @@ -71,6 +75,20 @@ void viMgr_getWatchdogState(ViMgrWatchdogState* out); #ifdef __cplusplus } + +namespace Lighthouse { +class ExpectedStall { + public: + explicit ExpectedStall(const char* reason) { + ThreadWatchdog_BeginExpectedStall(reason); + } + ~ExpectedStall() { + ThreadWatchdog_EndExpectedStall(); + } + ExpectedStall(const ExpectedStall&) = delete; + ExpectedStall& operator=(const ExpectedStall&) = delete; +}; +} // namespace Lighthouse #endif #endif // PORT_THREAD_WATCHDOG_H diff --git a/src/port/Enhancements/Events/Hooks/Events.h b/src/port/Enhancements/Events/Hooks/Events.h index 7a3a8b581..bb2970576 100644 --- a/src/port/Enhancements/Events/Hooks/Events.h +++ b/src/port/Enhancements/Events/Hooks/Events.h @@ -6,104 +6,109 @@ #include +// Grouped by the system that listens for them. Nothing depends on the numeric values -- +// every reference is by name at compile time and none are serialized -- so ids can be +// added to the group they belong to rather than to the end. typedef enum VBehaviorID { + // Return to Lair restoration, and the pause-menu adjustments VB_INIT_RETURN_TO_LAIR, VB_PAUSE_MENU_PORTRAIT_DEPTH, VB_ZOOMBOX_TEXT_ADJUST, // text scale (shrink pause text) + X nudge (JP kana clearance) + + // Camera behavior VB_STATIC_CAMERA_SET, VB_STATIC_CAMERA_EXIT, VB_CAMERA_LIVE_ASPECT, VB_CAMERA_FOLLOW, - VB_GRUNTY_DEFEATED_FLAG_BOSS, - VB_PLAY_JIGGY_DANCE, - VB_PLAY_NOTEDOOR_DANCE, + + // Cutscene and celebration skips VB_PLAY_BOOT_LOGOS, VB_PLAY_INTRO_CUTSCENE, - VB_DISABLE_SNACKER, + VB_PLAY_JIGGY_DANCE, + VB_PLAY_NOTEDOOR_DANCE, + + // Vanilla bug fixes and corrections + VB_GRUNTY_DEFEATED_FLAG_BOSS, VB_VOID_OUT_GAME_OVER, - VB_SAVE_AND_EXIT, VB_CCW_GNAWTY_SPRING_ROCK, VB_CCW_FLOWER_REPLANT, VB_TERMITE_MOUND_SLOPES, VB_CLAW_SWIPE_SLIDE, VB_BOGGY_RACE_GAME_OVER, VB_JINJO_CHARGE_SOUND, - // MM Chimpy stump: gates the rumble sfx that starts when the stump begins shaking. + VB_ENEMY_BECOME_BUNDLE, + VB_YUMYUM_DROP, VB_MM_CHIMPY_STUMP_RUMBLE, VB_MM_CHIMPY_NOISE, - // Gates the sfx a spline path node plays. Args: (Actor *pathWalker). VB_SPLINE_PATH_SFX, - // Cancelling hands Mumbo's transform state to the listener. Args: (Actor *mumbo). + VB_MAP_SAVESTATE_USE, + + // Gameplay options and cheats + VB_DISABLE_SNACKER, + VB_SAVE_AND_EXIT, VB_MUMBO_HUT_TRANSFORM_CUTSCENE, - VB_YUMYUM_DROP, + + // Rando object behavior VB_OVERRIDE_BOTTLES_TEXT_CALLBACK, VB_OVERRIDE_MOLEHILL_ABILITY, VB_OVERRIDE_JIGGY_SPAWN, VB_OVERRIDE_PROP_SPAWN, VB_OVERRIDE_BUNDLE_SPAWN, + VB_BUNDLE_SPAWN_SET_ACTOR_DATA, + VB_NAPPER_SET_JIGGY_POSITION, VB_OVERRIDE_SNS_MAP_CHECK, VB_OVERRIDE_TIMED_DIALOGUE, - VB_ENEMY_BECOME_BUNDLE, VB_UPDATE_JINJO_HUD, VB_SET_JINJO_COUNT, - VB_BUNDLE_SPAWN_SET_ACTOR_DATA, - VB_NAPPER_SET_JIGGY_POSITION, + + // Dialog and localization VB_RESET_DIALOG_LANGUAGE, - // Cancellable at the single dialog choke point (gcdialog_showDialogConditional). - // Listeners receive the dialog's text_id; returning should=true suppresses the popup. VB_OVERRIDE_DIALOG_SHOW, - // Mr. Vile minigame (Anchor authority gating): cancelled on clients following a - // remote authority so local random logic yields to network state. + + // Rendering and performance + VB_CUBE_PROP_SORT, + VB_GCLIGHTS_RECOLOR, + VB_SNOW_CAMERA_ROTATION, + VB_DRAWDIST_BOX_CULL, + VB_PICTUREBOX_TARGET_FB, + + // Anchor VB_VILE_YUMBLIE_EMERGE, VB_VILE_YUMBLIE_HIDE, VB_VILE_PLAYER_EAT_PIECE, VB_VILE_GAME_UPDATE, VB_VILE_CPU_AI, - // Anchor: lets a remotely-watered CCW flower grow without local camera/fanfare/jiggy. - VB_CCW_FLOWER_REMOTE_GROW, - // Anchor: gates FP twinkly minigame start so only one client owns a run at a time. - VB_FP_TWINKLY_START, - // Anchor: true while the SM tutorial choice is still open to the local player. Checked - // when opening the intro offer (first client to reach it claims ownership) and again - // when an answer lands (a stale opt-out folds into opt-in once the choice closed). - VB_SM_TUTORIAL_CHOICE_OPEN, - // Anchor: SM ability molehills stay inert until the tutorial choice is made, so no - // tutorial sequence can start while the decision is still open. - VB_SM_MOLEHILL_ACTIVE, - // Anchor: suppresses door-open camera lock when the flag came from a teammate, not us. - VB_DOOR_OPEN_CAMERA, - // CC rings water snap on run teardown (Anchor): suppressed when a teammate finished the rings. - VB_CC_RINGS_SNAP_WATER, - // Lair door remote-open "already handled" test (Anchor). Args: (s32 doorActorId, s32 doorState). - VB_LEVELDOOR_REMOTE_OPEN_DONE, - // Romhack port gates. Cancel to override the vanilla behavior; - // args carry the site-specific data. + VB_CCW_FLOWER_REMOTE_GROW, // Lets a remotely-watered CCW flower grow without local camera/fanfare/jiggy. + VB_FP_TWINKLY_START, // Gates FP twinkly minigame start so only one client owns a run at a time. + VB_SM_TUTORIAL_CHOICE_OPEN, // True while the SM tutorial choice is still open to the local player. + VB_SM_MOLEHILL_ACTIVE, // SM ability molehills stay inert until the tutorial choice is made. + VB_DOOR_OPEN_CAMERA, // Suppresses door-open camera lock when the flag came from a teammate, not us. + VB_CC_RINGS_SNAP_WATER, // CC rings water snap on run teardown: suppressed when a teammate finished the rings. + VB_LEVELDOOR_REMOTE_OPEN_DONE, // Lair door remote-open "already handled" test. + + // Romhack port gates VB_JIGGYSCORE_LEVEL_TOTAL, VB_PAUSEMENU_LEVEL_TO_PAGE, VB_PAUSEMENU_SET_NEXT_PAGE, - VB_MAP_CHANGE_REQUEST, - VB_VOID_OUT_RESPAWN_TRANSITION, - VB_MAP_TRANSITION_IN_INDEX, - VB_CCW_SEASON_SWITCH_PRESSED_INIT, VB_PAUSEMENU_DRAW_JOYSTICKS, VB_PAUSEMENU_BOLD_FONT_TEXTURE, VB_PAUSEMENU_LEVEL_NAME_X, VB_PAUSEMENU_ROW_VISIBLE, + VB_MAP_CHANGE_REQUEST, + VB_MAP_TRANSITION_IN_INDEX, + VB_VOID_OUT_RESPAWN_TRANSITION, + VB_WARP_DISPATCH, + VB_GAMESELECT_START_NEW_GAME, VB_NOTEDOOR_DRAW_NUMBER, VB_JIGGY_COLLECT_TUTORIAL, - VB_HONEYCOMB_PUMPKIN_REQUIREMENT, + VB_HONEYCOMB_PUMPKIN_REQUIREMENT, // also read by rando + VB_BRENTILDA_HEAL_DIALOG, VB_SKY_UPDATE, VB_SKY_DRAW_BACKDROP_RECT, - VB_BRENTILDA_HEAL_DIALOG, VB_GROUND_HAZARD_ACTIVE, - VB_GAMESELECT_START_NEW_GAME, - VB_WARP_DISPATCH, + VB_CCW_SEASON_SWITCH_PRESSED_INIT, VB_XMAS_TREE_ICE_UPDATE, VB_BOGGY_HOME_VISIBLE, - VB_CUBE_PROP_SORT, - VB_GCLIGHTS_RECOLOR, - VB_SNOW_CAMERA_ROTATION, - VB_DRAWDIST_BOX_CULL, } VBehaviorID; typedef enum DoorCameraId { diff --git a/src/port/Enhancements/Fixes/GameFixes.cpp b/src/port/Enhancements/Fixes/GameFixes.cpp index e61e80b4e..113f16768 100644 --- a/src/port/Enhancements/Fixes/GameFixes.cpp +++ b/src/port/Enhancements/Fixes/GameFixes.cpp @@ -182,6 +182,23 @@ void RegisterMumboTokenIdResolve_Init() { }); } +// Map savestates and demo playback +static bool isPlaybackMode(s32 mode) { + return (mode == GAME_MODE_5_UNKNOWN) || (mode == GAME_MODE_6_FILE_PLAYBACK) || (mode == GAME_MODE_7_ATTRACT_DEMO) || + (mode == GAME_MODE_8_BOTTLES_BONUS) || (mode == GAME_MODE_9_BANJO_AND_KAZOOIE) || + (mode == GAME_MODE_A_SNS_PICTURE); +} + +void RegisterMapSavestatePlayback_Init() { + REGISTER_VB_SHOULD(VB_MAP_SAVESTATE_USE, EVENT_PRIORITY_NORMAL, { + s32 mode = va_arg(args, s32); + if (isPlaybackMode(mode)) { + *should = false; + } + }); +} + +static RegisterShipInitFunc initMapSavestatePlaybackFunc(RegisterMapSavestatePlayback_Init); static RegisterShipInitFunc initVoidOutFunc(RegisterVoidOutGameOver_Init, { CVAR_VOID_OUT }); static RegisterShipInitFunc initFurnaceFunDialogFunc(RegisterFurnaceFunDialog_Init, { CVAR_FF_DIALOG }); static RegisterShipInitFunc initGruntyDefeatedFlagFunc(RegisterGruntyDefeatedFlag_Init, { CVAR_GRUNTY_FLAG }); diff --git a/src/port/Enhancements/Retention/NoteRetention.cpp b/src/port/Enhancements/Retention/NoteRetention.cpp index 1baf8b806..ed441c0b6 100644 --- a/src/port/Enhancements/Retention/NoteRetention.cpp +++ b/src/port/Enhancements/Retention/NoteRetention.cpp @@ -81,6 +81,9 @@ int64_t noteKey(int32_t mapId, int32_t noteIndex) { using retention::activeSlot; using retention::systemActive; +// Level whose note count is waiting to be seeded; -1 when nothing is pending. +int32_t sPendingSeedLevel = -1; + bool applyEnabled() { return CVAR_VALUE; } @@ -363,10 +366,27 @@ void RegisterNoteRetention_Init() { // Seed the level's note counter from collected notes. COND_HOOK(OnSetJiggyList, EVENT_PRIORITY_NORMAL, CVAR_VALUE, [](IEvent* event) { OnSetJiggyList* ev = (OnSetJiggyList*)event; + sPendingSeedLevel = ev->levelId; + }); + + COND_HOOK(GameFrameUpdate, EVENT_PRIORITY_NORMAL, CVAR_VALUE, [](IEvent*) { + if (sPendingSeedLevel < 0) { + return; + } + if (getGameMode() != GAME_MODE_3_NORMAL) { + // Demo or playback: drop the seed, its score state is scratch. Anything else + // (transition, pause) just waits for normal play to resume. + if (func_802E4A08()) { + sPendingSeedLevel = -1; + } + return; + } + const int32_t level = sPendingSeedLevel; + sPendingSeedLevel = -1; if (!systemActive() || !applyEnabled()) { return; } - item_adjustByDiffWithoutHud(ITEM_C_NOTE, countCollectedForLevel(ev->levelId) - item_getCount(ITEM_C_NOTE)); + item_adjustByDiffWithoutHud(ITEM_C_NOTE, countCollectedForLevel(level) - item_getCount(ITEM_C_NOTE)); }); // Seeding ITEM_C_NOTE re-triggers vanilla high-score dialogs; suppress them. diff --git a/src/port/Enhancements/Retention/Retention.cpp b/src/port/Enhancements/Retention/Retention.cpp index 59c88a3ee..0c26dfc39 100644 --- a/src/port/Enhancements/Retention/Retention.cpp +++ b/src/port/Enhancements/Retention/Retention.cpp @@ -25,15 +25,7 @@ bool systemActive() { if (slot < 0 || gameFile_saveData[slot].shipSaveData.fileType == FILE_TYPE_SAVE_RANDO) { return false; } - switch (getGameMode()) { - case GAME_MODE_7_ATTRACT_DEMO: - case GAME_MODE_8_BOTTLES_BONUS: - case GAME_MODE_9_BANJO_AND_KAZOOIE: - case GAME_MODE_A_SNS_PICTURE: - return false; - default: - return true; - } + return !func_802E4A08(); } } // namespace retention diff --git a/src/port/Enhancements/Retention/WormSync.cpp b/src/port/Enhancements/Retention/WormSync.cpp index 985530220..0515af21d 100644 --- a/src/port/Enhancements/Retention/WormSync.cpp +++ b/src/port/Enhancements/Retention/WormSync.cpp @@ -64,6 +64,10 @@ bool isCollected(int32_t slot, int32_t mapId, int32_t hash) { return sCollected.count({ slot, mapId, hash }) != 0; } +bool inDemoPlayback() { + return func_802E4A08() != 0; +} + } // namespace extern "C" void port_carriedSync_beginMapLoad(int32_t mapId) { @@ -80,14 +84,14 @@ extern "C" void port_carriedSync_register(int32_t kind, void* marker, int32_t x, int32_t mapId = (int32_t)gsworld_getMap(); int32_t hash = spawnHash(x, y, z); ObjectExtension::GetInstance().Set(marker, CarriedSpawnData(mapId, hash)); - if (isCollected(slot, mapId, hash)) { + if (!inDemoPlayback() && isCollected(slot, mapId, hash)) { *suppress = 1; } } extern "C" void port_carriedSync_onLocalCollect(int32_t kind, void* marker) { int32_t slot = slotForKind(kind); - if (slot < 0) { + if (slot < 0 || inDemoPlayback()) { return; } CarriedSpawnData* d = ObjectExtension::GetInstance().Get(marker); @@ -99,7 +103,7 @@ extern "C" void port_carriedSync_onLocalCollect(int32_t kind, void* marker) { } extern "C" void port_carriedSync_onLocalSpend(int32_t kind) { - if (slotForKind(kind) < 0) { + if (slotForKind(kind) < 0 || inDemoPlayback()) { return; } // A spend (feeding Eyrie/Nabnut) is -1 to the shared pool. diff --git a/src/port/FilePicker.cpp b/src/port/FilePicker.cpp index 8e75c09a7..438c242df 100644 --- a/src/port/FilePicker.cpp +++ b/src/port/FilePicker.cpp @@ -4,6 +4,7 @@ #include #include #include "portable-file-dialogs.h" +#include "port/DevTools/ThreadWatchdog.h" #endif namespace fs = std::filesystem; @@ -38,16 +39,19 @@ void PickFile(Ship::FileBrowserRequest request, std::function filters = ToPfdFilters(request.Filters); std::optional result; - if (request.Save) { - const std::string defaultPath = (fs::path(startDir) / request.DefaultName).string(); - std::string selection = pfd::save_file(request.Title, defaultPath, filters).result(); - if (!selection.empty()) { - result = fs::path(selection); - } - } else { - std::vector selection = pfd::open_file(request.Title, startDir, filters).result(); - if (!selection.empty()) { - result = fs::path(selection.front()); + { + Lighthouse::ExpectedStall watchdogPause("native file dialog"); + if (request.Save) { + const std::string defaultPath = (fs::path(startDir) / request.DefaultName).string(); + std::string selection = pfd::save_file(request.Title, defaultPath, filters).result(); + if (!selection.empty()) { + result = fs::path(selection); + } + } else { + std::vector selection = pfd::open_file(request.Title, startDir, filters).result(); + if (!selection.empty()) { + result = fs::path(selection.front()); + } } } if (onResult) { diff --git a/src/port/Patches/FramebufferPatches.cpp b/src/port/Patches/FramebufferPatches.cpp index 9eafbb586..3c6bc8a61 100644 --- a/src/port/Patches/FramebufferPatches.cpp +++ b/src/port/Patches/FramebufferPatches.cpp @@ -6,6 +6,8 @@ #include #include "port/Engine.h" +#include "port/Enhancements/Events/Hooks/Events.h" +#include "port/ShipInit.hpp" // From Patches.h; declared here because this file's definitions use concrete // Gfx/model types where the header declares void*. @@ -188,25 +190,63 @@ static void patchModelDL(BKModelBin* model_bin, uintptr_t seg_start, uintptr_t s #define IMAGE_WIDTH (TILE_SIZE * 5) #define IMAGE_HEIGHT (TILE_SIZE * 4) -// Aux picture FB readback (Bottles Bonus / SNS pictures) +// Aux picture FB (Bottles Bonus / SNS pictures) -extern s16* sPictureBoxColorBuffer; // aux picture CPU buffer (auxbuffer.c) -extern s32 sAuxGpuFbId; // aux picture GPU FB id (picturebuffer.c) +// Scale the framebuffer from 160x128 based on the application width -s32 port_getAuxGpuFbId(void) { - return sAuxGpuFbId; +static u16 sAuxFbDummy[1]; + +#define AUX_FB_SCALE_MAX 2 +#define AUX_FB_SCALE_STEP_WIDTH 640 + +static s32 sAuxGpuFbId = -1; +static int s_auxFbRenderW = 0; +static int s_auxFbRenderH = 0; + +static int auxFbScale(void) { + int scale = s_auxFbRenderW / AUX_FB_SCALE_STEP_WIDTH; + + if (scale > AUX_FB_SCALE_MAX) { + scale = AUX_FB_SCALE_MAX; + } + if (scale < 1) { + scale = 1; + } + return scale; +} + +static void createAuxFb(void* arg) { + (void)arg; + int scale = auxFbScale(); + int nativeW = s_auxFbRenderW / scale; + int nativeH = s_auxFbRenderH / scale; + + if (nativeW < 1) { + nativeW = 1; + } + if (nativeH < 1) { + nativeH = 1; + } + sAuxGpuFbId = gfx_create_framebuffer(IMAGE_WIDTH, IMAGE_HEIGHT, nativeW, nativeH, 1, 0); + if (sAuxGpuFbId >= 0) { + gfx_register_fb_texture(sAuxFbDummy, sAuxGpuFbId); + } } -void port_readAuxFbToCpu(Gfx** gfx) { - if (sAuxGpuFbId >= 0 && sPictureBoxColorBuffer != NULL) { - gDPReadFB((*gfx)++, sAuxGpuFbId, (u16*)sPictureBoxColorBuffer, 0, 0, IMAGE_WIDTH, IMAGE_HEIGHT, 1); - __gSPInvalidateTexCache((*gfx)++, 0); +static s32 auxGpuFbId(void) { + int w; + int h; + currentRenderSize(&w, &h); + if (sAuxGpuFbId < 0 || w != s_auxFbRenderW || h != s_auxFbRenderH) { + s_auxFbRenderW = w; + s_auxFbRenderH = h; + port_runOnRenderThread(createAuxFb, NULL); } + return sAuxGpuFbId; } // Picture model patching (Bottles Bonus / SNS pictures) -#define SEG4_TAGGED ((uintptr_t)0x04000000 | 1) #define FROM_XZ 0 #define FROM_YZ 1 @@ -236,8 +276,8 @@ void port_patchPictureModel(BKModelBin* model_bin, s32 min_xy, s32 max_xy, s32 m sPicMaxXY = max_xy; sPicMinZ = min_z; sPicMaxZ = max_z; - patchModelDL(model_bin, 0x04000000, 0x04100000, (const void*)SEG4_TAGGED, IMAGE_WIDTH, IMAGE_HEIGHT, - setPictureVertexTexcoord, G_TF_BILERP, 1); + patchModelDL(model_bin, 0x04000000, 0x04100000, sAuxFbDummy, IMAGE_WIDTH, IMAGE_HEIGHT, setPictureVertexTexcoord, + G_TF_BILERP, 1); } // Transition model patching (falling jiggy pieces) @@ -292,3 +332,16 @@ void port_patchTransitionModel(BKModelBin* model_bin) { } } // extern "C" + +void RegisterFramebufferPatches_Init() { + REGISTER_VB_SHOULD(VB_PICTUREBOX_TARGET_FB, EVENT_PRIORITY_NORMAL, { + Gfx** gdl = va_arg(args, Gfx**); + s32 auxFb = auxGpuFbId(); + if (gdl != nullptr && auxFb >= 0) { + gsSPSetFB((*gdl)++, auxFb); + } + (void)should; + }); +} + +static RegisterShipInitFunc initFramebufferPatches(RegisterFramebufferPatches_Init); diff --git a/src/port/Patches/Patches.h b/src/port/Patches/Patches.h index 3bb5a3872..51f003173 100644 --- a/src/port/Patches/Patches.h +++ b/src/port/Patches/Patches.h @@ -46,8 +46,6 @@ void port_getPauseFramebufferSize(int* w, int* h); int port_pauseConsumeRecaptureRequest(void); int port_shouldCaptureTransition(void); -int32_t port_getAuxGpuFbId(void); -void port_readAuxFbToCpu(void* gfx_ptr); void port_patchPictureModel(void* model_bin, int32_t min_xy, int32_t max_xy, int32_t min_z, int32_t max_z, uint32_t from); int32_t port_getTransitionGpuFbId(void); diff --git a/src/port/Rando/Logic/Logic.h b/src/port/Rando/Logic/Logic.h index 7f6edbe7e..609fb5ce6 100644 --- a/src/port/Rando/Logic/Logic.h +++ b/src/port/Rando/Logic/Logic.h @@ -234,7 +234,9 @@ inline bool CanOpenWorld(level_e levelId) { return true; } - int32_t puzzleCost = levelId == LEVEL_6_LAIR ? 25 : _puzzleCost(levelNum - 1); + // [port] index 9 is the Door of Grunty picture; 25 is only its vanilla cost, and a + // romhack can change it like any other. + int32_t puzzleCost = levelId == LEVEL_6_LAIR ? _puzzleCost(9) : _puzzleCost(levelNum - 1); int32_t jiggyCount = item_getCount(ITEM_E_JIGGY); if (jiggyCount >= puzzleCost) { diff --git a/src/port/Save/SaveManager.cpp b/src/port/Save/SaveManager.cpp index 839a167f5..20d8b0e03 100644 --- a/src/port/Save/SaveManager.cpp +++ b/src/port/Save/SaveManager.cpp @@ -16,6 +16,7 @@ #include "Types.h" #include "port/Rando/Logic/Logic.h" +#include "port/Romhack/RomhackConfig.h" extern "C" { #include "core1/sns.h" @@ -72,6 +73,64 @@ static void BitfieldSetNBits(uint8_t* array, int startIndex, int numBits, int va } } +struct ResolvedFlag { + int index; + int width; + int puzzle; +}; + +static int PuzzleIndexForFlag(const FlagDef& f) { + static const char* const kPuzzleFlagNames[] = { + "MM_PUZZLE_PIECES_PLACED", "TTC_PUZZLE_PIECES_PLACED", "CC_PUZZLE_PIECES_PLACED", + "BGS_PUZZLE_PIECES_PLACED", "FP_PUZZLE_PIECES_PLACED", "GV_PUZZLE_PIECES_PLACED", + "MMM_PUZZLE_PIECES_PLACED", "RBB_PUZZLE_PIECES_PLACED", "CCW_PUZZLE_PIECES_PLACED", + "DOG_PUZZLE_PIECES_PLACED", "DOUBLE_HEALTH_PUZZLE_PIECES_PLACED", + }; + if (f.name != nullptr) { + for (int i = 0; i < 11; i++) { + if (strcmp(f.name, kPuzzleFlagNames[i]) == 0) { + return i; + } + } + } + return -1; +} + +static ResolvedFlag ResolveFlag(const FlagDef& f) { + const int puzzle = PuzzleIndexForFlag(f); + if (puzzle < 0) { + return { f.bitIndex, f.bitWidth, -1 }; + } + + const int index = port_getRomhackJiggyPuzzleFlag(puzzle); + const int width = port_getRomhackJiggyPuzzleSize(puzzle); + if (index < 0 || width < 0) { + return { f.bitIndex, f.bitWidth, puzzle }; // no override, vanilla placement + } + // A malformed override would put the counter on top of unrelated progress flags. + // The vanilla counters tile 0x5D-0x81 exactly, and 0x82 is the next flag along. + if (width == 0 || index < 0x5D || index + width - 1 > 0x81) { + SPDLOG_WARN("[SaveManager] {} declares an out-of-range puzzle layout (offset {:#x}, {} bits); " + "falling back to the vanilla placement", + f.name, index, width); + return { f.bitIndex, f.bitWidth, puzzle }; + } + return { index, width, puzzle }; +} + +// A picture's cost can shrink when a romhack ships a revised aGameConfig, which leaves an +// existing save reporting more pieces placed than the picture now has slots. The podium +// picks its occupied slots by rejection sampling, which never terminates once every slot +// is taken, so pin the counter to what the current table can represent on the way in. +static uint32_t ClampPuzzleCount(int puzzle, uint32_t value, const char* name) { + const int cost = _puzzleCost(puzzle); + if (cost >= 0 && value > static_cast(cost)) { + SPDLOG_WARN("[SaveManager] {} is {} but the picture only has {} slots; clamping", name, value, cost); + return static_cast(cost); + } + return value; +} + void RandoSaveCheck_to_json(nlohmann::json& j, const RandoSaveCheck& randoSaveCheck) { j = nlohmann::json::array({ randoSaveCheck.randoCheckId, randoSaveCheck.randoItemId, randoSaveCheck.shuffledCheckId, randoSaveCheck.randoCollectionId, randoSaveCheck.isShuffled, randoSaveCheck.obtained, @@ -161,10 +220,11 @@ ordered_json Convert_SaveDataToJSON(SaveData* saveData, int32_t fileNum) { if (f.world != nullptr) { continue; } - if (f.bitWidth == 1) { - general[f.name] = BitfieldGetBit(progressFlags, f.bitIndex); + const ResolvedFlag r = ResolveFlag(f); + if (r.width == 1) { + general[f.name] = BitfieldGetBit(progressFlags, r.index); } else { - general[f.name] = BitfieldGetNBits(progressFlags, f.bitIndex, f.bitWidth); + general[f.name] = BitfieldGetNBits(progressFlags, r.index, r.width); } } j["progress"] = general; @@ -176,10 +236,11 @@ ordered_json Convert_SaveDataToJSON(SaveData* saveData, int32_t fileNum) { if (f.world == nullptr || strcmp(f.world, "CHEATS") != 0) { continue; } - if (f.bitWidth == 1) { - cheats[f.name] = BitfieldGetBit(progressFlags, f.bitIndex); + const ResolvedFlag r = ResolveFlag(f); + if (r.width == 1) { + cheats[f.name] = BitfieldGetBit(progressFlags, r.index); } else { - cheats[f.name] = BitfieldGetNBits(progressFlags, f.bitIndex, f.bitWidth); + cheats[f.name] = BitfieldGetNBits(progressFlags, r.index, r.width); } } j["cheats"] = cheats; @@ -264,10 +325,11 @@ ordered_json Convert_SaveDataToJSON(SaveData* saveData, int32_t fileNum) { if (f.world == nullptr || strcmp(f.world, wd.name) != 0) { continue; } - if (f.bitWidth == 1) { - worldProgress[f.name] = BitfieldGetBit(progressFlags, f.bitIndex); + const ResolvedFlag r = ResolveFlag(f); + if (r.width == 1) { + worldProgress[f.name] = BitfieldGetBit(progressFlags, r.index); } else { - worldProgress[f.name] = BitfieldGetNBits(progressFlags, f.bitIndex, f.bitWidth); + worldProgress[f.name] = BitfieldGetNBits(progressFlags, r.index, r.width); } } if (!worldProgress.empty()) { @@ -418,11 +480,15 @@ SaveData* Convert_JSONToSaveData(int32_t fileNum) { if (generalProgress.contains(f.name)) { uint32_t value = generalProgress[f.name].get(); + const ResolvedFlag r = ResolveFlag(f); + if (r.puzzle >= 0) { + value = ClampPuzzleCount(r.puzzle, value, f.name); + } - if (f.bitWidth == 1) { - BitfieldSetBit(progressFlags, f.bitIndex, value != 0); + if (r.width == 1) { + BitfieldSetBit(progressFlags, r.index, value != 0); } else { - BitfieldSetNBits(progressFlags, f.bitIndex, f.bitWidth, value); + BitfieldSetNBits(progressFlags, r.index, r.width, value); } } } @@ -439,13 +505,14 @@ SaveData* Convert_JSONToSaveData(int32_t fileNum) { if (cheats.contains(f.name)) { uint32_t value = cheats[f.name].get(); + const ResolvedFlag r = ResolveFlag(f); - if (f.bitWidth == 1) { + if (r.width == 1) { // Set single bit (0 or 1) - BitfieldSetBit(progressFlags, f.bitIndex, value != 0); + BitfieldSetBit(progressFlags, r.index, value != 0); } else { // Set multiple bits for specific cheat values - BitfieldSetNBits(progressFlags, f.bitIndex, f.bitWidth, value); + BitfieldSetNBits(progressFlags, r.index, r.width, value); } } } @@ -533,10 +600,14 @@ SaveData* Convert_JSONToSaveData(int32_t fileNum) { if (f.world != nullptr && strcmp(f.world, wd.name) == 0) { if (src.contains(f.name)) { uint32_t val = src[f.name].get(); - if (f.bitWidth == 1) - BitfieldSetBit(progressFlags, f.bitIndex, val != 0); + const ResolvedFlag r = ResolveFlag(f); + if (r.puzzle >= 0) { + val = ClampPuzzleCount(r.puzzle, val, f.name); + } + if (r.width == 1) + BitfieldSetBit(progressFlags, r.index, val != 0); else - BitfieldSetNBits(progressFlags, f.bitIndex, f.bitWidth, val); + BitfieldSetNBits(progressFlags, r.index, r.width, val); } } } diff --git a/src/port/ShipUtils.cpp b/src/port/ShipUtils.cpp index a9ee2e27d..5569a5b1f 100644 --- a/src/port/ShipUtils.cpp +++ b/src/port/ShipUtils.cpp @@ -319,9 +319,9 @@ float port_getRumbleScale(void) { } // extern "C" std::vector worldOpenFlags = { - FILEPROG_5D_MM_PUZZLE_PIECES_PLACED, FILEPROG_5E_TTC_PUZZLE_PIECES_PLACED, FILEPROG_60_CC_PUZZLE_PIECES_PLACED, - FILEPROG_63_BGS_PUZZLE_PIECES_PLACED, FILEPROG_66_FP_PUZZLE_PIECES_PLACED, FILEPROG_6A_GV_PUZZLE_PIECES_PLACED, - FILEPROG_6E_MMM_PUZZLE_PIECES_PLACED, FILEPROG_72_RBB_PUZZLE_PIECES_PLACED, FILEPROG_76_CCW_PUZZLE_PIECES_PLACED, + FILEPROG_31_MM_OPEN, FILEPROG_32_TTC_OPEN, FILEPROG_33_CC_OPEN, + FILEPROG_34_BGS_OPEN, FILEPROG_35_FP_OPEN, FILEPROG_36_GV_OPEN, + FILEPROG_37_MMM_OPEN, FILEPROG_38_RBB_OPEN, FILEPROG_39_CCW_OPEN, }; std::vector levelAbbreviations = { From d562d2c8ab95ad026657b4fd004052f58e962823 Mon Sep 17 00:00:00 2001 From: Malkierian Date: Fri, 31 Jul 2026 11:04:28 -0700 Subject: [PATCH 053/131] Bump Split Rock Alfa (#294) * Restore event call in `chmole_learnedAllSpiralMountainAbilities` * Bump version to 1.0.0 and name Split Rock. * Final pre-release clang. --- CMakeLists.txt | 4 ++-- src/port/DevTools/ThreadWatchdog.h | 2 +- src/port/Save/SaveManager.cpp | 15 +++++++++++---- src/port/ShipUtils.cpp | 5 ++--- 4 files changed, 16 insertions(+), 10 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index fd4aa5d33..ba98a0bc2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 3.26.0 FATAL_ERROR) set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>") # Set the project version and language -project(Lighthouse VERSION 0.0.1 LANGUAGES C CXX ASM) +project(Lighthouse VERSION 1.0.0 LANGUAGES C CXX ASM) include(FetchContent) include(cmake/lighthouse-cvars.cmake) @@ -28,7 +28,7 @@ math(EXPR PATCH_INDEX "${PROJECT_VERSION_PATCH}") # Use the patch number to select the correct word list(GET NATO_PHONETIC_ALPHABET ${PATCH_INDEX} PROJECT_PATCH_WORD) -set(PROJECT_BUILD_NAME "Barnard ${PROJECT_PATCH_WORD}" CACHE STRING "" FORCE) +set(PROJECT_BUILD_NAME "Split Rock ${PROJECT_PATCH_WORD}" CACHE STRING "" FORCE) #set(PROJECT_TEAM "SonicDcer & Lywx" CACHE STRING "" FORCE) # Get Git Information diff --git a/src/port/DevTools/ThreadWatchdog.h b/src/port/DevTools/ThreadWatchdog.h index 62d0aec34..35a644985 100644 --- a/src/port/DevTools/ThreadWatchdog.h +++ b/src/port/DevTools/ThreadWatchdog.h @@ -78,7 +78,7 @@ void viMgr_getWatchdogState(ViMgrWatchdogState* out); namespace Lighthouse { class ExpectedStall { - public: +public: explicit ExpectedStall(const char* reason) { ThreadWatchdog_BeginExpectedStall(reason); } diff --git a/src/port/Save/SaveManager.cpp b/src/port/Save/SaveManager.cpp index 20d8b0e03..5db6092b6 100644 --- a/src/port/Save/SaveManager.cpp +++ b/src/port/Save/SaveManager.cpp @@ -81,10 +81,17 @@ struct ResolvedFlag { static int PuzzleIndexForFlag(const FlagDef& f) { static const char* const kPuzzleFlagNames[] = { - "MM_PUZZLE_PIECES_PLACED", "TTC_PUZZLE_PIECES_PLACED", "CC_PUZZLE_PIECES_PLACED", - "BGS_PUZZLE_PIECES_PLACED", "FP_PUZZLE_PIECES_PLACED", "GV_PUZZLE_PIECES_PLACED", - "MMM_PUZZLE_PIECES_PLACED", "RBB_PUZZLE_PIECES_PLACED", "CCW_PUZZLE_PIECES_PLACED", - "DOG_PUZZLE_PIECES_PLACED", "DOUBLE_HEALTH_PUZZLE_PIECES_PLACED", + "MM_PUZZLE_PIECES_PLACED", + "TTC_PUZZLE_PIECES_PLACED", + "CC_PUZZLE_PIECES_PLACED", + "BGS_PUZZLE_PIECES_PLACED", + "FP_PUZZLE_PIECES_PLACED", + "GV_PUZZLE_PIECES_PLACED", + "MMM_PUZZLE_PIECES_PLACED", + "RBB_PUZZLE_PIECES_PLACED", + "CCW_PUZZLE_PIECES_PLACED", + "DOG_PUZZLE_PIECES_PLACED", + "DOUBLE_HEALTH_PUZZLE_PIECES_PLACED", }; if (f.name != nullptr) { for (int i = 0; i < 11; i++) { diff --git a/src/port/ShipUtils.cpp b/src/port/ShipUtils.cpp index 5569a5b1f..b22bbe3cd 100644 --- a/src/port/ShipUtils.cpp +++ b/src/port/ShipUtils.cpp @@ -319,9 +319,8 @@ float port_getRumbleScale(void) { } // extern "C" std::vector worldOpenFlags = { - FILEPROG_31_MM_OPEN, FILEPROG_32_TTC_OPEN, FILEPROG_33_CC_OPEN, - FILEPROG_34_BGS_OPEN, FILEPROG_35_FP_OPEN, FILEPROG_36_GV_OPEN, - FILEPROG_37_MMM_OPEN, FILEPROG_38_RBB_OPEN, FILEPROG_39_CCW_OPEN, + FILEPROG_31_MM_OPEN, FILEPROG_32_TTC_OPEN, FILEPROG_33_CC_OPEN, FILEPROG_34_BGS_OPEN, FILEPROG_35_FP_OPEN, + FILEPROG_36_GV_OPEN, FILEPROG_37_MMM_OPEN, FILEPROG_38_RBB_OPEN, FILEPROG_39_CCW_OPEN, }; std::vector levelAbbreviations = { From 9cf197a6dfe9ee9e0b173f806a0e501578eecb48 Mon Sep 17 00:00:00 2001 From: Malkierian Date: Fri, 31 Jul 2026 12:10:26 -0700 Subject: [PATCH 054/131] Missing include. (#296) --- src/core1/audio_manager.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/core1/audio_manager.c b/src/core1/audio_manager.c index 2489cefd5..d6d669dac 100644 --- a/src/core1/audio_manager.c +++ b/src/core1/audio_manager.c @@ -8,6 +8,7 @@ #include "n_audio/PR/n_libaudio.h" //#include "PR/os_system.h" #include "port/DevTools/ThreadWatchdog.h" +#include "port/OS/OS.h" #include "port/Patches/Patches.h" #include "port/ShipUtils.h" From f491f080569ef57b1d238683af2022939c3842a6 Mon Sep 17 00:00:00 2001 From: Eblo <7004497+Eblo@users.noreply.github.com> Date: Fri, 31 Jul 2026 15:10:35 -0400 Subject: [PATCH 055/131] Use cast on StopNSwop va_arg (#295) --- src/port/Rando/ObjectBehavior/StopNSwop.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/port/Rando/ObjectBehavior/StopNSwop.cpp b/src/port/Rando/ObjectBehavior/StopNSwop.cpp index df6b232d4..335f5cdec 100644 --- a/src/port/Rando/ObjectBehavior/StopNSwop.cpp +++ b/src/port/Rando/ObjectBehavior/StopNSwop.cpp @@ -40,7 +40,7 @@ void Rando::ObjectBehavior::ModifyStopNSwopWorldBehavior(void* snsActor) { void Rando::ObjectBehavior::InitStopNSwopBehavior() { COND_VB_SHOULD(VB_OVERRIDE_SNS_MAP_CHECK, EVENT_PRIORITY_NORMAL, IS_RANDO && OPTION_ENABLED, { *should = true; }) COND_VB_SHOULD(VB_OVERRIDE_TIMED_DIALOGUE, EVENT_PRIORITY_NORMAL, IS_RANDO && OPTION_ENABLED, { - asset_e textId = va_arg(args, asset_e); + asset_e textId = (asset_e)va_arg(args, int); if (textId == ASSET_DB3_DIALOG_SNS_EGG_1_TEXT || textId == ASSET_DB5_DIALOG_ICE_KEY_TEXT || textId == ASSET_DB2_DIALOG_MUMBO_MISTAKE_2) { From 6d30df9aa9240b2da393d7a8ac1194fcbfc89156 Mon Sep 17 00:00:00 2001 From: Malkierian Date: Fri, 31 Jul 2026 13:00:29 -0700 Subject: [PATCH 056/131] Add project description --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 424325d8d..af137949f 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,7 @@ [comment]: <> (Todo: Make Dark Mode Image) # Lighthouse +Harbour Masters port of Banjo Kazooie Lead Developer: * Malkierian From d02f6fcebbd299bb8cb1bad2cc84780672b71cbb Mon Sep 17 00:00:00 2001 From: Malkierian Date: Fri, 31 Jul 2026 14:44:48 -0700 Subject: [PATCH 057/131] Fix packet bleed in global Anchor room. (#301) * Fix packet bleed in global Anchor room. * Remove certain exceptions from global exclusion. Put windows .pdb back in debug folder in the release builds. --- .github/workflows/main.yml | 2 +- src/port/Network/Anchor/Anchor.cpp | 17 +++++++++++++++++ src/port/Network/Anchor/Anchor.h | 5 +++++ 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 1b109aa19..8f0e90668 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -71,7 +71,7 @@ jobs: mkdir lighthouse-release/debug mv build/x64/Lighthouse.exe lighthouse-release/ mv build/x64/lighthouse.o2r lighthouse-release/ - mv build/x64/*.pdb lighthouse-release/ + mv build/x64/*.pdb lighthouse-release/debug/ mv README.md lighthouse-release/readme.txt mv config.yml lighthouse-release/ mv assets lighthouse-release/ diff --git a/src/port/Network/Anchor/Anchor.cpp b/src/port/Network/Anchor/Anchor.cpp index 063649fab..545ac5910 100644 --- a/src/port/Network/Anchor/Anchor.cpp +++ b/src/port/Network/Anchor/Anchor.cpp @@ -92,11 +92,22 @@ void Anchor::ProcessOutgoingPackets() { } } +bool Anchor::AllowedWithoutGameSync(const std::string& packetType) { + return packetType == HANDSHAKE || packetType == ALL_CLIENT_STATE || packetType == UPDATE_CLIENT_STATE || + packetType == UPDATE_ROOM_STATE || packetType == MAP_LOAD || packetType == PLAYER_UPDATE || + packetType == PLAYER_UPDATE_FULL || packetType == PLAYER_ANIM || packetType == PLAYER_SUBRANGE || + packetType == PLAYER_TRANSFORM || packetType == PLAYER_SFX || packetType == SERVER_MESSAGE; +} + void Anchor::SendJsonToRemote(nlohmann::json payload) { if (!isConnected) { return; } + if (!roomState.syncItemsAndFlags && !AllowedWithoutGameSync(payload.value("type", std::string()))) { + return; + } + payload["clientId"] = ownClientId; if (!payload.contains("quiet")) { SPDLOG_DEBUG("[Anchor] Queuing payload:\n{}", payload.dump()); @@ -125,6 +136,12 @@ void Anchor::OnIncomingJson(nlohmann::json payload) { std::string packetType = payload["type"].get(); + // Same rule inbound: a peer on an older build must not push world state into a room + // that isn't syncing it. + if (!roomState.syncItemsAndFlags && !AllowedWithoutGameSync(packetType)) { + return; + } + // Ignore packets from mismatched clients, except for ALL_CLIENT_STATE, UPDATE_CLIENT_STATE, and // PLAYER_UPDATE(_FULL) if (packetType != ALL_CLIENT_STATE && packetType != UPDATE_CLIENT_STATE && packetType != PLAYER_UPDATE && diff --git a/src/port/Network/Anchor/Anchor.h b/src/port/Network/Anchor/Anchor.h index 1ef0b0738..2e42709aa 100644 --- a/src/port/Network/Anchor/Anchor.h +++ b/src/port/Network/Anchor/Anchor.h @@ -208,6 +208,11 @@ class Anchor : public Network { bool IsGlobalRoom(); + // Presence/position/plumbing packets, the only ones allowed through when the room + // is not syncing game state. Anything absent is treated as world state and dropped + // at the send and receive choke points, so a new packet type is unsynced by default. + static bool AllowedWithoutGameSync(const std::string& packetType); + void AdoptRemoteCheck(s32 rc); void CheckRandoRoomCompatibility(); From f9ff0ae46c0ffc73c6bfb5638fd29ae06b1668c1 Mon Sep 17 00:00:00 2001 From: Jeod <47716344+JeodC@users.noreply.github.com> Date: Fri, 31 Jul 2026 17:45:52 -0400 Subject: [PATCH 058/131] Capture framebuffer at a slightly later time (#304) --- src/core2/gameloop.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/core2/gameloop.c b/src/core2/gameloop.c index 0b3f74e4b..d6c760406 100644 --- a/src/core2/gameloop.c +++ b/src/core2/gameloop.c @@ -132,9 +132,6 @@ void func_802E39D0(Gfx **gfx, Mtx **mtx, Vtx **vtx, s32 framebuffer_idx, bool ar CALL_EVENT(OnWorldDraw, gfx, mtx, vtx); port_mirror_endScene(); port_mirror_undoProjection(gfx, mtx); - if (port_shouldCaptureTransition()) { - port_captureTransitionFb(gfx); - } if(!arg4){ func_802E67AC(); func_802E3BD0(getActiveFramebuffer()); @@ -143,6 +140,9 @@ void func_802E39D0(Gfx **gfx, Mtx **mtx, Vtx **vtx, s32 framebuffer_idx, bool ar } if ((D_8037E8E0.game_mode == GAME_MODE_A_SNS_PICTURE) && (D_8037E8E0.unk19 != 6) && (D_8037E8E0.unk19 != 5)) { + if (port_shouldCaptureTransition()) { + port_captureTransitionFb(gfx); + } gctransition_draw(gfx, mtx, vtx); } @@ -183,6 +183,10 @@ void func_802E39D0(Gfx **gfx, Mtx **mtx, Vtx **vtx, s32 framebuffer_idx, bool ar } if ((D_8037E8E0.game_mode != GAME_MODE_A_SNS_PICTURE) || (D_8037E8E0.unk19 == 6) || (D_8037E8E0.unk19 == 5)) { + // [port] Snapshot the composed frame for the falling-jiggy piece textures. + if (port_shouldCaptureTransition()) { + port_captureTransitionFb(gfx); + } gctransition_draw(gfx, mtx, vtx); } // [port] Populate gFramebuffers from the GPU via gDPReadFB at native resolution. From dcb2c2cbc08e9a3f204d4aba6fd3b55ba7726c60 Mon Sep 17 00:00:00 2001 From: Malkierian Date: Fri, 31 Jul 2026 18:48:49 -0700 Subject: [PATCH 059/131] Fix token and jiggy total sync with Share Consumables off. (#310) --- src/port/Network/Anchor/HookHandlers.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/port/Network/Anchor/HookHandlers.cpp b/src/port/Network/Anchor/HookHandlers.cpp index ec4aa7176..525028997 100644 --- a/src/port/Network/Anchor/HookHandlers.cpp +++ b/src/port/Network/Anchor/HookHandlers.cpp @@ -142,8 +142,10 @@ bool Anchor_ScopedFlagExcluded(s32 space, s32 index) { static bool Anchor_ShouldSyncItemCount(s32 item, const RoomState& room) { switch (item) { + // Progress counters, not consumables; the caller already gates on syncItemsAndFlags. case ITEM_1C_MUMBO_TOKEN: case ITEM_26_JIGGY_TOTAL: + return true; case ITEM_D_EGGS: case ITEM_F_RED_FEATHER: case ITEM_10_GOLD_FEATHER: From d8a4fb84fbb18408304726eb022691f66d5d916a Mon Sep 17 00:00:00 2001 From: Jeod <47716344+JeodC@users.noreply.github.com> Date: Fri, 31 Jul 2026 21:49:20 -0400 Subject: [PATCH 060/131] Interpolation and shadows (#311) * Adjust interpolation for shadows when camera moves, disable shadows for music notes * Give verrtex-animated models unique animations * Interpolate vertex-animated models --- src/core2/fx/badShad.c | 4 +- src/core2/model/modelRender.c | 2 + src/port/Engine.cpp | 6 + .../Enhancements/Retention/NoteRetention.cpp | 3 + src/port/Game.cpp | 1 + src/port/Interpolation/FrameInterpolation.cpp | 192 +++++++++++++++++- src/port/Interpolation/FrameInterpolation.h | 7 + src/port/Patches/AnimVertexPatches.cpp | 54 +++++ src/port/Patches/Patches.h | 8 + 9 files changed, 270 insertions(+), 7 deletions(-) create mode 100644 src/port/Patches/AnimVertexPatches.cpp diff --git a/src/core2/fx/badShad.c b/src/core2/fx/badShad.c index c1e040137..6804b9564 100644 --- a/src/core2/fx/badShad.c +++ b/src/core2/fx/badShad.c @@ -56,9 +56,9 @@ Actor *chBadShad_draw(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx){ modelRender_setAlpha(other->alpha_124_19); sp40 = ml_map_f(this->actor_specific_1_f, 0.0f , 800.0f, 0.53f, 0.18f)*this->unk1C[1]; modelRender_setDepthMode(MODEL_RENDER_DEPTH_COMPARE); - FrameInterpolation_NoInterpolatePush(); + FrameInterpolation_CameraRelativePush(); modelRender_draw(gfx, mtx, this->position, sp44, sp40, NULL, marker_loadModelBin(marker)); - FrameInterpolation_NoInterpolatePop(); + FrameInterpolation_CameraRelativePop(); return this; } diff --git a/src/core2/model/modelRender.c b/src/core2/model/modelRender.c index 715d072c0..8618a4641 100644 --- a/src/core2/model/modelRender.c +++ b/src/core2/model/modelRender.c @@ -1289,6 +1289,8 @@ BKModelBin *modelRender_draw(Gfx **gfx, Mtx **mtx, f32 position[3], f32 rotation if(model_bin->anim_vertices_list_offset != 0 && D_8038371C != NULL){ animVerticesList_transform((BKAnimVerticesList *)((uintptr_t)modelRenderModelBin + (uintptr_t)(u32)modelRenderModelBin->anim_vertices_list_offset), modelRendervertexList, D_8038371C); + // [port] The transform just posed the model's shared vertex array. Hand this draw a private copy. + port_modelRender_snapshotAnimVertices(gfx, vtxList_getVertices(modelRendervertexList), vtxList_getVtxCount(modelRendervertexList)); } mlMtxIdent(); diff --git a/src/port/Engine.cpp b/src/port/Engine.cpp index 099dd855e..2fc07f942 100644 --- a/src/port/Engine.cpp +++ b/src/port/Engine.cpp @@ -1269,6 +1269,12 @@ void GameEngine::RunCommands(Gfx* Commands, const std::vector 1) { + FrameInterpolation_ApplyAnimVertices((float)(frameIdx + 1) / (float)frameCount); + } bool isFinalFrame = (frameIdx == frameCount - 1); if (frameCount > 1 || wndBase->IsFrameReady()) { // Sample the full CPU cost of producing this sub-frame. diff --git a/src/port/Enhancements/Retention/NoteRetention.cpp b/src/port/Enhancements/Retention/NoteRetention.cpp index ed441c0b6..5e716fcfa 100644 --- a/src/port/Enhancements/Retention/NoteRetention.cpp +++ b/src/port/Enhancements/Retention/NoteRetention.cpp @@ -291,6 +291,9 @@ void RegisterNoteRetention_Init() { pos[1] = q.pos[1]; pos[2] = q.pos[2]; Actor* note = actor_new(pos, 0, &sumusicNote, ACTOR_FLAG_UNKNOWN_21); + if (note != nullptr) { + note->unk124_6 = 0; + } ActorMarker* marker = (note != nullptr) ? note->marker : nullptr; if (marker != nullptr) { // Key on the marker (stable across the actor's life). diff --git a/src/port/Game.cpp b/src/port/Game.cpp index ad2fbde83..5e1f19218 100644 --- a/src/port/Game.cpp +++ b/src/port/Game.cpp @@ -244,6 +244,7 @@ void push_frame() { } GameEngine::Instance->StartFrame(); + port_animVtx_beginTick(); // Demo/playback modes render at native rate with no interpolation, so skip recording it. const bool recordInterpolation = GameEngine::IsInterpolationEnabled() && !func_802E4A08(); if (recordInterpolation) { diff --git a/src/port/Interpolation/FrameInterpolation.cpp b/src/port/Interpolation/FrameInterpolation.cpp index e87cf8a0a..04182693a 100644 --- a/src/port/Interpolation/FrameInterpolation.cpp +++ b/src/port/Interpolation/FrameInterpolation.cpp @@ -9,12 +9,15 @@ #include #include +#include namespace { constexpr uint64_t kFnvSeed = 0xcbf29ce484222325ULL; constexpr uint64_t kSigKindToMtx = 0x1ULL; constexpr uint64_t kSigKindSprite = 0x2ULL; +constexpr uint64_t kSigKindAnimVtx = 0x3ULL; +constexpr float kAnimVtxSnapRatio = 0.5f; constexpr float kSpriteSnapDistSq = 300.0f * 300.0f; constexpr int kRingSlots = 4; constexpr uint32_t kAmbiguousSig = UINT32_MAX; @@ -24,9 +27,18 @@ struct ToMtxData { float src[4][4]; uint64_t pathSig; bool noInterpolate; + bool camRelFixup; bool ambiguousSig; }; +struct AnimVtxData { + void* dst; + uint32_t count; + uint64_t pathSig; + bool ambiguousSig; + std::vector pos; +}; + struct SpriteDrawData { void* dst; float camRelPos[3]; @@ -54,6 +66,7 @@ struct ScopeFrame { uint64_t pathHash; uint32_t toMtxIdx; uint32_t spriteIdx; + uint32_t animVtxIdx; const char* key; uintptr_t id; }; @@ -62,8 +75,10 @@ struct FrameTree { std::vector toMtxs; std::vector projRots; std::vector sprites; + std::vector animVtxs; std::unordered_map sigToToMtx; std::unordered_map sigToSprite; + std::unordered_map sigToAnimVtx; std::vector scopeStack; float cameraPos[3] = { 0.0f, 0.0f, 0.0f }; bool hasCameraPos = false; @@ -76,8 +91,10 @@ struct FrameTree { toMtxs.clear(); projRots.clear(); sprites.clear(); + animVtxs.clear(); sigToToMtx.clear(); sigToSprite.clear(); + sigToAnimVtx.clear(); scopeStack.clear(); cameraPos[0] = cameraPos[1] = cameraPos[2] = 0.0f; hasCameraPos = false; @@ -98,11 +115,21 @@ struct PairedSprite { bool snap; }; +struct PairedAnimVtx { + uint32_t currIdx; + uint32_t prevIdx; + bool snap; +}; + struct InterpolationCache { bool built = false; bool valid = false; std::vector pairedToMtxs; std::vector pairedSprites; + std::vector pairedAnimVtxs; + std::vector camRelFixups; + float cameraDelta[3] = { 0.0f, 0.0f, 0.0f }; + bool hasCameraDelta = false; bool prevHasCameraPos = false; float prevCameraPos[3] = { 0.0f, 0.0f, 0.0f }; @@ -111,6 +138,9 @@ struct InterpolationCache { valid = false; pairedToMtxs.clear(); pairedSprites.clear(); + pairedAnimVtxs.clear(); + camRelFixups.clear(); + hasCameraDelta = false; prevHasCameraPos = false; } }; @@ -128,6 +158,7 @@ bool gRenderShould = false; bool gRecording = false; bool gShouldInterpolate = true; int gNoInterpolateDepth = 0; +int gCameraRelativeDepth = 0; std::unordered_map gIdMap; uint64_t gNextId = 1; @@ -200,9 +231,10 @@ void FrameInterpolation_StartRecord(void) { gRecord->sprites.reserve(256); gRecord->sigToToMtx.reserve(512); gRecord->sigToSprite.reserve(64); - gRecord->scopeStack.push_back({ kFnvSeed, 0, 0, "root", 0 }); + gRecord->scopeStack.push_back({ kFnvSeed, 0, 0, 0, "root", 0 }); gShouldInterpolate = true; gNoInterpolateDepth = 0; + gCameraRelativeDepth = 0; gRecording = true; } @@ -285,7 +317,7 @@ void FrameInterpolation_RecordOpenChild(const void* key, uintptr_t id) { uint64_t h = gRecord->scopeStack.back().pathHash; h = fnvMix(h, reinterpret_cast(key)); h = fnvMix(h, static_cast(id)); - gRecord->scopeStack.push_back({ h, 0, 0, static_cast(key), id }); + gRecord->scopeStack.push_back({ h, 0, 0, 0, static_cast(key), id }); } void FrameInterpolation_RecordCloseChild(void) { @@ -322,7 +354,8 @@ void FrameInterpolation_RecordMatrixToMtx(void* dst, const float src[4][4]) { d.dst = dst; std::memcpy(d.src, src, sizeof(float) * 16); d.pathSig = sig; - d.noInterpolate = (gNoInterpolateDepth > 0); + d.noInterpolate = (gNoInterpolateDepth > 0 || gCameraRelativeDepth > 0); + d.camRelFixup = (gCameraRelativeDepth > 0); d.ambiguousSig = false; recordSigCollision(gRecord->sigToToMtx, gRecord->toMtxs, sig, idx, gRecord->sigCollisions, gRecord->scopeStack); } @@ -362,6 +395,16 @@ void FrameInterpolation_NoInterpolatePop(void) { } } +void FrameInterpolation_CameraRelativePush(void) { + gCameraRelativeDepth++; +} + +void FrameInterpolation_CameraRelativePop(void) { + if (gCameraRelativeDepth > 0) { + gCameraRelativeDepth--; + } +} + void FrameInterpolation_RecordSpriteDraw(int kind, void* dst, const float camRelPos[3], const float scale[3], float camYaw, float camPitch, float spriteRoll, const float rotation[3], int mirrored) { @@ -393,6 +436,34 @@ void FrameInterpolation_RecordSpriteDraw(int kind, void* dst, const float camRel recordSigCollision(gRecord->sigToSprite, gRecord->sprites, sig, idx, gRecord->sigCollisions, gRecord->scopeStack); } +void FrameInterpolation_RecordAnimVertices(void* dst, const void* vertices, int32_t count) { + if (!gRecording || dst == nullptr || vertices == nullptr || count <= 0) { + return; + } + ScopeFrame& scope = gRecord->scopeStack.back(); + uint64_t sig = fnvMix(fnvMix(scope.pathHash, kSigKindAnimVtx), scope.animVtxIdx); + scope.animVtxIdx++; + + uint32_t idx = static_cast(gRecord->animVtxs.size()); + gRecord->animVtxs.emplace_back(); + AnimVtxData& d = gRecord->animVtxs.back(); + d.dst = dst; + d.count = static_cast(count); + d.pathSig = sig; + d.ambiguousSig = false; + d.pos.resize(static_cast(count) * 3); + + // Only ob[] moves; everything else in the Vtx (uv, colour/normal) is what + // the tick's own copy already put in dst. + const Vtx* src = static_cast(vertices); + for (int32_t i = 0; i < count; i++) { + d.pos[i * 3 + 0] = src[i].v.ob[0]; + d.pos[i * 3 + 1] = src[i].v.ob[1]; + d.pos[i * 3 + 2] = src[i].v.ob[2]; + } + recordSigCollision(gRecord->sigToAnimVtx, gRecord->animVtxs, sig, idx, gRecord->sigCollisions, gRecord->scopeStack); +} + void FrameInterpolation_DontInterpolateCamera(void) { if (gLastRecordedSlot >= 0) { gRing[gLastRecordedSlot].valid = false; @@ -460,6 +531,16 @@ void BuildInterpolationCache() { gCache.prevCameraPos[2] = gRenderPrev->cameraPos[2]; } + // Same two positions the cut heuristic below compares, so a fixup can never + // shift further than the cut threshold before Interpolate() bails outright. + gCache.hasCameraDelta = false; + if (gRenderPrev->hasCameraPos && gRenderCurr->hasCameraPos) { + for (int k = 0; k < 3; k++) { + gCache.cameraDelta[k] = gRenderCurr->cameraPos[k] - gRenderPrev->cameraPos[k]; + gCache.hasCameraDelta |= (gCache.cameraDelta[k] != 0.0f); + } + } + const std::vector& currToMtxs = gRenderCurr->toMtxs; const std::vector& prevToMtxs = gRenderPrev->toMtxs; const std::vector& currSprites = gRenderCurr->sprites; @@ -476,7 +557,17 @@ void BuildInterpolationCache() { // matrix didn't change, can simply be dropped here. for (uint32_t i = 0; i < currToMtxs.size(); i++) { const ToMtxData& c = currToMtxs[i]; - if (c.dst == nullptr || c.noInterpolate || c.ambiguousSig) { + if (c.dst == nullptr) { + continue; + } + // Camera-relative fixups skip pairing entirely. + if (c.camRelFixup) { + if (gCache.hasCameraDelta) { + gCache.camRelFixups.push_back(i); + } + continue; + } + if (c.noInterpolate || c.ambiguousSig) { continue; } auto it = prevSigMap.find(c.pathSig); @@ -521,6 +612,46 @@ void BuildInterpolationCache() { gCache.pairedSprites.push_back({ i, it->second, snap }); } + // Same pairing as the sprite path. A vertex blend can't go degenerate the way + // a matrix lerp does, but blending across an animation cut still drags the + // model through itself, so measure the jump against the model's own size. + const std::vector& currAnimVtxs = gRenderCurr->animVtxs; + const std::vector& prevAnimVtxs = gRenderPrev->animVtxs; + const std::unordered_map& prevAnimVtxMap = gRenderPrev->sigToAnimVtx; + gCache.pairedAnimVtxs.reserve(currAnimVtxs.size()); + for (uint32_t i = 0; i < currAnimVtxs.size(); i++) { + const AnimVtxData& c = currAnimVtxs[i]; + if (c.dst == nullptr || c.ambiguousSig) { + continue; + } + auto it = prevAnimVtxMap.find(c.pathSig); + if (it == prevAnimVtxMap.end() || it->second >= prevAnimVtxs.size()) { + continue; + } + const AnimVtxData& p = prevAnimVtxs[it->second]; + // A different vertex count means the sig landed on a different model. + if (p.count != c.count || p.pos.size() != c.pos.size()) { + continue; + } + if (p.pos == c.pos) { + continue; // pose held still; dst already has it + } + int32_t maxExtent = 0; + int32_t maxDelta = 0; + for (size_t k = 0; k < c.pos.size(); k++) { + int32_t a = std::abs(static_cast(c.pos[k])); + int32_t d = std::abs(static_cast(c.pos[k]) - static_cast(p.pos[k])); + if (a > maxExtent) { + maxExtent = a; + } + if (d > maxDelta) { + maxDelta = d; + } + } + bool snap = maxExtent > 0 && static_cast(maxDelta) > kAnimVtxSnapRatio * static_cast(maxExtent); + gCache.pairedAnimVtxs.push_back({ i, it->second, snap }); + } + // A tree recycled while we walked it means every index above is suspect. // Drop the pass to uninterpolated and say which slot collided. if (gRenderPrev->generation.load(std::memory_order_acquire) != prevGen || @@ -610,6 +741,46 @@ void emitSprite(const SpriteDrawData& L, std::unordered_map& replace } // namespace +void FrameInterpolation_ApplyAnimVertices(float t) { + if (!gRenderShould) { + return; + } + if (!gCache.built) { + BuildInterpolationCache(); + } + if (!gCache.valid) { + return; + } + if (gCache.prevHasCameraPos && gRenderCurr->hasCameraPos) { + float dx = gRenderCurr->cameraPos[0] - gCache.prevCameraPos[0]; + float dy = gRenderCurr->cameraPos[1] - gCache.prevCameraPos[1]; + float dz = gRenderCurr->cameraPos[2] - gCache.prevCameraPos[2]; + constexpr float kCutDistSq = 1000.0f * 1000.0f; + if (dx * dx + dy * dy + dz * dz > kCutDistSq) { + return; + } + } + + const std::vector& currAnimVtxs = gRenderCurr->animVtxs; + const std::vector& prevAnimVtxs = gRenderPrev->animVtxs; + const float w = 1.0f - t; + + for (const PairedAnimVtx& pair : gCache.pairedAnimVtxs) { + const AnimVtxData& c = currAnimVtxs[pair.currIdx]; + if (pair.snap) { + continue; // never written, so dst still holds this tick's pose + } + const AnimVtxData& p = prevAnimVtxs[pair.prevIdx]; + Vtx* dst = reinterpret_cast(c.dst); + for (uint32_t i = 0; i < c.count; i++) { + for (int k = 0; k < 3; k++) { + float blended = w * static_cast(p.pos[i * 3 + k]) + t * static_cast(c.pos[i * 3 + k]); + dst[i].v.ob[k] = static_cast(std::lrintf(blended)); + } + } + } +} + void FrameInterpolation_Interpolate(float t, std::unordered_map& replacements) { replacements.clear(); @@ -639,9 +810,20 @@ void FrameInterpolation_Interpolate(float t, std::unordered_map& rep const std::vector& prevSpritesData = gRenderPrev->sprites; const std::vector& currSpritesData = gRenderCurr->sprites; - replacements.reserve(gCache.pairedToMtxs.size() + gCache.pairedSprites.size() + gRenderCurr->projRots.size() * 3); + replacements.reserve(gCache.pairedToMtxs.size() + gCache.pairedSprites.size() + gCache.camRelFixups.size() + + gRenderCurr->projRots.size() * 3); const float w = 1.0f - t; + // Re-aim the frozen matrix at the sub-frame's camera. + for (uint32_t idx : gCache.camRelFixups) { + const ToMtxData& c = currToMtxs[idx]; + MtxF& out = replacements[reinterpret_cast(c.dst)]; + std::memcpy(out.mf, c.src, sizeof(out.mf)); + for (int k = 0; k < 3; k++) { + out.mf[3][k] += w * gCache.cameraDelta[k]; + } + } + for (const PairedToMtx& pair : gCache.pairedToMtxs) { const ToMtxData& c = currToMtxs[pair.currIdx]; const ToMtxData& p = prevToMtxs[pair.prevIdx]; diff --git a/src/port/Interpolation/FrameInterpolation.h b/src/port/Interpolation/FrameInterpolation.h index 441384ff9..d462bb3a6 100644 --- a/src/port/Interpolation/FrameInterpolation.h +++ b/src/port/Interpolation/FrameInterpolation.h @@ -66,6 +66,10 @@ void FrameInterpolation_RecordCameraPosition(const float pos[3]); void FrameInterpolation_NoInterpolatePush(void); void FrameInterpolation_NoInterpolatePop(void); +// Like NoInterpolatePush, but keeps the camera half of the transform live. +void FrameInterpolation_CameraRelativePush(void); +void FrameInterpolation_CameraRelativePop(void); + // kind matches the three sprite paths in sprite/render.c: // BILLBOARD — func_80344138. camYaw/camPitch, no spriteRoll. // BILLBOARD_ROLL — func_80344424. camYaw/camPitch + spriteRoll forward. @@ -79,6 +83,9 @@ void FrameInterpolation_RecordSpriteDraw(int kind, void* dst, const float camRel float camYaw, float camPitch, float spriteRoll, const float rotation[3], int mirrored); +void FrameInterpolation_RecordAnimVertices(void* dst, const void* vertices, int32_t count); +void FrameInterpolation_ApplyAnimVertices(float t); + // Drop the prev tree at known camera cuts (map load, camera type change). void FrameInterpolation_DontInterpolateCamera(void); diff --git a/src/port/Patches/AnimVertexPatches.cpp b/src/port/Patches/AnimVertexPatches.cpp new file mode 100644 index 000000000..87595b545 --- /dev/null +++ b/src/port/Patches/AnimVertexPatches.cpp @@ -0,0 +1,54 @@ +#include +#include +#include + +extern "C" { +#include +#include "functions.h" +#include "libultraship/libultra/gbi.h" +#include "port/Patches/Patches.h" +} + +#include "port/Interpolation/FrameInterpolation.h" + +namespace { + +// A single anim-vertex model runs 500-750 vertices. This covers roughly 20-25 +// of them on screen at once; past that a draw falls back to the shared buffer, +// which is exactly the behaviour that existed before this file. +constexpr size_t kVerticesPerSlot = 16384; +constexpr int kSlots = 2; + +Vtx* gArena[kSlots] = {}; +size_t gUsed = 0; +int gSlot = 0; +bool gWarnedExhausted = false; + +} // namespace + +extern "C" void port_animVtx_beginTick(void) { + gSlot = (gSlot + 1) % kSlots; + gUsed = 0; + if (gArena[gSlot] == nullptr) { + gArena[gSlot] = new (std::nothrow) Vtx[kVerticesPerSlot]; + } +} + +extern "C" void port_modelRender_snapshotAnimVertices(Gfx** gfx, void* vertices, int32_t count) { + if (gfx == nullptr || vertices == nullptr || count <= 0) { + return; + } + Vtx* arena = gArena[gSlot]; + if (arena == nullptr || gUsed + (size_t)count > kVerticesPerSlot) { + return; + } + + Vtx* copy = arena + gUsed; + gUsed += (size_t)count; + std::memcpy(copy, vertices, (size_t)count * sizeof(Vtx)); + + // Hand the pose to interpolation. It owns the blend from here: this buffer + // is private to this draw, so replay can rewrite it per sub-frame. + FrameInterpolation_RecordAnimVertices(copy, vertices, count); + gSPSegment((*gfx)++, 0x01, osVirtualToPhysical(copy)); +} diff --git a/src/port/Patches/Patches.h b/src/port/Patches/Patches.h index 51f003173..d2bcbb7cb 100644 --- a/src/port/Patches/Patches.h +++ b/src/port/Patches/Patches.h @@ -83,6 +83,14 @@ int port_spriteSizeCulled(float depth, float size, float baseThreshold, int disa float port_hudOrthoShift(float refX); void port_modelRenderResetTLUT(Gfx** gfx); +// Vertex-animated models (AnimVertexPatches.cpp) + +// Recycles the per-draw vertex arena; once per tick, before the display list is built. +void port_animVtx_beginTick(void); +// Copies the just-posed vertices somewhere only this draw points at, and repoints +// segment 0x01 at the copy. +void port_modelRender_snapshotAnimVertices(Gfx** gfx, void* vertices, int32_t count); + // Mirror (MirrorPatches.cpp) int port_mirror_active(void); From 796b87b93dbf42375e5f4bac4d0e5319975d6ef9 Mon Sep 17 00:00:00 2001 From: Jeod <47716344+JeodC@users.noreply.github.com> Date: Fri, 31 Jul 2026 22:00:55 -0400 Subject: [PATCH 061/131] Fix rando savestate restore crashing and duplicating junk items (#312) --- src/core2/actor_array.c | 10 ++++--- src/port/Rando/CustomObject/CustomObject.cpp | 3 ++- .../Rando/ObjectBehavior/ObjectBehavior.cpp | 26 +++++++++---------- 3 files changed, 22 insertions(+), 17 deletions(-) diff --git a/src/core2/actor_array.c b/src/core2/actor_array.c index 28a07620c..d9ac1ad71 100644 --- a/src/core2/actor_array.c +++ b/src/core2/actor_array.c @@ -1936,9 +1936,13 @@ void actors_applyFromSavestate(void *savestate_ptr, ActorListSaveState *savestat pad = savestate_actor->yaw; CALL_CANCELLABLE_EVENT(OnLoadActorSaveState, savestate_actor, sp50[0], sp50[1], sp50[2]) { temp_v0_6 = actor_spawnWithYaw_s32(savestate_actor->modelCacheIndex, &sp50, pad); - actor_copy(savestate_actor, temp_v0_6); - func_80329B68(temp_v0_6); - func_803299B4(temp_v0_6); + // [port] The spawn is nullable: the id may not be spawnable here, and a + // cancelled OnActorSpawn returns whatever the listener supplied, including NULL. + if (temp_v0_6 != NULL) { + actor_copy(savestate_actor, temp_v0_6); + func_80329B68(temp_v0_6); + func_803299B4(temp_v0_6); + } } } savestate_actor++; diff --git a/src/port/Rando/CustomObject/CustomObject.cpp b/src/port/Rando/CustomObject/CustomObject.cpp index 4196ed129..aed5bcb2a 100644 --- a/src/port/Rando/CustomObject/CustomObject.cpp +++ b/src/port/Rando/CustomObject/CustomObject.cpp @@ -213,7 +213,8 @@ void CustomObject::FlushRandoSpawnQueue() { &actorInfoMap.at(randoActorId).first, actorInfoMap.at(randoActorId).second); - if (randoSaveCheck.obtained && RANDO_SAVE_OPTIONS[RO_SPAWN_JUNK].optionValue == RO_GENERIC_ON) { + if (customActor != NULL && randoSaveCheck.obtained && + RANDO_SAVE_OPTIONS[RO_SPAWN_JUNK].optionValue == RO_GENERIC_ON) { customActor->marker->unk14_21 = true; customActor->scale = 1.0f; } diff --git a/src/port/Rando/ObjectBehavior/ObjectBehavior.cpp b/src/port/Rando/ObjectBehavior/ObjectBehavior.cpp index 753db4c3b..0e45fed73 100644 --- a/src/port/Rando/ObjectBehavior/ObjectBehavior.cpp +++ b/src/port/Rando/ObjectBehavior/ObjectBehavior.cpp @@ -16,7 +16,6 @@ extern "C" { extern ActorArray* suBaddieActorArray; } -bool isSaveState = false; std::map> randoSaveState; // clang-format off @@ -89,12 +88,10 @@ bool IsActorWhitelisted(int32_t actorId) { } } - if (!isSaveState) { - if (CVarGetInteger(Rando::StaticData::Options[RO_SPAWN_JUNK].cvar, 0) == RO_GENERIC_ON) { - for (auto& junk : junkItemList) { - if (junk == actorId) { - return true; - } + if (CVarGetInteger(Rando::StaticData::Options[RO_SPAWN_JUNK].cvar, 0) == RO_GENERIC_ON) { + for (auto& junk : junkItemList) { + if (junk == actorId) { + return true; } } } @@ -316,11 +313,10 @@ void Rando::ObjectBehavior::Init() { COND_HOOK(OnLoadActorSaveState, EVENT_PRIORITY_NORMAL, IS_RANDO, [](IEvent* event) { OnLoadActorSaveState* ev = (OnLoadActorSaveState*)event; - // Junk doesn't count as rando-managed while restoring; only real checks do. - isSaveState = true; - bool randoManaged = IsActorWhitelisted((actor_e)ev->actor->modelCacheIndex); - isSaveState = false; - if (!randoManaged) { + // Decide up front whether this restore is ours: anything we don't manage falls + // through to the vanilla restore untouched. The predicate has to be the same one + // the save side recorded under, junk included. + if (!IsActorWhitelisted((actor_e)ev->actor->modelCacheIndex)) { return; } @@ -346,12 +342,16 @@ void Rando::ObjectBehavior::Init() { return; } + // The check already has a live actor. Restoring would stack a second one on + // top of it, so drop the restore entirely. if (CustomObject::CheckSpawnedIdList(randoCheckId)) { event->Cancelled = true; return; } - Actor* randoCustomActor = CustomObject::ShouldCreateCustomActorEX(randoCheckId, position, false, ev->actor); + // refActor keeps an obtained check restoring the junk actor it was saved as + // instead of rolling a fresh one. + CustomObject::ShouldCreateCustomActorEX(randoCheckId, position, false, ev->actor); randoSaveState.erase(randoCheckId); event->Cancelled = true; }) From 4423e0c1a10e70c42301bce2a5fb969964cf3537 Mon Sep 17 00:00:00 2001 From: Malkierian Date: Fri, 31 Jul 2026 19:10:27 -0700 Subject: [PATCH 062/131] Split Rock Bravo (#316) --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ba98a0bc2..7994662c1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 3.26.0 FATAL_ERROR) set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>") # Set the project version and language -project(Lighthouse VERSION 1.0.0 LANGUAGES C CXX ASM) +project(Lighthouse VERSION 1.0.1 LANGUAGES C CXX ASM) include(FetchContent) include(cmake/lighthouse-cvars.cmake) From e17b9ebcf1161045cec8ab435925b61082d05cbb Mon Sep 17 00:00:00 2001 From: Jeod <47716344+JeodC@users.noreply.github.com> Date: Sun, 2 Aug 2026 12:35:43 -0400 Subject: [PATCH 063/131] Anchor: fix ccw jiggy podium to be hidden for players in anchor and only perform logic when connected (#327) --- src/lair/jigsawpicture.c | 51 +++++++++++++++------ src/port/Enhancements/Events/Hooks/Events.h | 2 + src/port/Network/Anchor/HookHandlers.cpp | 4 ++ 3 files changed, 44 insertions(+), 13 deletions(-) diff --git a/src/lair/jigsawpicture.c b/src/lair/jigsawpicture.c index a58b77c37..cfb5be6ed 100644 --- a/src/lair/jigsawpicture.c +++ b/src/lair/jigsawpicture.c @@ -25,12 +25,13 @@ typedef struct { void jigsawPicture_setState(Actor *this, s32 next_state); void updateJigsawPictureActor(Actor *this); +Actor *jigsawPicture_draw(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx); static s32 sBuzzedPedestalField = 0; /* .data */ -ActorInfo JIGSAW_PICTURE_ACTOR = { 0x1EB, 0x3B7, 0x48B, 0x1, NULL, updateJigsawPictureActor, actor_update_func_80326224, actor_draw, 0, 0, 0.0f, 0}; -ActorInfo JIGSAW_PICTURE_ACTOR_2 = { 0x1EB, 0x3BC, 0x538, 0x1, NULL, updateJigsawPictureActor, actor_update_func_80326224, actor_draw, 0, 0, 0.0f, 0}; +ActorInfo JIGSAW_PICTURE_ACTOR = { 0x1EB, 0x3B7, 0x48B, 0x1, NULL, updateJigsawPictureActor, actor_update_func_80326224, jigsawPicture_draw, 0, 0, 0.0f, 0}; +ActorInfo JIGSAW_PICTURE_ACTOR_2 = { 0x1EB, 0x3BC, 0x538, 0x1, NULL, updateJigsawPictureActor, actor_update_func_80326224, jigsawPicture_draw, 0, 0, 0.0f, 0}; Struct_lair_86F0_0 D_803947F8[0xb] ={ { 1, 0x1, FILEPROG_5D_MM_PUZZLE_PIECES_PLACED}, { 2, 0x2, FILEPROG_5E_TTC_PUZZLE_PIECES_PLACED}, @@ -429,6 +430,26 @@ void addPieces(Actor *this, s32 arg1) { fileProgressFlag_set(FILEPROG_DE_USED_ALL_YOUR_PUZZLE_PIECES, 1); } +// [port] unk38_31 marks a podium that is spawned but not yet revealed by its switch (see boggy3). +Actor *jigsawPicture_draw(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx) { + Actor *this = marker_getActor(marker); + + if (this->unk38_31) return this; + + return actor_draw(marker, gfx, mtx, vtx); +} + +static void revealCcwPuzzlePodium(Actor *this) { + this->unk38_31 = false; + this->marker->propPtr->unk8_3 = true; + if (!fileProgressFlag_get(FILEPROG_54_CCW_PUZZLE_PODIUM_ACTIVE)) { + __bundle_spawnFromFirstActor(BUNDLE_20__UNKNOWN, this); + func_80324CFC(0.0f, COMUSIC_43_ENTER_LEVEL_GLITTER, 0x7FFF); + func_80324D2C(2.1f, COMUSIC_43_ENTER_LEVEL_GLITTER); + func_8030E6D4(SFX_113_PAD_APPEARS); + } +} + void updateJigsawPictureActor(Actor *this) { ActorLocal_lair_86F0 *local; s32 sp7C[6]; //buttons @@ -462,23 +483,27 @@ void updateJigsawPictureActor(Actor *this) { this->volatile_initialized = true; if (this->actorTypeSpecificField == 9) { this->unk1C[0] = 8.0f; - this->unk1C[1] = 0.0f; + if (!fileProgressFlag_get(FILEPROG_53_CCW_PUZZLE_PODIUM_SWITCH_PRESSED)) { + // [port] Anchor suppresses the despawn: a despawned podium only comes back when the + // cube re-streams, which would strand a teammate standing here when the flag arrives. + if (EventSystem_Should(VB_CCW_PODIUM_DESPAWN, true, this)) { + marker_despawn(this->marker); + } else { + this->unk38_31 = true; + this->marker->propPtr->unk8_3 = false; + } + return; + } + revealCcwPuzzlePodium(this); } } - if (this->actorTypeSpecificField == 9) { + // [port] Waiting on the switch: reveal in place the moment the flag lands, ours or a teammate's. + if (this->unk38_31) { if (!fileProgressFlag_get(FILEPROG_53_CCW_PUZZLE_PODIUM_SWITCH_PRESSED)) { return; } - if (this->unk1C[1] == 0.0f) { - this->unk1C[1] = 1.0f; - if (!fileProgressFlag_get(FILEPROG_54_CCW_PUZZLE_PODIUM_ACTIVE)) { - __bundle_spawnFromFirstActor(BUNDLE_20__UNKNOWN, this); - func_80324CFC(0.0f, COMUSIC_43_ENTER_LEVEL_GLITTER, 0x7FFF); - func_80324D2C(2.1f, COMUSIC_43_ENTER_LEVEL_GLITTER); - func_8030E6D4(SFX_113_PAD_APPEARS); - } - } + revealCcwPuzzlePodium(this); } if ((this->actorTypeSpecificField == 9) && !fileProgressFlag_get(FILEPROG_54_CCW_PUZZLE_PODIUM_ACTIVE)) { diff --git a/src/port/Enhancements/Events/Hooks/Events.h b/src/port/Enhancements/Events/Hooks/Events.h index bb2970576..5d3b4b373 100644 --- a/src/port/Enhancements/Events/Hooks/Events.h +++ b/src/port/Enhancements/Events/Hooks/Events.h @@ -85,6 +85,8 @@ typedef enum VBehaviorID { VB_DOOR_OPEN_CAMERA, // Suppresses door-open camera lock when the flag came from a teammate, not us. VB_CC_RINGS_SNAP_WATER, // CC rings water snap on run teardown: suppressed when a teammate finished the rings. VB_LEVELDOOR_REMOTE_OPEN_DONE, // Lair door remote-open "already handled" test. + VB_CCW_PODIUM_DESPAWN, // Despawn the unrevealed CCW puzzle podium: suppressed so a teammate's switch press can + // reveal it live. // Romhack port gates VB_JIGGYSCORE_LEVEL_TOTAL, diff --git a/src/port/Network/Anchor/HookHandlers.cpp b/src/port/Network/Anchor/HookHandlers.cpp index 525028997..f7dc3d47f 100644 --- a/src/port/Network/Anchor/HookHandlers.cpp +++ b/src/port/Network/Anchor/HookHandlers.cpp @@ -306,6 +306,10 @@ void Anchor::RegisterHooks() { COND_VB_SHOULD(VB_CC_RINGS_SNAP_WATER, EVENT_PRIORITY_NORMAL, isConnected, { *should = false; }); + // Vanilla despawns the CCW podium until its switch is pressed, and only rebuilds it when the cube + // re-streams. Keep the actor alive (hidden) instead, so a teammate's press reveals it in place. + COND_VB_SHOULD(VB_CCW_PODIUM_DESPAWN, EVENT_PRIORITY_NORMAL, isConnected, { *should = false; }); + // Lair door remote-open: Door of Grunty's open flag (0xE2) is already set on arrival; key off // visual state (fully open == 0x1B) instead. Other lair doors stay flag-based. COND_VB_SHOULD(VB_LEVELDOOR_REMOTE_OPEN_DONE, EVENT_PRIORITY_NORMAL, isConnected, { From 4613ef38a7f14ebcca2ca0a2743e9dbeecbb7927 Mon Sep 17 00:00:00 2001 From: Jeod <47716344+JeodC@users.noreply.github.com> Date: Sun, 2 Aug 2026 12:35:53 -0400 Subject: [PATCH 064/131] Fix starting abilities duplicating onto remaining molehills (#325) --- src/port/Rando/Logic/GlitchlessLogic.cpp | 50 ++++++++++++++++-------- 1 file changed, 33 insertions(+), 17 deletions(-) diff --git a/src/port/Rando/Logic/GlitchlessLogic.cpp b/src/port/Rando/Logic/GlitchlessLogic.cpp index 495a9df96..e93031ccc 100644 --- a/src/port/Rando/Logic/GlitchlessLogic.cpp +++ b/src/port/Rando/Logic/GlitchlessLogic.cpp @@ -381,13 +381,6 @@ void GenerateGlitchlessLogicPool(std::vector& checkPool, PlacedItemCounts placedItems = { .noteCount = 0, .jiggyCount = 0, .mumboTokenCount = 0 }; PlacedCheckObject placedCheckItems[RC_MAX] = {}; - for (auto& shuffledCheck : checkPool) { - reachableChecks[shuffledCheck].isShuffled = true; - } - for (auto& shuffledAbiity : abilityCheckPool) { - reachableChecks[shuffledAbiity].isShuffled = true; - } - if (CVarGetInteger(Rando::StaticData::Options[RO_SHUFFLE_JINJOS].cvar, 0) == RO_GENERIC_ON) { PopulateJinjoCheckIds(); } @@ -403,23 +396,46 @@ void GenerateGlitchlessLogicPool(std::vector& checkPool, reachableChecks[checkId].name = checkData.name; reachableChecks[checkId].canAccess = false; reachableChecks[checkId].isFilled = false; + reachableChecks[checkId].isShuffled = false; + } + + for (auto& shuffledCheck : checkPool) { + reachableChecks[shuffledCheck].isShuffled = true; + } + for (auto& shuffledAbiity : abilityCheckPool) { + reachableChecks[shuffledAbiity].isShuffled = true; } // Starting Initialization reachableRegions[RR_SPIRAL_MOUNTAIN_ENTRANCE].canAccess = true; Rando::Logic::GrantStartingLoadout(); for (auto& [ability, abilityInfo] : abilityLoadoutMap) { - if (CVarGetInteger(abilityInfo.second, 0)) { - RandoCheckId abilityCheck = Rando::StaticData::GetCheckByAbilityId(ability); - - auto it = std::find(abilityCheckPool.begin(), abilityCheckPool.end(), abilityCheck); - if (it != abilityCheckPool.end()) { - abilityCheckPool.erase(it); - UpdateAccessibility(RR_SPIRAL_MOUNTAIN_ENTRANCE, - reachableRegions[RR_SPIRAL_MOUNTAIN_ENTRANCE].canAccess); - continue; - } + if (!CVarGetInteger(abilityInfo.second, 0)) { + continue; } + + RandoCheckId abilityCheck = Rando::StaticData::GetCheckByAbilityId(ability); + + auto it = std::find(abilityCheckPool.begin(), abilityCheckPool.end(), abilityCheck); + if (it == abilityCheckPool.end()) { + continue; + } + + abilityCheckPool.erase(it); + + // The molehill left the pool, so it has to stop being a valid placement target as well. + reachableChecks[abilityCheck].isShuffled = false; + + // The player already owns this ability, so its item leaves the pool alongside the molehill. + auto item = std::find_if(abilityItemPool.begin(), abilityItemPool.end(), + [&](const std::tuple& abilityItem) { + return std::get<1>(abilityItem) == (int32_t)ability; + }); + if (item != abilityItemPool.end()) { + abilityItemPool.erase(item); + } + + UpdateAccessibility(RR_SPIRAL_MOUNTAIN_ENTRANCE, reachableRegions[RR_SPIRAL_MOUNTAIN_ENTRANCE].canAccess); } UpdateAccessibility(RR_SPIRAL_MOUNTAIN_ENTRANCE, reachableRegions[RR_SPIRAL_MOUNTAIN_ENTRANCE].canAccess); From 569750b9818e19afa4e78c39e61e01c7ebfded65 Mon Sep 17 00:00:00 2001 From: Jeod <47716344+JeodC@users.noreply.github.com> Date: Sun, 2 Aug 2026 12:36:04 -0400 Subject: [PATCH 065/131] Allow builders to define CPU_OPTION (#323) --- CMakeLists.txt | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7994662c1..86bebe71d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -694,10 +694,12 @@ if (CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang|AppleClang") > ) else() - if(CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64") - set(CPU_OPTION -msse2 -mfpmath=sse) - elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64") - set(CPU_OPTION -mcpu=native) + if(NOT DEFINED CPU_OPTION) + if(CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64") + set(CPU_OPTION -msse2 -mfpmath=sse) + elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64") + set(CPU_OPTION -mcpu=native) + endif() endif() target_compile_options(${PROJECT_NAME} PRIVATE From c2da3f62ad1a648c8c1a0775bf49882115f70956 Mon Sep 17 00:00:00 2001 From: Jeod <47716344+JeodC@users.noreply.github.com> Date: Sun, 2 Aug 2026 12:36:20 -0400 Subject: [PATCH 066/131] Slide all control schemes through LUS mappings proper (#322) --- src/port/Controller/ControlSchemes.cpp | 173 ++++++++++++------------- 1 file changed, 81 insertions(+), 92 deletions(-) diff --git a/src/port/Controller/ControlSchemes.cpp b/src/port/Controller/ControlSchemes.cpp index 53639908a..fc468690a 100644 --- a/src/port/Controller/ControlSchemes.cpp +++ b/src/port/Controller/ControlSchemes.cpp @@ -17,7 +17,6 @@ #include #include #include -#include #include #include #include @@ -92,20 +91,40 @@ void BindButtonToLeftStick(const std::shared_ptr& controller, Direct stick->SaveAxisDirectionMappingIdsToConfig(); } -// True if the given C-button is currently driven by a stick axis (the right -// stick), as opposed to a face button. Drives which directions the shaping pass -// regenerates from the raw right stick. -bool CButtonIsAxis(const std::shared_ptr& controller, CONTROLLERBUTTONS_T bitmask) { +// How many of a button's mappings are physically active right now. Lets a +// scheme tell one binding for a button apart from another without reaching past +// the mapper to poll hardware that the player may have unbound. +int CountActiveMappings(const std::shared_ptr& controller, CONTROLLERBUTTONS_T bitmask) { auto button = controller->GetButton(bitmask); if (button == nullptr) { - return false; + return 0; } + int active = 0; for (auto& [id, mapping] : button->GetAllButtonMappings()) { - if (dynamic_cast(mapping.get()) != nullptr) { - return true; + uint16_t held = 0; + mapping->UpdatePad(held); + if (held != 0) { + active++; + } + } + return active; +} + +// Splits a C-button's mappings into the two kinds the shaping pass cares about. +void CollectCButtonSources(const std::shared_ptr& controller, CONTROLLERBUTTONS_T bitmask, + uint16_t& axisMask, uint16_t& otherHeld) { + auto button = controller->GetButton(bitmask); + if (button == nullptr) { + return; + } + for (auto& [id, mapping] : button->GetAllButtonMappings()) { + auto axis = dynamic_cast(mapping.get()); + if (axis != nullptr && axis->AxisIsStick()) { + axisMask |= bitmask; + } else { + mapping->UpdatePad(otherHeld); } } - return false; } } // namespace @@ -180,8 +199,11 @@ void ControlSchemes_Apply(int scheme) { ClearButtonSDL(controller, BTN_CDOWN); BindButton(controller, BTN_CDOWN, SDL_CONTROLLER_BUTTON_B); - // Recenter camera + // Tip-toe / Talon Trot trigger. Recentering moves to a B hold, which + // frees R to carry Pocket's extra gesture as a real, rebindable + // binding instead of the shaping pass polling the trigger itself. ClearButtonSDL(controller, BTN_R); + BindAxisToButton(controller, BTN_R, SDL_CONTROLLER_AXIS_TRIGGERRIGHT, 1); // Crouch / Talon Trot ClearButtonSDL(controller, BTN_Z); @@ -217,10 +239,24 @@ extern "C" void port_shapeControllerInput(void* contPad) { return; } - const bool modern = CVarGetInteger(CVAR_SETTING("Controls.Scheme"), CONTROL_SCHEME_RETRO) == CONTROL_SCHEME_MODERN; + const int scheme = CVarGetInteger(CVAR_SETTING("Controls.Scheme"), CONTROL_SCHEME_RETRO); + const bool modern = (scheme == CONTROL_SCHEME_MODERN); + const bool pocket = (scheme == CONTROL_SCHEME_POCKET); const bool crouched = (bs_getState() == BS_7_CROUCH); const bool eggPooping = (bs_getState() == BS_A_EGG_ASS); + // Pocket takes its tip-toe / Talon Trot gesture from R and its crouch from + // Z, so both follow whatever the player has bound. Sample them here, before + // the blocks below start injecting synthetic R and Z bits, and consume R - + // in Pocket that button is the gesture channel, not the camera recenter. + bool pocketGesture = false; + bool pocketCrouch = false; + if (pocket) { + pocketGesture = (pad->button & BTN_R) != 0; + pocketCrouch = (pad->button & BTN_Z) != 0; + pad->button &= ~BTN_R; + } + int32_t rx = pad->right_stick_x; int32_t ry = pad->right_stick_y; int32_t arx = (rx < 0) ? -rx : rx; @@ -249,18 +285,14 @@ extern "C" void port_shapeControllerInput(void* contPad) { } } else { uint16_t axisMask = 0; - if (CButtonIsAxis(controller, BTN_CRIGHT)) { - axisMask |= BTN_CRIGHT; - } - if (CButtonIsAxis(controller, BTN_CLEFT)) { - axisMask |= BTN_CLEFT; - } - if (CButtonIsAxis(controller, BTN_CDOWN)) { - axisMask |= BTN_CDOWN; - } - if (CButtonIsAxis(controller, BTN_CUP)) { - axisMask |= BTN_CUP; + uint16_t otherHeld = 0; + static const CONTROLLERBUTTONS_T kCButtons[] = { BTN_CRIGHT, BTN_CLEFT, BTN_CDOWN, BTN_CUP }; + for (CONTROLLERBUTTONS_T cButton : kCButtons) { + CollectCButtonSources(controller, cButton, axisMask, otherHeld); } + // Directions the stick owns outright; anything a second binding is + // holding stays put instead of being cleared and regenerated. + const uint16_t clearMask = axisMask & ~otherHeld; static uint16_t sLatchDir = 0; static int32_t sLatchTTL = 0; @@ -274,11 +306,11 @@ extern "C" void port_shapeControllerInput(void* contPad) { stickBits = (ry > 0) ? BTN_CUP : BTN_CDOWN; } } - pad->button &= ~(stickBits & axisMask); + pad->button &= ~(stickBits & clearMask); sLatchDir = 0; sLatchTTL = 0; } else if (axisMask != 0) { - pad->button &= ~axisMask; + pad->button &= ~clearMask; if (arx * arx + ary * ary > 24 * 24) { uint16_t dir; @@ -318,44 +350,20 @@ extern "C" void port_shapeControllerInput(void* contPad) { } // Modern Talon Trot - static bool sPrevLeftTrigger = false; - static bool sPrevRightTrigger = false; - + // + // Crouch gets bound to both triggers, and pressing the second one while the + // first is held starts the trot. Counting how many crouch bindings are live + // expresses that without naming a trigger: whatever the player has on Z is + // what works, and a trigger they have unbound does nothing. + static int sPrevCrouchBindings = 0; if (modern) { - const Sint16 kTriggerThreshold = 8000; - bool leftTrigger = false; - bool rightTrigger = false; - - auto ctx = Ship::Context::GetRawInstance(); - auto controlDeck = ctx != nullptr ? ctx->GetControlDeck() : nullptr; - auto deviceManager = controlDeck != nullptr ? controlDeck->GetConnectedPhysicalDeviceManager() : nullptr; - if (deviceManager != nullptr) { - for (auto& [instanceId, gamepad] : deviceManager->GetConnectedSDLGamepadsForPort(0)) { - if (gamepad == nullptr) { - continue; - } - if (SDL_GameControllerGetAxis(gamepad, SDL_CONTROLLER_AXIS_TRIGGERLEFT) > kTriggerThreshold) { - leftTrigger = true; - } - if (SDL_GameControllerGetAxis(gamepad, SDL_CONTROLLER_AXIS_TRIGGERRIGHT) > kTriggerThreshold) { - rightTrigger = true; - } - } - } - - if (crouched) { - bool leftEdge = leftTrigger && !sPrevLeftTrigger; - bool rightEdge = rightTrigger && !sPrevRightTrigger; - if ((rightEdge && sPrevLeftTrigger) || (leftEdge && sPrevRightTrigger)) { - pad->button |= BTN_CLEFT; - } + const int crouchBindings = CountActiveMappings(controller, BTN_Z); + if (crouched && crouchBindings >= 2 && crouchBindings > sPrevCrouchBindings) { + pad->button |= BTN_CLEFT; } - - sPrevLeftTrigger = leftTrigger; - sPrevRightTrigger = rightTrigger; + sPrevCrouchBindings = crouchBindings; } else { - sPrevLeftTrigger = false; - sPrevRightTrigger = false; + sPrevCrouchBindings = 0; } // Toggle Trot @@ -393,8 +401,7 @@ extern "C" void port_shapeControllerInput(void* contPad) { static bool sBWasHeld = false; const int32_t kBHoldFrames = 12; // ~0.2s before a standing press counts as a hold bool bHeld = (pad->button & BTN_CDOWN) != 0; - if (CVarGetInteger(CVAR_SETTING("Controls.Scheme"), CONTROL_SCHEME_RETRO) == CONTROL_SCHEME_POCKET && !crouched && - !eggPooping) { + if (pocket && !crouched && !eggPooping) { pad->button &= ~BTN_CDOWN; if (bHeld) { if (sBHeldFrames < kBHoldFrames) { @@ -417,43 +424,25 @@ extern "C" void port_shapeControllerInput(void* contPad) { } sBWasHeld = bHeld; - // Pocket: Talon Trot (LT + RT) and tip-toe (RT) - // LT crouches. While crouched, an RT press injects C-Left to start the Talon Trot. - // RT on its own (no crouch) lightly touches the analog stick for a tip-toe. + // Pocket: Talon Trot (Z + R) and tip-toe (R) + // Z crouches. While crouched, an R press injects C-Left to start the Talon Trot. + // R on its own (no crouch) lightly touches the analog stick for a tip-toe. + // Both come off the mapped pad, so rebinding either button moves the gesture. static bool sTipToe = false; - static bool sPrevR2 = false; - if (CVarGetInteger(CVAR_SETTING("Controls.Scheme"), CONTROL_SCHEME_RETRO) == CONTROL_SCHEME_POCKET) { - bool r2 = false; - bool l2 = false; - auto ctx = Ship::Context::GetRawInstance(); - auto controlDeck = ctx != nullptr ? ctx->GetControlDeck() : nullptr; - auto deviceManager = controlDeck != nullptr ? controlDeck->GetConnectedPhysicalDeviceManager() : nullptr; - if (deviceManager != nullptr) { - for (auto& [instanceId, gamepad] : deviceManager->GetConnectedSDLGamepadsForPort(0)) { - if (gamepad == nullptr) { - continue; - } - if (SDL_GameControllerGetAxis(gamepad, SDL_CONTROLLER_AXIS_TRIGGERRIGHT) > 8000) { - r2 = true; - } - if (SDL_GameControllerGetAxis(gamepad, SDL_CONTROLLER_AXIS_TRIGGERLEFT) > 8000) { - l2 = true; - } - } - } - - if (l2) { - // Crouching: RT is the Talon Trot trigger, not tip-toe. - if (crouched && r2 && !sPrevR2) { + static bool sPrevGesture = false; + if (pocket) { + if (pocketCrouch) { + // Crouching: R is the Talon Trot trigger, not tip-toe. + if (crouched && pocketGesture && !sPrevGesture) { pad->button |= BTN_CLEFT; // C-Left while crouched starts the Talon Trot } sTipToe = false; } else if (CVarGetInteger(CVAR_SETTING("Controls.PocketTipToeHold"), 0) != 0) { - sTipToe = r2; // hold mode - } else if (r2 && !sPrevR2) { + sTipToe = pocketGesture; // hold mode + } else if (pocketGesture && !sPrevGesture) { sTipToe = !sTipToe; // tap toggles } - sPrevR2 = r2; + sPrevGesture = pocketGesture; if (sTipToe) { const float kTipToeScale = 0.25f; @@ -462,6 +451,6 @@ extern "C" void port_shapeControllerInput(void* contPad) { } } else { sTipToe = false; - sPrevR2 = false; + sPrevGesture = false; } } From cead60c11aea1ed35c919f45380f670096598d80 Mon Sep 17 00:00:00 2001 From: Malkierian Date: Sun, 2 Aug 2026 09:39:47 -0700 Subject: [PATCH 067/131] Fix default volume in new system. --- src/port/OS/OS_AI.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/port/OS/OS_AI.cpp b/src/port/OS/OS_AI.cpp index 3c4e89a99..c74047c84 100644 --- a/src/port/OS/OS_AI.cpp +++ b/src/port/OS/OS_AI.cpp @@ -33,7 +33,7 @@ extern "C" s32 osAiSetNextBuffer(void* buff, size_t len) { AudioPlayerPlayFrame(silence.data(), silence.size()); } - float masterVol = CVarGetInteger(CVAR_SETTING("Volume.Master"), 100) / 100.0f; + float masterVol = CVarGetInteger(CVAR_SETTING("Volume.Master"), 40) / 100.0f; if (masterVol >= 1.0f) { AudioPlayerPlayFrame((const uint8_t*)buff, len); return 0; From 1283dd693ddd82efdd634c9e734b14096836519a Mon Sep 17 00:00:00 2001 From: Malkierian Date: Sun, 2 Aug 2026 09:42:26 -0700 Subject: [PATCH 068/131] Fix alt assets default values. --- src/port/Engine.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/port/Engine.cpp b/src/port/Engine.cpp index 2fc07f942..29e47305b 100644 --- a/src/port/Engine.cpp +++ b/src/port/Engine.cpp @@ -1090,7 +1090,7 @@ void GameEngine::StartFrame() const { case KbScancode::LUS_KB_TAB: { // Toggle HD Assets CVarSetInteger(CVAR_SETTING("Mods.AlternateAssets"), - !CVarGetInteger(CVAR_SETTING("Mods.AlternateAssets"), 0)); + !CVarGetInteger(CVAR_SETTING("Mods.AlternateAssets"), 1)); break; } case KbScancode::LUS_KB_F4: { @@ -1298,7 +1298,7 @@ void GameEngine::RunCommands(Gfx* Commands, const std::vectormInterpolationIndex++; } - bool curAltAssets = CVarGetInteger(CVAR_SETTING("Mods.AlternateAssets"), 0); + bool curAltAssets = CVarGetInteger(CVAR_SETTING("Mods.AlternateAssets"), 1); if (prevAltAssets != curAltAssets) { prevAltAssets = curAltAssets; Ship::Context::GetRawInstance()->GetResourceManager()->SetAltAssetsEnabled(curAltAssets); From b376753ad46380c805d844a5971414e521bbf689 Mon Sep 17 00:00:00 2001 From: Jeod <47716344+JeodC@users.noreply.github.com> Date: Sun, 2 Aug 2026 13:13:39 -0400 Subject: [PATCH 069/131] Fix occlusion for stonehenge (#324) --- src/port/DevTools/OcclusionDebug.cpp | 3 +-- src/port/Patches/GeoCull.cpp | 12 +++++++++++- src/port/Patches/GeoCull.h | 4 ---- src/port/Patches/GraphicsPatches.cpp | 4 +++- 4 files changed, 15 insertions(+), 8 deletions(-) diff --git a/src/port/DevTools/OcclusionDebug.cpp b/src/port/DevTools/OcclusionDebug.cpp index 17e93e3ad..a21a8f8ff 100644 --- a/src/port/DevTools/OcclusionDebug.cpp +++ b/src/port/DevTools/OcclusionDebug.cpp @@ -41,8 +41,7 @@ const char* CmdTypeName(int type) { } } -// Each command is keyed by (model part, byte offset within the model bin). The offset is -// fixed per asset, so it never shifts when force-drawing reveals more geometry. +// Each command is keyed by (model part, byte offset within the model's geo command list). struct Key { int part; int offset; diff --git a/src/port/Patches/GeoCull.cpp b/src/port/Patches/GeoCull.cpp index 52d9e2f06..099e91a8c 100644 --- a/src/port/Patches/GeoCull.cpp +++ b/src/port/Patches/GeoCull.cpp @@ -2,6 +2,10 @@ #include "port/Enhancements/Events/Hooks/Events.h" +extern "C" { +#include "model.h" +} + static int sConsumerMask = 0; extern "C" void GeoCull_SetConsumer(int consumerBit, int active) { @@ -21,7 +25,13 @@ extern "C" int port_geoCullDraw(int type, const void* cmd, const void* modelBin, return drawnVanilla; } - int offset = (int)((const unsigned char*)cmd - (const unsigned char*)modelBin); + // Key commands by their offset within the geo command list. + const auto* bin = static_cast(modelBin); + const unsigned char* geoBase = (const unsigned char*)modelBin; + if (bin != nullptr) { + geoBase += bin->geo_list_offset; + } + int offset = (int)((const unsigned char*)cmd - geoBase); bool forceDraw = false; CALL_EVENT(OnGeoCull, type, offset, modelBin, areaIds, areaCount, detail0, detail1, drawnVanilla, &forceDraw); return (drawnVanilla || forceDraw) ? 1 : 0; diff --git a/src/port/Patches/GeoCull.h b/src/port/Patches/GeoCull.h index 93daa8cfb..f43303833 100644 --- a/src/port/Patches/GeoCull.h +++ b/src/port/Patches/GeoCull.h @@ -22,10 +22,6 @@ extern "C" { #define GEOCULL_CONSUMER_DEBUG 1 #define GEOCULL_CONSUMER_ENHANCEMENT 2 -// Called from each conditional cull command in render.c. `cmd`/`modelBin` give the command's -// stable byte offset; `drawnVanilla` is the unmodified recurse decision. areaIds/areaCount -// apply to CAMERA only (NULL/0 otherwise); detail0/detail1 are kind-specific extras (CAMERA: -// flags; LOD: min,max). Returns the final draw decision (1 = draw). int port_geoCullDraw(int type, const void* cmd, const void* modelBin, int drawnVanilla, const unsigned char* areaIds, int areaCount, int detail0, int detail1); diff --git a/src/port/Patches/GraphicsPatches.cpp b/src/port/Patches/GraphicsPatches.cpp index 01cb14cae..fcbe26fdf 100644 --- a/src/port/Patches/GraphicsPatches.cpp +++ b/src/port/Patches/GraphicsPatches.cpp @@ -114,7 +114,9 @@ static void OnGeoCull_LevelOcclusion(IEvent* event) { if (ev->type != OCCLUSION_CMD_CAMERA) { return; } - if (gsworld_getMap() == MAP_2_MM_MUMBOS_MOUNTAIN && ev->offset == 0x2CD0 && + // Offset into the opaque map model's geo command list (the "outside areas {1,2}" CAMERA + // command). Read it off the Occlusion Debugger, which reports the same geo-relative key. + if (gsworld_getMap() == MAP_2_MM_MUMBOS_MOUNTAIN && ev->offset == 0x2C98 && ev->modelBin == (const void*)mapModel_getModelBin(0)) { *ev->forceDraw = true; } From 33e13db7f17f99a2a95e309857fc9ce90bb62de7 Mon Sep 17 00:00:00 2001 From: Jeod <47716344+JeodC@users.noreply.github.com> Date: Sun, 2 Aug 2026 13:46:33 -0400 Subject: [PATCH 070/131] Uncap render fps for cutscenes and demos (#331) --- src/core2/font/print.c | 3 + src/core2/frame/rendermem.c | 5 ++ src/core2/gameloop.c | 3 + src/core2/gc/transition.c | 4 +- src/port/Engine.cpp | 41 ++++------ src/port/Game.cpp | 5 +- src/port/Interpolation/FrameInterpolation.cpp | 80 ++++++++++++++----- src/port/Patches/FramePacingPatches.cpp | 32 +++----- src/port/Patches/Patches.h | 2 +- 9 files changed, 107 insertions(+), 68 deletions(-) diff --git a/src/core2/font/print.c b/src/core2/font/print.c index 0eb3d84ff..61bf3ce4f 100644 --- a/src/core2/font/print.c +++ b/src/core2/font/print.c @@ -6,6 +6,7 @@ #include "port/Patches/Patches.h" #include "port/ResourceHelpers.h" +#include "port/Interpolation/FrameInterpolation.h" #define PRINT_JP (ResourceMgr_IsJapanese()) @@ -906,6 +907,7 @@ void printbuffer_draw(Gfx **gfx, Mtx **mtx, Vtx **vtx) { f32 _y; f32 width; + FrameInterpolation_RecordOpenChild("printbuffer", 0); gSPDisplayList((*gfx)++, D_80369238); for(print_sCurrentPtr = print_sPrintBuffer; print_sCurrentPtr < print_sPrintBuffer + 0x20; print_sCurrentPtr++){ if (print_sCurrentPtr->string != 0) { @@ -961,6 +963,7 @@ void printbuffer_draw(Gfx **gfx, Mtx **mtx, Vtx **vtx) { gDPSetTexturePersp((*gfx)++, G_TP_PERSP); gDPSetTextureFilter((*gfx)++, G_TF_BILERP); viewport_setRenderViewportAndPerspectiveMatrix(gfx, mtx); + FrameInterpolation_RecordCloseChild(); }//*/ //adds a new string to the print buffer and updates string buffer end ptr diff --git a/src/core2/frame/rendermem.c b/src/core2/frame/rendermem.c index 9be844cea..865009e91 100644 --- a/src/core2/frame/rendermem.c +++ b/src/core2/frame/rendermem.c @@ -5,6 +5,7 @@ #include "variables.h" #include "bk_time.h" +#include "port/Interpolation/FrameInterpolation.h" extern void func_8023DFF0(s32); extern void coMusicPlayer_update(void); @@ -54,13 +55,17 @@ void func_802E329C(s32 arg0, Gfx **gfx_begin, Gfx **gfx_end) { drawRectangle2D(&gfx, 0, 0, (s32) (f32) gFramebufferWidth, (s32) (f32) gFramebufferHeight, 0, 0, 0); } if ((D_8037E8C0.unk14 == 0) || (D_8037E8C0.unk14 == 3)) { + FrameInterpolation_RecordOpenChild("rendermem_bound", 0); viewport_setRenderViewportAndPerspectiveMatrix(&gfx, &mtx); gcbound_draw(&gfx); + FrameInterpolation_RecordCloseChild(); } if (D_8037E8C0.unk14 == 1) { + FrameInterpolation_RecordOpenChild("rendermem_pause", 0); drawRectangle2D(&gfx, 0, 0, (s32) (f32) gFramebufferWidth, (s32) (f32) gFramebufferHeight, 0, 0, 0); viewport_setRenderViewportAndPerspectiveMatrix(&gfx, &mtx); func_802F1858(D_8037E8C0.unk10, &gfx, &mtx, &vtx); + FrameInterpolation_RecordCloseChild(); } core1_15B30_finishDList(&gfx); graphicsCache_checkFrame(gfx_start, gfx, mtx_start, mtx, vtx_start, vtx); diff --git a/src/core2/gameloop.c b/src/core2/gameloop.c index d6c760406..139edd6a9 100644 --- a/src/core2/gameloop.c +++ b/src/core2/gameloop.c @@ -484,6 +484,9 @@ void func_802E4384(void){ } else{ func_8033DC18(); + // [port] Latch this cutscene frame's stutter before anything reads it, so the + // time delta below and the renderer's frame budget agree for the whole tick. + port_tickCutsceneStutter(); // [port] Use a fixed 2-VI timestep for normal gameplay. s32 viDivisor = viMgr_func_8024BFA0(); func_8033DC20(); // always consume wall-clock to keep last_ticks fresh diff --git a/src/core2/gc/transition.c b/src/core2/gc/transition.c index 08f0ca3ba..01408d48a 100644 --- a/src/core2/gc/transition.c +++ b/src/core2/gc/transition.c @@ -6,6 +6,7 @@ #include "gc/gctransition.h" #include "port/Patches/Patches.h" #include "port/Engine.h" +#include "port/Interpolation/FrameInterpolation.h" void anctrl_setAnimTimer(AnimCtrl*, f32); void func_8025AC20(s32, s32, s32, f32, char*, s32); @@ -253,6 +254,7 @@ void gctransition_draw(Gfx **gfx, Mtx **mtx, Vtx **vtx) { if(s_current_transition.state == 0) return; + FrameInterpolation_RecordOpenChild("transition", 0); viewport_backupState(); if(s_current_transition.anctrl != NULL){ vp_position[0] = 0.0f; @@ -377,7 +379,7 @@ void gctransition_draw(Gfx **gfx, Mtx **mtx, Vtx **vtx) { } viewport_restoreState(); viewport_setRenderViewportAndPerspectiveMatrix(gfx, mtx); - + FrameInterpolation_RecordCloseChild(); } void gctransition_8030BD4C(void){ diff --git a/src/port/Engine.cpp b/src/port/Engine.cpp index 29e47305b..7759f3d39 100644 --- a/src/port/Engine.cpp +++ b/src/port/Engine.cpp @@ -75,9 +75,6 @@ extern s32 D_80275610; bool prevAltAssets = false; // bool gEnableGammaBoost = true; -// Game mode helper -bool func_802E4A08(void); - // Soundfont ROM symbols — loaded from OTR in LoadSoundfonts() u8* soundfont1ctl_ROM_START = NULL; u8* soundfont1ctl_ROM_END = NULL; @@ -1317,21 +1314,12 @@ namespace { struct SubframePacing { int subframes; // renders to emit this tick (>= 1) int fps; // target present fps for this tick + int viPerTick; // VIs of game time this tick covers }; SubframePacing ComputeSubframePacing() { int target_fps = (int)GameEngine::Instance->GetInterpolationFPS(); - // Demo/replay modes render at the native rate - const bool replayMode = func_802E4A08(); - if (!replayMode) { - // Some music-synced cutscenes cap interpolation at native 30 - int fpsCap = port_getInterpolationFpsCap(); - if (fpsCap > 0 && target_fps > fpsCap) { - target_fps = fpsCap; - } - } - // Game-logic VI per tick: gVIsPerFrame (=2 -> 30 Hz) normally; demo // replay and cutscene stutter raise it for slow N64 frames. int viPerTick = port_getDemoViCount(); @@ -1341,6 +1329,12 @@ SubframePacing ComputeSubframePacing() { if (viPerTick < gVIsPerFrame) { viPerTick = gVIsPerFrame; } + // time_setDeltaReal_frames() clamps the demo's recorded VI count to 15, so the + // tick never advances more than that no matter what the demo asks for. Match it + // here or a bogus recorded value would scale the sub-frame count with it. + if (viPerTick > 15) { + viPerTick = 15; + } int effective_logic_fps = 60 / viPerTick; if (effective_logic_fps < 1) { @@ -1355,18 +1349,16 @@ SubframePacing ComputeSubframePacing() { subframesPerTick = 1; } - // Replay modes never interpolate: one render per tick, held to viPerTick/60 by the floor. - if (replayMode) { - subframesPerTick = 1; - } - // paceFps drives DXGI's per-present wait so that subframes * 1/paceFps = - // viPerTick/60 wall (= game time per tick). When viPerTick == gVIsPerFrame - // and target_fps is a multiple of eff, paceFps == target_fps and stays - // constant. Otherwise it varies per tick to keep wall == game. - int fps = subframesPerTick * effective_logic_fps; + // viPerTick/60 wall (= game time per tick). Derived from viPerTick rather than + // effective_logic_fps: the latter is truncated (VI=7 -> 8, not 8.57), which would + // stretch wall time on the odd VI counts demo playback hands us every tick. + int fps = subframesPerTick * 60 / viPerTick; + if (fps < 1) { + fps = 1; + } - return { subframesPerTick, fps }; + return { subframesPerTick, fps, viPerTick }; } } // namespace @@ -1415,7 +1407,8 @@ void GameEngine::ProcessGfxCommands(Gfx* commands) { activeFrames++; } - sPassBudgetNs = 1000000000LL * subframesPerTick / fps; + // Wall time this tick is worth, straight from its VI count. + sPassBudgetNs = 1000000000LL * pacing.viPerTick / 60; if (wnd != nullptr) { wnd->SetTargetFps(fps); diff --git a/src/port/Game.cpp b/src/port/Game.cpp index 5e1f19218..f77a023b9 100644 --- a/src/port/Game.cpp +++ b/src/port/Game.cpp @@ -40,8 +40,6 @@ void audioManagerThread_entry(void* arg); void core1_15B30_sendMesg3ToRenderThread(void); OSMesgQueue* thread5_getTaskQueue(void); OSMesgQueue* thread5_getSyncQueue(void); -// Non-interactive demo/playback modes (attract demo, file playback, etc.) -- decomp gameloop.c -bool func_802E4A08(void); } // The game tick runs on its own thread and submits display lists through the @@ -245,8 +243,7 @@ void push_frame() { GameEngine::Instance->StartFrame(); port_animVtx_beginTick(); - // Demo/playback modes render at native rate with no interpolation, so skip recording it. - const bool recordInterpolation = GameEngine::IsInterpolationEnabled() && !func_802E4A08(); + const bool recordInterpolation = GameEngine::IsInterpolationEnabled(); if (recordInterpolation) { FrameInterpolation_StartRecord(); } diff --git a/src/port/Interpolation/FrameInterpolation.cpp b/src/port/Interpolation/FrameInterpolation.cpp index 04182693a..a8d4fd90f 100644 --- a/src/port/Interpolation/FrameInterpolation.cpp +++ b/src/port/Interpolation/FrameInterpolation.cpp @@ -17,6 +17,7 @@ constexpr uint64_t kFnvSeed = 0xcbf29ce484222325ULL; constexpr uint64_t kSigKindToMtx = 0x1ULL; constexpr uint64_t kSigKindSprite = 0x2ULL; constexpr uint64_t kSigKindAnimVtx = 0x3ULL; +constexpr uint64_t kSigKindProjRot = 0x4ULL; constexpr float kAnimVtxSnapRatio = 0.5f; constexpr float kSpriteSnapDistSq = 300.0f * 300.0f; constexpr int kRingSlots = 4; @@ -60,6 +61,8 @@ struct CameraProjRotData { float rollDeg; float pitchDeg; float yawDeg; + uint64_t pathSig; + bool ambiguousSig; }; struct ScopeFrame { @@ -67,6 +70,7 @@ struct ScopeFrame { uint32_t toMtxIdx; uint32_t spriteIdx; uint32_t animVtxIdx; + uint32_t projRotIdx; const char* key; uintptr_t id; }; @@ -79,6 +83,7 @@ struct FrameTree { std::unordered_map sigToToMtx; std::unordered_map sigToSprite; std::unordered_map sigToAnimVtx; + std::unordered_map sigToProjRot; std::vector scopeStack; float cameraPos[3] = { 0.0f, 0.0f, 0.0f }; bool hasCameraPos = false; @@ -95,6 +100,7 @@ struct FrameTree { sigToToMtx.clear(); sigToSprite.clear(); sigToAnimVtx.clear(); + sigToProjRot.clear(); scopeStack.clear(); cameraPos[0] = cameraPos[1] = cameraPos[2] = 0.0f; hasCameraPos = false; @@ -121,12 +127,18 @@ struct PairedAnimVtx { bool snap; }; +struct PairedProjRot { + uint32_t currIdx; + uint32_t prevIdx; +}; + struct InterpolationCache { bool built = false; bool valid = false; std::vector pairedToMtxs; std::vector pairedSprites; std::vector pairedAnimVtxs; + std::vector pairedProjRots; std::vector camRelFixups; float cameraDelta[3] = { 0.0f, 0.0f, 0.0f }; bool hasCameraDelta = false; @@ -139,6 +151,7 @@ struct InterpolationCache { pairedToMtxs.clear(); pairedSprites.clear(); pairedAnimVtxs.clear(); + pairedProjRots.clear(); camRelFixups.clear(); hasCameraDelta = false; prevHasCameraPos = false; @@ -227,11 +240,12 @@ void FrameInterpolation_StartRecord(void) { gCollidedParentId = 0; gRecord->reset(); gRecord->toMtxs.reserve(512); - gRecord->projRots.reserve(4); + gRecord->projRots.reserve(16); gRecord->sprites.reserve(256); gRecord->sigToToMtx.reserve(512); gRecord->sigToSprite.reserve(64); - gRecord->scopeStack.push_back({ kFnvSeed, 0, 0, 0, "root", 0 }); + gRecord->sigToProjRot.reserve(16); + gRecord->scopeStack.push_back({ kFnvSeed, 0, 0, 0, 0, "root", 0 }); gShouldInterpolate = true; gNoInterpolateDepth = 0; gCameraRelativeDepth = 0; @@ -317,7 +331,7 @@ void FrameInterpolation_RecordOpenChild(const void* key, uintptr_t id) { uint64_t h = gRecord->scopeStack.back().pathHash; h = fnvMix(h, reinterpret_cast(key)); h = fnvMix(h, static_cast(id)); - gRecord->scopeStack.push_back({ h, 0, 0, 0, static_cast(key), id }); + gRecord->scopeStack.push_back({ h, 0, 0, 0, 0, static_cast(key), id }); } void FrameInterpolation_RecordCloseChild(void) { @@ -365,6 +379,12 @@ void FrameInterpolation_RecordCameraProjectionRotation(void* rollMtx, float roll if (!gRecording) { return; } + + ScopeFrame& scope = gRecord->scopeStack.back(); + uint64_t sig = fnvMix(fnvMix(scope.pathHash, kSigKindProjRot), scope.projRotIdx); + scope.projRotIdx++; + + uint32_t idx = static_cast(gRecord->projRots.size()); gRecord->projRots.emplace_back(); CameraProjRotData& d = gRecord->projRots.back(); d.rollMtx = rollMtx; @@ -373,6 +393,9 @@ void FrameInterpolation_RecordCameraProjectionRotation(void* rollMtx, float roll d.rollDeg = rollDeg; d.pitchDeg = pitchDeg; d.yawDeg = yawDeg; + d.pathSig = sig; + d.ambiguousSig = false; + recordSigCollision(gRecord->sigToProjRot, gRecord->projRots, sig, idx, gRecord->sigCollisions, gRecord->scopeStack); } void FrameInterpolation_RecordCameraPosition(const float pos[3]) { @@ -551,6 +574,27 @@ void BuildInterpolationCache() { gCache.pairedToMtxs.reserve(currToMtxs.size()); gCache.pairedSprites.reserve(currSprites.size()); + // Camera/viewport projection rotations, matched by path signature. Anything + // without a partner this tick keeps the matrix the game already wrote, which + // is this tick's own end state. + const std::vector& currProjRots = gRenderCurr->projRots; + const std::vector& prevProjRots = gRenderPrev->projRots; + gCache.pairedProjRots.reserve(currProjRots.size()); + for (uint32_t i = 0; i < currProjRots.size(); i++) { + const CameraProjRotData& c = currProjRots[i]; + if (c.ambiguousSig) { + continue; + } + auto it = gRenderPrev->sigToProjRot.find(c.pathSig); + if (it == gRenderPrev->sigToProjRot.end() || it->second >= prevProjRots.size()) { + continue; + } + if (prevProjRots[it->second].ambiguousSig) { + continue; + } + gCache.pairedProjRots.push_back({ i, it->second }); + } + // Whatever stays out of the cache falls back to the interpreter decoding // the Mtx bytes the game itself wrote, which already hold the correct // end-of-tick matrix. Entries with no previous partner, or whose @@ -860,21 +904,19 @@ void FrameInterpolation_Interpolate(float t, std::unordered_map& rep const std::vector& prevProj = gRenderPrev->projRots; const std::vector& currProj = gRenderCurr->projRots; - if (prevProj.size() == currProj.size()) { - for (size_t i = 0; i < currProj.size(); i++) { - const CameraProjRotData& p = prevProj[i]; - const CameraProjRotData& c = currProj[i]; - auto emitProj = [&](void* dst, float deg, float ax, float ay, float az) { - if (dst == nullptr) { - return; - } - MtxF& out = replacements[reinterpret_cast(dst)]; - guRotateF(out.mf, deg, ax, ay, az); - }; - // Axis conventions per viewport.c: roll about -Z, pitch +X, yaw +Y. - emitProj(c.rollMtx, lerpAngleDegSP(p.rollDeg, c.rollDeg, t), 0.0f, 0.0f, -1.0f); - emitProj(c.pitchMtx, lerpAngleDegSP(p.pitchDeg, c.pitchDeg, t), 1.0f, 0.0f, 0.0f); - emitProj(c.yawMtx, lerpAngleDegSP(p.yawDeg, c.yawDeg, t), 0.0f, 1.0f, 0.0f); - } + for (const PairedProjRot& pair : gCache.pairedProjRots) { + const CameraProjRotData& c = currProj[pair.currIdx]; + const CameraProjRotData& p = prevProj[pair.prevIdx]; + auto emitProj = [&](void* dst, float deg, float ax, float ay, float az) { + if (dst == nullptr) { + return; + } + MtxF& out = replacements[reinterpret_cast(dst)]; + guRotateF(out.mf, deg, ax, ay, az); + }; + // Axis conventions per viewport.c: roll about -Z, pitch +X, yaw +Y. + emitProj(c.rollMtx, lerpAngleDegSP(p.rollDeg, c.rollDeg, t), 0.0f, 0.0f, -1.0f); + emitProj(c.pitchMtx, lerpAngleDegSP(p.pitchDeg, c.pitchDeg, t), 1.0f, 0.0f, 0.0f); + emitProj(c.yawMtx, lerpAngleDegSP(p.yawDeg, c.yawDeg, t), 0.0f, 1.0f, 0.0f); } } diff --git a/src/port/Patches/FramePacingPatches.cpp b/src/port/Patches/FramePacingPatches.cpp index 5ff05d6ee..36795656b 100644 --- a/src/port/Patches/FramePacingPatches.cpp +++ b/src/port/Patches/FramePacingPatches.cpp @@ -62,6 +62,7 @@ static int sLairDingpotDurations[] = { 6, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, static int sCutsceneCounter = 0; static int sCutsceneNextStutter = 0; static int sCutsceneLagIndex = 0; +static int sCutsceneExtraVis = 0; static bool shouldLagCutscene(int* startFrames, int* durations, int count) { if (sCutsceneNextStutter == -1) { @@ -93,47 +94,40 @@ static void resetCutsceneTimings(void) { sCutsceneCounter = 0; sCutsceneNextStutter = 0; sCutsceneLagIndex = 0; + sCutsceneExtraVis = 0; } -int port_getCutsceneExtraVis(void) { - if (!CVarGetInteger(CVAR_CUTSCENE_SYNC, 1)) - return 0; +// Advances the stutter tables by one cutscene frame. Called from func_802E4384, +// the single point where a tick commits its time delta, so every consumer of +// port_getCutsceneExtraVis() sees the same answer for that tick. +void port_tickCutsceneStutter(void) { + sCutsceneExtraVis = 0; - int extra = 0; + if (!CVarGetInteger(CVAR_CUTSCENE_SYNC, 1)) + return; switch (gsworld_getMap()) { case MAP_1E_CS_START_NINTENDO: if (shouldLagCutscene(sConcertStartFrames, sConcertDurations, (int)(sizeof(sConcertStartFrames) / sizeof(sConcertStartFrames[0])))) { - extra = 1; + sCutsceneExtraVis = 1; } sCutsceneCounter++; break; case MAP_7B_CS_INTRO_GL_DINGPOT_1: if (shouldLagCutscene(sLairDingpotStartFrames, sLairDingpotDurations, (int)(sizeof(sLairDingpotStartFrames) / sizeof(sLairDingpotStartFrames[0])))) { - extra = 1; + sCutsceneExtraVis = 1; } sCutsceneCounter++; break; default: break; } - - return extra; } -int port_getInterpolationFpsCap(void) { - if (!CVarGetInteger(CVAR_CUTSCENE_SYNC, 1)) - return 0; - - switch (gsworld_getMap()) { - // [port] Cap concert to 30 fps - case MAP_1E_CS_START_NINTENDO: - return 30; - default: - return 0; - } +int port_getCutsceneExtraVis(void) { + return sCutsceneExtraVis; } } // extern "C" diff --git a/src/port/Patches/Patches.h b/src/port/Patches/Patches.h index d2bcbb7cb..dfb19d101 100644 --- a/src/port/Patches/Patches.h +++ b/src/port/Patches/Patches.h @@ -21,8 +21,8 @@ void port_pipelineSyncPoint(void); int port_getDemoViCount(void); void port_setDemoViCount(int viCount); int port_getDemoDisplayViCount(int rawViCount); +void port_tickCutsceneStutter(void); int port_getCutsceneExtraVis(void); -int port_getInterpolationFpsCap(void); // Localization (Localization.cpp) From 1f88b48c17ae44ee4d34799170238b57f36bcf92 Mon Sep 17 00:00:00 2001 From: Jeod <47716344+JeodC@users.noreply.github.com> Date: Sun, 2 Aug 2026 13:48:33 -0400 Subject: [PATCH 071/131] Align actor array and marker pool (#335) --- include/actor.h | 4 ++++ src/core2/actor_array.c | 4 +++- src/core2/actor_cubepropsystem.c | 5 +++-- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/include/actor.h b/include/actor.h index e786a2899..88e37cde7 100644 --- a/include/actor.h +++ b/include/actor.h @@ -5,6 +5,10 @@ struct actorMarker_s; +// [port] actor_new is the only allocator of ActorMarkers, one per actor, so the +// marker pool and the actor array have to be sized off the same number. +#define ACTOR_POOL_SIZE 0x200 + #define ACTOR_FLAG_NONE (0) #define ACTOR_FLAG_UNKNOWN_0 (1 << 0) // 0x1 #define ACTOR_FLAG_UNKNOWN_1 (1 << 1) // 0x2 diff --git a/src/core2/actor_array.c b/src/core2/actor_array.c index d9ac1ad71..7c6aa9ee8 100644 --- a/src/core2/actor_array.c +++ b/src/core2/actor_array.c @@ -56,7 +56,9 @@ typedef struct { }Actorlocal_Core2_9E370; // [port] Sized ahead of demand so actor_new never bk_reallocs (relocates) the array mid-map. -#define ACTOR_ARRAY_INITIAL_CAP 512 +// The marker pool is the binding limit (see ACTOR_POOL_SIZE); the grow chunk only exists so +// the array stays large enough to hold whatever the pool handed out, never the other way round. +#define ACTOR_ARRAY_INITIAL_CAP ACTOR_POOL_SIZE #define ACTOR_ARRAY_GROW_CHUNK 128 /* .data */ diff --git a/src/core2/actor_cubepropsystem.c b/src/core2/actor_cubepropsystem.c index 9a5dfdc9b..7fef90277 100644 --- a/src/core2/actor_cubepropsystem.c +++ b/src/core2/actor_cubepropsystem.c @@ -4,6 +4,7 @@ #include "functions.h" #include "variables.h" #include "enums.h" +#include "actor.h" #include #include "port/Patches/Patches.h" @@ -13,8 +14,8 @@ extern int ResourceMgr_IsModelAsset(uint32_t assetId); #define AssetCacheSize 0x3D5 -// Port Expand Marker Pool for Rando Allocation -#define MARKER_POOL_SIZE 0x1C0 +// [port] Expand Marker Pool for Rando Allocation +#define MARKER_POOL_SIZE ACTOR_POOL_SIZE #define MARKER_BITMAP_BYTES (MARKER_POOL_SIZE / 8) extern bool func_802E74A0(f32[3], f32, f32[3], f32[3]); From 649675b8cda89677432128ecc71b70eb3d3f6345 Mon Sep 17 00:00:00 2001 From: Jeod <47716344+JeodC@users.noreply.github.com> Date: Sun, 2 Aug 2026 13:48:48 -0400 Subject: [PATCH 072/131] Apply more hud adjustments (#336) --- src/port/Enhancements/Retention/JinjoRetention.cpp | 2 +- src/port/Rando/ObjectBehavior/MusicNote.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/port/Enhancements/Retention/JinjoRetention.cpp b/src/port/Enhancements/Retention/JinjoRetention.cpp index 949adb615..ea6d980f3 100644 --- a/src/port/Enhancements/Retention/JinjoRetention.cpp +++ b/src/port/Enhancements/Retention/JinjoRetention.cpp @@ -210,7 +210,7 @@ void RegisterJinjoRetention_Init() { } u8 bits = collectedBits(ev->levelId); if (bits != 0) { - item_set(ITEM_12_JINJOS, bits); + item_adjustByDiffWithoutHud(ITEM_12_JINJOS, bits - item_getCount(ITEM_12_JINJOS)); } }); diff --git a/src/port/Rando/ObjectBehavior/MusicNote.cpp b/src/port/Rando/ObjectBehavior/MusicNote.cpp index 115d860fe..77a42f272 100644 --- a/src/port/Rando/ObjectBehavior/MusicNote.cpp +++ b/src/port/Rando/ObjectBehavior/MusicNote.cpp @@ -27,6 +27,6 @@ void Rando::ObjectBehavior::InitMusicNoteBehavior() { } } - item_set(ITEM_C_NOTE, currentNotes); + item_adjustByDiffWithoutHud(ITEM_C_NOTE, currentNotes - item_getCount(ITEM_C_NOTE)); }) } From 1ecc6c66f95483c99fde739bdb92e3846238a872 Mon Sep 17 00:00:00 2001 From: Jeod <47716344+JeodC@users.noreply.github.com> Date: Sun, 2 Aug 2026 13:53:05 -0400 Subject: [PATCH 073/131] Fix dialog asset remap gaps and void conditional-dialog callbacks (#345) --- include/functions.h | 2 +- src/core2/gc/dialog.c | 2 +- src/core2/quiz/game.c | 4 +- src/core2/spline_pathfollow.c | 4 +- src/lair/ch/brentilda.c | 4 +- src/port/GameVersion/AssetVersionRemap.h | 692 ++++++++++++----------- 6 files changed, 356 insertions(+), 352 deletions(-) diff --git a/include/functions.h b/include/functions.h index 01dfa036b..531d6728e 100644 --- a/include/functions.h +++ b/include/functions.h @@ -2413,7 +2413,7 @@ void volatileFlag_clear(void); void volatileFlag_restoreAll(void); // --- core2/gc/dialog.c --- -int func_803110F8(s32 next_state, s32 arg1, s32 arg2, s32 arg3, void (*arg4)(ActorMarker *, enum asset_e, s32)); +int func_803110F8(s32 next_state, s32 arg1, s32 arg2, s32 arg3, s32 (*arg4)(ActorMarker *, enum asset_e, s32)); int gcdialog_showDialogConditional(s32 text_id, s32 arg1, f32 *pos, ActorMarker *marker, void(*callback)(ActorMarker *, enum asset_e, s32), void(*arg5)(ActorMarker *, enum asset_e, s32), s32(*arg6)(ActorMarker *, s32, s32)); int gcdialog_getCurrentTextId(void); int func_803115C4(s32 next_state); diff --git a/src/core2/gc/dialog.c b/src/core2/gc/dialog.c index 2a1deaa18..ad2493486 100644 --- a/src/core2/gc/dialog.c +++ b/src/core2/gc/dialog.c @@ -863,7 +863,7 @@ void func_80310D2C(void){ } } -int func_803110F8(s32 next_state, s32 arg1, s32 arg2, s32 arg3, void (*arg4)(ActorMarker *, enum asset_e, s32)){ +int func_803110F8(s32 next_state, s32 arg1, s32 arg2, s32 arg3, s32 (*arg4)(ActorMarker *, enum asset_e, s32)){ func_8025A55C(15000, 300, 2); gcdialog_showDialogConditional(next_state + 0xe57, 0x84, NULL, NULL, NULL, NULL, (s32(*)(ActorMarker *, s32, s32))arg4); func_80310A5C(arg2, arg3, arg1, 0, 0); diff --git a/src/core2/quiz/game.c b/src/core2/quiz/game.c index 4ebc2dfeb..f2654bf14 100644 --- a/src/core2/quiz/game.c +++ b/src/core2/quiz/game.c @@ -978,8 +978,8 @@ void func_getCameraViewFromLevel(enum map_e map_id, s32 arg1, bool arg2) { } -void func_802D5140(ActorMarker *caller, enum asset_e text_id, s32 arg2){ - itemscore_noteScores_get(volatileFlag_getN(VOLATILE_FLAG_19_CURRENT_LEVEL_ID, 4)); +s32 func_802D5140(ActorMarker *caller, enum asset_e text_id, s32 arg2){ + return itemscore_noteScores_get(volatileFlag_getN(VOLATILE_FLAG_19_CURRENT_LEVEL_ID, 4)); } void func_802D5178(s32 arg0, enum file_progress_e arg1, s32 arg2, enum map_e arg3, s32 arg4, s32 arg5, enum actor_e arg6, s32 arg7){ diff --git a/src/core2/spline_pathfollow.c b/src/core2/spline_pathfollow.c index 32ed34b5d..271422d9c 100644 --- a/src/core2/spline_pathfollow.c +++ b/src/core2/spline_pathfollow.c @@ -926,8 +926,8 @@ f32 func_80342260(s32 arg0, f32 arg1, s32 arg2){ return func_803234FC(func_80342038(arg0), arg1, 1.0f) / ((f32)arg2 /4); } -void func_803422AC(ActorMarker *caller, enum asset_e text_id, s32 arg2){ - jiggyscore_total(); +s32 func_803422AC(ActorMarker *caller, enum asset_e text_id, s32 arg2){ + return jiggyscore_total(); } s32 func_803422D4(Actor *arg0, Union_glspline *arg1, SplineList *arg2){ diff --git a/src/lair/ch/brentilda.c b/src/lair/ch/brentilda.c index e33438ea7..e5398be76 100644 --- a/src/lair/ch/brentilda.c +++ b/src/lair/ch/brentilda.c @@ -19,13 +19,13 @@ ActorAnimationInfo chBrentildaAnimations[] ={ ActorInfo chBrentilda = { 0x1E0, 0x348, 0x539, 0x1, chBrentildaAnimations, chBrentilda_update, actor_update_func_80326224, actor_draw, 2000, 0, 2.0f, 0}; /* .code */ -void func_8038BA30(ActorMarker *marker, enum asset_e text_id, s32 arg2){ +s32 func_8038BA30(ActorMarker *marker, enum asset_e text_id, s32 arg2){ Actor *this; s32 phi_v1; this = marker_getActor(marker); phi_v1 = this->unk10_12*2; - volatileFlag_getN(VOLATILE_FLAG_20_BEGIN_CHARACTER_PARADE + this->actorTypeSpecificField*6 + phi_v1, 2); + return volatileFlag_getN(VOLATILE_FLAG_20_BEGIN_CHARACTER_PARADE + this->actorTypeSpecificField*6 + phi_v1, 2); } void healDuoToFull(ActorMarker *marker, enum asset_e text_id, s32 arg2){ diff --git a/src/port/GameVersion/AssetVersionRemap.h b/src/port/GameVersion/AssetVersionRemap.h index 395ecdf5e..b905a2b55 100644 --- a/src/port/GameVersion/AssetVersionRemap.h +++ b/src/port/GameVersion/AssetVersionRemap.h @@ -4,7 +4,7 @@ #include #include -// v1.0 -> v1.1 asset ID remap table. 1300 entries. +// v1.0 -> v1.1 asset ID remap table. 1310 entries. static const std::unordered_map sV10toV11Remap = { { 2468, 2212 }, { 2469, 2213 }, { 2470, 2214 }, { 2471, 2215 }, { 2472, 2268 }, { 2473, 2269 }, { 2474, 2218 }, { 2475, 2219 }, { 2476, 2220 }, { 2477, 2221 }, { 2478, 2274 }, { 2481, 2277 }, { 2483, 2279 }, { 2484, 2228 }, @@ -21,180 +21,182 @@ static const std::unordered_map sV10toV11Remap = { { 2696, 2372 }, { 2771, 2373 }, { 2772, 2374 }, { 2773, 2375 }, { 2774, 2376 }, { 2775, 2377 }, { 2776, 2378 }, { 2777, 2379 }, { 2778, 2380 }, { 2779, 2381 }, { 2780, 2382 }, { 2781, 2383 }, { 2782, 2384 }, { 2783, 2385 }, { 2784, 2386 }, { 2785, 2387 }, { 2786, 2388 }, { 2871, 2389 }, { 2872, 2390 }, { 2873, 2391 }, { 2874, 2392 }, - { 2875, 2393 }, { 2876, 2394 }, { 2877, 2395 }, { 2879, 2397 }, { 2880, 2398 }, { 2881, 2399 }, { 2882, 2400 }, - { 2883, 2401 }, { 2884, 2402 }, { 2885, 2403 }, { 2886, 2404 }, { 2887, 2405 }, { 2888, 2406 }, { 2889, 2407 }, - { 2890, 2408 }, { 2891, 2409 }, { 2892, 2410 }, { 2893, 2411 }, { 2894, 2412 }, { 2895, 2413 }, { 2896, 2414 }, - { 2897, 2415 }, { 2971, 2416 }, { 2972, 2417 }, { 2973, 2418 }, { 2974, 2419 }, { 2975, 2420 }, { 2976, 2421 }, - { 2977, 2422 }, { 2978, 2423 }, { 2979, 2424 }, { 3071, 2425 }, { 3072, 2426 }, { 3073, 2427 }, { 3074, 2428 }, - { 3075, 2429 }, { 3076, 2430 }, { 3077, 2431 }, { 3078, 2432 }, { 3079, 2433 }, { 3080, 2434 }, { 3081, 2435 }, - { 3082, 2436 }, { 3083, 2437 }, { 3084, 2438 }, { 3085, 2439 }, { 3086, 2440 }, { 3087, 2441 }, { 3088, 2442 }, - { 3089, 2443 }, { 3090, 2444 }, { 3091, 2445 }, { 3092, 2446 }, { 3093, 2447 }, { 3094, 2448 }, { 3095, 2449 }, - { 3096, 2450 }, { 3097, 2451 }, { 3098, 2452 }, { 3099, 2453 }, { 3100, 2454 }, { 3101, 2455 }, { 3102, 2456 }, - { 3103, 2457 }, { 3104, 2458 }, { 3105, 2459 }, { 3106, 2460 }, { 3107, 2461 }, { 3108, 2462 }, { 3109, 2463 }, - { 3110, 2464 }, { 3111, 2465 }, { 3112, 2466 }, { 3113, 2467 }, { 3114, 2468 }, { 3115, 2469 }, { 3171, 2470 }, - { 3172, 2471 }, { 3173, 2472 }, { 3174, 2473 }, { 3175, 2474 }, { 3176, 2475 }, { 3177, 2476 }, { 3178, 2477 }, - { 3179, 2478 }, { 3180, 2479 }, { 3181, 2480 }, { 3182, 2481 }, { 3183, 2482 }, { 3184, 2483 }, { 3185, 2484 }, - { 3186, 2485 }, { 3187, 2486 }, { 3188, 2487 }, { 3189, 2488 }, { 3190, 2489 }, { 3191, 2490 }, { 3192, 2491 }, - { 3193, 2492 }, { 3194, 2493 }, { 3195, 2494 }, { 3196, 2495 }, { 3197, 2496 }, { 3198, 2497 }, { 3199, 2498 }, - { 3200, 2499 }, { 3201, 2500 }, { 3202, 2501 }, { 3203, 2502 }, { 3204, 2503 }, { 3205, 2504 }, { 3206, 2505 }, - { 3207, 2506 }, { 3208, 2507 }, { 3209, 2508 }, { 3210, 2509 }, { 3211, 2510 }, { 3212, 2511 }, { 3213, 2512 }, - { 3214, 2513 }, { 3215, 2514 }, { 3216, 2515 }, { 3217, 2516 }, { 3218, 2517 }, { 3219, 2518 }, { 3220, 2519 }, - { 3221, 2520 }, { 3222, 2521 }, { 3223, 2522 }, { 3224, 2523 }, { 3271, 2524 }, { 3272, 2525 }, { 3273, 2526 }, - { 3274, 2527 }, { 3275, 2528 }, { 3276, 2529 }, { 3277, 2530 }, { 3278, 2531 }, { 3279, 2532 }, { 3280, 2533 }, - { 3281, 2534 }, { 3282, 2535 }, { 3283, 2536 }, { 3284, 2537 }, { 3285, 2538 }, { 3286, 2539 }, { 3287, 2540 }, - { 3288, 2541 }, { 3289, 2542 }, { 3290, 2543 }, { 3291, 2544 }, { 3292, 2545 }, { 3293, 2546 }, { 3294, 2547 }, - { 3295, 2548 }, { 3296, 2549 }, { 3297, 2550 }, { 3298, 2551 }, { 3299, 2552 }, { 3300, 2553 }, { 3301, 2554 }, - { 3302, 2555 }, { 3303, 2556 }, { 3304, 2557 }, { 3371, 2558 }, { 3372, 2559 }, { 3373, 2560 }, { 3374, 2561 }, - { 3375, 2562 }, { 3376, 2563 }, { 3377, 2564 }, { 3378, 2565 }, { 3379, 2566 }, { 3380, 2567 }, { 3381, 2568 }, - { 3382, 2569 }, { 3383, 2570 }, { 3384, 3024 }, { 3385, 2572 }, { 3471, 2573 }, { 3472, 2574 }, { 3473, 2575 }, - { 3474, 2576 }, { 3475, 2577 }, { 3476, 2578 }, { 3477, 2579 }, { 3478, 2580 }, { 3479, 2581 }, { 3480, 2582 }, - { 3481, 2583 }, { 3482, 2584 }, { 3483, 2585 }, { 3484, 2586 }, { 3485, 2587 }, { 3486, 2588 }, { 3487, 2589 }, - { 3488, 2590 }, { 3489, 2591 }, { 3490, 2592 }, { 3491, 2593 }, { 3492, 2594 }, { 3493, 2595 }, { 3494, 2596 }, - { 3495, 2597 }, { 3496, 2598 }, { 3497, 2599 }, { 3498, 2600 }, { 3499, 2601 }, { 3500, 2602 }, { 3501, 2603 }, - { 3502, 2604 }, { 3503, 2605 }, { 3504, 2606 }, { 3505, 2607 }, { 3506, 2608 }, { 3507, 2609 }, { 3508, 2610 }, - { 3509, 2611 }, { 3510, 2612 }, { 3571, 2613 }, { 3572, 2614 }, { 3573, 2615 }, { 3574, 2616 }, { 3575, 2617 }, - { 3576, 2618 }, { 3577, 2619 }, { 3578, 2620 }, { 3579, 2621 }, { 3580, 2622 }, { 3581, 2623 }, { 3582, 2624 }, - { 3583, 2625 }, { 3584, 2626 }, { 3585, 2627 }, { 3586, 2628 }, { 3587, 2629 }, { 3588, 2630 }, { 3589, 2631 }, - { 3590, 2632 }, { 3591, 2633 }, { 3592, 2634 }, { 3593, 2635 }, { 3594, 2636 }, { 3595, 2637 }, { 3596, 2638 }, - { 3597, 2639 }, { 3598, 2640 }, { 3599, 2641 }, { 3600, 2642 }, { 3601, 2643 }, { 3602, 2644 }, { 3603, 2645 }, - { 3604, 2646 }, { 3605, 2647 }, { 3606, 2648 }, { 3607, 2649 }, { 3608, 2650 }, { 3609, 2651 }, { 3610, 2652 }, - { 3611, 2653 }, { 3612, 2654 }, { 3613, 2655 }, { 3614, 2656 }, { 3615, 2657 }, { 3616, 2658 }, { 3617, 2659 }, - { 3618, 2660 }, { 3619, 2661 }, { 3620, 2662 }, { 3621, 2663 }, { 3622, 2664 }, { 3623, 2665 }, { 3624, 2666 }, - { 3625, 2667 }, { 3626, 2668 }, { 3627, 2669 }, { 3628, 2670 }, { 3629, 2671 }, { 3630, 2672 }, { 3631, 2673 }, - { 3632, 2674 }, { 3633, 2675 }, { 3634, 2676 }, { 3635, 2677 }, { 3636, 2678 }, { 3637, 2679 }, { 3638, 2680 }, - { 3639, 2681 }, { 3640, 2682 }, { 3641, 2683 }, { 3642, 2684 }, { 3643, 2685 }, { 3644, 2686 }, { 3645, 2687 }, - { 3646, 2688 }, { 3671, 2689 }, { 3672, 2690 }, { 3673, 2691 }, { 3674, 2692 }, { 3675, 2693 }, { 3676, 2694 }, - { 3677, 2695 }, { 3678, 2696 }, { 3679, 2697 }, { 3680, 2698 }, { 3681, 2699 }, { 3682, 2700 }, { 3683, 2701 }, - { 3684, 2702 }, { 3685, 2703 }, { 3686, 2704 }, { 3687, 2705 }, { 3688, 2706 }, { 3689, 2707 }, { 3690, 2708 }, - { 3691, 2709 }, { 3692, 2710 }, { 3693, 2711 }, { 3694, 2712 }, { 3695, 2713 }, { 3696, 2714 }, { 3697, 2715 }, - { 3698, 2716 }, { 3699, 2717 }, { 3700, 2718 }, { 3701, 2719 }, { 3702, 2720 }, { 3703, 2721 }, { 3704, 2722 }, - { 3705, 2723 }, { 3706, 2724 }, { 3707, 2725 }, { 3708, 2726 }, { 3709, 2727 }, { 3710, 2728 }, { 3711, 2729 }, - { 3712, 2730 }, { 3713, 2731 }, { 3714, 2732 }, { 3715, 2733 }, { 3716, 2734 }, { 3717, 2735 }, { 3718, 2736 }, - { 3719, 2737 }, { 3720, 2738 }, { 3721, 2739 }, { 3722, 2740 }, { 3723, 2741 }, { 3724, 2742 }, { 3725, 2743 }, - { 3726, 2744 }, { 3727, 2745 }, { 3728, 2746 }, { 3729, 2747 }, { 3730, 2748 }, { 3927, 2749 }, { 3928, 2750 }, - { 3929, 2751 }, { 3930, 2752 }, { 3931, 2753 }, { 3932, 2754 }, { 3933, 2755 }, { 3934, 2756 }, { 3940, 2762 }, - { 3941, 2763 }, { 3942, 2764 }, { 3943, 2765 }, { 3944, 2766 }, { 3945, 2767 }, { 3946, 2768 }, { 3947, 2769 }, - { 3948, 2770 }, { 3949, 2771 }, { 3950, 2772 }, { 3951, 2773 }, { 3952, 2774 }, { 3953, 2775 }, { 3954, 2776 }, - { 3955, 2777 }, { 3956, 2778 }, { 3957, 2779 }, { 3958, 2780 }, { 3959, 2781 }, { 3960, 2782 }, { 3961, 2783 }, - { 3962, 2784 }, { 3963, 2785 }, { 3964, 2786 }, { 3965, 2787 }, { 3966, 2788 }, { 3967, 2789 }, { 3968, 2790 }, - { 3969, 2791 }, { 3970, 2792 }, { 3971, 2793 }, { 3972, 2794 }, { 3973, 2795 }, { 3974, 2796 }, { 3975, 2797 }, - { 3976, 2798 }, { 3977, 2799 }, { 3978, 2800 }, { 3979, 2801 }, { 3980, 2802 }, { 3981, 2803 }, { 3982, 2804 }, - { 3983, 2805 }, { 3984, 2806 }, { 3985, 2807 }, { 3986, 2808 }, { 3987, 2809 }, { 3988, 2810 }, { 3989, 2811 }, - { 3990, 2812 }, { 3991, 2813 }, { 3992, 2814 }, { 3993, 2815 }, { 3994, 2816 }, { 3995, 2817 }, { 3996, 2818 }, - { 3997, 2819 }, { 3998, 2820 }, { 3999, 2821 }, { 4000, 2822 }, { 4001, 2823 }, { 4002, 2824 }, { 4003, 2825 }, - { 4004, 2826 }, { 4005, 2827 }, { 4006, 2828 }, { 4007, 2829 }, { 4008, 2830 }, { 4009, 2831 }, { 4010, 2832 }, - { 4011, 2833 }, { 4012, 2834 }, { 4013, 2835 }, { 4014, 2836 }, { 4015, 2837 }, { 4016, 2838 }, { 4017, 2839 }, - { 4018, 2840 }, { 4019, 2841 }, { 4020, 2842 }, { 4021, 2843 }, { 4022, 2844 }, { 4023, 2845 }, { 4024, 2846 }, - { 4025, 2847 }, { 4026, 2848 }, { 4027, 2849 }, { 4028, 2850 }, { 4029, 2851 }, { 4030, 2852 }, { 4031, 2853 }, - { 4032, 2854 }, { 4127, 2855 }, { 4128, 2856 }, { 4129, 2857 }, { 4130, 2858 }, { 4131, 2859 }, { 4132, 2860 }, - { 4133, 2861 }, { 4134, 2862 }, { 4135, 2863 }, { 4136, 2864 }, { 4137, 2865 }, { 4138, 2866 }, { 4139, 2867 }, - { 4140, 2868 }, { 4145, 2873 }, { 4146, 2874 }, { 4147, 2875 }, { 4148, 2876 }, { 4149, 2877 }, { 4150, 2878 }, - { 4151, 2879 }, { 4152, 2880 }, { 4153, 2881 }, { 4154, 2882 }, { 4155, 2883 }, { 4156, 2884 }, { 4157, 2885 }, - { 4158, 2886 }, { 4159, 2887 }, { 4160, 2888 }, { 4227, 2889 }, { 4228, 2890 }, { 4229, 2891 }, { 4230, 2892 }, - { 4231, 2893 }, { 4232, 2894 }, { 4233, 2895 }, { 4234, 2896 }, { 4235, 2897 }, { 4236, 2898 }, { 4237, 2899 }, - { 4238, 2900 }, { 4239, 2901 }, { 4240, 2902 }, { 4241, 2903 }, { 4242, 2904 }, { 4243, 2905 }, { 4244, 2906 }, - { 4245, 2907 }, { 4246, 2908 }, { 4247, 2909 }, { 4248, 2910 }, { 4249, 2911 }, { 4250, 2912 }, { 4251, 2913 }, - { 4252, 2914 }, { 4253, 2915 }, { 4254, 2916 }, { 4255, 2917 }, { 4256, 2918 }, { 4257, 2919 }, { 4258, 2920 }, - { 4327, 2921 }, { 4328, 2922 }, { 4329, 2923 }, { 4330, 2924 }, { 4331, 2925 }, { 4332, 2926 }, { 4333, 2927 }, - { 4334, 2928 }, { 4335, 2929 }, { 4336, 2930 }, { 4337, 2931 }, { 4338, 2932 }, { 4339, 2933 }, { 4340, 2934 }, - { 4341, 2935 }, { 4342, 2936 }, { 4343, 2937 }, { 4344, 2938 }, { 4345, 2939 }, { 4346, 2940 }, { 4347, 2941 }, - { 4348, 2942 }, { 4349, 2943 }, { 4350, 2944 }, { 4351, 2945 }, { 4352, 2946 }, { 4353, 2947 }, { 4354, 2948 }, - { 4355, 2949 }, { 4356, 2950 }, { 4357, 2951 }, { 4358, 2952 }, { 4359, 2953 }, { 4360, 2954 }, { 4361, 2955 }, - { 4362, 2956 }, { 4363, 2957 }, { 4364, 2958 }, { 4365, 2959 }, { 4366, 2960 }, { 4367, 2961 }, { 4368, 2962 }, - { 4369, 2963 }, { 4370, 2964 }, { 4371, 2965 }, { 4372, 2966 }, { 4373, 2967 }, { 4374, 2968 }, { 4375, 2969 }, - { 4376, 2970 }, { 4377, 2971 }, { 4378, 2972 }, { 4379, 2973 }, { 4380, 2974 }, { 4381, 2975 }, { 4382, 2976 }, - { 4383, 2977 }, { 4384, 2978 }, { 4385, 2979 }, { 4386, 2980 }, { 4387, 2981 }, { 4388, 2982 }, { 4389, 2983 }, - { 4390, 2984 }, { 4391, 2985 }, { 4392, 2986 }, { 4393, 2987 }, { 4394, 2988 }, { 4395, 2989 }, { 4396, 2990 }, - { 4397, 2991 }, { 4398, 2992 }, { 4399, 2993 }, { 4400, 2994 }, { 4406, 3000 }, { 4407, 3001 }, { 4408, 3002 }, - { 4409, 3003 }, { 4410, 3004 }, { 4411, 3005 }, { 4412, 3006 }, { 4413, 3007 }, { 4414, 3008 }, { 4415, 3009 }, - { 4416, 3010 }, { 4417, 3011 }, { 4418, 3012 }, { 4419, 3013 }, { 4420, 3014 }, { 4421, 3015 }, { 4422, 3016 }, - { 4423, 3017 }, { 4424, 3018 }, { 4425, 3019 }, { 4426, 3020 }, { 4431, 3025 }, { 4432, 3026 }, { 4433, 3027 }, - { 4434, 3028 }, { 4435, 3029 }, { 4436, 3030 }, { 4437, 3031 }, { 4438, 3032 }, { 4439, 3033 }, { 4440, 3034 }, - { 4441, 3035 }, { 4442, 3036 }, { 4443, 3037 }, { 4444, 3038 }, { 4445, 3039 }, { 4446, 3040 }, { 4447, 3041 }, - { 4448, 3042 }, { 4449, 3043 }, { 4450, 3044 }, { 4527, 3045 }, { 4528, 3046 }, { 4529, 3047 }, { 4530, 3048 }, - { 4531, 3049 }, { 4532, 3050 }, { 4533, 3051 }, { 4534, 3052 }, { 4535, 3053 }, { 4536, 3054 }, { 4537, 3055 }, - { 4538, 3056 }, { 4539, 3057 }, { 4540, 3058 }, { 4541, 3059 }, { 4542, 3060 }, { 4543, 3061 }, { 4544, 3062 }, - { 4545, 3063 }, { 4546, 3064 }, { 4547, 3065 }, { 4548, 3066 }, { 4549, 3067 }, { 4550, 3068 }, { 4551, 3069 }, - { 4552, 3070 }, { 4553, 3071 }, { 4627, 3072 }, { 4628, 3073 }, { 4629, 3074 }, { 4630, 3075 }, { 4631, 3076 }, - { 4632, 3077 }, { 4633, 3078 }, { 4634, 3079 }, { 4635, 3080 }, { 4636, 3081 }, { 4637, 3082 }, { 4638, 3083 }, - { 4639, 3084 }, { 4640, 3085 }, { 4641, 3086 }, { 4642, 3087 }, { 4643, 3088 }, { 4644, 3089 }, { 4645, 3090 }, - { 4646, 3091 }, { 4647, 3092 }, { 4648, 3093 }, { 4649, 3094 }, { 4650, 3095 }, { 4651, 3096 }, { 4652, 3097 }, - { 4653, 3098 }, { 4654, 3099 }, { 4655, 3100 }, { 4656, 3101 }, { 4657, 3102 }, { 4658, 3103 }, { 4659, 3104 }, - { 4660, 3105 }, { 4661, 3106 }, { 4662, 3107 }, { 4663, 3108 }, { 4664, 3109 }, { 4665, 3110 }, { 4666, 3111 }, - { 4667, 3112 }, { 4668, 3113 }, { 4669, 3114 }, { 4670, 3115 }, { 4671, 3116 }, { 4672, 3117 }, { 4673, 3118 }, - { 4674, 3119 }, { 4675, 3120 }, { 4676, 3121 }, { 4677, 3122 }, { 4678, 3123 }, { 4679, 3124 }, { 4680, 3125 }, - { 4681, 3126 }, { 4682, 3127 }, { 4683, 3128 }, { 4684, 3129 }, { 4685, 3130 }, { 4686, 3131 }, { 4687, 3132 }, - { 4688, 3133 }, { 4689, 3134 }, { 4690, 3135 }, { 4691, 3136 }, { 4692, 3137 }, { 4693, 3138 }, { 4694, 3139 }, - { 4695, 3140 }, { 4696, 3141 }, { 4697, 3142 }, { 4698, 3143 }, { 4699, 3144 }, { 4700, 3145 }, { 4701, 3146 }, - { 4702, 3147 }, { 4703, 3148 }, { 4704, 3149 }, { 4705, 3150 }, { 4706, 3151 }, { 4707, 3152 }, { 4708, 3153 }, - { 4709, 3154 }, { 4710, 3155 }, { 4711, 3156 }, { 4712, 3157 }, { 4713, 3158 }, { 4714, 3159 }, { 4715, 3160 }, - { 4716, 3161 }, { 4717, 3162 }, { 4718, 3163 }, { 4719, 3164 }, { 4720, 3165 }, { 4721, 3166 }, { 4722, 3167 }, - { 4723, 3168 }, { 4724, 3169 }, { 4725, 3170 }, { 4726, 3171 }, { 4827, 3172 }, { 4828, 3173 }, { 4829, 3174 }, - { 4830, 3175 }, { 4831, 3176 }, { 4832, 3177 }, { 4833, 3178 }, { 4834, 3179 }, { 4835, 3180 }, { 4836, 3181 }, - { 4837, 3182 }, { 4838, 3183 }, { 4839, 3184 }, { 4840, 3185 }, { 4841, 3186 }, { 4842, 3187 }, { 4843, 3188 }, - { 4844, 3189 }, { 4845, 3190 }, { 5027, 3191 }, { 5028, 3192 }, { 5029, 3193 }, { 5030, 3194 }, { 5031, 3195 }, - { 5032, 3196 }, { 5033, 3197 }, { 5034, 3198 }, { 5035, 3199 }, { 5036, 3200 }, { 5037, 3201 }, { 5038, 3202 }, - { 5039, 3203 }, { 5040, 3204 }, { 5041, 3205 }, { 5042, 3206 }, { 5043, 3207 }, { 5044, 3208 }, { 5045, 3209 }, - { 5046, 3210 }, { 5047, 3211 }, { 5048, 3212 }, { 5049, 3213 }, { 5050, 3214 }, { 5051, 3215 }, { 5052, 3216 }, - { 5053, 3217 }, { 5054, 3218 }, { 5055, 3219 }, { 5056, 3220 }, { 5057, 3221 }, { 5058, 3222 }, { 5059, 3223 }, - { 5060, 3224 }, { 5061, 3225 }, { 5062, 3226 }, { 5063, 3227 }, { 5064, 3228 }, { 5065, 3229 }, { 5066, 3230 }, - { 5067, 3231 }, { 5068, 3232 }, { 5069, 3233 }, { 5070, 3234 }, { 5071, 3235 }, { 5072, 3236 }, { 5073, 3237 }, - { 5074, 3238 }, { 5075, 3239 }, { 5076, 3240 }, { 5077, 3241 }, { 5127, 3242 }, { 5128, 3243 }, { 5129, 3244 }, - { 5130, 3245 }, { 5131, 3246 }, { 5132, 3247 }, { 5133, 3248 }, { 5134, 3249 }, { 5135, 3250 }, { 5136, 3251 }, - { 5137, 3252 }, { 5138, 3253 }, { 5139, 3254 }, { 5140, 3255 }, { 5141, 3256 }, { 5142, 3257 }, { 5143, 3258 }, - { 5144, 3259 }, { 5145, 3260 }, { 5146, 3261 }, { 5147, 3262 }, { 5148, 3263 }, { 5149, 3264 }, { 5150, 3265 }, - { 5151, 3266 }, { 5152, 3267 }, { 5153, 3268 }, { 5154, 3269 }, { 5155, 3270 }, { 5156, 3271 }, { 5227, 3272 }, - { 5228, 3273 }, { 5229, 3274 }, { 5230, 3275 }, { 5231, 3276 }, { 5232, 3277 }, { 5233, 3278 }, { 5234, 3279 }, - { 5235, 3280 }, { 5236, 3281 }, { 5237, 3282 }, { 5238, 3283 }, { 5240, 3285 }, { 5241, 3286 }, { 5242, 3287 }, - { 5243, 3288 }, { 5244, 3289 }, { 5245, 3290 }, { 5246, 3291 }, { 5247, 3292 }, { 5248, 3293 }, { 5249, 3294 }, - { 5250, 3295 }, { 5251, 3296 }, { 5252, 3297 }, { 5253, 3298 }, { 5254, 3299 }, { 5255, 3300 }, { 5256, 3301 }, - { 5257, 3302 }, { 5258, 3303 }, { 5259, 3304 }, { 5260, 3305 }, { 5261, 3306 }, { 5262, 3307 }, { 5263, 3308 }, - { 5264, 3309 }, { 5265, 3310 }, { 5266, 3311 }, { 5267, 3312 }, { 5268, 3313 }, { 5269, 3314 }, { 5270, 3315 }, - { 5271, 3316 }, { 5272, 3317 }, { 5273, 3318 }, { 5274, 3319 }, { 5275, 3320 }, { 5276, 3321 }, { 5277, 3322 }, - { 5278, 3323 }, { 5279, 3324 }, { 5280, 3325 }, { 5281, 3326 }, { 5282, 3327 }, { 5283, 3328 }, { 5284, 3329 }, - { 5285, 3330 }, { 5286, 3331 }, { 5288, 3333 }, { 5289, 3334 }, { 5290, 3335 }, { 5291, 3336 }, { 5292, 3337 }, - { 5293, 3338 }, { 5294, 3339 }, { 5296, 3341 }, { 5297, 3342 }, { 5298, 3343 }, { 5299, 3344 }, { 5300, 3345 }, - { 5301, 3346 }, { 5302, 3347 }, { 5303, 3348 }, { 5304, 3349 }, { 5305, 3350 }, { 5306, 3351 }, { 5307, 3352 }, - { 5308, 3353 }, { 5309, 3354 }, { 5310, 3355 }, { 5311, 3356 }, { 5312, 3357 }, { 5313, 3358 }, { 5314, 3359 }, - { 5315, 3360 }, { 5316, 3361 }, { 5317, 3362 }, { 5318, 3363 }, { 5319, 3364 }, { 5320, 3365 }, { 5321, 3366 }, - { 5322, 3367 }, { 5323, 3368 }, { 5324, 3369 }, { 5325, 3370 }, { 5326, 3371 }, { 5327, 3372 }, { 5328, 3373 }, - { 5329, 3374 }, { 5330, 3375 }, { 5331, 3376 }, { 5332, 3377 }, { 5333, 3378 }, { 5336, 3381 }, { 5337, 3382 }, - { 5338, 3383 }, { 5339, 3384 }, { 5340, 3385 }, { 5341, 3386 }, { 5342, 3387 }, { 5343, 3388 }, { 5344, 3389 }, - { 5345, 3390 }, { 5346, 3391 }, { 5347, 3392 }, { 5348, 3393 }, { 5349, 3394 }, { 5350, 3395 }, { 5351, 3396 }, - { 5352, 3397 }, { 5357, 3402 }, { 5358, 3403 }, { 5359, 3404 }, { 5360, 3405 }, { 5361, 3406 }, { 5362, 3407 }, - { 5363, 3408 }, { 5364, 3409 }, { 5365, 3410 }, { 5366, 3411 }, { 5367, 3412 }, { 5368, 3413 }, { 5369, 3414 }, - { 5370, 3415 }, { 5371, 3416 }, { 5372, 3417 }, { 5373, 3418 }, { 5374, 3419 }, { 5375, 3420 }, { 5376, 3421 }, - { 5377, 3422 }, { 5378, 3423 }, { 5379, 3424 }, { 5380, 3425 }, { 5381, 3426 }, { 5382, 3427 }, { 5383, 3428 }, - { 5384, 3429 }, { 5385, 3430 }, { 5386, 3431 }, { 5387, 3432 }, { 5388, 3433 }, { 5389, 3434 }, { 5390, 3435 }, - { 5391, 3436 }, { 5392, 3437 }, { 5393, 3438 }, { 5394, 3439 }, { 5395, 3440 }, { 5396, 3441 }, { 5397, 3442 }, - { 5398, 3443 }, { 5399, 3444 }, { 5400, 3445 }, { 5401, 3446 }, { 5402, 3447 }, { 5403, 3448 }, { 5404, 3449 }, - { 5405, 3450 }, { 5406, 3451 }, { 5407, 3452 }, { 5408, 3453 }, { 5409, 3454 }, { 5410, 3455 }, { 5411, 3456 }, - { 5412, 3457 }, { 5413, 3458 }, { 5414, 3459 }, { 5415, 3460 }, { 5416, 3461 }, { 5417, 3462 }, { 5418, 3463 }, - { 5419, 3464 }, { 5420, 3465 }, { 5421, 3466 }, { 5422, 3467 }, { 5423, 3468 }, { 5424, 3469 }, { 5425, 3470 }, - { 5426, 3471 }, { 5427, 3472 }, { 5428, 3473 }, { 5429, 3474 }, { 5430, 3475 }, { 5431, 3476 }, { 5432, 3477 }, - { 5433, 3478 }, { 5434, 3479 }, { 5435, 3480 }, { 5436, 3481 }, { 5437, 3482 }, { 5438, 3483 }, { 5439, 3484 }, - { 5440, 3485 }, { 5441, 3486 }, { 5442, 3487 }, { 5443, 3488 }, { 5444, 3489 }, { 5445, 3490 }, { 5446, 3491 }, - { 5447, 3492 }, { 5448, 3493 }, { 5449, 3494 }, { 5450, 3495 }, { 5451, 3496 }, { 5452, 3497 }, { 5453, 3498 }, - { 5454, 3499 }, { 5455, 3500 }, { 5456, 3501 }, { 5457, 3502 }, { 5458, 3503 }, { 5459, 3504 }, { 5460, 3505 }, - { 5461, 3506 }, { 5462, 3507 }, { 5463, 3508 }, { 5464, 3509 }, { 5465, 3510 }, { 5466, 3511 }, { 5467, 3512 }, - { 5468, 3513 }, { 5469, 3514 }, { 5470, 3515 }, { 5471, 3516 }, { 5472, 3517 }, { 5473, 3518 }, { 5474, 3519 }, - { 5475, 3520 }, { 5476, 3521 }, { 5477, 3522 }, { 5478, 3523 }, { 5479, 3524 }, { 5480, 3525 }, { 5481, 3526 }, - { 5482, 3527 }, { 5483, 3528 }, { 5484, 3529 }, { 5485, 3530 }, { 5486, 3531 }, { 5487, 3532 }, { 5488, 3533 }, - { 5489, 3534 }, { 5490, 3535 }, { 5491, 3536 }, { 5492, 3537 }, { 5493, 3538 }, { 5494, 3539 }, { 5495, 3540 }, - { 5496, 3541 }, { 5497, 3542 }, { 5498, 3543 }, { 5499, 3544 }, { 5500, 3545 }, { 5501, 3546 }, { 5502, 3547 }, - { 5503, 3548 }, { 5504, 3549 }, { 5505, 3550 }, { 5506, 3551 }, { 5507, 3552 }, { 5508, 3553 }, { 5509, 3554 }, - { 5510, 3555 }, { 5511, 3556 }, { 5512, 3557 }, { 5513, 3558 }, { 5514, 3559 }, { 5515, 3560 }, { 5516, 3561 }, - { 5517, 3562 }, { 5518, 3563 }, { 5519, 3564 }, { 5520, 3565 }, { 5521, 3566 }, { 5522, 3567 }, { 5523, 3568 }, - { 5524, 3569 }, { 5525, 3570 }, { 5526, 3571 }, { 5527, 3572 }, { 5528, 3573 }, { 5529, 3574 }, { 5530, 3575 }, - { 5531, 3576 }, { 5532, 3577 }, { 5533, 3578 }, { 5534, 3579 }, { 5535, 3580 }, { 5536, 3581 }, { 5537, 3582 }, - { 5538, 3583 }, { 5539, 3584 }, { 5540, 3585 }, { 5541, 3586 }, { 5542, 3587 }, { 5543, 3588 }, { 5544, 3589 }, - { 5545, 3590 }, { 5546, 3591 }, { 5547, 3592 }, { 5548, 3593 }, { 5549, 3594 }, { 5550, 3595 }, { 5551, 3596 }, - { 5552, 3597 }, { 5553, 3598 }, { 5554, 3599 }, { 5555, 3600 }, { 5556, 3601 }, { 5557, 3602 }, { 5558, 3603 }, - { 5559, 3604 }, { 5560, 3605 }, { 5561, 3606 }, { 5562, 3607 }, { 5563, 3608 }, { 5564, 3609 }, { 5565, 3610 }, - { 5566, 3611 }, { 5567, 3612 }, { 5568, 3613 }, { 5569, 3614 }, { 5570, 3615 } + { 2875, 2393 }, { 2876, 2394 }, { 2877, 2395 }, { 2878, 2396 }, { 2879, 2397 }, { 2880, 2398 }, { 2881, 2399 }, + { 2882, 2400 }, { 2883, 2401 }, { 2884, 2402 }, { 2885, 2403 }, { 2886, 2404 }, { 2887, 2405 }, { 2888, 2406 }, + { 2889, 2407 }, { 2890, 2408 }, { 2891, 2409 }, { 2892, 2410 }, { 2893, 2411 }, { 2894, 2412 }, { 2895, 2413 }, + { 2896, 2414 }, { 2897, 2415 }, { 2971, 2416 }, { 2972, 2417 }, { 2973, 2418 }, { 2974, 2419 }, { 2975, 2420 }, + { 2976, 2421 }, { 2977, 2422 }, { 2978, 2423 }, { 2979, 2424 }, { 3071, 2425 }, { 3072, 2426 }, { 3073, 2427 }, + { 3074, 2428 }, { 3075, 2429 }, { 3076, 2430 }, { 3077, 2431 }, { 3078, 2432 }, { 3079, 2433 }, { 3080, 2434 }, + { 3081, 2435 }, { 3082, 2436 }, { 3083, 2437 }, { 3084, 2438 }, { 3085, 2439 }, { 3086, 2440 }, { 3087, 2441 }, + { 3088, 2442 }, { 3089, 2443 }, { 3090, 2444 }, { 3091, 2445 }, { 3092, 2446 }, { 3093, 2447 }, { 3094, 2448 }, + { 3095, 2449 }, { 3096, 2450 }, { 3097, 2451 }, { 3098, 2452 }, { 3099, 2453 }, { 3100, 2454 }, { 3101, 2455 }, + { 3102, 2456 }, { 3103, 2457 }, { 3104, 2458 }, { 3105, 2459 }, { 3106, 2460 }, { 3107, 2461 }, { 3108, 2462 }, + { 3109, 2463 }, { 3110, 2464 }, { 3111, 2465 }, { 3112, 2466 }, { 3113, 2467 }, { 3114, 2468 }, { 3115, 2469 }, + { 3171, 2470 }, { 3172, 2471 }, { 3173, 2472 }, { 3174, 2473 }, { 3175, 2474 }, { 3176, 2475 }, { 3177, 2476 }, + { 3178, 2477 }, { 3179, 2478 }, { 3180, 2479 }, { 3181, 2480 }, { 3182, 2481 }, { 3183, 2482 }, { 3184, 2483 }, + { 3185, 2484 }, { 3186, 2485 }, { 3187, 2486 }, { 3188, 2487 }, { 3189, 2488 }, { 3190, 2489 }, { 3191, 2490 }, + { 3192, 2491 }, { 3193, 2492 }, { 3194, 2493 }, { 3195, 2494 }, { 3196, 2495 }, { 3197, 2496 }, { 3198, 2497 }, + { 3199, 2498 }, { 3200, 2499 }, { 3201, 2500 }, { 3202, 2501 }, { 3203, 2502 }, { 3204, 2503 }, { 3205, 2504 }, + { 3206, 2505 }, { 3207, 2506 }, { 3208, 2507 }, { 3209, 2508 }, { 3210, 2509 }, { 3211, 2510 }, { 3212, 2511 }, + { 3213, 2512 }, { 3214, 2513 }, { 3215, 2514 }, { 3216, 2515 }, { 3217, 2516 }, { 3218, 2517 }, { 3219, 2518 }, + { 3220, 2519 }, { 3221, 2520 }, { 3222, 2521 }, { 3223, 2522 }, { 3224, 2523 }, { 3271, 2524 }, { 3272, 2525 }, + { 3273, 2526 }, { 3274, 2527 }, { 3275, 2528 }, { 3276, 2529 }, { 3277, 2530 }, { 3278, 2531 }, { 3279, 2532 }, + { 3280, 2533 }, { 3281, 2534 }, { 3282, 2535 }, { 3283, 2536 }, { 3284, 2537 }, { 3285, 2538 }, { 3286, 2539 }, + { 3287, 2540 }, { 3288, 2541 }, { 3289, 2542 }, { 3290, 2543 }, { 3291, 2544 }, { 3292, 2545 }, { 3293, 2546 }, + { 3294, 2547 }, { 3295, 2548 }, { 3296, 2549 }, { 3297, 2550 }, { 3298, 2551 }, { 3299, 2552 }, { 3300, 2553 }, + { 3301, 2554 }, { 3302, 2555 }, { 3303, 2556 }, { 3304, 2557 }, { 3371, 2558 }, { 3372, 2559 }, { 3373, 2560 }, + { 3374, 2561 }, { 3375, 2562 }, { 3376, 2563 }, { 3377, 2564 }, { 3378, 2565 }, { 3379, 2566 }, { 3380, 2567 }, + { 3381, 2568 }, { 3382, 2569 }, { 3383, 2570 }, { 3384, 2571 }, { 3385, 2572 }, { 3471, 2573 }, { 3472, 2574 }, + { 3473, 2575 }, { 3474, 2576 }, { 3475, 2577 }, { 3476, 2578 }, { 3477, 2579 }, { 3478, 2580 }, { 3479, 2581 }, + { 3480, 2582 }, { 3481, 2583 }, { 3482, 2584 }, { 3483, 2585 }, { 3484, 2586 }, { 3485, 2587 }, { 3486, 2588 }, + { 3487, 2589 }, { 3488, 2590 }, { 3489, 2591 }, { 3490, 2592 }, { 3491, 2593 }, { 3492, 2594 }, { 3493, 2595 }, + { 3494, 2596 }, { 3495, 2597 }, { 3496, 2598 }, { 3497, 2599 }, { 3498, 2600 }, { 3499, 2601 }, { 3500, 2602 }, + { 3501, 2603 }, { 3502, 2604 }, { 3503, 2605 }, { 3504, 2606 }, { 3505, 2607 }, { 3506, 2608 }, { 3507, 2609 }, + { 3508, 2610 }, { 3509, 2611 }, { 3510, 2612 }, { 3571, 2613 }, { 3572, 2614 }, { 3573, 2615 }, { 3574, 2616 }, + { 3575, 2617 }, { 3576, 2618 }, { 3577, 2619 }, { 3578, 2620 }, { 3579, 2621 }, { 3580, 2622 }, { 3581, 2623 }, + { 3582, 2624 }, { 3583, 2625 }, { 3584, 2626 }, { 3585, 2627 }, { 3586, 2628 }, { 3587, 2629 }, { 3588, 2630 }, + { 3589, 2631 }, { 3590, 2632 }, { 3591, 2633 }, { 3592, 2634 }, { 3593, 2635 }, { 3594, 2636 }, { 3595, 2637 }, + { 3596, 2638 }, { 3597, 2639 }, { 3598, 2640 }, { 3599, 2641 }, { 3600, 2642 }, { 3601, 2643 }, { 3602, 2644 }, + { 3603, 2645 }, { 3604, 2646 }, { 3605, 2647 }, { 3606, 2648 }, { 3607, 2649 }, { 3608, 2650 }, { 3609, 2651 }, + { 3610, 2652 }, { 3611, 2653 }, { 3612, 2654 }, { 3613, 2655 }, { 3614, 2656 }, { 3615, 2657 }, { 3616, 2658 }, + { 3617, 2659 }, { 3618, 2660 }, { 3619, 2661 }, { 3620, 2662 }, { 3621, 2663 }, { 3622, 2664 }, { 3623, 2665 }, + { 3624, 2666 }, { 3625, 2667 }, { 3626, 2668 }, { 3627, 2669 }, { 3628, 2670 }, { 3629, 2671 }, { 3630, 2672 }, + { 3631, 2673 }, { 3632, 2674 }, { 3633, 2675 }, { 3634, 2676 }, { 3635, 2677 }, { 3636, 2678 }, { 3637, 2679 }, + { 3638, 2680 }, { 3639, 2681 }, { 3640, 2682 }, { 3641, 2683 }, { 3642, 2684 }, { 3643, 2685 }, { 3644, 2686 }, + { 3645, 2687 }, { 3646, 2688 }, { 3671, 2689 }, { 3672, 2690 }, { 3673, 2691 }, { 3674, 2692 }, { 3675, 2693 }, + { 3676, 2694 }, { 3677, 2695 }, { 3678, 2696 }, { 3679, 2697 }, { 3680, 2698 }, { 3681, 2699 }, { 3682, 2700 }, + { 3683, 2701 }, { 3684, 2702 }, { 3685, 2703 }, { 3686, 2704 }, { 3687, 2705 }, { 3688, 2706 }, { 3689, 2707 }, + { 3690, 2708 }, { 3691, 2709 }, { 3692, 2710 }, { 3693, 2711 }, { 3694, 2712 }, { 3695, 2713 }, { 3696, 2714 }, + { 3697, 2715 }, { 3698, 2716 }, { 3699, 2717 }, { 3700, 2718 }, { 3701, 2719 }, { 3702, 2720 }, { 3703, 2721 }, + { 3704, 2722 }, { 3705, 2723 }, { 3706, 2724 }, { 3707, 2725 }, { 3708, 2726 }, { 3709, 2727 }, { 3710, 2728 }, + { 3711, 2729 }, { 3712, 2730 }, { 3713, 2731 }, { 3714, 2732 }, { 3715, 2733 }, { 3716, 2734 }, { 3717, 2735 }, + { 3718, 2736 }, { 3719, 2737 }, { 3720, 2738 }, { 3721, 2739 }, { 3722, 2740 }, { 3723, 2741 }, { 3724, 2742 }, + { 3725, 2743 }, { 3726, 2744 }, { 3727, 2745 }, { 3728, 2746 }, { 3729, 2747 }, { 3730, 2748 }, { 3927, 2749 }, + { 3928, 2750 }, { 3929, 2751 }, { 3930, 2752 }, { 3931, 2753 }, { 3932, 2754 }, { 3933, 2755 }, { 3934, 2756 }, + { 3940, 2762 }, { 3941, 2763 }, { 3942, 2764 }, { 3943, 2765 }, { 3944, 2766 }, { 3945, 2767 }, { 3946, 2768 }, + { 3947, 2769 }, { 3948, 2770 }, { 3949, 2771 }, { 3950, 2772 }, { 3951, 2773 }, { 3952, 2774 }, { 3953, 2775 }, + { 3954, 2776 }, { 3955, 2777 }, { 3956, 2778 }, { 3957, 2779 }, { 3958, 2780 }, { 3959, 2781 }, { 3960, 2782 }, + { 3961, 2783 }, { 3962, 2784 }, { 3963, 2785 }, { 3964, 2786 }, { 3965, 2787 }, { 3966, 2788 }, { 3967, 2789 }, + { 3968, 2790 }, { 3969, 2791 }, { 3970, 2792 }, { 3971, 2793 }, { 3972, 2794 }, { 3973, 2795 }, { 3974, 2796 }, + { 3975, 2797 }, { 3976, 2798 }, { 3977, 2799 }, { 3978, 2800 }, { 3979, 2801 }, { 3980, 2802 }, { 3981, 2803 }, + { 3982, 2804 }, { 3983, 2805 }, { 3984, 2806 }, { 3985, 2807 }, { 3986, 2808 }, { 3987, 2809 }, { 3988, 2810 }, + { 3989, 2811 }, { 3990, 2812 }, { 3991, 2813 }, { 3992, 2814 }, { 3993, 2815 }, { 3994, 2816 }, { 3995, 2817 }, + { 3996, 2818 }, { 3997, 2819 }, { 3998, 2820 }, { 3999, 2821 }, { 4000, 2822 }, { 4001, 2823 }, { 4002, 2824 }, + { 4003, 2825 }, { 4004, 2826 }, { 4005, 2827 }, { 4006, 2828 }, { 4007, 2829 }, { 4008, 2830 }, { 4009, 2831 }, + { 4010, 2832 }, { 4011, 2833 }, { 4012, 2834 }, { 4013, 2835 }, { 4014, 2836 }, { 4015, 2837 }, { 4016, 2838 }, + { 4017, 2839 }, { 4018, 2840 }, { 4019, 2841 }, { 4020, 2842 }, { 4021, 2843 }, { 4022, 2844 }, { 4023, 2845 }, + { 4024, 2846 }, { 4025, 2847 }, { 4026, 2848 }, { 4027, 2849 }, { 4028, 2850 }, { 4029, 2851 }, { 4030, 2852 }, + { 4031, 2853 }, { 4032, 2854 }, { 4127, 2855 }, { 4128, 2856 }, { 4129, 2857 }, { 4130, 2858 }, { 4131, 2859 }, + { 4132, 2860 }, { 4133, 2861 }, { 4134, 2862 }, { 4135, 2863 }, { 4136, 2864 }, { 4137, 2865 }, { 4138, 2866 }, + { 4139, 2867 }, { 4140, 2868 }, { 4145, 2873 }, { 4146, 2874 }, { 4147, 2875 }, { 4148, 2876 }, { 4149, 2877 }, + { 4150, 2878 }, { 4151, 2879 }, { 4152, 2880 }, { 4153, 2881 }, { 4154, 2882 }, { 4155, 2883 }, { 4156, 2884 }, + { 4157, 2885 }, { 4158, 2886 }, { 4159, 2887 }, { 4160, 2888 }, { 4227, 2889 }, { 4228, 2890 }, { 4229, 2891 }, + { 4230, 2892 }, { 4231, 2893 }, { 4232, 2894 }, { 4233, 2895 }, { 4234, 2896 }, { 4235, 2897 }, { 4236, 2898 }, + { 4237, 2899 }, { 4238, 2900 }, { 4239, 2901 }, { 4240, 2902 }, { 4241, 2903 }, { 4242, 2904 }, { 4243, 2905 }, + { 4244, 2906 }, { 4245, 2907 }, { 4246, 2908 }, { 4247, 2909 }, { 4248, 2910 }, { 4249, 2911 }, { 4250, 2912 }, + { 4251, 2913 }, { 4252, 2914 }, { 4253, 2915 }, { 4254, 2916 }, { 4255, 2917 }, { 4256, 2918 }, { 4257, 2919 }, + { 4258, 2920 }, { 4327, 2921 }, { 4328, 2922 }, { 4329, 2923 }, { 4330, 2924 }, { 4331, 2925 }, { 4332, 2926 }, + { 4333, 2927 }, { 4334, 2928 }, { 4335, 2929 }, { 4336, 2930 }, { 4337, 2931 }, { 4338, 2932 }, { 4339, 2933 }, + { 4340, 2934 }, { 4341, 2935 }, { 4342, 2936 }, { 4343, 2937 }, { 4344, 2938 }, { 4345, 2939 }, { 4346, 2940 }, + { 4347, 2941 }, { 4348, 2942 }, { 4349, 2943 }, { 4350, 2944 }, { 4351, 2945 }, { 4352, 2946 }, { 4353, 2947 }, + { 4354, 2948 }, { 4355, 2949 }, { 4356, 2950 }, { 4357, 2951 }, { 4358, 2952 }, { 4359, 2953 }, { 4360, 2954 }, + { 4361, 2955 }, { 4362, 2956 }, { 4363, 2957 }, { 4364, 2958 }, { 4365, 2959 }, { 4366, 2960 }, { 4367, 2961 }, + { 4368, 2962 }, { 4369, 2963 }, { 4370, 2964 }, { 4371, 2965 }, { 4372, 2966 }, { 4373, 2967 }, { 4374, 2968 }, + { 4375, 2969 }, { 4376, 2970 }, { 4377, 2971 }, { 4378, 2972 }, { 4379, 2973 }, { 4380, 2974 }, { 4381, 2975 }, + { 4382, 2976 }, { 4383, 2977 }, { 4384, 2978 }, { 4385, 2979 }, { 4386, 2980 }, { 4387, 2981 }, { 4388, 2982 }, + { 4389, 2983 }, { 4390, 2984 }, { 4391, 2985 }, { 4392, 2986 }, { 4393, 2987 }, { 4394, 2988 }, { 4395, 2989 }, + { 4396, 2990 }, { 4397, 2991 }, { 4398, 2992 }, { 4399, 2993 }, { 4400, 2994 }, { 4401, 2995 }, { 4402, 2996 }, + { 4403, 2997 }, { 4404, 2998 }, { 4405, 2999 }, { 4406, 3000 }, { 4407, 3001 }, { 4408, 3002 }, { 4409, 3003 }, + { 4410, 3004 }, { 4411, 3005 }, { 4412, 3006 }, { 4413, 3007 }, { 4414, 3008 }, { 4415, 3009 }, { 4416, 3010 }, + { 4417, 3011 }, { 4418, 3012 }, { 4419, 3013 }, { 4420, 3014 }, { 4421, 3015 }, { 4422, 3016 }, { 4423, 3017 }, + { 4424, 3018 }, { 4425, 3019 }, { 4426, 3020 }, { 4427, 3021 }, { 4428, 3022 }, { 4429, 3023 }, { 4430, 3024 }, + { 4431, 3025 }, { 4432, 3026 }, { 4433, 3027 }, { 4434, 3028 }, { 4435, 3029 }, { 4436, 3030 }, { 4437, 3031 }, + { 4438, 3032 }, { 4439, 3033 }, { 4440, 3034 }, { 4441, 3035 }, { 4442, 3036 }, { 4443, 3037 }, { 4444, 3038 }, + { 4445, 3039 }, { 4446, 3040 }, { 4447, 3041 }, { 4448, 3042 }, { 4449, 3043 }, { 4450, 3044 }, { 4527, 3045 }, + { 4528, 3046 }, { 4529, 3047 }, { 4530, 3048 }, { 4531, 3049 }, { 4532, 3050 }, { 4533, 3051 }, { 4534, 3052 }, + { 4535, 3053 }, { 4536, 3054 }, { 4537, 3055 }, { 4538, 3056 }, { 4539, 3057 }, { 4540, 3058 }, { 4541, 3059 }, + { 4542, 3060 }, { 4543, 3061 }, { 4544, 3062 }, { 4545, 3063 }, { 4546, 3064 }, { 4547, 3065 }, { 4548, 3066 }, + { 4549, 3067 }, { 4550, 3068 }, { 4551, 3069 }, { 4552, 3070 }, { 4553, 3071 }, { 4627, 3072 }, { 4628, 3073 }, + { 4629, 3074 }, { 4630, 3075 }, { 4631, 3076 }, { 4632, 3077 }, { 4633, 3078 }, { 4634, 3079 }, { 4635, 3080 }, + { 4636, 3081 }, { 4637, 3082 }, { 4638, 3083 }, { 4639, 3084 }, { 4640, 3085 }, { 4641, 3086 }, { 4642, 3087 }, + { 4643, 3088 }, { 4644, 3089 }, { 4645, 3090 }, { 4646, 3091 }, { 4647, 3092 }, { 4648, 3093 }, { 4649, 3094 }, + { 4650, 3095 }, { 4651, 3096 }, { 4652, 3097 }, { 4653, 3098 }, { 4654, 3099 }, { 4655, 3100 }, { 4656, 3101 }, + { 4657, 3102 }, { 4658, 3103 }, { 4659, 3104 }, { 4660, 3105 }, { 4661, 3106 }, { 4662, 3107 }, { 4663, 3108 }, + { 4664, 3109 }, { 4665, 3110 }, { 4666, 3111 }, { 4667, 3112 }, { 4668, 3113 }, { 4669, 3114 }, { 4670, 3115 }, + { 4671, 3116 }, { 4672, 3117 }, { 4673, 3118 }, { 4674, 3119 }, { 4675, 3120 }, { 4676, 3121 }, { 4677, 3122 }, + { 4678, 3123 }, { 4679, 3124 }, { 4680, 3125 }, { 4681, 3126 }, { 4682, 3127 }, { 4683, 3128 }, { 4684, 3129 }, + { 4685, 3130 }, { 4686, 3131 }, { 4687, 3132 }, { 4688, 3133 }, { 4689, 3134 }, { 4690, 3135 }, { 4691, 3136 }, + { 4692, 3137 }, { 4693, 3138 }, { 4694, 3139 }, { 4695, 3140 }, { 4696, 3141 }, { 4697, 3142 }, { 4698, 3143 }, + { 4699, 3144 }, { 4700, 3145 }, { 4701, 3146 }, { 4702, 3147 }, { 4703, 3148 }, { 4704, 3149 }, { 4705, 3150 }, + { 4706, 3151 }, { 4707, 3152 }, { 4708, 3153 }, { 4709, 3154 }, { 4710, 3155 }, { 4711, 3156 }, { 4712, 3157 }, + { 4713, 3158 }, { 4714, 3159 }, { 4715, 3160 }, { 4716, 3161 }, { 4717, 3162 }, { 4718, 3163 }, { 4719, 3164 }, + { 4720, 3165 }, { 4721, 3166 }, { 4722, 3167 }, { 4723, 3168 }, { 4724, 3169 }, { 4725, 3170 }, { 4726, 3171 }, + { 4827, 3172 }, { 4828, 3173 }, { 4829, 3174 }, { 4830, 3175 }, { 4831, 3176 }, { 4832, 3177 }, { 4833, 3178 }, + { 4834, 3179 }, { 4835, 3180 }, { 4836, 3181 }, { 4837, 3182 }, { 4838, 3183 }, { 4839, 3184 }, { 4840, 3185 }, + { 4841, 3186 }, { 4842, 3187 }, { 4843, 3188 }, { 4844, 3189 }, { 4845, 3190 }, { 5027, 3191 }, { 5028, 3192 }, + { 5029, 3193 }, { 5030, 3194 }, { 5031, 3195 }, { 5032, 3196 }, { 5033, 3197 }, { 5034, 3198 }, { 5035, 3199 }, + { 5036, 3200 }, { 5037, 3201 }, { 5038, 3202 }, { 5039, 3203 }, { 5040, 3204 }, { 5041, 3205 }, { 5042, 3206 }, + { 5043, 3207 }, { 5044, 3208 }, { 5045, 3209 }, { 5046, 3210 }, { 5047, 3211 }, { 5048, 3212 }, { 5049, 3213 }, + { 5050, 3214 }, { 5051, 3215 }, { 5052, 3216 }, { 5053, 3217 }, { 5054, 3218 }, { 5055, 3219 }, { 5056, 3220 }, + { 5057, 3221 }, { 5058, 3222 }, { 5059, 3223 }, { 5060, 3224 }, { 5061, 3225 }, { 5062, 3226 }, { 5063, 3227 }, + { 5064, 3228 }, { 5065, 3229 }, { 5066, 3230 }, { 5067, 3231 }, { 5068, 3232 }, { 5069, 3233 }, { 5070, 3234 }, + { 5071, 3235 }, { 5072, 3236 }, { 5073, 3237 }, { 5074, 3238 }, { 5075, 3239 }, { 5076, 3240 }, { 5077, 3241 }, + { 5127, 3242 }, { 5128, 3243 }, { 5129, 3244 }, { 5130, 3245 }, { 5131, 3246 }, { 5132, 3247 }, { 5133, 3248 }, + { 5134, 3249 }, { 5135, 3250 }, { 5136, 3251 }, { 5137, 3252 }, { 5138, 3253 }, { 5139, 3254 }, { 5140, 3255 }, + { 5141, 3256 }, { 5142, 3257 }, { 5143, 3258 }, { 5144, 3259 }, { 5145, 3260 }, { 5146, 3261 }, { 5147, 3262 }, + { 5148, 3263 }, { 5149, 3264 }, { 5150, 3265 }, { 5151, 3266 }, { 5152, 3267 }, { 5153, 3268 }, { 5154, 3269 }, + { 5155, 3270 }, { 5156, 3271 }, { 5227, 3272 }, { 5228, 3273 }, { 5229, 3274 }, { 5230, 3275 }, { 5231, 3276 }, + { 5232, 3277 }, { 5233, 3278 }, { 5234, 3279 }, { 5235, 3280 }, { 5236, 3281 }, { 5237, 3282 }, { 5238, 3283 }, + { 5240, 3285 }, { 5241, 3286 }, { 5242, 3287 }, { 5243, 3288 }, { 5244, 3289 }, { 5245, 3290 }, { 5246, 3291 }, + { 5247, 3292 }, { 5248, 3293 }, { 5249, 3294 }, { 5250, 3295 }, { 5251, 3296 }, { 5252, 3297 }, { 5253, 3298 }, + { 5254, 3299 }, { 5255, 3300 }, { 5256, 3301 }, { 5257, 3302 }, { 5258, 3303 }, { 5259, 3304 }, { 5260, 3305 }, + { 5261, 3306 }, { 5262, 3307 }, { 5263, 3308 }, { 5264, 3309 }, { 5265, 3310 }, { 5266, 3311 }, { 5267, 3312 }, + { 5268, 3313 }, { 5269, 3314 }, { 5270, 3315 }, { 5271, 3316 }, { 5272, 3317 }, { 5273, 3318 }, { 5274, 3319 }, + { 5275, 3320 }, { 5276, 3321 }, { 5277, 3322 }, { 5278, 3323 }, { 5279, 3324 }, { 5280, 3325 }, { 5281, 3326 }, + { 5282, 3327 }, { 5283, 3328 }, { 5284, 3329 }, { 5285, 3330 }, { 5286, 3331 }, { 5288, 3333 }, { 5289, 3334 }, + { 5290, 3335 }, { 5291, 3336 }, { 5292, 3337 }, { 5293, 3338 }, { 5294, 3339 }, { 5296, 3341 }, { 5297, 3342 }, + { 5298, 3343 }, { 5299, 3344 }, { 5300, 3345 }, { 5301, 3346 }, { 5302, 3347 }, { 5303, 3348 }, { 5304, 3349 }, + { 5305, 3350 }, { 5306, 3351 }, { 5307, 3352 }, { 5308, 3353 }, { 5309, 3354 }, { 5310, 3355 }, { 5311, 3356 }, + { 5312, 3357 }, { 5313, 3358 }, { 5314, 3359 }, { 5315, 3360 }, { 5316, 3361 }, { 5317, 3362 }, { 5318, 3363 }, + { 5319, 3364 }, { 5320, 3365 }, { 5321, 3366 }, { 5322, 3367 }, { 5323, 3368 }, { 5324, 3369 }, { 5325, 3370 }, + { 5326, 3371 }, { 5327, 3372 }, { 5328, 3373 }, { 5329, 3374 }, { 5330, 3375 }, { 5331, 3376 }, { 5332, 3377 }, + { 5333, 3378 }, { 5336, 3381 }, { 5337, 3382 }, { 5338, 3383 }, { 5339, 3384 }, { 5340, 3385 }, { 5341, 3386 }, + { 5342, 3387 }, { 5343, 3388 }, { 5344, 3389 }, { 5345, 3390 }, { 5346, 3391 }, { 5347, 3392 }, { 5348, 3393 }, + { 5349, 3394 }, { 5350, 3395 }, { 5351, 3396 }, { 5352, 3397 }, { 5357, 3402 }, { 5358, 3403 }, { 5359, 3404 }, + { 5360, 3405 }, { 5361, 3406 }, { 5362, 3407 }, { 5363, 3408 }, { 5364, 3409 }, { 5365, 3410 }, { 5366, 3411 }, + { 5367, 3412 }, { 5368, 3413 }, { 5369, 3414 }, { 5370, 3415 }, { 5371, 3416 }, { 5372, 3417 }, { 5373, 3418 }, + { 5374, 3419 }, { 5375, 3420 }, { 5376, 3421 }, { 5377, 3422 }, { 5378, 3423 }, { 5379, 3424 }, { 5380, 3425 }, + { 5381, 3426 }, { 5382, 3427 }, { 5383, 3428 }, { 5384, 3429 }, { 5385, 3430 }, { 5386, 3431 }, { 5387, 3432 }, + { 5388, 3433 }, { 5389, 3434 }, { 5390, 3435 }, { 5391, 3436 }, { 5392, 3437 }, { 5393, 3438 }, { 5394, 3439 }, + { 5395, 3440 }, { 5396, 3441 }, { 5397, 3442 }, { 5398, 3443 }, { 5399, 3444 }, { 5400, 3445 }, { 5401, 3446 }, + { 5402, 3447 }, { 5403, 3448 }, { 5404, 3449 }, { 5405, 3450 }, { 5406, 3451 }, { 5407, 3452 }, { 5408, 3453 }, + { 5409, 3454 }, { 5410, 3455 }, { 5411, 3456 }, { 5412, 3457 }, { 5413, 3458 }, { 5414, 3459 }, { 5415, 3460 }, + { 5416, 3461 }, { 5417, 3462 }, { 5418, 3463 }, { 5419, 3464 }, { 5420, 3465 }, { 5421, 3466 }, { 5422, 3467 }, + { 5423, 3468 }, { 5424, 3469 }, { 5425, 3470 }, { 5426, 3471 }, { 5427, 3472 }, { 5428, 3473 }, { 5429, 3474 }, + { 5430, 3475 }, { 5431, 3476 }, { 5432, 3477 }, { 5433, 3478 }, { 5434, 3479 }, { 5435, 3480 }, { 5436, 3481 }, + { 5437, 3482 }, { 5438, 3483 }, { 5439, 3484 }, { 5440, 3485 }, { 5441, 3486 }, { 5442, 3487 }, { 5443, 3488 }, + { 5444, 3489 }, { 5445, 3490 }, { 5446, 3491 }, { 5447, 3492 }, { 5448, 3493 }, { 5449, 3494 }, { 5450, 3495 }, + { 5451, 3496 }, { 5452, 3497 }, { 5453, 3498 }, { 5454, 3499 }, { 5455, 3500 }, { 5456, 3501 }, { 5457, 3502 }, + { 5458, 3503 }, { 5459, 3504 }, { 5460, 3505 }, { 5461, 3506 }, { 5462, 3507 }, { 5463, 3508 }, { 5464, 3509 }, + { 5465, 3510 }, { 5466, 3511 }, { 5467, 3512 }, { 5468, 3513 }, { 5469, 3514 }, { 5470, 3515 }, { 5471, 3516 }, + { 5472, 3517 }, { 5473, 3518 }, { 5474, 3519 }, { 5475, 3520 }, { 5476, 3521 }, { 5477, 3522 }, { 5478, 3523 }, + { 5479, 3524 }, { 5480, 3525 }, { 5481, 3526 }, { 5482, 3527 }, { 5483, 3528 }, { 5484, 3529 }, { 5485, 3530 }, + { 5486, 3531 }, { 5487, 3532 }, { 5488, 3533 }, { 5489, 3534 }, { 5490, 3535 }, { 5491, 3536 }, { 5492, 3537 }, + { 5493, 3538 }, { 5494, 3539 }, { 5495, 3540 }, { 5496, 3541 }, { 5497, 3542 }, { 5498, 3543 }, { 5499, 3544 }, + { 5500, 3545 }, { 5501, 3546 }, { 5502, 3547 }, { 5503, 3548 }, { 5504, 3549 }, { 5505, 3550 }, { 5506, 3551 }, + { 5507, 3552 }, { 5508, 3553 }, { 5509, 3554 }, { 5510, 3555 }, { 5511, 3556 }, { 5512, 3557 }, { 5513, 3558 }, + { 5514, 3559 }, { 5515, 3560 }, { 5516, 3561 }, { 5517, 3562 }, { 5518, 3563 }, { 5519, 3564 }, { 5520, 3565 }, + { 5521, 3566 }, { 5522, 3567 }, { 5523, 3568 }, { 5524, 3569 }, { 5525, 3570 }, { 5526, 3571 }, { 5527, 3572 }, + { 5528, 3573 }, { 5529, 3574 }, { 5530, 3575 }, { 5531, 3576 }, { 5532, 3577 }, { 5533, 3578 }, { 5534, 3579 }, + { 5535, 3580 }, { 5536, 3581 }, { 5537, 3582 }, { 5538, 3583 }, { 5539, 3584 }, { 5540, 3585 }, { 5541, 3586 }, + { 5542, 3587 }, { 5543, 3588 }, { 5544, 3589 }, { 5545, 3590 }, { 5546, 3591 }, { 5547, 3592 }, { 5548, 3593 }, + { 5549, 3594 }, { 5550, 3595 }, { 5551, 3596 }, { 5552, 3597 }, { 5553, 3598 }, { 5554, 3599 }, { 5555, 3600 }, + { 5556, 3601 }, { 5557, 3602 }, { 5558, 3603 }, { 5559, 3604 }, { 5560, 3605 }, { 5561, 3606 }, { 5562, 3607 }, + { 5563, 3608 }, { 5564, 3609 }, { 5565, 3610 }, { 5566, 3611 }, { 5567, 3612 }, { 5568, 3613 }, { 5569, 3614 }, + { 5570, 3615 } }; -// v1.0 -> PAL asset ID remap table. 1300 entries. +// v1.0 -> PAL asset ID remap table. 1311 entries. static const std::unordered_map sV10toPALRemap = { { 2468, 2212 }, { 2469, 2213 }, { 2470, 2214 }, { 2471, 2215 }, { 2472, 2268 }, { 2473, 2269 }, { 2474, 2218 }, { 2475, 2219 }, { 2476, 2220 }, { 2477, 2221 }, { 2478, 2274 }, { 2481, 2277 }, { 2483, 2279 }, { 2484, 2228 }, @@ -211,177 +213,179 @@ static const std::unordered_map sV10toPALRemap = { { 2696, 2372 }, { 2771, 2373 }, { 2772, 2374 }, { 2773, 2375 }, { 2774, 2376 }, { 2775, 2377 }, { 2776, 2378 }, { 2777, 2379 }, { 2778, 2380 }, { 2779, 2381 }, { 2780, 2382 }, { 2781, 2383 }, { 2782, 2384 }, { 2783, 2385 }, { 2784, 2386 }, { 2785, 2387 }, { 2786, 2388 }, { 2871, 2389 }, { 2872, 2390 }, { 2873, 2391 }, { 2874, 2392 }, - { 2875, 2393 }, { 2876, 2394 }, { 2877, 2395 }, { 2879, 2397 }, { 2880, 2398 }, { 2881, 2399 }, { 2882, 2400 }, - { 2883, 2401 }, { 2884, 2402 }, { 2885, 2403 }, { 2886, 2404 }, { 2887, 2405 }, { 2888, 2406 }, { 2889, 2407 }, - { 2890, 2408 }, { 2891, 2409 }, { 2892, 2410 }, { 2893, 2411 }, { 2894, 2412 }, { 2895, 2413 }, { 2896, 2414 }, - { 2897, 2415 }, { 2971, 2416 }, { 2972, 2417 }, { 2973, 2418 }, { 2974, 2419 }, { 2975, 2420 }, { 2976, 2421 }, - { 2977, 2422 }, { 2978, 2423 }, { 2979, 2424 }, { 3071, 2425 }, { 3072, 2426 }, { 3073, 2427 }, { 3074, 2428 }, - { 3075, 2429 }, { 3076, 2430 }, { 3077, 2431 }, { 3078, 2432 }, { 3079, 2433 }, { 3080, 2434 }, { 3081, 2435 }, - { 3082, 2436 }, { 3083, 2437 }, { 3084, 2438 }, { 3085, 2439 }, { 3086, 2440 }, { 3087, 2441 }, { 3088, 2442 }, - { 3089, 2443 }, { 3090, 2444 }, { 3091, 2445 }, { 3092, 2446 }, { 3093, 2447 }, { 3094, 2448 }, { 3095, 2449 }, - { 3096, 2450 }, { 3097, 2451 }, { 3098, 2452 }, { 3099, 2453 }, { 3100, 2454 }, { 3101, 2455 }, { 3102, 2456 }, - { 3103, 2457 }, { 3104, 2458 }, { 3105, 2459 }, { 3106, 2460 }, { 3107, 2461 }, { 3108, 2462 }, { 3109, 2463 }, - { 3110, 2464 }, { 3111, 2465 }, { 3112, 2466 }, { 3113, 2467 }, { 3114, 2468 }, { 3115, 2469 }, { 3171, 2470 }, - { 3172, 2471 }, { 3173, 2472 }, { 3174, 2473 }, { 3175, 2474 }, { 3176, 2475 }, { 3177, 2476 }, { 3178, 2477 }, - { 3179, 2478 }, { 3180, 2479 }, { 3181, 2480 }, { 3182, 2481 }, { 3183, 2482 }, { 3184, 2483 }, { 3185, 2484 }, - { 3186, 2485 }, { 3187, 2486 }, { 3188, 2487 }, { 3189, 2488 }, { 3190, 2489 }, { 3191, 2490 }, { 3192, 2491 }, - { 3193, 2492 }, { 3194, 2493 }, { 3195, 2494 }, { 3196, 2495 }, { 3197, 2496 }, { 3198, 2497 }, { 3199, 2498 }, - { 3200, 2499 }, { 3201, 2500 }, { 3202, 2501 }, { 3203, 2502 }, { 3204, 2503 }, { 3205, 2504 }, { 3206, 2505 }, - { 3207, 2506 }, { 3208, 2507 }, { 3209, 2508 }, { 3210, 2509 }, { 3211, 2510 }, { 3212, 2511 }, { 3213, 2512 }, - { 3214, 2513 }, { 3215, 2514 }, { 3216, 2515 }, { 3217, 2516 }, { 3218, 2517 }, { 3219, 2518 }, { 3220, 2519 }, - { 3221, 2520 }, { 3222, 2521 }, { 3223, 2522 }, { 3224, 2523 }, { 3271, 2524 }, { 3272, 2525 }, { 3273, 2526 }, - { 3274, 2527 }, { 3275, 2528 }, { 3276, 2529 }, { 3277, 2530 }, { 3278, 2531 }, { 3279, 2532 }, { 3280, 2533 }, - { 3281, 2534 }, { 3282, 2535 }, { 3283, 2536 }, { 3284, 2537 }, { 3285, 2538 }, { 3286, 2539 }, { 3287, 2540 }, - { 3288, 2541 }, { 3289, 2542 }, { 3290, 2543 }, { 3291, 2544 }, { 3292, 2545 }, { 3293, 2546 }, { 3294, 2547 }, - { 3295, 2548 }, { 3296, 2549 }, { 3297, 2550 }, { 3298, 2551 }, { 3299, 2552 }, { 3300, 2553 }, { 3301, 2554 }, - { 3302, 2555 }, { 3303, 2556 }, { 3304, 2557 }, { 3371, 2558 }, { 3372, 2559 }, { 3373, 2560 }, { 3374, 2561 }, - { 3375, 2562 }, { 3376, 2563 }, { 3377, 2564 }, { 3378, 2565 }, { 3379, 2566 }, { 3380, 2567 }, { 3381, 2568 }, - { 3382, 2569 }, { 3383, 2570 }, { 3384, 3024 }, { 3385, 2572 }, { 3471, 2573 }, { 3472, 2574 }, { 3473, 2575 }, - { 3474, 2576 }, { 3475, 2577 }, { 3476, 2578 }, { 3477, 2579 }, { 3478, 2580 }, { 3479, 2581 }, { 3480, 2582 }, - { 3481, 2583 }, { 3482, 2584 }, { 3483, 2585 }, { 3484, 2586 }, { 3485, 2587 }, { 3486, 2588 }, { 3487, 2589 }, - { 3488, 2590 }, { 3489, 2591 }, { 3490, 2592 }, { 3491, 2593 }, { 3492, 2594 }, { 3493, 2595 }, { 3494, 2596 }, - { 3495, 2597 }, { 3496, 2598 }, { 3497, 2599 }, { 3498, 2600 }, { 3499, 2601 }, { 3500, 2602 }, { 3501, 2603 }, - { 3502, 2604 }, { 3503, 2605 }, { 3504, 2606 }, { 3505, 2607 }, { 3506, 2608 }, { 3507, 2609 }, { 3508, 2610 }, - { 3509, 2611 }, { 3510, 2612 }, { 3571, 2613 }, { 3572, 2614 }, { 3573, 2615 }, { 3574, 2616 }, { 3575, 2617 }, - { 3576, 2618 }, { 3577, 2619 }, { 3578, 2620 }, { 3579, 2621 }, { 3580, 2622 }, { 3581, 2623 }, { 3582, 2624 }, - { 3583, 2625 }, { 3584, 2626 }, { 3585, 2627 }, { 3586, 2628 }, { 3587, 2629 }, { 3588, 2630 }, { 3589, 2631 }, - { 3590, 2632 }, { 3591, 2633 }, { 3592, 2634 }, { 3593, 2635 }, { 3594, 2636 }, { 3595, 2637 }, { 3596, 2638 }, - { 3597, 2639 }, { 3598, 2640 }, { 3599, 2641 }, { 3600, 2642 }, { 3601, 2643 }, { 3602, 2644 }, { 3603, 2645 }, - { 3604, 2646 }, { 3605, 2647 }, { 3606, 2648 }, { 3607, 2649 }, { 3608, 2650 }, { 3609, 2651 }, { 3610, 2652 }, - { 3611, 2653 }, { 3612, 2654 }, { 3613, 2655 }, { 3614, 2656 }, { 3615, 2657 }, { 3616, 2658 }, { 3617, 2659 }, - { 3618, 2660 }, { 3619, 2661 }, { 3620, 2662 }, { 3621, 2663 }, { 3622, 2664 }, { 3623, 2665 }, { 3624, 2666 }, - { 3625, 2667 }, { 3626, 2668 }, { 3627, 2669 }, { 3628, 2670 }, { 3629, 2671 }, { 3630, 2672 }, { 3631, 2673 }, - { 3632, 2674 }, { 3633, 2675 }, { 3634, 2676 }, { 3635, 2677 }, { 3636, 2678 }, { 3637, 2679 }, { 3638, 2680 }, - { 3639, 2681 }, { 3640, 2682 }, { 3641, 2683 }, { 3642, 2684 }, { 3643, 2685 }, { 3644, 2686 }, { 3645, 2687 }, - { 3646, 2688 }, { 3671, 2689 }, { 3672, 2690 }, { 3673, 2691 }, { 3674, 2692 }, { 3675, 2693 }, { 3676, 2694 }, - { 3677, 2695 }, { 3678, 2696 }, { 3679, 2697 }, { 3680, 2698 }, { 3681, 2699 }, { 3682, 2700 }, { 3683, 2701 }, - { 3684, 2702 }, { 3685, 2703 }, { 3686, 2704 }, { 3687, 2705 }, { 3688, 2706 }, { 3689, 2707 }, { 3690, 2708 }, - { 3691, 2709 }, { 3692, 2710 }, { 3693, 2711 }, { 3694, 2712 }, { 3695, 2713 }, { 3696, 2714 }, { 3697, 2715 }, - { 3698, 2716 }, { 3699, 2717 }, { 3700, 2718 }, { 3701, 2719 }, { 3702, 2720 }, { 3703, 2721 }, { 3704, 2722 }, - { 3705, 2723 }, { 3706, 2724 }, { 3707, 2725 }, { 3708, 2726 }, { 3709, 2727 }, { 3710, 2728 }, { 3711, 2729 }, - { 3712, 2730 }, { 3713, 2731 }, { 3714, 2732 }, { 3715, 2733 }, { 3716, 2734 }, { 3717, 2735 }, { 3718, 2736 }, - { 3719, 2737 }, { 3720, 2738 }, { 3721, 2739 }, { 3722, 2740 }, { 3723, 2741 }, { 3724, 2742 }, { 3725, 2743 }, - { 3726, 2744 }, { 3727, 2745 }, { 3728, 2746 }, { 3729, 2747 }, { 3730, 2748 }, { 3927, 2749 }, { 3928, 2750 }, - { 3929, 2751 }, { 3930, 2752 }, { 3931, 2753 }, { 3932, 2754 }, { 3933, 2755 }, { 3934, 2756 }, { 3940, 2762 }, - { 3941, 2763 }, { 3942, 2764 }, { 3943, 2765 }, { 3944, 2766 }, { 3945, 2767 }, { 3946, 2768 }, { 3947, 2769 }, - { 3948, 2770 }, { 3949, 2771 }, { 3950, 2772 }, { 3951, 2773 }, { 3952, 2774 }, { 3953, 2775 }, { 3954, 2776 }, - { 3955, 2777 }, { 3956, 2778 }, { 3957, 2779 }, { 3958, 2780 }, { 3959, 2781 }, { 3960, 2782 }, { 3961, 2783 }, - { 3962, 2784 }, { 3963, 2785 }, { 3964, 2786 }, { 3965, 2787 }, { 3966, 2788 }, { 3967, 2789 }, { 3968, 2790 }, - { 3969, 2791 }, { 3970, 2792 }, { 3971, 2793 }, { 3972, 2794 }, { 3973, 2795 }, { 3974, 2796 }, { 3975, 2797 }, - { 3976, 2798 }, { 3977, 2799 }, { 3978, 2800 }, { 3979, 2801 }, { 3980, 2802 }, { 3981, 2803 }, { 3982, 2804 }, - { 3983, 2805 }, { 3984, 2806 }, { 3985, 2807 }, { 3986, 2808 }, { 3987, 2809 }, { 3988, 2810 }, { 3989, 2811 }, - { 3990, 2812 }, { 3991, 2813 }, { 3992, 2814 }, { 3993, 2815 }, { 3994, 2816 }, { 3995, 2817 }, { 3996, 2818 }, - { 3997, 2819 }, { 3998, 2820 }, { 3999, 2821 }, { 4000, 2822 }, { 4001, 2823 }, { 4002, 2824 }, { 4003, 2825 }, - { 4004, 2826 }, { 4005, 2827 }, { 4006, 2828 }, { 4007, 2829 }, { 4008, 2830 }, { 4009, 2831 }, { 4010, 2832 }, - { 4011, 2833 }, { 4012, 2834 }, { 4013, 2835 }, { 4014, 2836 }, { 4015, 2837 }, { 4016, 2838 }, { 4017, 2839 }, - { 4018, 2840 }, { 4019, 2841 }, { 4020, 2842 }, { 4021, 2843 }, { 4022, 2844 }, { 4023, 2845 }, { 4024, 2846 }, - { 4025, 2847 }, { 4026, 2848 }, { 4027, 2849 }, { 4028, 2850 }, { 4029, 2851 }, { 4030, 2852 }, { 4031, 2853 }, - { 4032, 2854 }, { 4127, 2855 }, { 4128, 2856 }, { 4129, 2857 }, { 4130, 2858 }, { 4131, 2859 }, { 4132, 2860 }, - { 4133, 2861 }, { 4134, 2862 }, { 4135, 2863 }, { 4136, 2864 }, { 4137, 2865 }, { 4138, 2866 }, { 4139, 2867 }, - { 4140, 2868 }, { 4145, 2873 }, { 4146, 2874 }, { 4147, 2875 }, { 4148, 2876 }, { 4149, 2877 }, { 4150, 2878 }, - { 4151, 2879 }, { 4152, 2880 }, { 4153, 2881 }, { 4154, 2882 }, { 4155, 2883 }, { 4156, 2884 }, { 4157, 2885 }, - { 4158, 2886 }, { 4159, 2887 }, { 4160, 2888 }, { 4227, 2889 }, { 4228, 2890 }, { 4229, 2891 }, { 4230, 2892 }, - { 4231, 2893 }, { 4232, 2894 }, { 4233, 2895 }, { 4234, 2896 }, { 4235, 2897 }, { 4236, 2898 }, { 4237, 2899 }, - { 4238, 2900 }, { 4239, 2901 }, { 4240, 2902 }, { 4241, 2903 }, { 4242, 2904 }, { 4243, 2905 }, { 4244, 2906 }, - { 4245, 2907 }, { 4246, 2908 }, { 4247, 2909 }, { 4248, 2910 }, { 4249, 2911 }, { 4250, 2912 }, { 4251, 2913 }, - { 4252, 2914 }, { 4253, 2915 }, { 4254, 2916 }, { 4255, 2917 }, { 4256, 2918 }, { 4257, 2919 }, { 4258, 2920 }, - { 4327, 2921 }, { 4328, 2922 }, { 4329, 2923 }, { 4330, 2924 }, { 4331, 2925 }, { 4332, 2926 }, { 4333, 2927 }, - { 4334, 2928 }, { 4335, 2929 }, { 4336, 2930 }, { 4337, 2931 }, { 4338, 2932 }, { 4339, 2933 }, { 4340, 2934 }, - { 4341, 2935 }, { 4342, 2936 }, { 4343, 2937 }, { 4344, 2938 }, { 4345, 2939 }, { 4346, 2940 }, { 4347, 2941 }, - { 4348, 2942 }, { 4349, 2943 }, { 4350, 2944 }, { 4351, 2945 }, { 4352, 2946 }, { 4353, 2947 }, { 4354, 2948 }, - { 4355, 2949 }, { 4356, 2950 }, { 4357, 2951 }, { 4358, 2952 }, { 4359, 2953 }, { 4360, 2954 }, { 4361, 2955 }, - { 4362, 2956 }, { 4363, 2957 }, { 4364, 2958 }, { 4365, 2959 }, { 4366, 2960 }, { 4367, 2961 }, { 4368, 2962 }, - { 4369, 2963 }, { 4370, 2964 }, { 4371, 2965 }, { 4372, 2966 }, { 4373, 2967 }, { 4374, 2968 }, { 4375, 2969 }, - { 4376, 2970 }, { 4377, 2971 }, { 4378, 2972 }, { 4379, 2973 }, { 4380, 2974 }, { 4381, 2975 }, { 4382, 2976 }, - { 4383, 2977 }, { 4384, 2978 }, { 4385, 2979 }, { 4386, 2980 }, { 4387, 2981 }, { 4388, 2982 }, { 4389, 2983 }, - { 4390, 2984 }, { 4391, 2985 }, { 4392, 2986 }, { 4393, 2987 }, { 4394, 2988 }, { 4395, 2989 }, { 4396, 2990 }, - { 4397, 2991 }, { 4398, 2992 }, { 4399, 2993 }, { 4400, 2994 }, { 4406, 3000 }, { 4407, 3001 }, { 4408, 3002 }, - { 4409, 3003 }, { 4410, 3004 }, { 4411, 3005 }, { 4412, 3006 }, { 4413, 3007 }, { 4414, 3008 }, { 4415, 3009 }, - { 4416, 3010 }, { 4417, 3011 }, { 4418, 3012 }, { 4419, 3013 }, { 4420, 3014 }, { 4421, 3015 }, { 4422, 3016 }, - { 4423, 3017 }, { 4424, 3018 }, { 4425, 3019 }, { 4426, 3020 }, { 4431, 3025 }, { 4432, 3026 }, { 4433, 3027 }, - { 4434, 3028 }, { 4435, 3029 }, { 4436, 3030 }, { 4437, 3031 }, { 4438, 3032 }, { 4439, 3033 }, { 4440, 3034 }, - { 4441, 3035 }, { 4442, 3036 }, { 4443, 3037 }, { 4444, 3038 }, { 4445, 3039 }, { 4446, 3040 }, { 4447, 3041 }, - { 4448, 3042 }, { 4449, 3043 }, { 4450, 3044 }, { 4527, 3045 }, { 4528, 3046 }, { 4529, 3047 }, { 4530, 3048 }, - { 4531, 3049 }, { 4532, 3050 }, { 4533, 3051 }, { 4534, 3052 }, { 4535, 3053 }, { 4536, 3054 }, { 4537, 3055 }, - { 4538, 3056 }, { 4539, 3057 }, { 4540, 3058 }, { 4541, 3059 }, { 4542, 3060 }, { 4543, 3061 }, { 4544, 3062 }, - { 4545, 3063 }, { 4546, 3064 }, { 4547, 3066 }, { 4548, 3067 }, { 4549, 3068 }, { 4550, 3069 }, { 4551, 3070 }, - { 4552, 3071 }, { 4553, 3072 }, { 4627, 3073 }, { 4628, 3074 }, { 4629, 3075 }, { 4630, 3076 }, { 4631, 3077 }, - { 4632, 3078 }, { 4633, 3079 }, { 4634, 3080 }, { 4635, 3081 }, { 4636, 3082 }, { 4637, 3083 }, { 4638, 3084 }, - { 4639, 3085 }, { 4640, 3086 }, { 4641, 3087 }, { 4642, 3088 }, { 4643, 3089 }, { 4644, 3090 }, { 4645, 3091 }, - { 4646, 3092 }, { 4647, 3093 }, { 4648, 3094 }, { 4649, 3095 }, { 4650, 3096 }, { 4651, 3097 }, { 4652, 3098 }, - { 4653, 3099 }, { 4654, 3100 }, { 4655, 3101 }, { 4656, 3102 }, { 4657, 3103 }, { 4658, 3104 }, { 4659, 3105 }, - { 4660, 3106 }, { 4661, 3107 }, { 4662, 3108 }, { 4663, 3109 }, { 4664, 3110 }, { 4665, 3111 }, { 4666, 3112 }, - { 4667, 3113 }, { 4668, 3114 }, { 4669, 3115 }, { 4670, 3116 }, { 4671, 3117 }, { 4672, 3118 }, { 4673, 3119 }, - { 4674, 3120 }, { 4675, 3121 }, { 4676, 3122 }, { 4677, 3123 }, { 4678, 3124 }, { 4679, 3125 }, { 4680, 3126 }, - { 4681, 3127 }, { 4682, 3128 }, { 4683, 3129 }, { 4684, 3130 }, { 4685, 3131 }, { 4686, 3132 }, { 4687, 3133 }, - { 4688, 3134 }, { 4689, 3135 }, { 4690, 3136 }, { 4691, 3137 }, { 4692, 3138 }, { 4693, 3139 }, { 4694, 3140 }, - { 4695, 3141 }, { 4696, 3142 }, { 4697, 3143 }, { 4698, 3144 }, { 4699, 3145 }, { 4700, 3146 }, { 4701, 3147 }, - { 4702, 3148 }, { 4703, 3149 }, { 4704, 3150 }, { 4705, 3151 }, { 4706, 3152 }, { 4707, 3153 }, { 4708, 3154 }, - { 4709, 3155 }, { 4710, 3156 }, { 4711, 3157 }, { 4712, 3158 }, { 4713, 3159 }, { 4714, 3160 }, { 4715, 3161 }, - { 4716, 3162 }, { 4717, 3163 }, { 4718, 3164 }, { 4719, 3165 }, { 4720, 3166 }, { 4721, 3167 }, { 4722, 3168 }, - { 4723, 3169 }, { 4724, 3170 }, { 4725, 3171 }, { 4726, 3172 }, { 4827, 3173 }, { 4828, 3174 }, { 4829, 3175 }, - { 4830, 3176 }, { 4831, 3177 }, { 4832, 3178 }, { 4833, 3179 }, { 4834, 3180 }, { 4835, 3181 }, { 4836, 3182 }, - { 4837, 3183 }, { 4838, 3184 }, { 4839, 3185 }, { 4840, 3186 }, { 4841, 3187 }, { 4842, 3188 }, { 4843, 3189 }, - { 4844, 3190 }, { 4845, 3191 }, { 5027, 3192 }, { 5028, 3193 }, { 5029, 3194 }, { 5030, 3195 }, { 5031, 3196 }, - { 5032, 3197 }, { 5033, 3198 }, { 5034, 3199 }, { 5035, 3200 }, { 5036, 3201 }, { 5037, 3202 }, { 5038, 3203 }, - { 5039, 3204 }, { 5040, 3205 }, { 5041, 3206 }, { 5042, 3207 }, { 5043, 3208 }, { 5044, 3209 }, { 5045, 3210 }, - { 5046, 3211 }, { 5047, 3212 }, { 5048, 3213 }, { 5049, 3214 }, { 5050, 3215 }, { 5051, 3216 }, { 5052, 3217 }, - { 5053, 3218 }, { 5054, 3219 }, { 5055, 3220 }, { 5056, 3221 }, { 5057, 3222 }, { 5058, 3223 }, { 5059, 3224 }, - { 5060, 3225 }, { 5061, 3226 }, { 5062, 3227 }, { 5063, 3228 }, { 5064, 3229 }, { 5065, 3230 }, { 5066, 3231 }, - { 5067, 3232 }, { 5068, 3233 }, { 5069, 3234 }, { 5070, 3235 }, { 5071, 3236 }, { 5072, 3237 }, { 5073, 3238 }, - { 5074, 3239 }, { 5075, 3240 }, { 5076, 3241 }, { 5077, 3242 }, { 5127, 3243 }, { 5128, 3244 }, { 5129, 3245 }, - { 5130, 3246 }, { 5131, 3247 }, { 5132, 3248 }, { 5133, 3249 }, { 5134, 3250 }, { 5135, 3251 }, { 5136, 3252 }, - { 5137, 3253 }, { 5138, 3254 }, { 5139, 3255 }, { 5140, 3256 }, { 5141, 3257 }, { 5142, 3258 }, { 5143, 3259 }, - { 5144, 3260 }, { 5145, 3261 }, { 5146, 3262 }, { 5147, 3263 }, { 5148, 3264 }, { 5149, 3265 }, { 5150, 3266 }, - { 5151, 3267 }, { 5152, 3268 }, { 5153, 3269 }, { 5154, 3270 }, { 5155, 3271 }, { 5156, 3272 }, { 5227, 3273 }, - { 5228, 3274 }, { 5229, 3275 }, { 5230, 3276 }, { 5231, 3277 }, { 5232, 3278 }, { 5233, 3279 }, { 5234, 3280 }, - { 5235, 3281 }, { 5236, 3282 }, { 5237, 3283 }, { 5238, 3284 }, { 5240, 3286 }, { 5241, 3287 }, { 5242, 3288 }, - { 5243, 3289 }, { 5244, 3290 }, { 5245, 3291 }, { 5246, 3292 }, { 5247, 3293 }, { 5248, 3294 }, { 5249, 3295 }, - { 5250, 3296 }, { 5251, 3297 }, { 5252, 3298 }, { 5253, 3299 }, { 5254, 3300 }, { 5255, 3301 }, { 5256, 3302 }, - { 5257, 3303 }, { 5258, 3304 }, { 5259, 3305 }, { 5260, 3306 }, { 5261, 3307 }, { 5262, 3308 }, { 5263, 3309 }, - { 5264, 3310 }, { 5265, 3311 }, { 5266, 3312 }, { 5267, 3313 }, { 5268, 3314 }, { 5269, 3315 }, { 5270, 3316 }, - { 5271, 3317 }, { 5272, 3318 }, { 5273, 3319 }, { 5274, 3320 }, { 5275, 3321 }, { 5276, 3322 }, { 5277, 3323 }, - { 5278, 3324 }, { 5279, 3325 }, { 5280, 3326 }, { 5281, 3327 }, { 5282, 3328 }, { 5283, 3329 }, { 5284, 3330 }, - { 5285, 3331 }, { 5286, 3332 }, { 5288, 3334 }, { 5289, 3335 }, { 5290, 3336 }, { 5291, 3337 }, { 5292, 3338 }, - { 5293, 3339 }, { 5294, 3340 }, { 5296, 3342 }, { 5297, 3343 }, { 5298, 3344 }, { 5299, 3345 }, { 5300, 3346 }, - { 5301, 3347 }, { 5302, 3348 }, { 5303, 3349 }, { 5304, 3350 }, { 5305, 3351 }, { 5306, 3352 }, { 5307, 3353 }, - { 5308, 3354 }, { 5309, 3355 }, { 5310, 3356 }, { 5311, 3357 }, { 5312, 3358 }, { 5313, 3359 }, { 5314, 3360 }, - { 5315, 3361 }, { 5316, 3362 }, { 5317, 3363 }, { 5318, 3364 }, { 5319, 3365 }, { 5320, 3366 }, { 5321, 3367 }, - { 5322, 3368 }, { 5323, 3369 }, { 5324, 3370 }, { 5325, 3371 }, { 5326, 3372 }, { 5327, 3373 }, { 5328, 3374 }, - { 5329, 3375 }, { 5330, 3376 }, { 5331, 3377 }, { 5332, 3378 }, { 5333, 3379 }, { 5336, 3382 }, { 5337, 3383 }, - { 5338, 3384 }, { 5339, 3385 }, { 5340, 3386 }, { 5341, 3387 }, { 5342, 3388 }, { 5343, 3389 }, { 5344, 3390 }, - { 5345, 3391 }, { 5346, 3392 }, { 5347, 3393 }, { 5348, 3394 }, { 5349, 3395 }, { 5350, 3396 }, { 5351, 3397 }, - { 5352, 3398 }, { 5357, 3403 }, { 5358, 3404 }, { 5359, 3405 }, { 5360, 3406 }, { 5361, 3407 }, { 5362, 3408 }, - { 5363, 3409 }, { 5364, 3410 }, { 5365, 3411 }, { 5366, 3412 }, { 5367, 3413 }, { 5368, 3414 }, { 5369, 3415 }, - { 5370, 3416 }, { 5371, 3417 }, { 5372, 3418 }, { 5373, 3419 }, { 5374, 3420 }, { 5375, 3421 }, { 5376, 3422 }, - { 5377, 3423 }, { 5378, 3424 }, { 5379, 3425 }, { 5380, 3426 }, { 5381, 3427 }, { 5382, 3428 }, { 5383, 3429 }, - { 5384, 3430 }, { 5385, 3431 }, { 5386, 3432 }, { 5387, 3433 }, { 5388, 3434 }, { 5389, 3435 }, { 5390, 3436 }, - { 5391, 3437 }, { 5392, 3438 }, { 5393, 3439 }, { 5394, 3440 }, { 5395, 3441 }, { 5396, 3442 }, { 5397, 3443 }, - { 5398, 3444 }, { 5399, 3445 }, { 5400, 3446 }, { 5401, 3447 }, { 5402, 3448 }, { 5403, 3449 }, { 5404, 3450 }, - { 5405, 3451 }, { 5406, 3452 }, { 5407, 3453 }, { 5408, 3454 }, { 5409, 3455 }, { 5410, 3456 }, { 5411, 3457 }, - { 5412, 3458 }, { 5413, 3459 }, { 5414, 3460 }, { 5415, 3461 }, { 5416, 3462 }, { 5417, 3463 }, { 5418, 3464 }, - { 5419, 3465 }, { 5420, 3466 }, { 5421, 3467 }, { 5422, 3468 }, { 5423, 3469 }, { 5424, 3470 }, { 5425, 3471 }, - { 5426, 3472 }, { 5427, 3473 }, { 5428, 3474 }, { 5429, 3475 }, { 5430, 3476 }, { 5431, 3477 }, { 5432, 3478 }, - { 5433, 3479 }, { 5434, 3480 }, { 5435, 3481 }, { 5436, 3482 }, { 5437, 3483 }, { 5438, 3484 }, { 5439, 3485 }, - { 5440, 3486 }, { 5441, 3487 }, { 5442, 3488 }, { 5443, 3489 }, { 5444, 3490 }, { 5445, 3491 }, { 5446, 3492 }, - { 5447, 3493 }, { 5448, 3494 }, { 5449, 3495 }, { 5450, 3496 }, { 5451, 3497 }, { 5452, 3498 }, { 5453, 3499 }, - { 5454, 3500 }, { 5455, 3501 }, { 5456, 3502 }, { 5457, 3503 }, { 5458, 3504 }, { 5459, 3505 }, { 5460, 3506 }, - { 5461, 3507 }, { 5462, 3508 }, { 5463, 3509 }, { 5464, 3510 }, { 5465, 3511 }, { 5466, 3512 }, { 5467, 3513 }, - { 5468, 3514 }, { 5469, 3515 }, { 5470, 3516 }, { 5471, 3517 }, { 5472, 3518 }, { 5473, 3519 }, { 5474, 3520 }, - { 5475, 3521 }, { 5476, 3522 }, { 5477, 3523 }, { 5478, 3524 }, { 5479, 3525 }, { 5480, 3526 }, { 5481, 3527 }, - { 5482, 3528 }, { 5483, 3529 }, { 5484, 3530 }, { 5485, 3531 }, { 5486, 3532 }, { 5487, 3533 }, { 5488, 3534 }, - { 5489, 3535 }, { 5490, 3536 }, { 5491, 3537 }, { 5492, 3538 }, { 5493, 3539 }, { 5494, 3540 }, { 5495, 3541 }, - { 5496, 3542 }, { 5497, 3543 }, { 5498, 3544 }, { 5499, 3545 }, { 5500, 3546 }, { 5501, 3547 }, { 5502, 3548 }, - { 5503, 3549 }, { 5504, 3550 }, { 5505, 3551 }, { 5506, 3552 }, { 5507, 3553 }, { 5508, 3554 }, { 5509, 3555 }, - { 5510, 3556 }, { 5511, 3557 }, { 5512, 3558 }, { 5513, 3559 }, { 5514, 3560 }, { 5515, 3561 }, { 5516, 3562 }, - { 5517, 3563 }, { 5518, 3564 }, { 5519, 3565 }, { 5520, 3566 }, { 5521, 3567 }, { 5522, 3568 }, { 5523, 3569 }, - { 5524, 3570 }, { 5525, 3571 }, { 5526, 3572 }, { 5527, 3573 }, { 5528, 3574 }, { 5529, 3575 }, { 5530, 3576 }, - { 5531, 3577 }, { 5532, 3578 }, { 5533, 3579 }, { 5534, 3580 }, { 5535, 3581 }, { 5536, 3582 }, { 5537, 3583 }, - { 5538, 3584 }, { 5539, 3585 }, { 5540, 3586 }, { 5541, 3587 }, { 5542, 3588 }, { 5543, 3589 }, { 5544, 3590 }, - { 5545, 3591 }, { 5546, 3592 }, { 5547, 3593 }, { 5548, 3594 }, { 5549, 3595 }, { 5550, 3596 }, { 5551, 3597 }, - { 5552, 3598 }, { 5553, 3599 }, { 5554, 3600 }, { 5555, 3601 }, { 5556, 3602 }, { 5557, 3603 }, { 5558, 3604 }, - { 5559, 3605 }, { 5560, 3606 }, { 5561, 3607 }, { 5562, 3608 }, { 5563, 3609 }, { 5564, 3610 }, { 5565, 3611 }, - { 5566, 3612 }, { 5567, 3613 }, { 5568, 3614 }, { 5569, 3615 }, { 5570, 3616 }, { 4554, 3065 }, + { 2875, 2393 }, { 2876, 2394 }, { 2877, 2395 }, { 2878, 2396 }, { 2879, 2397 }, { 2880, 2398 }, { 2881, 2399 }, + { 2882, 2400 }, { 2883, 2401 }, { 2884, 2402 }, { 2885, 2403 }, { 2886, 2404 }, { 2887, 2405 }, { 2888, 2406 }, + { 2889, 2407 }, { 2890, 2408 }, { 2891, 2409 }, { 2892, 2410 }, { 2893, 2411 }, { 2894, 2412 }, { 2895, 2413 }, + { 2896, 2414 }, { 2897, 2415 }, { 2971, 2416 }, { 2972, 2417 }, { 2973, 2418 }, { 2974, 2419 }, { 2975, 2420 }, + { 2976, 2421 }, { 2977, 2422 }, { 2978, 2423 }, { 2979, 2424 }, { 3071, 2425 }, { 3072, 2426 }, { 3073, 2427 }, + { 3074, 2428 }, { 3075, 2429 }, { 3076, 2430 }, { 3077, 2431 }, { 3078, 2432 }, { 3079, 2433 }, { 3080, 2434 }, + { 3081, 2435 }, { 3082, 2436 }, { 3083, 2437 }, { 3084, 2438 }, { 3085, 2439 }, { 3086, 2440 }, { 3087, 2441 }, + { 3088, 2442 }, { 3089, 2443 }, { 3090, 2444 }, { 3091, 2445 }, { 3092, 2446 }, { 3093, 2447 }, { 3094, 2448 }, + { 3095, 2449 }, { 3096, 2450 }, { 3097, 2451 }, { 3098, 2452 }, { 3099, 2453 }, { 3100, 2454 }, { 3101, 2455 }, + { 3102, 2456 }, { 3103, 2457 }, { 3104, 2458 }, { 3105, 2459 }, { 3106, 2460 }, { 3107, 2461 }, { 3108, 2462 }, + { 3109, 2463 }, { 3110, 2464 }, { 3111, 2465 }, { 3112, 2466 }, { 3113, 2467 }, { 3114, 2468 }, { 3115, 2469 }, + { 3171, 2470 }, { 3172, 2471 }, { 3173, 2472 }, { 3174, 2473 }, { 3175, 2474 }, { 3176, 2475 }, { 3177, 2476 }, + { 3178, 2477 }, { 3179, 2478 }, { 3180, 2479 }, { 3181, 2480 }, { 3182, 2481 }, { 3183, 2482 }, { 3184, 2483 }, + { 3185, 2484 }, { 3186, 2485 }, { 3187, 2486 }, { 3188, 2487 }, { 3189, 2488 }, { 3190, 2489 }, { 3191, 2490 }, + { 3192, 2491 }, { 3193, 2492 }, { 3194, 2493 }, { 3195, 2494 }, { 3196, 2495 }, { 3197, 2496 }, { 3198, 2497 }, + { 3199, 2498 }, { 3200, 2499 }, { 3201, 2500 }, { 3202, 2501 }, { 3203, 2502 }, { 3204, 2503 }, { 3205, 2504 }, + { 3206, 2505 }, { 3207, 2506 }, { 3208, 2507 }, { 3209, 2508 }, { 3210, 2509 }, { 3211, 2510 }, { 3212, 2511 }, + { 3213, 2512 }, { 3214, 2513 }, { 3215, 2514 }, { 3216, 2515 }, { 3217, 2516 }, { 3218, 2517 }, { 3219, 2518 }, + { 3220, 2519 }, { 3221, 2520 }, { 3222, 2521 }, { 3223, 2522 }, { 3224, 2523 }, { 3271, 2524 }, { 3272, 2525 }, + { 3273, 2526 }, { 3274, 2527 }, { 3275, 2528 }, { 3276, 2529 }, { 3277, 2530 }, { 3278, 2531 }, { 3279, 2532 }, + { 3280, 2533 }, { 3281, 2534 }, { 3282, 2535 }, { 3283, 2536 }, { 3284, 2537 }, { 3285, 2538 }, { 3286, 2539 }, + { 3287, 2540 }, { 3288, 2541 }, { 3289, 2542 }, { 3290, 2543 }, { 3291, 2544 }, { 3292, 2545 }, { 3293, 2546 }, + { 3294, 2547 }, { 3295, 2548 }, { 3296, 2549 }, { 3297, 2550 }, { 3298, 2551 }, { 3299, 2552 }, { 3300, 2553 }, + { 3301, 2554 }, { 3302, 2555 }, { 3303, 2556 }, { 3304, 2557 }, { 3371, 2558 }, { 3372, 2559 }, { 3373, 2560 }, + { 3374, 2561 }, { 3375, 2562 }, { 3376, 2563 }, { 3377, 2564 }, { 3378, 2565 }, { 3379, 2566 }, { 3380, 2567 }, + { 3381, 2568 }, { 3382, 2569 }, { 3383, 2570 }, { 3384, 2571 }, { 3385, 2572 }, { 3471, 2573 }, { 3472, 2574 }, + { 3473, 2575 }, { 3474, 2576 }, { 3475, 2577 }, { 3476, 2578 }, { 3477, 2579 }, { 3478, 2580 }, { 3479, 2581 }, + { 3480, 2582 }, { 3481, 2583 }, { 3482, 2584 }, { 3483, 2585 }, { 3484, 2586 }, { 3485, 2587 }, { 3486, 2588 }, + { 3487, 2589 }, { 3488, 2590 }, { 3489, 2591 }, { 3490, 2592 }, { 3491, 2593 }, { 3492, 2594 }, { 3493, 2595 }, + { 3494, 2596 }, { 3495, 2597 }, { 3496, 2598 }, { 3497, 2599 }, { 3498, 2600 }, { 3499, 2601 }, { 3500, 2602 }, + { 3501, 2603 }, { 3502, 2604 }, { 3503, 2605 }, { 3504, 2606 }, { 3505, 2607 }, { 3506, 2608 }, { 3507, 2609 }, + { 3508, 2610 }, { 3509, 2611 }, { 3510, 2612 }, { 3571, 2613 }, { 3572, 2614 }, { 3573, 2615 }, { 3574, 2616 }, + { 3575, 2617 }, { 3576, 2618 }, { 3577, 2619 }, { 3578, 2620 }, { 3579, 2621 }, { 3580, 2622 }, { 3581, 2623 }, + { 3582, 2624 }, { 3583, 2625 }, { 3584, 2626 }, { 3585, 2627 }, { 3586, 2628 }, { 3587, 2629 }, { 3588, 2630 }, + { 3589, 2631 }, { 3590, 2632 }, { 3591, 2633 }, { 3592, 2634 }, { 3593, 2635 }, { 3594, 2636 }, { 3595, 2637 }, + { 3596, 2638 }, { 3597, 2639 }, { 3598, 2640 }, { 3599, 2641 }, { 3600, 2642 }, { 3601, 2643 }, { 3602, 2644 }, + { 3603, 2645 }, { 3604, 2646 }, { 3605, 2647 }, { 3606, 2648 }, { 3607, 2649 }, { 3608, 2650 }, { 3609, 2651 }, + { 3610, 2652 }, { 3611, 2653 }, { 3612, 2654 }, { 3613, 2655 }, { 3614, 2656 }, { 3615, 2657 }, { 3616, 2658 }, + { 3617, 2659 }, { 3618, 2660 }, { 3619, 2661 }, { 3620, 2662 }, { 3621, 2663 }, { 3622, 2664 }, { 3623, 2665 }, + { 3624, 2666 }, { 3625, 2667 }, { 3626, 2668 }, { 3627, 2669 }, { 3628, 2670 }, { 3629, 2671 }, { 3630, 2672 }, + { 3631, 2673 }, { 3632, 2674 }, { 3633, 2675 }, { 3634, 2676 }, { 3635, 2677 }, { 3636, 2678 }, { 3637, 2679 }, + { 3638, 2680 }, { 3639, 2681 }, { 3640, 2682 }, { 3641, 2683 }, { 3642, 2684 }, { 3643, 2685 }, { 3644, 2686 }, + { 3645, 2687 }, { 3646, 2688 }, { 3671, 2689 }, { 3672, 2690 }, { 3673, 2691 }, { 3674, 2692 }, { 3675, 2693 }, + { 3676, 2694 }, { 3677, 2695 }, { 3678, 2696 }, { 3679, 2697 }, { 3680, 2698 }, { 3681, 2699 }, { 3682, 2700 }, + { 3683, 2701 }, { 3684, 2702 }, { 3685, 2703 }, { 3686, 2704 }, { 3687, 2705 }, { 3688, 2706 }, { 3689, 2707 }, + { 3690, 2708 }, { 3691, 2709 }, { 3692, 2710 }, { 3693, 2711 }, { 3694, 2712 }, { 3695, 2713 }, { 3696, 2714 }, + { 3697, 2715 }, { 3698, 2716 }, { 3699, 2717 }, { 3700, 2718 }, { 3701, 2719 }, { 3702, 2720 }, { 3703, 2721 }, + { 3704, 2722 }, { 3705, 2723 }, { 3706, 2724 }, { 3707, 2725 }, { 3708, 2726 }, { 3709, 2727 }, { 3710, 2728 }, + { 3711, 2729 }, { 3712, 2730 }, { 3713, 2731 }, { 3714, 2732 }, { 3715, 2733 }, { 3716, 2734 }, { 3717, 2735 }, + { 3718, 2736 }, { 3719, 2737 }, { 3720, 2738 }, { 3721, 2739 }, { 3722, 2740 }, { 3723, 2741 }, { 3724, 2742 }, + { 3725, 2743 }, { 3726, 2744 }, { 3727, 2745 }, { 3728, 2746 }, { 3729, 2747 }, { 3730, 2748 }, { 3927, 2749 }, + { 3928, 2750 }, { 3929, 2751 }, { 3930, 2752 }, { 3931, 2753 }, { 3932, 2754 }, { 3933, 2755 }, { 3934, 2756 }, + { 3940, 2762 }, { 3941, 2763 }, { 3942, 2764 }, { 3943, 2765 }, { 3944, 2766 }, { 3945, 2767 }, { 3946, 2768 }, + { 3947, 2769 }, { 3948, 2770 }, { 3949, 2771 }, { 3950, 2772 }, { 3951, 2773 }, { 3952, 2774 }, { 3953, 2775 }, + { 3954, 2776 }, { 3955, 2777 }, { 3956, 2778 }, { 3957, 2779 }, { 3958, 2780 }, { 3959, 2781 }, { 3960, 2782 }, + { 3961, 2783 }, { 3962, 2784 }, { 3963, 2785 }, { 3964, 2786 }, { 3965, 2787 }, { 3966, 2788 }, { 3967, 2789 }, + { 3968, 2790 }, { 3969, 2791 }, { 3970, 2792 }, { 3971, 2793 }, { 3972, 2794 }, { 3973, 2795 }, { 3974, 2796 }, + { 3975, 2797 }, { 3976, 2798 }, { 3977, 2799 }, { 3978, 2800 }, { 3979, 2801 }, { 3980, 2802 }, { 3981, 2803 }, + { 3982, 2804 }, { 3983, 2805 }, { 3984, 2806 }, { 3985, 2807 }, { 3986, 2808 }, { 3987, 2809 }, { 3988, 2810 }, + { 3989, 2811 }, { 3990, 2812 }, { 3991, 2813 }, { 3992, 2814 }, { 3993, 2815 }, { 3994, 2816 }, { 3995, 2817 }, + { 3996, 2818 }, { 3997, 2819 }, { 3998, 2820 }, { 3999, 2821 }, { 4000, 2822 }, { 4001, 2823 }, { 4002, 2824 }, + { 4003, 2825 }, { 4004, 2826 }, { 4005, 2827 }, { 4006, 2828 }, { 4007, 2829 }, { 4008, 2830 }, { 4009, 2831 }, + { 4010, 2832 }, { 4011, 2833 }, { 4012, 2834 }, { 4013, 2835 }, { 4014, 2836 }, { 4015, 2837 }, { 4016, 2838 }, + { 4017, 2839 }, { 4018, 2840 }, { 4019, 2841 }, { 4020, 2842 }, { 4021, 2843 }, { 4022, 2844 }, { 4023, 2845 }, + { 4024, 2846 }, { 4025, 2847 }, { 4026, 2848 }, { 4027, 2849 }, { 4028, 2850 }, { 4029, 2851 }, { 4030, 2852 }, + { 4031, 2853 }, { 4032, 2854 }, { 4127, 2855 }, { 4128, 2856 }, { 4129, 2857 }, { 4130, 2858 }, { 4131, 2859 }, + { 4132, 2860 }, { 4133, 2861 }, { 4134, 2862 }, { 4135, 2863 }, { 4136, 2864 }, { 4137, 2865 }, { 4138, 2866 }, + { 4139, 2867 }, { 4140, 2868 }, { 4145, 2873 }, { 4146, 2874 }, { 4147, 2875 }, { 4148, 2876 }, { 4149, 2877 }, + { 4150, 2878 }, { 4151, 2879 }, { 4152, 2880 }, { 4153, 2881 }, { 4154, 2882 }, { 4155, 2883 }, { 4156, 2884 }, + { 4157, 2885 }, { 4158, 2886 }, { 4159, 2887 }, { 4160, 2888 }, { 4227, 2889 }, { 4228, 2890 }, { 4229, 2891 }, + { 4230, 2892 }, { 4231, 2893 }, { 4232, 2894 }, { 4233, 2895 }, { 4234, 2896 }, { 4235, 2897 }, { 4236, 2898 }, + { 4237, 2899 }, { 4238, 2900 }, { 4239, 2901 }, { 4240, 2902 }, { 4241, 2903 }, { 4242, 2904 }, { 4243, 2905 }, + { 4244, 2906 }, { 4245, 2907 }, { 4246, 2908 }, { 4247, 2909 }, { 4248, 2910 }, { 4249, 2911 }, { 4250, 2912 }, + { 4251, 2913 }, { 4252, 2914 }, { 4253, 2915 }, { 4254, 2916 }, { 4255, 2917 }, { 4256, 2918 }, { 4257, 2919 }, + { 4258, 2920 }, { 4327, 2921 }, { 4328, 2922 }, { 4329, 2923 }, { 4330, 2924 }, { 4331, 2925 }, { 4332, 2926 }, + { 4333, 2927 }, { 4334, 2928 }, { 4335, 2929 }, { 4336, 2930 }, { 4337, 2931 }, { 4338, 2932 }, { 4339, 2933 }, + { 4340, 2934 }, { 4341, 2935 }, { 4342, 2936 }, { 4343, 2937 }, { 4344, 2938 }, { 4345, 2939 }, { 4346, 2940 }, + { 4347, 2941 }, { 4348, 2942 }, { 4349, 2943 }, { 4350, 2944 }, { 4351, 2945 }, { 4352, 2946 }, { 4353, 2947 }, + { 4354, 2948 }, { 4355, 2949 }, { 4356, 2950 }, { 4357, 2951 }, { 4358, 2952 }, { 4359, 2953 }, { 4360, 2954 }, + { 4361, 2955 }, { 4362, 2956 }, { 4363, 2957 }, { 4364, 2958 }, { 4365, 2959 }, { 4366, 2960 }, { 4367, 2961 }, + { 4368, 2962 }, { 4369, 2963 }, { 4370, 2964 }, { 4371, 2965 }, { 4372, 2966 }, { 4373, 2967 }, { 4374, 2968 }, + { 4375, 2969 }, { 4376, 2970 }, { 4377, 2971 }, { 4378, 2972 }, { 4379, 2973 }, { 4380, 2974 }, { 4381, 2975 }, + { 4382, 2976 }, { 4383, 2977 }, { 4384, 2978 }, { 4385, 2979 }, { 4386, 2980 }, { 4387, 2981 }, { 4388, 2982 }, + { 4389, 2983 }, { 4390, 2984 }, { 4391, 2985 }, { 4392, 2986 }, { 4393, 2987 }, { 4394, 2988 }, { 4395, 2989 }, + { 4396, 2990 }, { 4397, 2991 }, { 4398, 2992 }, { 4399, 2993 }, { 4400, 2994 }, { 4401, 2995 }, { 4402, 2996 }, + { 4403, 2997 }, { 4404, 2998 }, { 4405, 2999 }, { 4406, 3000 }, { 4407, 3001 }, { 4408, 3002 }, { 4409, 3003 }, + { 4410, 3004 }, { 4411, 3005 }, { 4412, 3006 }, { 4413, 3007 }, { 4414, 3008 }, { 4415, 3009 }, { 4416, 3010 }, + { 4417, 3011 }, { 4418, 3012 }, { 4419, 3013 }, { 4420, 3014 }, { 4421, 3015 }, { 4422, 3016 }, { 4423, 3017 }, + { 4424, 3018 }, { 4425, 3019 }, { 4426, 3020 }, { 4427, 3021 }, { 4428, 3022 }, { 4429, 3023 }, { 4430, 3024 }, + { 4431, 3025 }, { 4432, 3026 }, { 4433, 3027 }, { 4434, 3028 }, { 4435, 3029 }, { 4436, 3030 }, { 4437, 3031 }, + { 4438, 3032 }, { 4439, 3033 }, { 4440, 3034 }, { 4441, 3035 }, { 4442, 3036 }, { 4443, 3037 }, { 4444, 3038 }, + { 4445, 3039 }, { 4446, 3040 }, { 4447, 3041 }, { 4448, 3042 }, { 4449, 3043 }, { 4450, 3044 }, { 4527, 3045 }, + { 4528, 3046 }, { 4529, 3047 }, { 4530, 3048 }, { 4531, 3049 }, { 4532, 3050 }, { 4533, 3051 }, { 4534, 3052 }, + { 4535, 3053 }, { 4536, 3054 }, { 4537, 3055 }, { 4538, 3056 }, { 4539, 3057 }, { 4540, 3058 }, { 4541, 3059 }, + { 4542, 3060 }, { 4543, 3061 }, { 4544, 3062 }, { 4545, 3063 }, { 4546, 3064 }, { 4547, 3066 }, { 4548, 3067 }, + { 4549, 3068 }, { 4550, 3069 }, { 4551, 3070 }, { 4552, 3071 }, { 4553, 3072 }, { 4627, 3073 }, { 4628, 3074 }, + { 4629, 3075 }, { 4630, 3076 }, { 4631, 3077 }, { 4632, 3078 }, { 4633, 3079 }, { 4634, 3080 }, { 4635, 3081 }, + { 4636, 3082 }, { 4637, 3083 }, { 4638, 3084 }, { 4639, 3085 }, { 4640, 3086 }, { 4641, 3087 }, { 4642, 3088 }, + { 4643, 3089 }, { 4644, 3090 }, { 4645, 3091 }, { 4646, 3092 }, { 4647, 3093 }, { 4648, 3094 }, { 4649, 3095 }, + { 4650, 3096 }, { 4651, 3097 }, { 4652, 3098 }, { 4653, 3099 }, { 4654, 3100 }, { 4655, 3101 }, { 4656, 3102 }, + { 4657, 3103 }, { 4658, 3104 }, { 4659, 3105 }, { 4660, 3106 }, { 4661, 3107 }, { 4662, 3108 }, { 4663, 3109 }, + { 4664, 3110 }, { 4665, 3111 }, { 4666, 3112 }, { 4667, 3113 }, { 4668, 3114 }, { 4669, 3115 }, { 4670, 3116 }, + { 4671, 3117 }, { 4672, 3118 }, { 4673, 3119 }, { 4674, 3120 }, { 4675, 3121 }, { 4676, 3122 }, { 4677, 3123 }, + { 4678, 3124 }, { 4679, 3125 }, { 4680, 3126 }, { 4681, 3127 }, { 4682, 3128 }, { 4683, 3129 }, { 4684, 3130 }, + { 4685, 3131 }, { 4686, 3132 }, { 4687, 3133 }, { 4688, 3134 }, { 4689, 3135 }, { 4690, 3136 }, { 4691, 3137 }, + { 4692, 3138 }, { 4693, 3139 }, { 4694, 3140 }, { 4695, 3141 }, { 4696, 3142 }, { 4697, 3143 }, { 4698, 3144 }, + { 4699, 3145 }, { 4700, 3146 }, { 4701, 3147 }, { 4702, 3148 }, { 4703, 3149 }, { 4704, 3150 }, { 4705, 3151 }, + { 4706, 3152 }, { 4707, 3153 }, { 4708, 3154 }, { 4709, 3155 }, { 4710, 3156 }, { 4711, 3157 }, { 4712, 3158 }, + { 4713, 3159 }, { 4714, 3160 }, { 4715, 3161 }, { 4716, 3162 }, { 4717, 3163 }, { 4718, 3164 }, { 4719, 3165 }, + { 4720, 3166 }, { 4721, 3167 }, { 4722, 3168 }, { 4723, 3169 }, { 4724, 3170 }, { 4725, 3171 }, { 4726, 3172 }, + { 4827, 3173 }, { 4828, 3174 }, { 4829, 3175 }, { 4830, 3176 }, { 4831, 3177 }, { 4832, 3178 }, { 4833, 3179 }, + { 4834, 3180 }, { 4835, 3181 }, { 4836, 3182 }, { 4837, 3183 }, { 4838, 3184 }, { 4839, 3185 }, { 4840, 3186 }, + { 4841, 3187 }, { 4842, 3188 }, { 4843, 3189 }, { 4844, 3190 }, { 4845, 3191 }, { 5027, 3192 }, { 5028, 3193 }, + { 5029, 3194 }, { 5030, 3195 }, { 5031, 3196 }, { 5032, 3197 }, { 5033, 3198 }, { 5034, 3199 }, { 5035, 3200 }, + { 5036, 3201 }, { 5037, 3202 }, { 5038, 3203 }, { 5039, 3204 }, { 5040, 3205 }, { 5041, 3206 }, { 5042, 3207 }, + { 5043, 3208 }, { 5044, 3209 }, { 5045, 3210 }, { 5046, 3211 }, { 5047, 3212 }, { 5048, 3213 }, { 5049, 3214 }, + { 5050, 3215 }, { 5051, 3216 }, { 5052, 3217 }, { 5053, 3218 }, { 5054, 3219 }, { 5055, 3220 }, { 5056, 3221 }, + { 5057, 3222 }, { 5058, 3223 }, { 5059, 3224 }, { 5060, 3225 }, { 5061, 3226 }, { 5062, 3227 }, { 5063, 3228 }, + { 5064, 3229 }, { 5065, 3230 }, { 5066, 3231 }, { 5067, 3232 }, { 5068, 3233 }, { 5069, 3234 }, { 5070, 3235 }, + { 5071, 3236 }, { 5072, 3237 }, { 5073, 3238 }, { 5074, 3239 }, { 5075, 3240 }, { 5076, 3241 }, { 5077, 3242 }, + { 5127, 3243 }, { 5128, 3244 }, { 5129, 3245 }, { 5130, 3246 }, { 5131, 3247 }, { 5132, 3248 }, { 5133, 3249 }, + { 5134, 3250 }, { 5135, 3251 }, { 5136, 3252 }, { 5137, 3253 }, { 5138, 3254 }, { 5139, 3255 }, { 5140, 3256 }, + { 5141, 3257 }, { 5142, 3258 }, { 5143, 3259 }, { 5144, 3260 }, { 5145, 3261 }, { 5146, 3262 }, { 5147, 3263 }, + { 5148, 3264 }, { 5149, 3265 }, { 5150, 3266 }, { 5151, 3267 }, { 5152, 3268 }, { 5153, 3269 }, { 5154, 3270 }, + { 5155, 3271 }, { 5156, 3272 }, { 5227, 3273 }, { 5228, 3274 }, { 5229, 3275 }, { 5230, 3276 }, { 5231, 3277 }, + { 5232, 3278 }, { 5233, 3279 }, { 5234, 3280 }, { 5235, 3281 }, { 5236, 3282 }, { 5237, 3283 }, { 5238, 3284 }, + { 5240, 3286 }, { 5241, 3287 }, { 5242, 3288 }, { 5243, 3289 }, { 5244, 3290 }, { 5245, 3291 }, { 5246, 3292 }, + { 5247, 3293 }, { 5248, 3294 }, { 5249, 3295 }, { 5250, 3296 }, { 5251, 3297 }, { 5252, 3298 }, { 5253, 3299 }, + { 5254, 3300 }, { 5255, 3301 }, { 5256, 3302 }, { 5257, 3303 }, { 5258, 3304 }, { 5259, 3305 }, { 5260, 3306 }, + { 5261, 3307 }, { 5262, 3308 }, { 5263, 3309 }, { 5264, 3310 }, { 5265, 3311 }, { 5266, 3312 }, { 5267, 3313 }, + { 5268, 3314 }, { 5269, 3315 }, { 5270, 3316 }, { 5271, 3317 }, { 5272, 3318 }, { 5273, 3319 }, { 5274, 3320 }, + { 5275, 3321 }, { 5276, 3322 }, { 5277, 3323 }, { 5278, 3324 }, { 5279, 3325 }, { 5280, 3326 }, { 5281, 3327 }, + { 5282, 3328 }, { 5283, 3329 }, { 5284, 3330 }, { 5285, 3331 }, { 5286, 3332 }, { 5288, 3334 }, { 5289, 3335 }, + { 5290, 3336 }, { 5291, 3337 }, { 5292, 3338 }, { 5293, 3339 }, { 5294, 3340 }, { 5296, 3342 }, { 5297, 3343 }, + { 5298, 3344 }, { 5299, 3345 }, { 5300, 3346 }, { 5301, 3347 }, { 5302, 3348 }, { 5303, 3349 }, { 5304, 3350 }, + { 5305, 3351 }, { 5306, 3352 }, { 5307, 3353 }, { 5308, 3354 }, { 5309, 3355 }, { 5310, 3356 }, { 5311, 3357 }, + { 5312, 3358 }, { 5313, 3359 }, { 5314, 3360 }, { 5315, 3361 }, { 5316, 3362 }, { 5317, 3363 }, { 5318, 3364 }, + { 5319, 3365 }, { 5320, 3366 }, { 5321, 3367 }, { 5322, 3368 }, { 5323, 3369 }, { 5324, 3370 }, { 5325, 3371 }, + { 5326, 3372 }, { 5327, 3373 }, { 5328, 3374 }, { 5329, 3375 }, { 5330, 3376 }, { 5331, 3377 }, { 5332, 3378 }, + { 5333, 3379 }, { 5336, 3382 }, { 5337, 3383 }, { 5338, 3384 }, { 5339, 3385 }, { 5340, 3386 }, { 5341, 3387 }, + { 5342, 3388 }, { 5343, 3389 }, { 5344, 3390 }, { 5345, 3391 }, { 5346, 3392 }, { 5347, 3393 }, { 5348, 3394 }, + { 5349, 3395 }, { 5350, 3396 }, { 5351, 3397 }, { 5352, 3398 }, { 5357, 3403 }, { 5358, 3404 }, { 5359, 3405 }, + { 5360, 3406 }, { 5361, 3407 }, { 5362, 3408 }, { 5363, 3409 }, { 5364, 3410 }, { 5365, 3411 }, { 5366, 3412 }, + { 5367, 3413 }, { 5368, 3414 }, { 5369, 3415 }, { 5370, 3416 }, { 5371, 3417 }, { 5372, 3418 }, { 5373, 3419 }, + { 5374, 3420 }, { 5375, 3421 }, { 5376, 3422 }, { 5377, 3423 }, { 5378, 3424 }, { 5379, 3425 }, { 5380, 3426 }, + { 5381, 3427 }, { 5382, 3428 }, { 5383, 3429 }, { 5384, 3430 }, { 5385, 3431 }, { 5386, 3432 }, { 5387, 3433 }, + { 5388, 3434 }, { 5389, 3435 }, { 5390, 3436 }, { 5391, 3437 }, { 5392, 3438 }, { 5393, 3439 }, { 5394, 3440 }, + { 5395, 3441 }, { 5396, 3442 }, { 5397, 3443 }, { 5398, 3444 }, { 5399, 3445 }, { 5400, 3446 }, { 5401, 3447 }, + { 5402, 3448 }, { 5403, 3449 }, { 5404, 3450 }, { 5405, 3451 }, { 5406, 3452 }, { 5407, 3453 }, { 5408, 3454 }, + { 5409, 3455 }, { 5410, 3456 }, { 5411, 3457 }, { 5412, 3458 }, { 5413, 3459 }, { 5414, 3460 }, { 5415, 3461 }, + { 5416, 3462 }, { 5417, 3463 }, { 5418, 3464 }, { 5419, 3465 }, { 5420, 3466 }, { 5421, 3467 }, { 5422, 3468 }, + { 5423, 3469 }, { 5424, 3470 }, { 5425, 3471 }, { 5426, 3472 }, { 5427, 3473 }, { 5428, 3474 }, { 5429, 3475 }, + { 5430, 3476 }, { 5431, 3477 }, { 5432, 3478 }, { 5433, 3479 }, { 5434, 3480 }, { 5435, 3481 }, { 5436, 3482 }, + { 5437, 3483 }, { 5438, 3484 }, { 5439, 3485 }, { 5440, 3486 }, { 5441, 3487 }, { 5442, 3488 }, { 5443, 3489 }, + { 5444, 3490 }, { 5445, 3491 }, { 5446, 3492 }, { 5447, 3493 }, { 5448, 3494 }, { 5449, 3495 }, { 5450, 3496 }, + { 5451, 3497 }, { 5452, 3498 }, { 5453, 3499 }, { 5454, 3500 }, { 5455, 3501 }, { 5456, 3502 }, { 5457, 3503 }, + { 5458, 3504 }, { 5459, 3505 }, { 5460, 3506 }, { 5461, 3507 }, { 5462, 3508 }, { 5463, 3509 }, { 5464, 3510 }, + { 5465, 3511 }, { 5466, 3512 }, { 5467, 3513 }, { 5468, 3514 }, { 5469, 3515 }, { 5470, 3516 }, { 5471, 3517 }, + { 5472, 3518 }, { 5473, 3519 }, { 5474, 3520 }, { 5475, 3521 }, { 5476, 3522 }, { 5477, 3523 }, { 5478, 3524 }, + { 5479, 3525 }, { 5480, 3526 }, { 5481, 3527 }, { 5482, 3528 }, { 5483, 3529 }, { 5484, 3530 }, { 5485, 3531 }, + { 5486, 3532 }, { 5487, 3533 }, { 5488, 3534 }, { 5489, 3535 }, { 5490, 3536 }, { 5491, 3537 }, { 5492, 3538 }, + { 5493, 3539 }, { 5494, 3540 }, { 5495, 3541 }, { 5496, 3542 }, { 5497, 3543 }, { 5498, 3544 }, { 5499, 3545 }, + { 5500, 3546 }, { 5501, 3547 }, { 5502, 3548 }, { 5503, 3549 }, { 5504, 3550 }, { 5505, 3551 }, { 5506, 3552 }, + { 5507, 3553 }, { 5508, 3554 }, { 5509, 3555 }, { 5510, 3556 }, { 5511, 3557 }, { 5512, 3558 }, { 5513, 3559 }, + { 5514, 3560 }, { 5515, 3561 }, { 5516, 3562 }, { 5517, 3563 }, { 5518, 3564 }, { 5519, 3565 }, { 5520, 3566 }, + { 5521, 3567 }, { 5522, 3568 }, { 5523, 3569 }, { 5524, 3570 }, { 5525, 3571 }, { 5526, 3572 }, { 5527, 3573 }, + { 5528, 3574 }, { 5529, 3575 }, { 5530, 3576 }, { 5531, 3577 }, { 5532, 3578 }, { 5533, 3579 }, { 5534, 3580 }, + { 5535, 3581 }, { 5536, 3582 }, { 5537, 3583 }, { 5538, 3584 }, { 5539, 3585 }, { 5540, 3586 }, { 5541, 3587 }, + { 5542, 3588 }, { 5543, 3589 }, { 5544, 3590 }, { 5545, 3591 }, { 5546, 3592 }, { 5547, 3593 }, { 5548, 3594 }, + { 5549, 3595 }, { 5550, 3596 }, { 5551, 3597 }, { 5552, 3598 }, { 5553, 3599 }, { 5554, 3600 }, { 5555, 3601 }, + { 5556, 3602 }, { 5557, 3603 }, { 5558, 3604 }, { 5559, 3605 }, { 5560, 3606 }, { 5561, 3607 }, { 5562, 3608 }, + { 5563, 3609 }, { 5564, 3610 }, { 5565, 3611 }, { 5566, 3612 }, { 5567, 3613 }, { 5568, 3614 }, { 5569, 3615 }, + { 5570, 3616 }, { 4554, 3065 }, }; // v1.0 -> JP asset ID remap table. 1309 entries. From b906efd9bdbf578523a35e14c0526e46600b7553 Mon Sep 17 00:00:00 2001 From: Jeod <47716344+JeodC@users.noreply.github.com> Date: Sun, 2 Aug 2026 14:01:24 -0400 Subject: [PATCH 074/131] Fix language pack redirects not working (#349) --- src/port/GameVersion/BaseGameVersion.cpp | 79 +++++++++++------------- src/port/GameVersion/BaseGameVersion.h | 3 + src/port/Localization/Language.cpp | 21 ++++++- src/port/Patches/FramePacingPatches.cpp | 3 +- 4 files changed, 61 insertions(+), 45 deletions(-) diff --git a/src/port/GameVersion/BaseGameVersion.cpp b/src/port/GameVersion/BaseGameVersion.cpp index 52b16fb37..717bbb0fd 100644 --- a/src/port/GameVersion/BaseGameVersion.cpp +++ b/src/port/GameVersion/BaseGameVersion.cpp @@ -12,6 +12,22 @@ namespace Lighthouse { namespace { +bool IsKnownVersion(uint32_t crc) { + switch (crc) { + case BK_VER_US_10: + case BK_VER_US_11: + case BK_VER_PAL: + case BK_VER_JP: + return true; + default: + return false; + } +} + +uint32_t ByteSwap32(uint32_t v) { + return (v >> 24) | ((v >> 8) & 0x0000FF00u) | ((v << 8) & 0x00FF0000u) | (v << 24); +} + bool ReadStampedCrc(const std::string& archivePath, uint32_t& outCrc) { int err = 0; zip_t* z = zip_open(archivePath.c_str(), ZIP_RDONLY, &err); @@ -24,31 +40,9 @@ bool ReadStampedCrc(const std::string& archivePath, uint32_t& outCrc) { if (zip_file_t* f = zip_fopen_index(z, idx, 0)) { uint8_t buf[5] = {}; if (zip_fread(f, buf, sizeof(buf)) == sizeof(buf)) { - const uint32_t crcBE = (static_cast(buf[1]) << 24) | (static_cast(buf[2]) << 16) | - (static_cast(buf[3]) << 8) | static_cast(buf[4]); - - const uint32_t crcLE = (static_cast(buf[4]) << 24) | (static_cast(buf[3]) << 16) | - (static_cast(buf[2]) << 8) | static_cast(buf[1]); - - auto isKnownVersion = [](uint32_t crc) { - switch (crc) { - case BK_VER_US_10: - case BK_VER_US_11: - case BK_VER_PAL: - case BK_VER_JP: - return true; - default: - return false; - } - }; - - if (isKnownVersion(crcBE)) { - outCrc = crcBE; - ok = true; - } else if (isKnownVersion(crcLE)) { - outCrc = crcLE; - ok = true; - } + outCrc = (static_cast(buf[1]) << 24) | (static_cast(buf[2]) << 16) | + (static_cast(buf[3]) << 8) | static_cast(buf[4]); + ok = true; } zip_fclose(f); } @@ -58,21 +52,6 @@ bool ReadStampedCrc(const std::string& archivePath, uint32_t& outCrc) { return ok; } -BKVersion ClassifyCrc(uint32_t crc) { - switch (crc) { - case BK_VER_US_11: - return BK_VER_US_11; - case BK_VER_PAL: - return BK_VER_PAL; - case BK_VER_JP: - return BK_VER_JP; - case BK_VER_US_10: - default: - // Vanilla v1.0, a v1.0-based romhack, or an unknown dump. - return BK_VER_US_10; - } -} - } // namespace BKVersion GetBaseVersion() { @@ -88,13 +67,27 @@ BKVersion GetBaseVersion() { } uint32_t crc = 0; - if (ReadStampedCrc(basePath, crc)) { - sVersion = ClassifyCrc(crc); + BKVersion version = BK_VER_US_10; + if (ReadStampedCrc(basePath, crc) && ClassifyArchiveVersion(crc, version)) { + sVersion = version; sResolved = true; SPDLOG_INFO("[BaseGameVersion] base bk.o2r CRC 0x{:08X} -> BKVersion 0x{:08X}", crc, static_cast(sVersion)); } - return sVersion; + return sVersion; // unstamped or unrecognised: stay on the v1.0 default and retry +} + +bool ClassifyArchiveVersion(uint32_t rawVersion, BKVersion& out) { + if (IsKnownVersion(rawVersion)) { + out = static_cast(rawVersion); + return true; + } + const uint32_t swapped = ByteSwap32(rawVersion); + if (IsKnownVersion(swapped)) { + out = static_cast(swapped); + return true; + } + return false; } bool BaseGameSupportsRomhacks() { diff --git a/src/port/GameVersion/BaseGameVersion.h b/src/port/GameVersion/BaseGameVersion.h index 4d463b806..916293690 100644 --- a/src/port/GameVersion/BaseGameVersion.h +++ b/src/port/GameVersion/BaseGameVersion.h @@ -9,6 +9,9 @@ namespace Lighthouse { // The ROM CRC that Torch inserts into the o2r version file BKVersion GetBaseVersion(); +// Classify a version stamp taken from an archive +bool ClassifyArchiveVersion(uint32_t rawVersion, BKVersion& out); + // Romhacks are generally only supported by US 1.0 bool BaseGameSupportsRomhacks(); diff --git a/src/port/Localization/Language.cpp b/src/port/Localization/Language.cpp index 78bfea80c..c066c854f 100644 --- a/src/port/Localization/Language.cpp +++ b/src/port/Localization/Language.cpp @@ -221,8 +221,14 @@ void SetActiveLanguage(const std::string& name) { std::unordered_map dialogOverride; if (entry->source != nullptr) { + // The pack's assets are numbered for the ROM it was extracted from, so they have + // to be translated into the base's v1.0 id space before they can override anything. + const uint32_t rawVersion = static_cast(entry->source->GetGameVersion()); + BKVersion packVersion = BK_VER_US_10; + const bool classified = ClassifyArchiveVersion(rawVersion, packVersion); + const std::unordered_map* remap = nullptr; - switch (static_cast(entry->source->GetGameVersion())) { + switch (packVersion) { case BK_VER_US_11: remap = &sV10toV11Remap; break; @@ -232,9 +238,20 @@ void SetActiveLanguage(const std::string& name) { case BK_VER_JP: remap = &sV10toJPRemap; break; + case BK_VER_US_10: default: break; // pack ids already match v1.0 } + + // Without a recognised stamp there is no way to know which id space the pack is in. + // Installing its assets under their own ids would drop them onto whatever v1.0 asset + // happens to share the number, so leave the language alone instead. + if (!classified) { + SPDLOG_ERROR("[Lang] '{}': pack version stamp {:#010x} matches no known ROM; refusing to apply it " + "(its asset ids cannot be translated to the base game's).", + name, rawVersion); + return; + } std::unordered_map inverse; if (remap != nullptr) { for (const auto& [v10Id, targetId] : *remap) { @@ -263,6 +280,8 @@ void SetActiveLanguage(const std::string& name) { } else if (auto it = inverse.find(packId); it != inverse.end()) { v10Id = it->second; } else { + // Nothing to translate: the asset has no v1.0 counterpart (the JP-only + // font and friends, which the port asks for by their pack id). v10Id = packId; } dialogOverride[v10Id] = path; diff --git a/src/port/Patches/FramePacingPatches.cpp b/src/port/Patches/FramePacingPatches.cpp index 36795656b..56a16eeeb 100644 --- a/src/port/Patches/FramePacingPatches.cpp +++ b/src/port/Patches/FramePacingPatches.cpp @@ -20,13 +20,14 @@ enum map_e gsworld_getMap(void); // Demo Display Pacing static int sDemoViCount = 0; +static constexpr int kMaxDemoViCount = 0xF; int port_getDemoViCount(void) { return sDemoViCount; } void port_setDemoViCount(int viCount) { - sDemoViCount = viCount; + sDemoViCount = (viCount > kMaxDemoViCount) ? kMaxDemoViCount : viCount; } int port_getDemoDisplayViCount(int rawViCount) { From abb69572f1c269e39ded2ab845aba0fcf8bfe527 Mon Sep 17 00:00:00 2001 From: Jeod <47716344+JeodC@users.noreply.github.com> Date: Sun, 2 Aug 2026 14:01:32 -0400 Subject: [PATCH 075/131] Bump Torch (#350) --- Torch | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Torch b/Torch index b4b75e664..270279d41 160000 --- a/Torch +++ b/Torch @@ -1 +1 @@ -Subproject commit b4b75e6649d66c028f56116f0bf48a119862b1bb +Subproject commit 270279d4193d9a09b4525903f5f0471dd3d203fd From 0605d1b9eb12036914b52128d61e62e50d67542c Mon Sep 17 00:00:00 2001 From: Jeod <47716344+JeodC@users.noreply.github.com> Date: Sun, 2 Aug 2026 14:13:18 -0400 Subject: [PATCH 076/131] Fix snow particle alpha transparency and xmas tree light interpolation (#330) --- src/core2/fx/weather_snow.c | 38 ++++++++++++--------- src/core2/model/modelRender.c | 3 ++ src/core2/sprite/screenoverlay.c | 4 ++- src/port/Enhancements/Events/Hooks/Events.h | 3 ++ src/port/Patches/GraphicsPatches.cpp | 32 +++++++++++++++++ src/port/Patches/SpritePatches.cpp | 8 +++++ 6 files changed, 70 insertions(+), 18 deletions(-) diff --git a/src/core2/fx/weather_snow.c b/src/core2/fx/weather_snow.c index 7148b5046..894ecfe53 100644 --- a/src/core2/fx/weather_snow.c +++ b/src/core2/fx/weather_snow.c @@ -29,22 +29,22 @@ Gfx D_80369290[] = gsSPEndDisplayList(), }; -Gfx D_803692B0[] = +// [port] The flake model reaches these render modes through segment 3 at fixed byte +// offsets; one 2D array guarantees the contiguity three separate globals did not. +Gfx D_803692B0[][2] = { - gsDPSetRenderMode(Z_CMP | CVG_DST_CLAMP | ZMODE_OPA | FORCE_BL | G_RM_PASS, Z_CMP | CVG_DST_CLAMP | ZMODE_OPA | FORCE_BL | GBL_c2(G_BL_CLR_IN, G_BL_0, G_BL_CLR_IN, G_BL_1)), - gsSPEndDisplayList(), -}; - -Gfx D_803692C0[] = -{ - gsDPSetRenderMode(AA_EN | Z_CMP | IM_RD | CVG_DST_CLAMP | ZMODE_OPA | ALPHA_CVG_SEL | G_RM_PASS, AA_EN | Z_CMP | IM_RD | CVG_DST_CLAMP | ZMODE_OPA | ALPHA_CVG_SEL | GBL_c2(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM)), - gsSPEndDisplayList(), -}; - -Gfx D_803692D0[] = -{ - gsDPSetRenderMode(Z_CMP | IM_RD | CVG_DST_FULL | ZMODE_OPA | FORCE_BL | G_RM_PASS, Z_CMP | IM_RD | CVG_DST_FULL | ZMODE_OPA | FORCE_BL | GBL_c2(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA)), - gsSPEndDisplayList(), + { + gsDPSetRenderMode(Z_CMP | CVG_DST_CLAMP | ZMODE_OPA | FORCE_BL | G_RM_PASS, Z_CMP | CVG_DST_CLAMP | ZMODE_OPA | FORCE_BL | GBL_c2(G_BL_CLR_IN, G_BL_0, G_BL_CLR_IN, G_BL_1)), + gsSPEndDisplayList(), + }, + { + gsDPSetRenderMode(AA_EN | Z_CMP | IM_RD | CVG_DST_CLAMP | ZMODE_OPA | ALPHA_CVG_SEL | G_RM_PASS, AA_EN | Z_CMP | IM_RD | CVG_DST_CLAMP | ZMODE_OPA | ALPHA_CVG_SEL | GBL_c2(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM)), + gsSPEndDisplayList(), + }, + { + gsDPSetRenderMode(Z_CMP | IM_RD | CVG_DST_FULL | ZMODE_OPA | FORCE_BL | G_RM_PASS, Z_CMP | IM_RD | CVG_DST_FULL | ZMODE_OPA | FORCE_BL | GBL_c2(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA)), + gsSPEndDisplayList(), + }, }; /* .bss */ @@ -208,9 +208,13 @@ void func_802F962C(Gfx **gfx, Mtx **mtx, Vtx **vtx) { func_80349AD0(); gSPSegment((*gfx)++, 1, osVirtualToPhysical(temp_s3 + 1)); gSPSegment((*gfx)++, 0x02, osVirtualToPhysical((void*)((uintptr_t)D_80369288 + D_80369288->texture_list_offset + sizeof(BKTextureList) + sizeof(BKTextureInfo)))); - gSPSetGeometryMode((*gfx)++, G_ZBUFFER); + // [port] Vanilla only sets G_ZBUFFER here, inheriting the rest of the RSP/RDP state + // from whatever drew last. GraphicsPatches.cpp substitutes a self-contained preamble. + if (EventSystem_Should(VB_SNOW_RENDER_STATE, true, gfx)) { + gSPSetGeometryMode((*gfx)++, G_ZBUFFER); + } gSPDisplayList((*gfx)++, D_80369290); - gSPSegment((*gfx)++, 0x03, osVirtualToPhysical(&D_803692B0)); + gSPSegment((*gfx)++, 0x03, osVirtualToPhysical(D_803692B0)); D_80381094 = (Struct_core2_72060_0 *)((uintptr_t)D_80369288 + D_80369288->geo_list_offset); diff --git a/src/core2/model/modelRender.c b/src/core2/model/modelRender.c index 8618a4641..d701fb000 100644 --- a/src/core2/model/modelRender.c +++ b/src/core2/model/modelRender.c @@ -711,6 +711,7 @@ void modelRender_geoCmd_Unk0(Gfx **gfx, Mtx **mtx, struct bk_geo_cmd_s *arg2){ f32 sp30[3]; if(cmd->unk8){ + FrameInterpolation_RecordOpenChildHash3("billboard", (uintptr_t)cmd, 0, 0); mlMtx_apply_vec3f(sp30, cmd->unkC); mlMtx_push_translation(sp30[0], sp30[1], sp30[2]); mlMtxRotYaw(modelRenderCameraRotation[1]); @@ -724,6 +725,7 @@ void modelRender_geoCmd_Unk0(Gfx **gfx, Mtx **mtx, struct bk_geo_cmd_s *arg2){ modelRender_executeGeoCmds(gfx, mtx, (BKGeoCmd*)((u8*)cmd + cmd->unk8)); mlMtxPop(); gSPPopMatrix((*gfx)++, G_MTX_MODELVIEW); + FrameInterpolation_RecordCloseChild(); } } @@ -1157,6 +1159,7 @@ BKModelBin *modelRender_draw(Gfx **gfx, Mtx **mtx, f32 position[3], f32 rotation tmp_f0 = D_80383708 - 500.0f; if(tmp_f0 < camera_focus_distance){ alpha = (s32)((1.0f - (camera_focus_distance - tmp_f0)/500.0f)*255.0f); + EventSystem_Should(VB_MODEL_DRAWDIST_FADE_ALPHA, true, &alpha); if(modelRenderColorMode == COLOR_MODE_DYNAMIC_PRIM_AND_ENV){ modelRenderDynColors.prim[3] = (modelRenderDynColors.prim[3] * alpha) / 0xff; } diff --git a/src/core2/sprite/screenoverlay.c b/src/core2/sprite/screenoverlay.c index 132012a8f..55a166e8e 100644 --- a/src/core2/sprite/screenoverlay.c +++ b/src/core2/sprite/screenoverlay.c @@ -206,7 +206,9 @@ void codeAEDA0_drawSprite( Gfx **gfx ) D_80370338[0] = 1; } - if(D_80383634 == 0x0E){ + // [port] Vanilla only disarms G_AC_THRESHOLD when the draw-mode global still reads + // 0x0E. SpritePatches.cpp forces it so a mode change cannot leak it into later draws. + if (EventSystem_Should(VB_SPRITE_RESTORE_ALPHA_COMPARE, D_80383634 == 0x0E, gfx)) { gDPSetAlphaCompare((*gfx)++, G_AC_NONE); } } diff --git a/src/port/Enhancements/Events/Hooks/Events.h b/src/port/Enhancements/Events/Hooks/Events.h index 5d3b4b373..99148ae6b 100644 --- a/src/port/Enhancements/Events/Hooks/Events.h +++ b/src/port/Enhancements/Events/Hooks/Events.h @@ -69,6 +69,9 @@ typedef enum VBehaviorID { VB_CUBE_PROP_SORT, VB_GCLIGHTS_RECOLOR, VB_SNOW_CAMERA_ROTATION, + VB_SNOW_RENDER_STATE, + VB_MODEL_DRAWDIST_FADE_ALPHA, + VB_SPRITE_RESTORE_ALPHA_COMPARE, VB_DRAWDIST_BOX_CULL, VB_PICTUREBOX_TARGET_FB, diff --git a/src/port/Patches/GraphicsPatches.cpp b/src/port/Patches/GraphicsPatches.cpp index fcbe26fdf..d8082b1f4 100644 --- a/src/port/Patches/GraphicsPatches.cpp +++ b/src/port/Patches/GraphicsPatches.cpp @@ -269,3 +269,35 @@ static void RegisterStaleTileFix_Init() { } static RegisterShipInitFunc staleTileFixInit(RegisterStaleTileFix_Init, { CVAR_FP_LOBBY_DOOR_TILE }); + +// ============================ +// INHERITED RENDER STATE +// ============================ + +static void ApplySnowRenderState(Gfx** gfx) { + gSPClearGeometryMode((*gfx)++, G_ZBUFFER | G_SHADE | G_CULL_BOTH | G_FOG | G_LIGHTING | G_TEXTURE_GEN | + G_TEXTURE_GEN_LINEAR | G_LOD | G_SHADING_SMOOTH); + gSPSetGeometryMode((*gfx)++, G_ZBUFFER | G_SHADE | G_SHADING_SMOOTH); + gDPSetAlphaCompare((*gfx)++, G_AC_NONE); + gDPSetPrimColor((*gfx)++, 0, 0, 0xFF, 0xFF, 0xFF, 0xFF); + gDPSetEnvColor((*gfx)++, 0xFF, 0xFF, 0xFF, 0xFF); + gDPSetBlendColor((*gfx)++, 0x00, 0x00, 0x00, 0x80); +} + +static void RegisterSnowRenderState_Init() { + COND_VB_SHOULD(VB_SNOW_RENDER_STATE, EVENT_PRIORITY_NORMAL, true, { + ApplySnowRenderState(va_arg(args, Gfx**)); + *should = false; + }); +} + +static RegisterShipInitFunc sSnowRenderStateInit(RegisterSnowRenderState_Init); + +static void RegisterModelDrawDistFadeAlpha_Init() { + COND_VB_SHOULD(VB_MODEL_DRAWDIST_FADE_ALPHA, EVENT_PRIORITY_NORMAL, true, { + s32* alpha = va_arg(args, s32*); + *alpha = std::clamp(*alpha, 0, 0xFF); + }); +} + +static RegisterShipInitFunc sModelDrawDistFadeAlphaInit(RegisterModelDrawDistFadeAlpha_Init); diff --git a/src/port/Patches/SpritePatches.cpp b/src/port/Patches/SpritePatches.cpp index 9f5df2199..5f225d5d2 100644 --- a/src/port/Patches/SpritePatches.cpp +++ b/src/port/Patches/SpritePatches.cpp @@ -4,7 +4,9 @@ #include +#include "port/Enhancements/Events/Hooks/Events.h" #include "port/Patches/Patches.h" +#include "port/ShipInit.hpp" extern "C" { @@ -222,3 +224,9 @@ void port_pauseBannerFree(void) { } } // extern "C" + +static void RegisterSpriteRestoreAlphaCompare_Init() { + COND_VB_SHOULD(VB_SPRITE_RESTORE_ALPHA_COMPARE, EVENT_PRIORITY_NORMAL, true, { *should = true; }); +} + +static RegisterShipInitFunc sSpriteRestoreAlphaCompareInit(RegisterSpriteRestoreAlphaCompare_Init); From 337a8a08bb44a703822ab7ac9fb5c241daf7501d Mon Sep 17 00:00:00 2001 From: Jeod <47716344+JeodC@users.noreply.github.com> Date: Sun, 2 Aug 2026 14:13:31 -0400 Subject: [PATCH 077/131] Repair Banjo Dreamie (#346) --- src/core2/map/cutscene_skip.c | 12 ++++-- .../Events/Hooks/List/GameEvent.h | 3 ++ src/port/Romhack/RomhackConfig.cpp | 5 +++ src/port/Romhack/RomhackConfig.h | 1 + src/port/Romhack/RomhackRegistration.cpp | 1 + src/port/Romhack/RomhackTable.h | 3 ++ src/port/Romhack/Specific/Dreamie.cpp | 38 +++++++++++++++++++ 7 files changed, 60 insertions(+), 3 deletions(-) create mode 100644 src/port/Romhack/Specific/Dreamie.cpp diff --git a/src/core2/map/cutscene_skip.c b/src/core2/map/cutscene_skip.c index 029d3f28c..18155463f 100644 --- a/src/core2/map/cutscene_skip.c +++ b/src/core2/map/cutscene_skip.c @@ -1522,9 +1522,15 @@ void func_8031FAB4(NodeProp *arg0, ActorMarker *arg1) { void warp_lairEnterLairFromSMLevel(NodeProp *arg0, ActorMarker *arg1) { if (fileProgressFlag_get(FILEPROG_BD_ENTER_LAIR_CUTSCENE) != 0) { // MM Lobby - // [port] BB romhacks can override this warp destination - s32 override = port_getRomhackWarpEnterLair(); - func_8031CC8C(arg0, override >= 0 ? override : 0x6912); + // [port] BB romhacks can override this warp destination via BKCF; port + // listeners can refine further by responding to OnWarpResolveDest. + s32 dest = 0x6912; + s32 bkcf = port_getRomhackWarpEnterLair(); + if (bkcf >= 0) { + dest = bkcf; + } + CALL_EVENT(OnWarpResolveDest, WARP_ID_LAIR_ENTER_LAIR_FROM_SM_LEVEL, 0x6912, bkcf, &dest); + func_8031CC8C(arg0, dest); } else { fileProgressFlag_set(FILEPROG_BD_ENTER_LAIR_CUTSCENE, 1); // Enter Lair Cutscene diff --git a/src/port/Enhancements/Events/Hooks/List/GameEvent.h b/src/port/Enhancements/Events/Hooks/List/GameEvent.h index 37af7a155..6f682b5c6 100644 --- a/src/port/Enhancements/Events/Hooks/List/GameEvent.h +++ b/src/port/Enhancements/Events/Hooks/List/GameEvent.h @@ -28,6 +28,9 @@ DEFINE_EVENT(OnSaveFileSave, void* saveBuffer; int32_t fileNum; int32_t * result typedef enum WarpId { WARP_ID_SM_EXIT_BANJOS_HOUSE = 1, WARP_ID_LAIR_ENTER_MM_LOBBY_FROM_SM_LEVEL = 2, + // Also lands in the MM Lobby, but from the post-cutscene branch of a different + // dispatcher. Listeners that treat both lair entrances alike should match on 2 || 3. + WARP_ID_LAIR_ENTER_LAIR_FROM_SM_LEVEL = 3, } WarpId; DEFINE_EVENT(OnWarpResolveDest, int32_t warpId; int32_t defaultDest; int32_t bkcfOverride; int32_t * dest;) diff --git a/src/port/Romhack/RomhackConfig.cpp b/src/port/Romhack/RomhackConfig.cpp index ddcbee98d..303dd86a9 100644 --- a/src/port/Romhack/RomhackConfig.cpp +++ b/src/port/Romhack/RomhackConfig.cpp @@ -769,3 +769,8 @@ extern "C" int port_getRomhackWarpDest(int warp_index) { auto it = sWarpDests.find(warp_index); return (it != sWarpDests.end()) ? it->second : -1; } + +extern "C" void port_clearRomhackWarpDest(int warp_index) { + LoadGameConfig(); + sWarpDests.erase(warp_index); +} diff --git a/src/port/Romhack/RomhackConfig.h b/src/port/Romhack/RomhackConfig.h index dc614ebf8..2dc678181 100644 --- a/src/port/Romhack/RomhackConfig.h +++ b/src/port/Romhack/RomhackConfig.h @@ -42,6 +42,7 @@ int port_getRomhackJiggyPuzzleSize(int puzzle_index); int port_getRomhackJiggyPuzzleFlag(int puzzle_index); const char* port_getRomhackLevelName(int level_index); int port_getRomhackWarpDest(int warp_index); +void port_clearRomhackWarpDest(int warp_index); bool port_getRomhackCustomCodeHash(char out_hex[41]); int port_getRomhackCustomCodeKind(void); bool port_getRomhackRomHash(char out_hex[41]); diff --git a/src/port/Romhack/RomhackRegistration.cpp b/src/port/Romhack/RomhackRegistration.cpp index 98760acef..0cf49a7fb 100644 --- a/src/port/Romhack/RomhackRegistration.cpp +++ b/src/port/Romhack/RomhackRegistration.cpp @@ -16,6 +16,7 @@ #include "port/ShipInit.hpp" #define ROMHACK_PORT_LIST(PORT) \ + PORT(Dreamie) \ PORT(JiggiesOfTime) \ PORT(NewHorizons) \ PORT(Nostalgia64) \ diff --git a/src/port/Romhack/RomhackTable.h b/src/port/Romhack/RomhackTable.h index b613a636a..3e96f7247 100644 --- a/src/port/Romhack/RomhackTable.h +++ b/src/port/Romhack/RomhackTable.h @@ -48,6 +48,9 @@ static constexpr RomhackTableEntry kRomhackTable[] = { // rebinds, though Nostalgia 64 also fills spare overlay space with its own // functions and repoints update funcs at them. + // Banjo-Dreamie + { "3972b2a3aca230dde1cbf66ffa6f052327b7d3fa", "Dreamie", true }, + // Jiggies of Time { "ad7ef5ba9051c6a360c1d60546d5ca8cf61f0d92", "JiggiesOfTime", true }, diff --git a/src/port/Romhack/Specific/Dreamie.cpp b/src/port/Romhack/Specific/Dreamie.cpp new file mode 100644 index 000000000..e176a277e --- /dev/null +++ b/src/port/Romhack/Specific/Dreamie.cpp @@ -0,0 +1,38 @@ +/* + * Banjo-Dreamie + * + * Dreamie ships no custom code at all - it rewires the world purely through BB + * globalized-overlay data, so the BKCF carries everything. Spiral Mountain becomes + * the hub, and two of the ~86 warp edits retarget the Spiral Mountain transitions: + * + * warp_smExitBanjosHouse 0x0112 -> 0x0105 + * warp_lairEnterLairFromSMLevel 0x6912 -> 0x0112 + * + * Both resolve to map 0x01, which is also Dreamie's new-game map (START_MAP = 1, + * START_LEVEL_2 = 1, down from vanilla 0x69). Honoring them verbatim drops every hub + * transition back into the starting room instead of moving between areas. + * + * On every OnWarpResolveDest fire, restore the dispatcher's vanilla default for these + * two warps, ignoring what the BKCF claims. The other BKCF warp remaps are genuine and + * pass through untouched. + * + */ + +#include + +#include "port/Enhancements/Events/Hooks/Events.h" +#include "port/Romhack/RomhackConfig.h" + +static constexpr int kWarpIdxSmExitBanjosHouse = 281; + +void RegisterDreamiePatches() { + port_clearRomhackWarpDest(kWarpIdxSmExitBanjosHouse); + + REGISTER_LISTENER(OnWarpResolveDest, EVENT_PRIORITY_NORMAL, [](IEvent* event) { + auto* ev = reinterpret_cast(event); + if (ev->warpId == WARP_ID_SM_EXIT_BANJOS_HOUSE || ev->warpId == WARP_ID_LAIR_ENTER_MM_LOBBY_FROM_SM_LEVEL || + ev->warpId == WARP_ID_LAIR_ENTER_LAIR_FROM_SM_LEVEL) { + *ev->dest = ev->defaultDest; + } + }); +} From da1fe31fcc578c8ea1a8a03b2ca17ed265db28dd Mon Sep 17 00:00:00 2001 From: Jeod <47716344+JeodC@users.noreply.github.com> Date: Sun, 2 Aug 2026 15:29:58 -0400 Subject: [PATCH 078/131] Add anchor color customization and nametags (#334) --- src/core2/ba/model.c | 4 + src/port/Engine.cpp | 7 +- .../Enhancements/Cosmetics/PlayerColors.cpp | 480 ++++++++++++++++++ .../Enhancements/Cosmetics/PlayerColors.h | 43 ++ src/port/Game.cpp | 3 + src/port/Nametag/Nametag.cpp | 172 ++++++- src/port/Nametag/Nametag.h | 11 +- src/port/Nametag/NametagBindings.cpp | 48 +- src/port/Network/Anchor/Anchor.cpp | 48 ++ src/port/Network/Anchor/Anchor.h | 5 +- src/port/Network/Anchor/DummyPlayer.cpp | 2 + src/port/Network/Anchor/DummyPlayer.h | 10 + src/port/Network/Anchor/JsonConversions.hpp | 33 ++ src/port/Network/Anchor/Menu.cpp | 93 +++- .../Network/Anchor/Packets/AllClientState.cpp | 6 + .../Anchor/Packets/UpdateClientState.cpp | 6 + src/port/UI/LighthouseMenuDevTools.cpp | 3 - src/port/UI/UIWidgets.cpp | 5 +- 18 files changed, 903 insertions(+), 76 deletions(-) create mode 100644 src/port/Enhancements/Cosmetics/PlayerColors.cpp create mode 100644 src/port/Enhancements/Cosmetics/PlayerColors.h diff --git a/src/core2/ba/model.c b/src/core2/ba/model.c index 4b16065fd..286240997 100644 --- a/src/core2/ba/model.c +++ b/src/core2/ba/model.c @@ -7,6 +7,8 @@ #include "core2/ba/physics.h" #include "bk_math.h" +#include "port/Enhancements/Cosmetics/PlayerColors.h" + void assetcache_release(void *); //assetcache_free void modelRender_func_8033A280(f32); @@ -101,6 +103,8 @@ void baModel_draw(Gfx **gfx, Mtx **mtx, Vtx **vtx){ modelRender_setPreDrawCallback((model_render_pre_draw_callback_f)_baModel_preDraw, 0); modelRender_setRefPoints(D_80363780); modelRender_setDepthMode(MODEL_RENDER_DEPTH_FULL); + // [port] Swap in this player's recoloured palettes/vertex colours for this draw. + PlayerColors_applyLocalForDraw(baModel_getModelId(), baModelBin); if(D_8037C150.unk0){ D_8037C150.unk0 = 0; modelRender_draw(gfx, mtx, D_8037C150.unk4, rotation, baModelScale, sp38, baModelBin); diff --git a/src/port/Engine.cpp b/src/port/Engine.cpp index 7759f3d39..75132ca07 100644 --- a/src/port/Engine.cpp +++ b/src/port/Engine.cpp @@ -35,6 +35,7 @@ #include "Extractor/GameExtractor.h" #include "ship/window/gui/FileBrowserWindow.h" #include "Interpolation/FrameInterpolation.h" +#include "Nametag/Nametag.h" #include "OS/OS.h" #include "Network/Anchor/Anchor.h" #include "port/Enhancements/Events/PortEnhancements.h" @@ -1269,9 +1270,13 @@ void GameEngine::RunCommands(Gfx* Commands, const std::vector 1) ? (float)(frameIdx + 1) / (float)frameCount : 1.0f; if (frameCount > 1) { - FrameInterpolation_ApplyAnimVertices((float)(frameIdx + 1) / (float)frameCount); + FrameInterpolation_ApplyAnimVertices(subframeBlend); } + // Overlays drawn by the Gui pass below place themselves per tick, so they need the + // same blend the geometry is being posed with or they step while the world glides. + Nametag::SetSubframeBlend(subframeBlend); bool isFinalFrame = (frameIdx == frameCount - 1); if (frameCount > 1 || wndBase->IsFrameReady()) { // Sample the full CPU cost of producing this sub-frame. diff --git a/src/port/Enhancements/Cosmetics/PlayerColors.cpp b/src/port/Enhancements/Cosmetics/PlayerColors.cpp new file mode 100644 index 000000000..e625e0971 --- /dev/null +++ b/src/port/Enhancements/Cosmetics/PlayerColors.cpp @@ -0,0 +1,480 @@ +#include "PlayerColors.h" + +#include +#include +#include +#include +#include +#include + +#include + +#include "port/UI/cvar_prefixes.h" + +extern "C" { +#include "model.h" +#include "enums.h" +#include "core2/modelRender.h" +s32 port_anchor_isConnected(void); +} + +namespace { + +// --------------------------------------------------------------------------- +// Part tables +// +// Derived from the two player model bins: every CI4 texture and every distinct +// vertex colour was attributed to a bone (via the geo layout) and to a body +// region, then grouped by part. Textures are listed per model because the +// low- and high-poly bins have different texture counts and orderings. +// --------------------------------------------------------------------------- + +struct ChannelInfo { + u8 vanilla[3]; + float minSaturation; + float minHueDeg, maxHueDeg; +}; + +const ChannelInfo kChannels[] = { + /* BANJO_FUR */ { { 0x83, 0x32, 0x03 }, 0.50f, 5.0f, 50.0f }, + /* BANJO_SHORTS */ { { 0xFF, 0xF6, 0x20 }, 0.50f, 0.0f, 70.0f }, + /* KAZOOIE_FEATHERS */ { { 0xF6, 0x10, 0x00 }, 0.50f, 0.0f, 70.0f }, + /* KAZOOIE_BEAK */ { { 0xFE, 0xA1, 0x31 }, 0.12f, 0.0f, 70.0f }, + /* BANJO_BACKPACK */ { { 0x00, 0x4A, 0xE0 }, 0.35f, 190.0f, 250.0f }, + /* BANJO_SKIN */ { { 0xEB, 0x83, 0x6D }, 0.15f, 0.0f, 60.0f }, +}; + +struct TextureTable { + const s16* index; + s32 count; +}; + +// ASSET_34D_MODEL_BANJOKAZOOIE_LOW_POLY +const s16 kLowFur[] = { 12, 13, 15, 18 }; +const s16 kLowShorts[] = { 5, 6 }; +const s16 kLowFeathers[] = { 14 }; +const s16 kLowBeak[] = { 19, 20 }; +const s16 kLowSkin[] = { 2, 7 }; + +// ASSET_34E_MODEL_BANJOKAZOOIE_HIGH_POLY +const s16 kHighFur[] = { 13, 14, 16, 19 }; +const s16 kHighShorts[] = { 6, 7 }; +const s16 kHighFeathers[] = { 15 }; +const s16 kHighBeak[] = { 20, 21 }; +const s16 kHighSkin[] = { 3, 8 }; + +#define TEXTABLE(array) \ + { array, (s32)(sizeof(array) / sizeof((array)[0])) } + +// The backpack is shaded entirely by vertex colour. The only blue palettes in +// the model belong to the eyes and Banjo's claws, which must stay put. +const TextureTable kLowTextures[] = { TEXTABLE(kLowFur), TEXTABLE(kLowShorts), TEXTABLE(kLowFeathers), + TEXTABLE(kLowBeak), { nullptr, 0 }, TEXTABLE(kLowSkin) }; +const TextureTable kHighTextures[] = { TEXTABLE(kHighFur), TEXTABLE(kHighShorts), TEXTABLE(kHighFeathers), + TEXTABLE(kHighBeak), { nullptr, 0 }, TEXTABLE(kHighSkin) }; + +#undef TEXTABLE + +const u32 kFurVerts[] = { 0xFA6F12, 0xCC560B, 0xAE4707, 0x833203, 0x632501, 0x411700, 0x270E00 }; +const u32 kShortsVerts[] = { 0xFFFF28, 0xEAEA00, 0xF6B400, 0xCE8700, 0xBA5500, 0x874708 }; +const u32 kFeatherVerts[] = { 0xFF3300, 0xD00000, 0x880000, 0x520000, 0xFF5F00, 0xFF8900 }; +const u32 kBeakVerts[] = { 0xFFFF9F, 0xFFCF3D, 0xFFC700, 0xFEA131, 0xBA7F4B, 0x923900, 0xC74700, 0x662300 }; +const u32 kBackpackVerts[] = { 0x7FA9FF, 0x558DFF, 0x2B71FF, 0x004AE0, 0x003092, 0x002268, 0x001A4E }; +const u32 kSkinVerts[] = { 0xFFEAB4, 0xFFBE97, 0xFFA385, 0xEB836D, 0xC66E5C, 0x995447, 0x66372F, 0x45251F }; + +struct VertexTable { + const u32* color; + s32 count; +}; + +#define VTXTABLE(array) \ + { array, (s32)(sizeof(array) / sizeof((array)[0])) } +const VertexTable kVertexTables[] = { VTXTABLE(kFurVerts), VTXTABLE(kShortsVerts), VTXTABLE(kFeatherVerts), + VTXTABLE(kBeakVerts), VTXTABLE(kBackpackVerts), VTXTABLE(kSkinVerts) }; +#undef VTXTABLE + +// --------------------------------------------------------------------------- +// Color math +// --------------------------------------------------------------------------- + +struct Hsv { + float hue; // degrees, 0..360 + float saturation, value; +}; + +Hsv ToHsv(float red, float green, float blue) { + const float maxComponent = std::max({ red, green, blue }); + const float minComponent = std::min({ red, green, blue }); + const float chroma = maxComponent - minComponent; + Hsv hsv{ 0.0f, maxComponent > 0.0f ? chroma / maxComponent : 0.0f, maxComponent }; + if (chroma > 0.0f) { + if (maxComponent == red) { + hsv.hue = 60.0f * std::fmod((green - blue) / chroma, 6.0f); + } else if (maxComponent == green) { + hsv.hue = 60.0f * (((blue - red) / chroma) + 2.0f); + } else { + hsv.hue = 60.0f * (((red - green) / chroma) + 4.0f); + } + if (hsv.hue < 0.0f) { + hsv.hue += 360.0f; + } + } + return hsv; +} + +void FromHsv(const Hsv& hsv, float* red, float* green, float* blue) { + const float chroma = hsv.value * hsv.saturation; + const float sector = std::fmod(std::fmod(hsv.hue, 360.0f) + 360.0f, 360.0f) / 60.0f; + const float ramp = chroma * (1.0f - std::fabs(std::fmod(sector, 2.0f) - 1.0f)); + float highest = 0.0f, middle = 0.0f, lowest = 0.0f; + switch ((int)sector) { + case 0: + highest = chroma; + middle = ramp; + break; + case 1: + highest = ramp; + middle = chroma; + break; + case 2: + middle = chroma; + lowest = ramp; + break; + case 3: + middle = ramp; + lowest = chroma; + break; + case 4: + highest = ramp; + lowest = chroma; + break; + default: + highest = chroma; + lowest = ramp; + break; + } + const float offset = hsv.value - chroma; + *red = highest + offset; + *green = middle + offset; + *blue = lowest + offset; +} + +float Clamp01(float value) { + return value < 0.0f ? 0.0f : (value > 1.0f ? 1.0f : value); +} + +// Re-tints one source colour so the channel's vanilla colour lands exactly on `target` and +// every other shade of the part keeps its position in the shading ramp. +void Recolor(const ChannelInfo& channel, const BKColorChannelSetting& target, u8 sourceRed, u8 sourceGreen, + u8 sourceBlue, u8* outRed, u8* outGreen, u8* outBlue) { + const Hsv source = ToHsv(sourceRed / 255.0f, sourceGreen / 255.0f, sourceBlue / 255.0f); + const Hsv vanilla = ToHsv(channel.vanilla[0] / 255.0f, channel.vanilla[1] / 255.0f, channel.vanilla[2] / 255.0f); + const Hsv chosen = ToHsv(target.r / 255.0f, target.g / 255.0f, target.b / 255.0f); + + float hueOffset = source.hue - vanilla.hue; + while (hueOffset > 180.0f) { + hueOffset -= 360.0f; + } + while (hueOffset < -180.0f) { + hueOffset += 360.0f; + } + const float rampPosition = std::min(std::fabs(hueOffset), 45.0f) / 45.0f; + + Hsv result; + result.hue = chosen.hue + (hueOffset < 0.0f ? -1.0f : 1.0f) * rampPosition * 8.0f; + result.saturation = + vanilla.saturation > 0.001f ? chosen.saturation * (source.saturation / vanilla.saturation) : chosen.saturation; + result.value = vanilla.value > 0.001f ? chosen.value * (source.value / vanilla.value) : chosen.value; + result.saturation = Clamp01(result.saturation * (1.0f - 0.55f * rampPosition)); + result.value = Clamp01(result.value * (1.0f + 0.55f * rampPosition)); + + float red, green, blue; + FromHsv(result, &red, &green, &blue); + *outRed = (u8)std::lround(Clamp01(red) * 255.0f); + *outGreen = (u8)std::lround(Clamp01(green) * 255.0f); + *outBlue = (u8)std::lround(Clamp01(blue) * 255.0f); +} + +bool PassesFilter(const ChannelInfo& channel, u8 red, u8 green, u8 blue) { + const Hsv hsv = ToHsv(red / 255.0f, green / 255.0f, blue / 255.0f); + if (hsv.value <= 0.0f || hsv.saturation < channel.minSaturation) { + return false; + } + return hsv.hue >= channel.minHueDeg && hsv.hue <= channel.maxHueDeg; +} + +// --------------------------------------------------------------------------- +// Per-owner recolored copies +// --------------------------------------------------------------------------- + +constexpr size_t kPaletteArenaWords = 128 * 1024; // 1 MiB + +void* PaletteArenaTake(size_t bytes) { + static std::unique_ptr arena; + static size_t usedWords = 0; + + const size_t wordCount = (bytes + 7) / 8; + if (wordCount > kPaletteArenaWords) { + return nullptr; + } + if (arena == nullptr) { + arena = std::make_unique(kPaletteArenaWords); + } + if (usedWords + wordCount > kPaletteArenaWords) { + usedWords = 0; + } + u64* region = arena.get() + usedWords; + usedWords += wordCount; + return region; +} + +struct Variant { + const void* sourceBin = nullptr; + u64 colorHash = 0; + // Palettes live in the ring arena above; vertices are read fresh every draw and are not + // cached by address, so they can be rebuilt in place. + void* textures = nullptr; + std::unique_ptr vertices; +}; + +std::unordered_map sVariants; + +u64 VariantKey(u32 ownerKey, s32 modelId) { + return ((u64)ownerKey << 32) | (u32)modelId; +} + +u64 HashColors(const BKPlayerColorSet& colors) { + u64 hash = 1469598103934665603ull; + const u8* bytes = (const u8*)&colors; + for (size_t index = 0; index < sizeof(colors); index++) { + hash = (hash ^ bytes[index]) * 1099511628211ull; + } + return hash; +} + +bool AnyEnabled(const BKPlayerColorSet& colors) { + for (int channelIndex = 0; channelIndex < BK_COLOR_CHANNEL_COUNT; channelIndex++) { + if (colors.channel[channelIndex].enabled) { + return true; + } + } + return false; +} + +const TextureTable* TexturesForModel(s32 modelId) { + switch (modelId) { + case ASSET_34D_MODEL_BANJOKAZOOIE_LOW_POLY: + return kLowTextures; + case ASSET_34E_MODEL_BANJOKAZOOIE_HIGH_POLY: + return kHighTextures; + default: + return nullptr; + } +} + +void RecolorTextures(void* textureBlob, const TextureTable* textureTable, const BKPlayerColorSet& colors) { + BKTextureList* textureList = (BKTextureList*)textureBlob; + u8* pixelBase = (u8*)textureList + sizeof(BKTextureList) + (size_t)textureList->count * sizeof(BKTextureInfo); + + for (int channelIndex = 0; channelIndex < BK_COLOR_CHANNEL_COUNT; channelIndex++) { + if (!colors.channel[channelIndex].enabled) { + continue; + } + const ChannelInfo& channel = kChannels[channelIndex]; + for (s32 entry = 0; entry < textureTable[channelIndex].count; entry++) { + const s16 textureIndex = textureTable[channelIndex].index[entry]; + if (textureIndex < 0 || textureIndex >= textureList->count) { + continue; + } + BKTextureInfo* texture = &textureList->texture_infos[textureIndex]; + const s32 paletteBytes = textureInfo_getPaletteSize(texture); + if (paletteBytes <= 0) { + continue; + } + if ((size_t)texture->offset + (size_t)paletteBytes > (size_t)textureList->size) { + continue; + } + // TLUT entries are big-endian RGBA5551, matching what the RDP (and Fast3D's + // CI4 importer) reads out of DRAM. + u8* palette = pixelBase + texture->offset; + for (s32 paletteEntry = 0; paletteEntry < paletteBytes / 2; paletteEntry++) { + const u16 packedColor = (u16)((palette[paletteEntry * 2] << 8) | palette[paletteEntry * 2 + 1]); + const u8 red = (u8)(((packedColor >> 11) & 0x1F) * 255 / 31); + const u8 green = (u8)(((packedColor >> 6) & 0x1F) * 255 / 31); + const u8 blue = (u8)(((packedColor >> 1) & 0x1F) * 255 / 31); + if (!PassesFilter(channel, red, green, blue)) { + continue; + } + u8 newRed, newGreen, newBlue; + Recolor(channel, colors.channel[channelIndex], red, green, blue, &newRed, &newGreen, &newBlue); + const u16 recolored = (u16)(((newRed * 31 / 255) << 11) | ((newGreen * 31 / 255) << 6) | + ((newBlue * 31 / 255) << 1) | (packedColor & 1)); + palette[paletteEntry * 2] = (u8)(recolored >> 8); + palette[paletteEntry * 2 + 1] = (u8)(recolored & 0xFF); + } + } + } +} + +void RecolorVertices(void* vertexBlob, const BKPlayerColorSet& colors) { + BKVertexList* vertexList = (BKVertexList*)vertexBlob; + Vtx* vertices = vertexList->vertices; + const s32 vertexCount = vertexList->count; + + for (s32 vertexIndex = 0; vertexIndex < vertexCount; vertexIndex++) { + Vtx_t& vertex = vertices[vertexIndex].v; + const u32 packedColor = ((u32)vertex.cn[0] << 16) | ((u32)vertex.cn[1] << 8) | (u32)vertex.cn[2]; + for (int channelIndex = 0; channelIndex < BK_COLOR_CHANNEL_COUNT; channelIndex++) { + if (!colors.channel[channelIndex].enabled) { + continue; + } + const VertexTable& vertexColors = kVertexTables[channelIndex]; + bool matched = false; + for (s32 entry = 0; entry < vertexColors.count; entry++) { + if (vertexColors.color[entry] == packedColor) { + matched = true; + break; + } + } + if (!matched) { + continue; + } + u8 newRed, newGreen, newBlue; + Recolor(kChannels[channelIndex], colors.channel[channelIndex], vertex.cn[0], vertex.cn[1], vertex.cn[2], + &newRed, &newGreen, &newBlue); + vertex.cn[0] = newRed; + vertex.cn[1] = newGreen; + vertex.cn[2] = newBlue; + break; + } + } +} + +Variant* BuildVariant(u32 ownerKey, s32 modelId, BKModelBin* modelBin, const BKPlayerColorSet& colors) { + const TextureTable* textureTable = TexturesForModel(modelId); + if (textureTable == nullptr || modelBin == nullptr || modelBin->texture_list_offset == 0 || + modelBin->vtx_list_offset == 0) { + return nullptr; + } + + Variant& variant = sVariants[VariantKey(ownerKey, modelId)]; + const u64 colorHash = HashColors(colors); + if (variant.sourceBin == modelBin && variant.colorHash == colorHash && variant.textures != nullptr) { + return &variant; + } + + const BKTextureList* sourceTextures = modelbin_getTextureList(modelBin); + const BKVertexList* sourceVertices = modelbin_getVtxList(modelBin); + if (sourceTextures == nullptr || sourceVertices == nullptr) { + return nullptr; + } + + const size_t textureBytes = + sizeof(BKTextureList) + (size_t)sourceTextures->count * sizeof(BKTextureInfo) + (size_t)sourceTextures->size; + const size_t vertexBytes = sizeof(BKVertexList) + (size_t)sourceVertices->count * sizeof(Vtx); + + void* textures = PaletteArenaTake(textureBytes); + if (textures == nullptr) { + return nullptr; + } + std::memcpy(textures, sourceTextures, textureBytes); + + variant.vertices = std::make_unique((vertexBytes + 7) / 8); + std::memcpy(variant.vertices.get(), sourceVertices, vertexBytes); + + variant.sourceBin = modelBin; + variant.colorHash = colorHash; + variant.textures = textures; + + RecolorTextures(variant.textures, textureTable, colors); + RecolorVertices(variant.vertices.get(), colors); + return &variant; +} + +const char* kChannelCVars[] = { + CVAR_REMOTE_ANCHOR("Colors.BanjoFur"), CVAR_REMOTE_ANCHOR("Colors.BanjoShorts"), + CVAR_REMOTE_ANCHOR("Colors.KazooieFeathers"), CVAR_REMOTE_ANCHOR("Colors.KazooieBeak"), + CVAR_REMOTE_ANCHOR("Colors.BanjoBackpack"), CVAR_REMOTE_ANCHOR("Colors.BanjoSkin"), +}; + +#define CHANNEL_TABLE_COMPLETE(table) \ + static_assert(sizeof(table) / sizeof((table)[0]) == BK_COLOR_CHANNEL_COUNT, #table) +CHANNEL_TABLE_COMPLETE(kChannelCVars); +CHANNEL_TABLE_COMPLETE(kChannels); +CHANNEL_TABLE_COMPLETE(kVertexTables); +CHANNEL_TABLE_COMPLETE(kLowTextures); +CHANNEL_TABLE_COMPLETE(kHighTextures); +#undef CHANNEL_TABLE_COMPLETE + +} // namespace + +extern "C" { + +const char* PlayerColors_getChannelCVar(s32 channel) { + if (channel < 0 || channel >= BK_COLOR_CHANNEL_COUNT) { + return nullptr; + } + return kChannelCVars[channel]; +} + +void PlayerColors_getVanilla(s32 channel, u8* red, u8* green, u8* blue) { + if (channel < 0 || channel >= BK_COLOR_CHANNEL_COUNT) { + return; + } + *red = kChannels[channel].vanilla[0]; + *green = kChannels[channel].vanilla[1]; + *blue = kChannels[channel].vanilla[2]; +} + +void PlayerColors_getLocal(BKPlayerColorSet* out) { + if (out == nullptr) { + return; + } + for (int channelIndex = 0; channelIndex < BK_COLOR_CHANNEL_COUNT; channelIndex++) { + const ChannelInfo& channel = kChannels[channelIndex]; + const std::string valueCVar = std::string(kChannelCVars[channelIndex]) + ".Value"; + const std::string enabledCVar = std::string(kChannelCVars[channelIndex]) + ".Enabled"; + const Color_RGBA8 vanilla = { channel.vanilla[0], channel.vanilla[1], channel.vanilla[2], 255 }; + const Color_RGBA8 chosen = CVarGetColor(valueCVar.c_str(), vanilla); + out->channel[channelIndex].enabled = CVarGetInteger(enabledCVar.c_str(), 0) ? 1 : 0; + out->channel[channelIndex].r = chosen.r; + out->channel[channelIndex].g = chosen.g; + out->channel[channelIndex].b = chosen.b; + } +} + +void PlayerColors_applyForDraw(u32 ownerKey, s32 modelId, void* modelBin, const BKPlayerColorSet* colors) { + if (!port_anchor_isConnected()) { + return; + } + if (colors == nullptr || modelBin == nullptr || !AnyEnabled(*colors)) { + return; + } + Variant* variant = BuildVariant(ownerKey, modelId, (BKModelBin*)modelBin, *colors); + if (variant == nullptr) { + return; + } + modelRender_setTextureList((BKTextureList*)variant->textures); + modelRender_setVertexList((BKVertexList*)variant->vertices.get()); +} + +void PlayerColors_applyLocalForDraw(s32 modelId, void* modelBin) { + if (TexturesForModel(modelId) == nullptr) { + return; + } + BKPlayerColorSet colors; + PlayerColors_getLocal(&colors); + PlayerColors_applyForDraw(BK_COLORS_LOCAL_OWNER, modelId, modelBin, &colors); +} + +void PlayerColors_forgetOwner(u32 ownerKey) { + for (auto entry = sVariants.begin(); entry != sVariants.end();) { + entry = ((u32)(entry->first >> 32) == ownerKey) ? sVariants.erase(entry) : std::next(entry); + } +} + +void PlayerColors_reset(void) { + sVariants.clear(); +} + +} // extern "C" diff --git a/src/port/Enhancements/Cosmetics/PlayerColors.h b/src/port/Enhancements/Cosmetics/PlayerColors.h new file mode 100644 index 000000000..c7aae365c --- /dev/null +++ b/src/port/Enhancements/Cosmetics/PlayerColors.h @@ -0,0 +1,43 @@ +#ifndef PORT_ENHANCEMENTS_COSMETICS_PLAYERCOLORS_H +#define PORT_ENHANCEMENTS_COSMETICS_PLAYERCOLORS_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + BK_COLOR_BANJO_FUR = 0, + BK_COLOR_BANJO_SHORTS, + BK_COLOR_KAZOOIE_FEATHERS, + BK_COLOR_KAZOOIE_BEAK, + BK_COLOR_BANJO_BACKPACK, + BK_COLOR_BANJO_SKIN, + BK_COLOR_CHANNEL_COUNT +} BKColorChannel; + +typedef struct { + u8 enabled; + u8 r, g, b; +} BKColorChannelSetting; + +typedef struct { + BKColorChannelSetting channel[BK_COLOR_CHANNEL_COUNT]; +} BKPlayerColorSet; + +#define BK_COLORS_LOCAL_OWNER 0u + +void PlayerColors_getVanilla(s32 channel, u8* red, u8* green, u8* blue); +const char* PlayerColors_getChannelCVar(s32 channel); +void PlayerColors_applyForDraw(u32 ownerKey, s32 modelId, void* modelBin, const BKPlayerColorSet* colors); +void PlayerColors_applyLocalForDraw(s32 modelId, void* modelBin); +void PlayerColors_getLocal(BKPlayerColorSet* out); +void PlayerColors_forgetOwner(u32 ownerKey); +void PlayerColors_reset(void); + +#ifdef __cplusplus +} +#endif + +#endif /* PORT_ENHANCEMENTS_COSMETICS_PLAYERCOLORS_H */ diff --git a/src/port/Game.cpp b/src/port/Game.cpp index f77a023b9..bc46b015d 100644 --- a/src/port/Game.cpp +++ b/src/port/Game.cpp @@ -21,6 +21,7 @@ #include "DevTools/ThreadWatchdog.h" #include "GameStatus.h" #include "Interpolation/FrameInterpolation.h" +#include "Nametag/Nametag.h" #include "Network/Anchor/Anchor.h" #include "OS/OS.h" #include "Patches/Patches.h" @@ -107,6 +108,7 @@ extern "C" void port_thread5_onSubmit(void* taskData) { FrameInterpolation_GetRecordingPair(&pair.prev, &pair.curr, &pair.should); FrameInterpolation_ClaimPair(pair.prev, pair.curr); FrameInterpolation_StopRecord(); + Nametag::SubmitFrame(task->data_ptr); std::lock_guard lock(sInterpMutex); pair.serial = ++sInterpSerial; auto [it, inserted] = sTaskInterp.emplace(task->data_ptr, pair); @@ -141,6 +143,7 @@ void RenderTask(void* dlStart) { } } FrameInterpolation_BeginRenderPass(pair.prev, pair.curr, pair.should); + Nametag::BeginRenderPass(dlStart, pair.should); GameEngine::ProcessGfxCommands((Gfx*)dlStart); FrameInterpolation_ReleasePair(pair.prev, pair.curr); } diff --git a/src/port/Nametag/Nametag.cpp b/src/port/Nametag/Nametag.cpp index 116777e54..3c0a52518 100644 --- a/src/port/Nametag/Nametag.cpp +++ b/src/port/Nametag/Nametag.cpp @@ -2,7 +2,9 @@ #include #include +#include #include +#include #include #include @@ -29,16 +31,61 @@ constexpr float kBorderThickness = 1.5f; constexpr float kGameAspect = 4.0f / 3.0f; constexpr float kLowResAspect = 320.0f / 240.0f; +// Distance over which a tag fades out as it reaches the edge of its range. +constexpr float kFadeBand = 500.0f; +constexpr float kMaxFadeShare = 0.25f; + struct Entry { - float pos[3]; + uint32_t id; + float screen[2]; + bool onScreen; + float alpha; std::string text; }; -std::vector sQueue; +ImU32 WithAlpha(ImU32 color, float alpha) { + const float scaled = (float)((color >> IM_COL32_A_SHIFT) & 0xFF) * alpha; + const ImU32 value = (ImU32)(scaled < 0.0f ? 0.0f : (scaled > 255.0f ? 255.0f : scaled)); + return (color & ~IM_COL32_A_MASK) | (value << IM_COL32_A_SHIFT); +} + +// Game thread only. +std::vector sRecording; +bool sRecordingStale = false; + +void RetireRecording() { + sRecording.clear(); +} + +struct FrameTags { + uint64_t serial; + std::vector entries; +}; +std::mutex sHandoffMutex; +std::unordered_map sHandoff; +uint64_t sHandoffSerial = 0; +constexpr uint64_t kHandoffStaleAfter = 8; + +// Render thread only. +std::vector sRenderCurr; +std::vector sRenderPrev; +bool sRenderInterpolate = false; +float sSubframeBlend = 1.0f; + Nametag::ProjectFn sProject = nullptr; +Nametag::DistanceFn sDistance = nullptr; const int* sFbWidth = nullptr; const int* sFbHeight = nullptr; +const Entry* FindPrevious(uint32_t id) { + for (const auto& entry : sRenderPrev) { + if (entry.id == id) { + return &entry; + } + } + return nullptr; +} + // Mirrors LUS Gui::GetIntegerScaleFactor; mGameWindowViewport lags one // frame, matching DrawGame's own read order. int16_t ComputeIntegerScaleFactor(const std::shared_ptr& interp) { @@ -174,19 +221,28 @@ class NametagOverlay : public Ship::GuiWindow { const float scaleY = contentH / static_cast(*sFbHeight); ImDrawList* drawList = ImGui::GetForegroundDrawList(); - for (const auto& entry : sQueue) { - float pos[3] = { entry.pos[0], entry.pos[1], entry.pos[2] }; - float screen[2]; - if (sProject(pos, screen)) { - ImVec2 textSize = ImGui::CalcTextSize(entry.text.c_str()); - ImVec2 anchor(originX + screen[0] * scaleX, originY + screen[1] * scaleY); - ImVec2 textTL(anchor.x - textSize.x * 0.5f, anchor.y - textSize.y * 0.5f); - ImVec2 boxTL(textTL.x - kPaddingX, textTL.y - kPaddingY); - ImVec2 boxBR(textTL.x + textSize.x + kPaddingX, textTL.y + textSize.y + kPaddingY); - drawList->AddRectFilled(boxTL, boxBR, kBgColor, kCornerRadius); - drawList->AddRect(boxTL, boxBR, kBorderColor, kCornerRadius, 0, kBorderThickness); - drawList->AddText(textTL, kTextColor, entry.text.c_str()); + for (const auto& entry : sRenderCurr) { + if (!entry.onScreen) { + continue; } + float screenX = entry.screen[0]; + float screenY = entry.screen[1]; + float alpha = entry.alpha; + const Entry* previous = sRenderInterpolate ? FindPrevious(entry.id) : nullptr; + if (previous != nullptr && previous->onScreen) { + screenX = previous->screen[0] + (screenX - previous->screen[0]) * sSubframeBlend; + screenY = previous->screen[1] + (screenY - previous->screen[1]) * sSubframeBlend; + alpha = previous->alpha + (alpha - previous->alpha) * sSubframeBlend; + } + + ImVec2 textSize = ImGui::CalcTextSize(entry.text.c_str()); + ImVec2 anchor(originX + screenX * scaleX, originY + screenY * scaleY); + ImVec2 textTL(anchor.x - textSize.x * 0.5f, anchor.y - textSize.y * 0.5f); + ImVec2 boxTL(textTL.x - kPaddingX, textTL.y - kPaddingY); + ImVec2 boxBR(textTL.x + textSize.x + kPaddingX, textTL.y + textSize.y + kPaddingY); + drawList->AddRectFilled(boxTL, boxBR, WithAlpha(kBgColor, alpha), kCornerRadius); + drawList->AddRect(boxTL, boxBR, WithAlpha(kBorderColor, alpha), kCornerRadius, 0, kBorderThickness); + drawList->AddText(textTL, WithAlpha(kTextColor, alpha), entry.text.c_str()); } } }; @@ -199,6 +255,10 @@ void SetProjectFn(ProjectFn fn) { sProject = fn; } +void SetDistanceFn(DistanceFn fn) { + sDistance = fn; +} + void SetNativeFramebufferSize(const int* width, const int* height) { sFbWidth = width; sFbHeight = height; @@ -211,20 +271,88 @@ void RegisterOverlay() { overlay->Show(); } -void Clear() { - sQueue.clear(); +void BeginDraw() { + if (sRecordingStale) { + RetireRecording(); + } + sRecordingStale = true; } -void Push(float x, float y, float z, const char* label) { - if (label == nullptr) { +void Push(uint32_t id, float x, float y, float z, const char* label, float alpha) { + if (label == nullptr || alpha <= 0.0f || sProject == nullptr) { return; } + if (sRecordingStale) { + RetireRecording(); + sRecordingStale = false; + } Entry entry; - entry.pos[0] = x; - entry.pos[1] = y; - entry.pos[2] = z; + entry.id = id; + float pos[3] = { x, y, z }; + entry.onScreen = sProject(pos, entry.screen); + entry.alpha = alpha > 1.0f ? 1.0f : alpha; entry.text = label; - sQueue.push_back(std::move(entry)); + sRecording.push_back(std::move(entry)); +} + +// Game thread. A list is submitted while its tick is still recording, so the +// tags travel with the task the same way the interpolation pair does. +void SubmitFrame(const void* key) { + std::lock_guard lock(sHandoffMutex); + const uint64_t serial = ++sHandoffSerial; + auto [it, inserted] = sHandoff.emplace(key, FrameTags{ serial, sRecording }); + if (!inserted) { + it->second.serial = serial; + it->second.entries = sRecording; + } + + // Anything still here after a full trip round the ring will never be picked + // up by a render pass, so drop it rather than grow the map forever. + for (auto stale = sHandoff.begin(); stale != sHandoff.end();) { + if (stale->second.serial + kHandoffStaleAfter < serial) { + stale = sHandoff.erase(stale); + } else { + ++stale; + } + } +} + +// Render thread. Adopt the tags submitted with this list; what the previous +// pass drew stays behind as the interpolation source. +void BeginRenderPass(const void* key, bool interpolate) { + std::vector tags; + { + std::lock_guard lock(sHandoffMutex); + auto it = sHandoff.find(key); + if (it != sHandoff.end()) { + tags = std::move(it->second.entries); + sHandoff.erase(it); + } + } + sRenderPrev = std::move(sRenderCurr); + sRenderCurr = std::move(tags); + sRenderInterpolate = interpolate; +} + +float FadeForDistance(float x, float y, float z, float maxDistance) { + if (sDistance == nullptr) { + return 1.0f; + } + float pos[3] = { x, y, z }; + const float distance = sDistance(pos); + if (distance >= maxDistance) { + return 0.0f; + } + const float band = std::min(kFadeBand, maxDistance * kMaxFadeShare); + const float fadeStart = maxDistance - band; + if (distance <= fadeStart || band <= 0.0f) { + return 1.0f; + } + return (maxDistance - distance) / band; +} + +void SetSubframeBlend(float blend) { + sSubframeBlend = blend < 0.0f ? 0.0f : (blend > 1.0f ? 1.0f : blend); } } // namespace Nametag \ No newline at end of file diff --git a/src/port/Nametag/Nametag.h b/src/port/Nametag/Nametag.h index 478fde36a..32a767787 100644 --- a/src/port/Nametag/Nametag.h +++ b/src/port/Nametag/Nametag.h @@ -10,12 +10,17 @@ namespace Nametag { // World -> native-framebuffer-pixel projector. Writes (screen[0], screen[1]) // and returns true if the point is in front of the camera. using ProjectFn = bool (*)(float pos[3], float* screen); +using DistanceFn = float (*)(float pos[3]); void SetProjectFn(ProjectFn fn); +void SetDistanceFn(DistanceFn fn); void SetNativeFramebufferSize(const int* width, const int* height); void RegisterOverlay(); - -void Clear(); -void Push(float x, float y, float z, const char* label); +void BeginDraw(); +void Push(uint32_t id, float x, float y, float z, const char* label, float alpha = 1.0f); +float FadeForDistance(float x, float y, float z, float maxDistance); +void SetSubframeBlend(float blend); +void SubmitFrame(const void* key); +void BeginRenderPass(const void* key, bool interpolate); } // namespace Nametag \ No newline at end of file diff --git a/src/port/Nametag/NametagBindings.cpp b/src/port/Nametag/NametagBindings.cpp index 88220be18..c3fb481ce 100644 --- a/src/port/Nametag/NametagBindings.cpp +++ b/src/port/Nametag/NametagBindings.cpp @@ -1,16 +1,13 @@ -// BK-specific bindings for the portable Nametag overlay: projection, FB -// dimensions, tick-event listeners, and the asset-id -> label table. +// BK-specific bindings for the portable Nametag overlay: projection, distance, +// FB dimensions, and the per-draw tick listener. #include #include "Nametag.h" #include "port/Enhancements/Events/Hooks/Events.h" #include "port/ShipInit.hpp" -#include "port/UI/cvar_prefixes.h" -#include "port/ObjectExtension/ObjectExtension.h" extern "C" { -#include "enums.h" #include "core1/viewport.h" extern int gFramebufferWidth; extern int gFramebufferHeight; @@ -18,41 +15,9 @@ extern int gFramebufferHeight; namespace { -struct NametagTableEntry { - int32_t assetId; - const char* label; - float yOffset; -}; - -// Asset-id -> nametag lookup. Shared across the actor / prop / sprite-prop paths. -constexpr NametagTableEntry sNametagTable[] = { - { ASSET_350_MODEL_TERMITE, "Termite", 150.0f }, { ASSET_3C5_MODEL_GRUBLIN, "Grublin", 150.0f }, - { ASSET_353_MODEL_BIGBUTT, "BigButt", 150.0f }, { ASSET_3C0_MODEL_JINJO_BLUE, "Blue Jinjo", 150.0f }, - { ASSET_3C2_MODEL_JINJO_GREEN, "Green Jinjo", 150.0f }, { ASSET_3BC_MODEL_JINJO_ORANGE, "Orange Jinjo", 150.0f }, - { ASSET_3C1_MODEL_JINJO_PINK, "Pink Jinjo", 150.0f }, { ASSET_3BB_MODEL_JINJO_YELLOW, "Yellow Jinjo", 150.0f }, - { ASSET_6D6_SPRITE_MUSIC_NOTE, "Note", 80.0f }, { ASSET_41A_SPRITE_MUMBO_TOKEN, "Mumbo Token", 80.0f }, -}; - -const NametagTableEntry* LookupNametag(int32_t assetId) { - for (const auto& entry : sNametagTable) { - if (entry.assetId == assetId) { - return &entry; - } - } - return nullptr; -} - -static bool inRange(float x, float y, float z) { - float pos[3] = { x, y, z }; - return viewport_getDistance(pos) < CVarGetFloat(CVAR_DEVELOPER_TOOLS("NametagDist"), 3000.0f); -} - -static bool inRange(int16_t pos[3]) { - return inRange((float)pos[0], (float)pos[1], (float)pos[2]); -} - void InitNametagBindings() { Nametag::SetProjectFn(&viewport_func_8024E030); + Nametag::SetDistanceFn(&viewport_getDistance); Nametag::SetNativeFramebufferSize(&gFramebufferWidth, &gFramebufferHeight); Nametag::RegisterOverlay(); } @@ -60,6 +25,9 @@ void InitNametagBindings() { } // namespace static RegisterShipInitFunc initNametagBindings(InitNametagBindings, { "BOOT" }); + +// Tags are queued during the world draw, so the queue turns over on OnPlayerDraw rather than +// on the game tick. Ordering against the producers on this event does not matter. static RegisterShipInitFunc init([]() { - REGISTER_LISTENER(GameFrameUpdate, EVENT_PRIORITY_HIGH, [](IEvent* event) { Nametag::Clear(); }); -}); \ No newline at end of file + REGISTER_LISTENER(OnPlayerDraw, EVENT_PRIORITY_HIGH, [](IEvent* event) { Nametag::BeginDraw(); }); +}); diff --git a/src/port/Network/Anchor/Anchor.cpp b/src/port/Network/Anchor/Anchor.cpp index 545ac5910..0e9fd79cb 100644 --- a/src/port/Network/Anchor/Anchor.cpp +++ b/src/port/Network/Anchor/Anchor.cpp @@ -47,6 +47,7 @@ void Anchor::Disable() { } } clients.clear(); + PlayerColors_reset(); RefreshClientActors(); } @@ -301,13 +302,32 @@ void Anchor::SetDummyPlayerClientId(const Actor* actor, uint32_t clientId) { ObjectExtension::GetInstance().Set(actor, DummyPlayerClientId{ clientId }); } +// Roughly the top of Banjo's head. +static constexpr f32 kNametagHeight = 155.0f; + +// The menu exposes the nametag range as a multiplier of this, the same way Extended Draw +// Distance scales off its own base. +static constexpr f32 kNametagRangeUnit = 3000.0f; + void Anchor::DrawDummies(OnPlayerDraw* event) { if (!isConnected) return; + const bool showNametags = CVarGetInteger(CVAR_REMOTE_ANCHOR("Nametags"), 1) != 0; + const f32 nametagRange = kNametagRangeUnit * CVarGetFloat(CVAR_REMOTE_ANCHOR("NametagScale"), 1.0f); for (const auto& [id, dummy] : dummies) { FrameInterpolation_RecordOpenChild(clients[id].name.c_str(), 0); dummy->Draw(event->gfx, event->mtx, event->vtx); FrameInterpolation_RecordCloseChild(); + + // A nameless client would otherwise get an empty tag box floating over them. + const std::string label = showNametags ? GetNametagLabel(id) : std::string(); + if (dummy->dummy_isVisible() && !label.empty()) { + f32 position[3]; + dummy->dummy_getPosition(position); + position[1] += kNametagHeight; + const f32 fade = Nametag::FadeForDistance(position[0], position[1], position[2], nametagRange); + Nametag::Push(id, position[0], position[1], position[2], label.c_str(), fade); + } } } @@ -416,6 +436,19 @@ void Anchor::RegisterDummy(DummyPlayer* dummy, uint32_t clientID) { dummies.emplace(clientID, dummy); } +// Pushes a client's chosen model colours onto their stand-in so the next draw picks them up. +void Anchor::ApplyClientCosmetics(uint32_t clientId) { + if (!clients.contains(clientId)) { + return; + } + AnchorClient& client = clients[clientId]; + if (client.dummy == nullptr) { + return; + } + client.dummy->dummy_setOwner(clientId); + client.dummy->dummy_setColors(client.colors); +} + void Anchor::EvaluateDummyForClient(uint32_t clientId) { if (!clients.contains(clientId)) return; @@ -456,6 +489,21 @@ bool Anchor::ShouldShowNotifications() { return CVarGetInteger(CVAR_REMOTE_ANCHOR("Notifications"), 1) != 0; } +// Public global room shows player number instead of custom name +std::string Anchor::GetNametagLabel(uint32_t clientId) { + auto it = clients.find(clientId); + if (it == clients.end()) { + return ""; + } + if (!IsGlobalRoom()) { + return it->second.name; + } + if (it->second.joinOrder == 0) { + return "Player"; + } + return "Player " + std::to_string(it->second.joinOrder); +} + std::string Anchor::GetClientName(uint32_t clientId) { auto it = clients.find(clientId); if (it != clients.end() && !it->second.name.empty()) { diff --git a/src/port/Network/Anchor/Anchor.h b/src/port/Network/Anchor/Anchor.h index 2e42709aa..7f4fa1359 100644 --- a/src/port/Network/Anchor/Anchor.h +++ b/src/port/Network/Anchor/Anchor.h @@ -20,11 +20,12 @@ extern "C" { typedef struct { uint32_t clientId; std::string name; - // Color_RGB8 color; + BKPlayerColorSet colors; std::string clientVersion; std::string teamId; bool online; bool self; + uint32_t joinOrder; uint32_t seed; bool isSaveLoaded; bool isGameComplete; @@ -79,6 +80,7 @@ class Anchor : public Network { void RemoveDummy(uint32_t clientId); void EvaluateDummyForClient(uint32_t clientId); + void ApplyClientCosmetics(uint32_t clientId); void HandlePacket_AllClientState(nlohmann::json& payload); void HandlePacket_AuthorityState(nlohmann::json& payload); @@ -218,6 +220,7 @@ class Anchor : public Network { bool ShouldShowNotifications(); std::string GetClientName(uint32_t clientId); + std::string GetNametagLabel(uint32_t clientId); void SendPacket_AuthorityState(u8 activity, bool claimed); void SendPacket_ClearTeamState(std::string teamId); diff --git a/src/port/Network/Anchor/DummyPlayer.cpp b/src/port/Network/Anchor/DummyPlayer.cpp index f04798ddb..88fe6e033 100644 --- a/src/port/Network/Anchor/DummyPlayer.cpp +++ b/src/port/Network/Anchor/DummyPlayer.cpp @@ -199,6 +199,8 @@ void DummyPlayer::Draw(Gfx** gfx, Mtx** mtx, Vtx** vtx) { // modelRender_preDraw((GenFunction_1)_dummy_preDraw, 0); modelRender_setRefPoints(dummy_D_80363780); modelRender_setDepthMode(MODEL_RENDER_DEPTH_FULL); + // Each dummy draws the shared model bin through its own recolored palettes. + PlayerColors_applyForDraw(dummyOwnerId, dummy_getModelId(), dummyBin, &dummyColors); if (dummy_D_8037C150.unk0) { dummy_D_8037C150.unk0 = 0; modelRender_draw(gfx, mtx, dummy_D_8037C150.unk4, rotation, dummyScale, sp38, dummyBin); diff --git a/src/port/Network/Anchor/DummyPlayer.h b/src/port/Network/Anchor/DummyPlayer.h index 825e36091..c472559f6 100644 --- a/src/port/Network/Anchor/DummyPlayer.h +++ b/src/port/Network/Anchor/DummyPlayer.h @@ -2,6 +2,7 @@ #include "functions.h" #include "core2/ba/model.h" #include "variables.h" +#include "port/Enhancements/Cosmetics/PlayerColors.h" class DummyPlayer { public: @@ -81,6 +82,13 @@ class DummyPlayer { return dummyMarker; } void dummy_despawnActor(void); + // Cosmetics: which Anchor client this stand-in belongs to, and the model colors they chose. + void dummy_setOwner(uint32_t clientId) { + dummyOwnerId = clientId; + } + void dummy_setColors(const BKPlayerColorSet& colors) { + dummyColors = colors; + } private: uint32_t PlayerID; @@ -138,4 +146,6 @@ class DummyPlayer { f32 dummy_banjoRightEye; Transformation dummy_transformation; s32 dummyBottlesBonus = 0; + uint32_t dummyOwnerId = 0; + BKPlayerColorSet dummyColors = {}; }; \ No newline at end of file diff --git a/src/port/Network/Anchor/JsonConversions.hpp b/src/port/Network/Anchor/JsonConversions.hpp index 243b8b25e..ada991d3b 100644 --- a/src/port/Network/Anchor/JsonConversions.hpp +++ b/src/port/Network/Anchor/JsonConversions.hpp @@ -22,9 +22,42 @@ inline void to_json(json& j, const Color_RGB8& color) { j = json{ { "r", color.r }, { "g", color.g }, { "b", color.b } }; } +// Model colors travel as a fixed-length array, one entry per BKColorChannel. Clients that +// predate the feature simply omit the key and everyone renders them with vanilla colors. +inline void from_json(const json& j, BKPlayerColorSet& colors) { + colors = BKPlayerColorSet{}; + if (!j.is_array()) { + return; + } + for (size_t i = 0; i < j.size() && i < (size_t)BK_COLOR_CHANNEL_COUNT; i++) { + const json& entry = j[i]; + if (!entry.is_object()) { + continue; + } + colors.channel[i].enabled = entry.value("on", false) ? 1 : 0; + colors.channel[i].r = entry.value("r", (u8)0); + colors.channel[i].g = entry.value("g", (u8)0); + colors.channel[i].b = entry.value("b", (u8)0); + } +} + +inline void to_json(json& j, const BKPlayerColorSet& colors) { + j = json::array(); + for (int i = 0; i < BK_COLOR_CHANNEL_COUNT; i++) { + j.push_back(json{ { "on", colors.channel[i].enabled != 0 }, + { "r", colors.channel[i].r }, + { "g", colors.channel[i].g }, + { "b", colors.channel[i].b } }); + } +} + inline void from_json(const json& j, AnchorClient& client) { client.clientId = j.value("clientId", (u32)0); client.name = j.value("name", "???"); + client.colors = BKPlayerColorSet{}; + if (j.contains("colors")) { + from_json(j.at("colors"), client.colors); + } client.clientVersion = j.value("clientVersion", "???"); client.teamId = j.value("teamId", "default"); client.online = j.value("online", false); diff --git a/src/port/Network/Anchor/Menu.cpp b/src/port/Network/Anchor/Menu.cpp index e5d543fb2..f9080c128 100644 --- a/src/port/Network/Anchor/Menu.cpp +++ b/src/port/Network/Anchor/Menu.cpp @@ -1,4 +1,5 @@ #include "Anchor.h" +#include #include #include "port/UI/LighthouseGui.hpp" #include "port/UI/LighthouseMenu.h" @@ -16,6 +17,68 @@ static const char* pvpModes[3] = { "Off", "On", "On + Friendly Fire" }; static std::vector teleportModes = { "None", "Team Only", "All" }; static std::vector showLocationsModes = { "None", "Team Only", "All" }; +static const char* playerColorLabels[BK_COLOR_CHANNEL_COUNT] = { + "Banjo's fur", "Banjo's shorts", "Kazooie's feathers", "Kazooie's beak & legs", "Banjo's backpack", "Banjo's skin", +}; + +// Channel order is the wire order; this is the order the rows are listed in. +static const int playerColorOrder[BK_COLOR_CHANNEL_COUNT] = { + BK_COLOR_BANJO_FUR, BK_COLOR_BANJO_SKIN, BK_COLOR_BANJO_SHORTS, + BK_COLOR_BANJO_BACKPACK, BK_COLOR_KAZOOIE_FEATHERS, BK_COLOR_KAZOOIE_BEAK, +}; + +// Per-part recoloring of the player model. Any mix of channels can be enabled; each one +// re-tints only the palette entries and vertex colors belonging to that part, so shading +// is preserved. The selection is part of client state, so everyone in the room sees it. +static void AnchorPlayerColorSection(Anchor* anchor) { + UIWidgets::PushStyleHeader(THEME_COLOR); + if (!ImGui::CollapsingHeader("Player Colors")) { + UIWidgets::PopStyleHeader(); + return; + } + + ImGui::TextWrapped("Tick a part and pick a color to recolor Banjo & Kazooie. Other players in your " + "room see your choices. Transformations keep their own colors."); + ImGui::Spacing(); + + for (int row = 0; row < BK_COLOR_CHANNEL_COUNT; row++) { + const int i = playerColorOrder[row]; + const char* baseCVar = PlayerColors_getChannelCVar(i); + if (baseCVar == nullptr) { + continue; + } + u8 r, g, b; + PlayerColors_getVanilla(i, &r, &g, &b); + const Color_RGBA8 vanilla = { r, g, b, 255 }; + const std::string enabledCVar = std::string(baseCVar) + ".Enabled"; + const std::string pickerLabel = std::string("##") + baseCVar; + + ImGui::PushID(i); + UIWidgets::CVarColorPicker(pickerLabel.c_str(), baseCVar, vanilla, false, + UIWidgets::ColorPickerResetButton | UIWidgets::ColorPickerRandomButton, THEME_COLOR); + ImGui::SameLine(); + UIWidgets::CVarCheckbox(playerColorLabels[i], enabledCVar.c_str(), + UIWidgets::CheckboxOptions().DefaultValue(false).Color(THEME_COLOR)); + ImGui::PopID(); + } + + // Compare the resulting set rather than the widgets' return values: Reset and Random + // write the CVar without reporting a change. + static BKPlayerColorSet lastSent = {}; + static bool haveLastSent = false; + BKPlayerColorSet current; + PlayerColors_getLocal(¤t); + if (!haveLastSent || std::memcmp(¤t, &lastSent, sizeof(current)) != 0) { + lastSent = current; + haveLastSent = true; + if (anchor->isEnabled) { + anchor->SendPacket_UpdateClientState(); + } + } + + UIWidgets::PopStyleHeader(); +} + void AnchorMainMenu(WidgetInfo& info) { auto anchor = Anchor::GetInstance(); @@ -48,10 +111,7 @@ void AnchorMainMenu(WidgetInfo& info) { } UIWidgets::PopStyleInput(); - ImGui::Text("Name & Color"); - static Color_RGBA8 defaultColor = { 100, 255, 100, 255 }; - UIWidgets::CVarColorPicker("##Color", CVAR_REMOTE_ANCHOR("Color"), defaultColor); - ImGui::SameLine(); + ImGui::Text("Name"); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); if (UIWidgets::InputString("##Name", &anchorName, UIWidgets::InputOptions().Color(THEME_COLOR))) { CVarSetString(CVAR_REMOTE_ANCHOR("Name"), anchorName.c_str()); @@ -120,6 +180,31 @@ void AnchorMainMenu(WidgetInfo& info) { ImGui::EndDisabled(); ImGui::Spacing(); + AnchorPlayerColorSection(anchor); + + ImGui::Spacing(); + + UIWidgets::CVarCheckbox("Show Player Nametags", CVAR_REMOTE_ANCHOR("Nametags"), + UIWidgets::CheckboxOptions() + .DefaultValue(true) + .Color(THEME_COLOR) + .Tooltip("Draw each other player's name above their character.")); + + if (CVarGetInteger(CVAR_REMOTE_ANCHOR("Nametags"), 1)) { + UIWidgets::CVarSliderFloat("Nametag Distance", CVAR_REMOTE_ANCHOR("NametagScale"), + UIWidgets::FloatSliderOptions() + .Min(0.5f) + .Max(6.0f) + .Step(0.5f) + .DefaultValue(1.0f) + .ShowButtons(true) + .Format("%.1fx") + .Color(THEME_COLOR) + .Tooltip("Multiplies how far away another player's nametag stays visible.")); + } + + ImGui::Spacing(); + UIWidgets::CVarCheckbox( "Show Teammate Notifications", CVAR_REMOTE_ANCHOR("Notifications"), UIWidgets::CheckboxOptions() diff --git a/src/port/Network/Anchor/Packets/AllClientState.cpp b/src/port/Network/Anchor/Packets/AllClientState.cpp index e793947e3..59d6ee01a 100644 --- a/src/port/Network/Anchor/Packets/AllClientState.cpp +++ b/src/port/Network/Anchor/Packets/AllClientState.cpp @@ -21,8 +21,10 @@ void Anchor::HandlePacket_AllClientState(nlohmann::json& payload) { bool isGlobalRoom = IsGlobalRoom(); std::vector clientsToRemove; + uint32_t joinOrder = 0; // add new clients for (auto& client : newClients) { + client.joinOrder = client.online ? ++joinOrder : 0; if (!client.online && clients.contains(client.clientId)) { clientsToRemove.push_back(client.clientId); } @@ -62,6 +64,9 @@ void Anchor::HandlePacket_AllClientState(nlohmann::json& payload) { clients[client.clientId].isGameComplete = client.isGameComplete; clients[client.clientId].map = client.map; clients[client.clientId].exit = client.exit; + clients[client.clientId].joinOrder = client.joinOrder; + clients[client.clientId].colors = client.colors; + ApplyClientCosmetics(client.clientId); Authority_OnClientStateChanged(client.clientId, client.online, client.map); } @@ -78,6 +83,7 @@ void Anchor::HandlePacket_AllClientState(nlohmann::json& payload) { if (dummies.contains(clientId)) { dummies.erase(clientId); } + PlayerColors_forgetOwner(clientId); if (clients.at(clientId).dummy != nullptr) { clients.at(clientId).dummy->dummy_free(); free(clients.at(clientId).dummy); diff --git a/src/port/Network/Anchor/Packets/UpdateClientState.cpp b/src/port/Network/Anchor/Packets/UpdateClientState.cpp index 43c658b24..12ef0a91b 100644 --- a/src/port/Network/Anchor/Packets/UpdateClientState.cpp +++ b/src/port/Network/Anchor/Packets/UpdateClientState.cpp @@ -26,6 +26,10 @@ nlohmann::json Anchor::PrepClientState() { payload["teamId"] = CVarGetString(CVAR_REMOTE_ANCHOR("TeamId"), "default"); payload["online"] = true; + BKPlayerColorSet colors; + PlayerColors_getLocal(&colors); + to_json(payload["colors"], colors); + if (IsSaveLoaded()) { payload["seed"] = (uint32_t)(IS_RANDO ? RANDO_SEED : 0); payload["isSaveLoaded"] = true; @@ -66,6 +70,8 @@ void Anchor::HandlePacket_UpdateClientState(nlohmann::json& payload) { clients[clientId].isGameComplete = client.isGameComplete; clients[clientId].map = client.map; clients[clientId].exit = client.exit; + clients[clientId].colors = client.colors; + ApplyClientCosmetics(clientId); EvaluateDummyForClient(clientId); Authority_OnClientStateChanged(clientId, client.online, client.map); SweepUnoccupiedLevelState((GameMap)gsworld_getMap()); diff --git a/src/port/UI/LighthouseMenuDevTools.cpp b/src/port/UI/LighthouseMenuDevTools.cpp index e36c7ae71..c72e60bf2 100644 --- a/src/port/UI/LighthouseMenuDevTools.cpp +++ b/src/port/UI/LighthouseMenuDevTools.cpp @@ -72,9 +72,6 @@ void LighthouseMenu::AddMenuDevTools() { .Options(CheckboxOptions().Tooltip( "Enables the Gfx trace mode, which will output information about the Gfx commands being run.")); #endif - AddWidget(path, "Nametag Distance", WIDGET_CVAR_SLIDER_FLOAT) - .CVar(CVAR_DEVELOPER_TOOLS("NametagDist")) - .Options(FloatSliderOptions().DefaultValue(3000.0f).Min(1000.0f).Max(10000.0f).Step(10.0f)); AddWidget(path, "Dump Thread State", WIDGET_BUTTON) .Callback([](WidgetInfo&) { ThreadWatchdog_DumpNow(); }) .Options( diff --git a/src/port/UI/UIWidgets.cpp b/src/port/UI/UIWidgets.cpp index 518e051f8..e41ab88db 100644 --- a/src/port/UI/UIWidgets.cpp +++ b/src/port/UI/UIWidgets.cpp @@ -903,7 +903,8 @@ bool CVarColorPicker(const char* label, const char* cvarName, Color_RGBA8 defaul ImGui::AlignTextToFramePadding(); if (showReset) { ImGui::SameLine(); - std::string uniqueTag = "Reset##" + std::string(label); + // Tag off the CVar, not the label. + std::string uniqueTag = "Reset##" + std::string(cvarName) + ".Reset"; if (UIWidgets::Button(uniqueTag.c_str(), UIWidgets::ButtonOptions({ { .tooltip = "Resets this color to its default value" } }) .Color(themeColor) @@ -920,7 +921,7 @@ bool CVarColorPicker(const char* label, const char* cvarName, Color_RGBA8 defaul } if (showRandom) { ImGui::SameLine(); - std::string uniqueTag = "Random##" + std::string(label); + std::string uniqueTag = "Random##" + std::string(cvarName) + ".Random"; if (UIWidgets::Button(uniqueTag.c_str(), UIWidgets::ButtonOptions({ { .tooltip = "Generates a random color value to use" } }) .Color(themeColor) From bc12aed171dbb5566252488c5b242bc84f5789fe Mon Sep 17 00:00:00 2001 From: aMannus Date: Sun, 2 Aug 2026 22:40:21 +0200 Subject: [PATCH 079/131] Custom actor mostly done, item queue half done --- include/functions.h | 3 + src/core2/actor_cubepropsystem.c | 5 +- src/core2/gameSelect.c | 1 + .../Backports/TooieJiggyDance.cpp | 7 +- .../Events/Hooks/List/GameEvent.h | 3 + .../Enhancements/Events/PortEnhancements.cpp | 1 + .../CustomCollectible/CustomCollectible.cpp | 135 +- .../CustomCollectible/CustomCollectible.h | 26 +- .../CustomCollectibleDrawCustom.h | 2 - src/port/Rando/ItemQueue.cpp | 189 ++ src/port/Rando/ItemQueue.h | 10 + src/port/Rando/MiscBehavior/OnFileLoad.cpp | 3 + src/port/Rando/StaticData/Checks.cpp | 1584 ++++++++--------- src/port/Rando/StaticData/Items.cpp | 40 +- src/port/Rando/Types.h | 36 +- src/port/UI/DeveloperTools/GameplayTools.cpp | 12 +- 16 files changed, 1150 insertions(+), 907 deletions(-) create mode 100644 src/port/Rando/ItemQueue.cpp create mode 100644 src/port/Rando/ItemQueue.h diff --git a/include/functions.h b/include/functions.h index b6b8d686b..f301053cf 100644 --- a/include/functions.h +++ b/include/functions.h @@ -3492,4 +3492,7 @@ void _guMtxIdentF_80245D44(float mf[4][4]); //static should NOT be here void func_80241304(Mtx *m, float x, float y, float z); BKModelBin * marker_loadModelBin(ActorMarker *marker); +// --- port/TooieJiggyDance.cpp +void spawnOrbit(); + #endif // FUNCTIONS_H diff --git a/src/core2/actor_cubepropsystem.c b/src/core2/actor_cubepropsystem.c index 466e31455..63f058d43 100644 --- a/src/core2/actor_cubepropsystem.c +++ b/src/core2/actor_cubepropsystem.c @@ -1785,7 +1785,7 @@ BKSpriteDisplayData *func_80330E54(ActorMarker *marker, BKSprite **sprite_ptr) { return 0; } model_cache_ptr = &modelCache[marker_getActor(marker)->modelCacheIndex]; - if (model_cache_ptr->unk4 == 0) { + if (model_cache_ptr->unk4 == 00 || marker->id == MARKER_300_CUSTOM_COLLECTIBLE) { model_cache_ptr->unk4 = codeB3A80_getSprite(marker->modelId, &model_cache_ptr->unk8); } model_cache_ptr->unk10 = globalTimer_getTime(); @@ -2203,6 +2203,9 @@ f32 func_80331E64(ActorMarker *marker) { if (marker->modelId == 0) { return 0.0f; } + if (marker->id == MARKER_300_CUSTOM_COLLECTIBLE) { + return 150.0f; + } sp24 = func_80331D20(func_80330F50(marker)); marker->unk38[1] = (s16) (sp24 / 2); if (marker->unk3E_0) { diff --git a/src/core2/gameSelect.c b/src/core2/gameSelect.c index 22c1322a7..fe537df96 100644 --- a/src/core2/gameSelect.c +++ b/src/core2/gameSelect.c @@ -441,6 +441,7 @@ void gameSelect_update(Actor *this){ chBottlesBonus_resetCompleted(); gameFile_load(gSelectedGameNum); port_syncBottlesBonusIndex(); + CALL_EVENT(OnGameStart); if(!gameFile_isNotEmpty(sp84)){ s32 skipIntro = 0; CALL_EVENT(OnNewGame, &skipIntro); diff --git a/src/port/Enhancements/Backports/TooieJiggyDance.cpp b/src/port/Enhancements/Backports/TooieJiggyDance.cpp index 8846ed8c5..3a8d1ee0c 100644 --- a/src/port/Enhancements/Backports/TooieJiggyDance.cpp +++ b/src/port/Enhancements/Backports/TooieJiggyDance.cpp @@ -8,6 +8,7 @@ #include "port/UI/cvar_prefixes.h" #include "port/Enhancements/Events/Hooks/Events.h" #include "port/ShipInit.hpp" +#include "port/Rando/Rando.h" extern "C" { #include "enums.h" @@ -114,7 +115,7 @@ void emitSparkle(f32 x, f32 y, f32 z) { } } -void spawnOrbit() { +extern "C" void spawnOrbit() { clearOrbit(); f32 banjo[3]; @@ -268,7 +269,7 @@ void RegisterJiggyCollect_Init() { clearOrbit(); const bool skip = CVarGetInteger(CVAR_SKIP_JIGGY_DANCE, 0); const bool tooie = CVarGetInteger(CVAR_TOOIE_JIGGY_DANCE, 0); - const bool playOrbit = tooie && !skip; + const bool playOrbit = (tooie && !skip) || IS_RANDO; COND_VB_SHOULD(VB_PLAY_JIGGY_DANCE, EVENT_PRIORITY_NORMAL, skip || tooie, { *should = false; }); @@ -278,4 +279,4 @@ void RegisterJiggyCollect_Init() { } static RegisterShipInitFunc initJiggyCollect(RegisterJiggyCollect_Init, - { CVAR_TOOIE_JIGGY_DANCE, CVAR_SKIP_JIGGY_DANCE }); + { CVAR_TOOIE_JIGGY_DANCE, CVAR_SKIP_JIGGY_DANCE, "IS_RANDO" }); diff --git a/src/port/Enhancements/Events/Hooks/List/GameEvent.h b/src/port/Enhancements/Events/Hooks/List/GameEvent.h index e53254847..ae6d13e6e 100644 --- a/src/port/Enhancements/Events/Hooks/List/GameEvent.h +++ b/src/port/Enhancements/Events/Hooks/List/GameEvent.h @@ -18,6 +18,9 @@ typedef enum WarpId { DEFINE_EVENT(OnWarpResolveDest, int32_t warpId; int32_t defaultDest; int32_t bkcfOverride; int32_t * dest;) DEFINE_EVENT(OnNewGame, int32_t* skipIntro;) +// The file-select commit, for both new game and continue. Unlike OnGameLoad this +// does not fire for the zoombox preview. +DEFINE_EVENT(OnGameStart) DEFINE_EVENT(EggHeadSpawn, float* pitch; float* spawnHeight; float* minVerticalVelocity; float* yawBias; int32_t * flattenTrajectory;) diff --git a/src/port/Enhancements/Events/PortEnhancements.cpp b/src/port/Enhancements/Events/PortEnhancements.cpp index f369bb3be..ffdc30735 100644 --- a/src/port/Enhancements/Events/PortEnhancements.cpp +++ b/src/port/Enhancements/Events/PortEnhancements.cpp @@ -81,6 +81,7 @@ void PortEnhancements_Register() { REGISTER_EVENT(OnPropInit); REGISTER_EVENT(OnWarpResolveDest); REGISTER_EVENT(OnNewGame); + REGISTER_EVENT(OnGameStart); REGISTER_EVENT(EggHeadSpawn); REGISTER_EVENT(OnActorDestroy); REGISTER_EVENT(OnCheckSpiralMountainAbilities); diff --git a/src/port/Rando/CustomCollectible/CustomCollectible.cpp b/src/port/Rando/CustomCollectible/CustomCollectible.cpp index 2ff1bbe3c..2f96a0bc8 100644 --- a/src/port/Rando/CustomCollectible/CustomCollectible.cpp +++ b/src/port/Rando/CustomCollectible/CustomCollectible.cpp @@ -1,26 +1,36 @@ #include "CustomCollectible.h" #include "CustomCollectibleDrawCustom.h" #include -#include "port/Rando/Rando.h" -#include -extern "C" { -#include "core1/sns.h" -Actor* actor_new(s32 position[3], s32 yaw, ActorInfo* actorInfo, u32 flags); -Actor* actor_draw(ActorMarker* marker, Gfx** gfx, Mtx** mtx, Vtx** vtx); -Actor* fxTouchSparkle_draw(ActorMarker* marker, Gfx** gfx, Mtx** mtx, Vtx** vtx); -Actor* marker_getActor(ActorMarker* thisx); -void marker_despawn(ActorMarker* marker); +#include +extern "C" { +#include "functions.h" +#include "actor.h" +void __chJinjo_802CDC9C(Actor* thisx, s16 arg1); Actor* func_802D94B4(ActorMarker* marker, Gfx** gfx, Mtx** mtx, Vtx** vtx); -void func_8028E964(f32 pos[3]); -int func_80257F18(f32 src[3], f32 target[3], f32* yaw); -bool func_8028AED4(f32 arg0[3], f32 arg1); -void coMusicPlayer_playMusic(enum comusic_e track_id, s32 volume); -void __chJinjo_802CDC9C(Actor* actor, s16 arg1); -void fxSparkle_honeycomb(s16 position[3]); +Actor* func_802D41C4(ActorMarker* marker, Gfx** gfx, Mtx** mtx, Vtx** vtx); } +std::unordered_map customCollectibleDrawInfo = { + { ACTOR_52_BLUE_EGG, { ASSET_36D_SPRITE_BLUE_EGG, CCT_VANILLA_SPRITE } }, + { ACTOR_47_EMPTY_HONEYCOMB, { ASSET_361_MODEL_EMPTY_HONEYCOMB, CCT_VANILLA_MODEL } }, + { ACTOR_49_EXTRA_LIFE, { ASSET_36E_MODEL_EXTRA_LIFE, CCT_VANILLA_SPRITE } }, + { ACTOR_50_HONEYCOMB, { ASSET_363_MODEL_HONEYCOMB, CCT_VANILLA_MODEL } }, + { ACTOR_46_JIGGY, { ASSET_35F_MODEL_JIGGY, CCT_VANILLA_MODEL } }, + { ACTOR_60_JINJO_BLUE, { ASSET_3C0_MODEL_JINJO_BLUE, CCT_JINJO } }, + { ACTOR_62_JINJO_GREEN, { ASSET_3C2_MODEL_JINJO_GREEN, CCT_JINJO } }, + { ACTOR_5F_JINJO_ORANGE, { ASSET_3BC_MODEL_JINJO_ORANGE, CCT_JINJO } }, + { ACTOR_61_JINJO_PINK, { ASSET_3C1_MODEL_JINJO_PINK, CCT_JINJO } }, + { ACTOR_5E_JINJO_YELLOW, { ASSET_3BB_MODEL_JINJO_YELLOW, CCT_JINJO } }, + { ACTOR_12C_MOLEHILL, { ASSET_387_MODEL_BOTTLES, CCT_MOLEHILL } }, + { ACTOR_2D_MUMBO_TOKEN, { ASSET_41A_SPRITE_MUMBO_TOKEN, CCT_VANILLA_SPRITE } }, + { ACTOR_51_MUSIC_NOTE, { ASSET_6D6_SPRITE_MUSIC_NOTE, CCT_VANILLA_SPRITE } }, + { ACTOR_25E_SNS_EGG, { ASSET_50D_MODEL_SNS_EGG, CCT_VANILLA_SNS_EGG } }, + { ACTOR_25D_ICE_KEY, { ASSET_50C_MODEL_ICE_KEY, CCT_VANILLA_MODEL } }, + { ACTOR_3CD_CUSTOM_COLLECTIBLE, { ASSET_0_NONE, CCT_CUSTOM_MODEL } }, +}; + ActorAnimationInfo moleAnimations[] = { { 0, 0.0f }, { ASSET_13A_ANIM_BOTTLES_ENTER, 2000000000.0f }, @@ -30,10 +40,22 @@ ActorAnimationInfo moleAnimations[] = { { ASSET_13A_ANIM_BOTTLES_ENTER, 2000000000.0f }, }; +ActorAnimationInfo chJinjoAnimations[] = { { 0, 0.0f }, + { ASSET_2D_ANIM_JINJO_IDLE, 1000000.0f }, + { ASSET_2D_ANIM_JINJO_IDLE, 1.5f }, + { ASSET_2F_ANIM_JINJO_HELP, 1.5f }, + { ASSET_31_ANIM_JINJO_JUMP, 0.75f }, + { ASSET_2D_ANIM_JINJO_IDLE, 1000000.0f }, + { ASSET_31_ANIM_JINJO_JUMP, 0.4f }, + { ASSET_130_ANIM_JINJO_FLY_START, 1.75f }, + { ASSET_131_ANIM_JINJO_FLY_END, 2.13333f }, + { ASSET_31_ANIM_JINJO_JUMP, 0.75f }, +}; + ActorInfo customActorInfo = { MARKER_300_CUSTOM_COLLECTIBLE, ACTOR_3CD_CUSTOM_COLLECTIBLE, - ASSET_387_MODEL_BOTTLES, - 3, + ASSET_0_NONE, + 1, NULL, CustomCollectible_Update, NULL, @@ -49,10 +71,15 @@ void CustomCollectible_Update(Actor* actor) { if (!actor->initialized) { actor->initialized = true; actor->marker->collidable = true; + + if (customLocal->itemType == RITYPE_MUSIC_NOTE) { + actor->scale = 0.4f; + } else if (customLocal->itemType == RITYPE_SNS_EGG) { + actor->scale = 0.4f; + } } - RandoItemType itemType = Rando::StaticData::Items[(RandoItemId)customLocal->randoItemId].randoItemType; - if (itemType == RITYPE_MOLEHILL) { + if (customLocal->itemType == RITYPE_MOLEHILL || customLocal->itemType == RITYPE_JINJO) { CustomCollectible::FacePlayer(actor); } else { actor->yaw += 5.0f; @@ -73,21 +100,28 @@ void CustomCollectible::FacePlayer(Actor* actor) { __chJinjo_802CDC9C(actor, sp66); } -Actor* CustomCollectible::AttachCustomVariables(int32_t randoItemId, Actor* customCollectible) { +Actor* CustomCollectible::AttachCustomVariables(RandoCheckId randoCheckId, Actor* customCollectible) { ActorLocal_CustomCollectible* customLocal = (ActorLocal_CustomCollectible*)&customCollectible->local; + + RandoItemId randoItemId = RANDO_SAVE_CHECKS[randoCheckId].randoItemId; + + customLocal->randoCheckId = randoCheckId; customLocal->randoItemId = randoItemId; + customLocal->actorId = (actor_e)Rando::StaticData::Items[randoItemId].actorId; + customLocal->itemType = Rando::StaticData::Items[randoItemId].randoItemType; return customCollectible; } -Actor* CustomCollectible::Spawn(int32_t position[3], RandoItemId randoItemId) { +Actor* CustomCollectible::Spawn(int32_t position[3], RandoCheckId randoCheckId) { int32_t spawnPosition[3] = { position[0], position[1], position[2] }; int32_t flags = ACTOR_FLAG_UNKNOWN_6 | ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_21; - // Custom models exported for OoT are centered instead of offset to the marker, so they appear underground otherwise - actor_e actorId = (actor_e)Rando::StaticData::Items[randoItemId].actorId; + RandoItemId randoItemId = RANDO_SAVE_CHECKS[randoCheckId].randoItemId; RandoItemType itemType = Rando::StaticData::Items[randoItemId].randoItemType; + + // Custom models exported for OoT are centered instead of offset to the marker, so they appear underground otherwise if (itemType == RITYPE_AP_ITEM) { spawnPosition[1] += 50; } @@ -99,36 +133,75 @@ Actor* CustomCollectible::Spawn(int32_t position[3], RandoItemId randoItemId) { // Spawn actor Actor* customCollectible = actor_new(spawnPosition, 0, &collectibleInfo, flags); + if (itemType == RITYPE_SNS_EGG) { + customCollectible->actorTypeSpecificField = CustomCollectible::GetSNSEggColor(randoItemId); + } customCollectible->marker->collisionFunc = CustomCollectible::OnCollect; - customCollectible = CustomCollectible::AttachCustomVariables(randoItemId, customCollectible); + customCollectible = CustomCollectible::AttachCustomVariables(randoCheckId, customCollectible); return customCollectible; } +uint32_t CustomCollectible::GetSNSEggColor(RandoItemId randoItemId) { + switch (randoItemId) { + case RI_STOP_N_SWOP_EGG_BLUE: + return (uint32_t)SNS_ITEM_EGG_BLUE; + case RI_STOP_N_SWOP_EGG_CYAN: + return (uint32_t)SNS_ITEM_EGG_CYAN; + case RI_STOP_N_SWOP_EGG_GREEN: + return (uint32_t)SNS_ITEM_EGG_GREEN; + case RI_STOP_N_SWOP_EGG_PINK: + return (uint32_t)SNS_ITEM_EGG_PINK; + case RI_STOP_N_SWOP_EGG_RED: + return (uint32_t)SNS_ITEM_EGG_RED; + case RI_STOP_N_SWOP_EGG_YELLOW: + return (uint32_t)SNS_ITEM_EGG_YELLOW; + default: + return (uint32_t)SNS_ITEM_EGG_CYAN; + } +} + ActorInfo CustomCollectible::GetActorAndDrawInfo(RandoItemId randoItemId) { ActorInfo collectibleInfo = customActorInfo; actor_e actorId = (actor_e)Rando::StaticData::Items[randoItemId].actorId; - RandoItemType itemType = Rando::StaticData::Items[randoItemId].randoItemType; + auto drawInfo = customCollectibleDrawInfo[actorId]; + + collectibleInfo.modelId = drawInfo.drawModel; - switch (itemType) { - case RITYPE_MOLEHILL: + switch (drawInfo.drawType) { + case CCT_VANILLA_MODEL: + collectibleInfo.draw_func = actor_draw; + break; + case CCT_VANILLA_SPRITE: + collectibleInfo.draw_func = fxTouchSparkle_draw; + break; + case CCT_JINJO: + collectibleInfo.draw_func = actor_draw; + collectibleInfo.animations = chJinjoAnimations; + collectibleInfo.startAnimation = 3; + break; + case CCT_MOLEHILL: collectibleInfo.draw_func = func_802D94B4; - collectibleInfo.modelId = ASSET_387_MODEL_BOTTLES; collectibleInfo.animations = moleAnimations; + collectibleInfo.startAnimation = 3; break; - case RITYPE_AP_ITEM: + case CCT_VANILLA_SNS_EGG: + collectibleInfo.draw_func = func_802D41C4; + break; + case CCT_CUSTOM_MODEL: collectibleInfo.draw_func = CustomCollectible_DrawCustomModel; break; default: break; } - return collectibleInfo; } void CustomCollectible::OnCollect(struct actorMarker_s* self, struct actorMarker_s* other) { + Actor* actor = marker_getActor(self); + ActorLocal_CustomCollectible* customLocal = (ActorLocal_CustomCollectible*)&actor->local; fxSparkle_honeycomb(&self->propPtr->x); - coMusicPlayer_playMusic(COMUSIC_9_NOTE_COLLECTED, 16000); + ItemQueue::AddCheck(customLocal->randoCheckId); marker_despawn(self); } diff --git a/src/port/Rando/CustomCollectible/CustomCollectible.h b/src/port/Rando/CustomCollectible/CustomCollectible.h index 2c5b12ada..889114a5a 100644 --- a/src/port/Rando/CustomCollectible/CustomCollectible.h +++ b/src/port/Rando/CustomCollectible/CustomCollectible.h @@ -1,20 +1,38 @@ #pragma once +#include "port/Rando/ItemQueue.h" #include "prop.h" -#include "port/Rando/Types.h" typedef struct { - uint16_t randoItemId; + RandoCheckId randoCheckId; + RandoItemId randoItemId; + actor_e actorId; + RandoItemType itemType; } ActorLocal_CustomCollectible; +enum CustomCollectibleDrawTypes { + CCT_VANILLA_MODEL, + CCT_VANILLA_SPRITE, + CCT_JINJO, + CCT_MOLEHILL, + CCT_VANILLA_SNS_EGG, + CCT_CUSTOM_MODEL, +}; + +typedef struct { + asset_e drawModel; + CustomCollectibleDrawTypes drawType; +} CustomCollectibleDrawInfo; + void CustomCollectible_Update(Actor* actor); class CustomCollectible { private: - static Actor* AttachCustomVariables(int32_t randoItemId, Actor* customCollectible); + static Actor* AttachCustomVariables(RandoCheckId randoItemId, Actor* customCollectible); static void OnCollect(struct actorMarker_s* self, struct actorMarker_s* other); static ActorInfo GetActorAndDrawInfo(RandoItemId randoItemId); + static uint32_t GetSNSEggColor(RandoItemId randoItemId); public: - static Actor* Spawn(int32_t position[3], RandoItemId randoItemId); + static Actor* Spawn(int32_t position[3], RandoCheckId randoCheckId); static void FacePlayer(Actor* actor); }; diff --git a/src/port/Rando/CustomCollectible/CustomCollectibleDrawCustom.h b/src/port/Rando/CustomCollectible/CustomCollectibleDrawCustom.h index 5a31b3d24..ce87b41bf 100644 --- a/src/port/Rando/CustomCollectible/CustomCollectibleDrawCustom.h +++ b/src/port/Rando/CustomCollectible/CustomCollectibleDrawCustom.h @@ -4,8 +4,6 @@ #include #include -#include "actor.h" - #ifdef __cplusplus extern "C" { #endif diff --git a/src/port/Rando/ItemQueue.cpp b/src/port/Rando/ItemQueue.cpp new file mode 100644 index 000000000..80abe64d2 --- /dev/null +++ b/src/port/Rando/ItemQueue.cpp @@ -0,0 +1,189 @@ +#include "ItemQueue.h" + +#include +#include +#include + +#include "port/UI/Notification.h" +#include "port/UI/UIWidgets.hpp" +#include +#include "port/ShipInit.hpp" +#include "port/Rando/Logic/Logic.h" +#include "actor.h" + +extern "C" { +#include "functions.h" +extern u8 sHoneycombScore[3]; +extern struct { + u8 D_803832C0[0xD]; + u8 D_803832CD[0xD]; +} jiggyscore; +} + +#define CVAR_NAME_SHOW_COLLISION_NOTIFICATIONS "gRandoSettings.RandoNotifications" +#define CVAR_SHOW_COLLISION_NOTIFICATIONS CVarGetInteger(CVAR_NAME_SHOW_COLLISION_NOTIFICATIONS, 0) + +#define JIGGY_ID_MULTIPLIER(levelId) (1 + (10 * (levelId - 1))) +#define HONEYCOMB_ID_MULTIPLIER(levelId) (1 + (2 * (levelId - 1))) + +static std::queue itemQueue; + +std::map itemColors = { + { ACTOR_1_UNKNOWN, UIWidgets::Colors::Brown }, { ACTOR_52_BLUE_EGG, UIWidgets::Colors::Cyan }, + { ACTOR_47_EMPTY_HONEYCOMB, UIWidgets::Colors::Yellow }, { ACTOR_49_EXTRA_LIFE, UIWidgets::Colors::Yellow }, + { ACTOR_50_HONEYCOMB, UIWidgets::Colors::Yellow }, { ACTOR_46_JIGGY, UIWidgets::Colors::Yellow }, + { ACTOR_60_JINJO_BLUE, UIWidgets::Colors::SkyBlue }, { ACTOR_62_JINJO_GREEN, UIWidgets::Colors::Green }, + { ACTOR_5F_JINJO_ORANGE, UIWidgets::Colors::Orange }, { ACTOR_61_JINJO_PINK, UIWidgets::Colors::Pink }, + { ACTOR_5E_JINJO_YELLOW, UIWidgets::Colors::Yellow }, { ACTOR_12C_MOLEHILL, UIWidgets::Colors::Cyan }, + { ACTOR_2D_MUMBO_TOKEN, UIWidgets::Colors::Gray }, { ACTOR_51_MUSIC_NOTE, UIWidgets::Colors::Yellow }, + { ACTOR_25E_SNS_EGG, UIWidgets::Colors::Pink }, { ACTOR_25D_ICE_KEY, UIWidgets::Colors::White }, +}; + +std::map snsColors = { + { RI_STOP_N_SWOP_EGG_YELLOW, UIWidgets::Colors::Yellow }, { RI_STOP_N_SWOP_EGG_RED, UIWidgets::Colors::Red }, + { RI_STOP_N_SWOP_EGG_GREEN, UIWidgets::Colors::Green }, { RI_STOP_N_SWOP_EGG_BLUE, UIWidgets::Colors::Blue }, + { RI_STOP_N_SWOP_EGG_PINK, UIWidgets::Colors::Pink }, { RI_STOP_N_SWOP_EGG_CYAN, UIWidgets::Colors::Cyan }, + { RI_STOP_N_SWOP_ICE_KEY, UIWidgets::Colors::White }, +}; + +void ItemQueue::Process() { + if (itemQueue.size() < 1) { + return; + } + + RandoCheckId randoCheckId = itemQueue.front(); + + // Grant item + RandoSaveCheck randoSaveCheck = RANDO_SAVE_CHECKS[randoCheckId]; + ItemQueue::GiveItem(randoSaveCheck.randoItemId); + ItemQueue::SendNotification(randoSaveCheck.randoItemId); + + itemQueue.pop(); +} + +void ItemQueue::GiveItem(RandoItemId randoItemId) { + RandoItemType itemType = Rando::StaticData::Items[randoItemId].randoItemType; + int16_t worldId = Rando::StaticData::Items[randoItemId].worldId; + uint16_t combId; + uint16_t maxHoneycombs; + uint32_t jiggyId; + + switch (itemType) { + case RITYPE_BLUE_EGG: + coMusicPlayer_playMusic(COMUSIC_C_EGG_COLLECTED, 32000); + item_inc(ITEM_D_EGGS); + break; + case RITYPE_EMPTY_HONEYCOMB: + combId = HONEYCOMB_ID_MULTIPLIER(worldId); + maxHoneycombs = worldId == LEVEL_B_SPIRAL_MOUNTAIN ? 6 : 2; + if (worldId > LEVEL_6_LAIR) { + combId = HONEYCOMB_ID_MULTIPLIER(worldId - 1); + } + for (int i = 0; i < (maxHoneycombs); i++) { + if ((sHoneycombScore[((combId + i) - 1) / 8] & (1 << ((combId + i) & 7))) == 0) { + honeycombscore_set((honeycomb_e)(combId + i), 1); + break; + } + } + coMusicPlayer_playMusic(COMUSIC_17_EMPTY_HONEYCOMB_COLLECTED, 28000); + item_inc(ITEM_13_EMPTY_HONEYCOMB); + if (!(item_getCount(ITEM_13_EMPTY_HONEYCOMB) < 6)) { + gcpausemenu_80314AC8(0); + } + break; + case RITYPE_EXTRA_LIFE: + coMusicPlayer_playMusic(COMUSIC_15_EXTRA_LIFE_COLLECTED, 0x7FFF); + item_inc(ITEM_16_LIFE); + break; + case RITYPE_HONEYCOMB: + coMusicPlayer_playMusic(COMUSIC_16_HONEYCOMB_COLLECTED, 28000); + item_inc(ITEM_14_HEALTH); + break; + case RITYPE_JIGGY: + jiggyId = JIGGY_ID_MULTIPLIER(worldId); + for (int32_t i = jiggyId; i <= (jiggyId + 9); i++) { + if ((jiggyscore.D_803832C0[(i - 1) / 8] & (1 << (i & 7))) == 0) { + jiggyscore_setCollected(i, 1); + break; + } + } + coMusicPlayer_playMusic(COMUSIC_D_JINGLE_JIGGY_COLLECTED, -1); + item_inc(ITEM_E_JIGGY); + spawnOrbit(); + break; + case RITYPE_JINJO: + break; + case RITYPE_MOLEHILL: + break; + case RITYPE_MUMBO_TOKEN: + break; + case RITYPE_MUSIC_NOTE: + break; + case RITYPE_SNS_EGG: + break; + case RITYPE_SNS_KEY: + break; + case RITYPE_AP_ITEM: + break; + default: + break; + } +} + +void ItemQueue::SendNotification(RandoItemId randoItemId) { + if (CVAR_SHOW_COLLISION_NOTIFICATIONS) { + RandoItemType itemType = Rando::StaticData::Items[randoItemId].randoItemType; + actor_e actorId = (actor_e)Rando::StaticData::Items[randoItemId].actorId; + std::string prefix = ""; + std::string message = Rando::StaticData::Items[randoItemId].name; + std::string suffix = ""; + ImVec4 itemColor = UIWidgets::ColorValues.at(itemColors.at(actorId)); + + if (itemType == RITYPE_MOLEHILL) { + prefix = "You learned"; + } else if (itemType == RITYPE_SNS_EGG || itemType == RITYPE_SNS_KEY) { + int32_t totalsnsItems = Rando::Logic::GetTotalSnsItemsCollected(); + prefix = "You collected "; + prefix += Rando::StaticData::Items[randoItemId].article; + suffix = "("; + suffix += std::to_string(totalsnsItems); + suffix += " / 7)"; + + itemColor = UIWidgets::ColorValues.at(snsColors.at(randoItemId)); + } else { + prefix = "You collected "; + prefix += Rando::StaticData::Items[randoItemId].article; + } + + Notification::Emit({ + .prefix = prefix, + .prefixColor = UIWidgets::ColorValues.at(UIWidgets::Colors::White), + .message = message, + .messageColor = itemColor, + .suffix = suffix, + .suffixColor = UIWidgets::ColorValues.at(UIWidgets::Colors::White), + }); + } +} + +void ItemQueue::Clear() { + while (!itemQueue.empty()) { + itemQueue.pop(); + } +} + +void ItemQueue::AddCheck(RandoCheckId randoCheckId) { + itemQueue.push(randoCheckId); +} + +void RegisterItemQueue() { + COND_HOOK(GameFrameUpdate, EVENT_PRIORITY_NORMAL, IS_RANDO, [](IEvent* event) { + ItemQueue::Process(); + }); + + COND_HOOK(OnSaveFileLoad, EVENT_PRIORITY_NORMAL, IS_RANDO, [](IEvent* event) { + ItemQueue::Clear(); + }); +} + +static RegisterShipInitFunc initFunc(RegisterItemQueue, { "IS_RANDO" }); diff --git a/src/port/Rando/ItemQueue.h b/src/port/Rando/ItemQueue.h new file mode 100644 index 000000000..0e526b04d --- /dev/null +++ b/src/port/Rando/ItemQueue.h @@ -0,0 +1,10 @@ +#include "port/Rando/Rando.h" + +class ItemQueue { +public: + static void Process(); + static void Clear(); + static void GiveItem(RandoItemId randoItemId); + static void SendNotification(RandoItemId randoItemId); + static void AddCheck(RandoCheckId randoCheckId); +}; diff --git a/src/port/Rando/MiscBehavior/OnFileLoad.cpp b/src/port/Rando/MiscBehavior/OnFileLoad.cpp index e8d8161f9..bcbf56bc7 100644 --- a/src/port/Rando/MiscBehavior/OnFileLoad.cpp +++ b/src/port/Rando/MiscBehavior/OnFileLoad.cpp @@ -1,5 +1,6 @@ #include "MiscBehavior.h" #include +#include "src/port/ShipInit.hpp" #include "port/Enhancements/Events/Hooks/Events.h" #include "port/UI/Notification.h" @@ -21,6 +22,8 @@ void Rando::MiscBehavior::OnFileLoad() { Rando::Logic::shuffledPool.clear(); }); + REGISTER_LISTENER(OnGameStart, EVENT_PRIORITY_NORMAL, [](IEvent* event) { ShipInit::Init("IS_RANDO"); }); + REGISTER_LISTENER(OnSaveLoad, EVENT_PRIORITY_NORMAL, [](IEvent* event) { OnSaveLoad* ev = (OnSaveLoad*)event; SaveData* saveData = (SaveData*)ev->saveData; diff --git a/src/port/Rando/StaticData/Checks.cpp b/src/port/Rando/StaticData/Checks.cpp index 8a23c19b4..2470f2866 100644 --- a/src/port/Rando/StaticData/Checks.cpp +++ b/src/port/Rando/StaticData/Checks.cpp @@ -24,75 +24,75 @@ std::array CheckNames = std::array(); // clang-format off std::map Checks = { RC(RC_UNKNOWN, RCTYPE_UNKNOWN, LEVEL_D_CUTSCENE, RI_UNKNOWN, NULL, 0, 0, 0), - RC(RC_BGS_BLUE_EGG_BEHIND_ENTRANCE_1, RCTYPE_BLUE_EGG, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_BLUE_EGG_BUBBLEGLOOP_SWAMP, NULL, 4309, 100, 6025), - RC(RC_BGS_BLUE_EGG_BEHIND_ENTRANCE_2, RCTYPE_BLUE_EGG, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_BLUE_EGG_BUBBLEGLOOP_SWAMP, NULL, 4368, 100, 6106), - RC(RC_BGS_BLUE_EGG_BEHIND_ENTRANCE_3, RCTYPE_BLUE_EGG, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_BLUE_EGG_BUBBLEGLOOP_SWAMP, NULL, 4428, 100, 6198), - RC(RC_BGS_BLUE_EGG_BEHIND_ENTRANCE_4, RCTYPE_BLUE_EGG, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_BLUE_EGG_BUBBLEGLOOP_SWAMP, NULL, 4484, 100, 6296), - RC(RC_BGS_BLUE_EGG_BEHIND_ENTRANCE_5, RCTYPE_BLUE_EGG, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_BLUE_EGG_BUBBLEGLOOP_SWAMP, NULL, 4541, 100, 6389), - RC(RC_BGS_BLUE_EGG_ELEVATED_WALKWAY_1, RCTYPE_BLUE_EGG, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_BLUE_EGG_BUBBLEGLOOP_SWAMP, NULL, 4133, 1400, -1304), - RC(RC_BGS_BLUE_EGG_ELEVATED_WALKWAY_2, RCTYPE_BLUE_EGG, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_BLUE_EGG_BUBBLEGLOOP_SWAMP, NULL, 4208, 1400, -1422), - RC(RC_BGS_BLUE_EGG_ELEVATED_WALKWAY_3, RCTYPE_BLUE_EGG, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_BLUE_EGG_BUBBLEGLOOP_SWAMP, NULL, 4343, 1400, -1422), - RC(RC_BGS_BLUE_EGG_ELEVATED_WALKWAY_4, RCTYPE_BLUE_EGG, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_BLUE_EGG_BUBBLEGLOOP_SWAMP, NULL, 4412, 1400, -1304), - RC(RC_BGS_BLUE_EGG_ELEVATED_WALKWAY_5, RCTYPE_BLUE_EGG, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_BLUE_EGG_BUBBLEGLOOP_SWAMP, NULL, 4342, 1400, -1184), - RC(RC_BGS_BLUE_EGG_ELEVATED_WALKWAY_6, RCTYPE_BLUE_EGG, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_BLUE_EGG_BUBBLEGLOOP_SWAMP, NULL, 4207, 1400, -1184), - RC(RC_BGS_BLUE_EGG_INSIDE_MR_VILES_1, RCTYPE_BLUE_EGG, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_BLUE_EGG_BUBBLEGLOOP_SWAMP, NULL, 1185, 0, 0), - RC(RC_BGS_BLUE_EGG_INSIDE_MR_VILES_2, RCTYPE_BLUE_EGG, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_BLUE_EGG_BUBBLEGLOOP_SWAMP, NULL, -1189, 0, 0), - RC(RC_BGS_BLUE_EGG_INSIDE_TANKTUP_1, RCTYPE_BLUE_EGG, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_BLUE_EGG_BUBBLEGLOOP_SWAMP, NULL, 300, 0, -1830), - RC(RC_BGS_BLUE_EGG_INSIDE_TANKTUP_2, RCTYPE_BLUE_EGG, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_BLUE_EGG_BUBBLEGLOOP_SWAMP, NULL, 150, 0, -1829), - RC(RC_BGS_BLUE_EGG_INSIDE_TANKTUP_3, RCTYPE_BLUE_EGG, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_BLUE_EGG_BUBBLEGLOOP_SWAMP, NULL, -150, 0, -1832), - RC(RC_BGS_BLUE_EGG_INSIDE_TANKTUP_4, RCTYPE_BLUE_EGG, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_BLUE_EGG_BUBBLEGLOOP_SWAMP, NULL, -300, 0, -1831), - RC(RC_BGS_BLUE_EGG_MAZE_WALKWAY_1, RCTYPE_BLUE_EGG, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_BLUE_EGG_BUBBLEGLOOP_SWAMP, NULL, -7873, 1000, -6525), - RC(RC_BGS_BLUE_EGG_MAZE_WALKWAY_2, RCTYPE_BLUE_EGG, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_BLUE_EGG_BUBBLEGLOOP_SWAMP, NULL, -7591, 1000, -6568), - RC(RC_BGS_BLUE_EGG_MAZE_WALKWAY_3, RCTYPE_BLUE_EGG, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_BLUE_EGG_BUBBLEGLOOP_SWAMP, NULL, -7309, 1000, -6610), - RC(RC_BGS_BLUE_EGG_MAZE_WALKWAY_4, RCTYPE_BLUE_EGG, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_BLUE_EGG_BUBBLEGLOOP_SWAMP, NULL, -7017, 1000, -6552), - RC(RC_BGS_BLUE_EGG_MAZE_WALKWAY_5, RCTYPE_BLUE_EGG, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_BLUE_EGG_BUBBLEGLOOP_SWAMP, NULL, -6729, 1000, -6507), - RC(RC_BGS_BLUE_EGG_POLE_NEAR_BLUE_JINJO_1, RCTYPE_BLUE_EGG, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_BLUE_EGG_BUBBLEGLOOP_SWAMP, NULL, -3920, 1250, -7549), - RC(RC_BGS_BLUE_EGG_POLE_NEAR_BLUE_JINJO_2, RCTYPE_BLUE_EGG, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_BLUE_EGG_BUBBLEGLOOP_SWAMP, NULL, -3920, 1350, -7549), - RC(RC_BGS_BLUE_EGG_POLE_NEAR_BLUE_JINJO_3, RCTYPE_BLUE_EGG, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_BLUE_EGG_BUBBLEGLOOP_SWAMP, NULL, -3920, 1450, -7549), - RC(RC_BGS_BLUE_EGG_POLE_NEAR_ENTRANCE_1, RCTYPE_BLUE_EGG, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_BLUE_EGG_BUBBLEGLOOP_SWAMP, NULL, 839, 1250, 2740), - RC(RC_BGS_BLUE_EGG_POLE_NEAR_ENTRANCE_2, RCTYPE_BLUE_EGG, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_BLUE_EGG_BUBBLEGLOOP_SWAMP, NULL, 839, 1350, 2740), - RC(RC_BGS_BLUE_EGG_POLE_NEAR_ENTRANCE_3, RCTYPE_BLUE_EGG, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_BLUE_EGG_BUBBLEGLOOP_SWAMP, NULL, 839, 1450, 2740), - RC(RC_BGS_BLUE_EGG_STUMP_NEAR_BIG_EGG_1, RCTYPE_BLUE_EGG, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_BLUE_EGG_BUBBLEGLOOP_SWAMP, NULL, -3209, 150, -253), - RC(RC_BGS_BLUE_EGG_STUMP_NEAR_BIG_EGG_2, RCTYPE_BLUE_EGG, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_BLUE_EGG_BUBBLEGLOOP_SWAMP, NULL, -3403, 150, -761), - RC(RC_BGS_BLUE_EGG_SWAMP_BEHIND_TANKTUP_1, RCTYPE_BLUE_EGG, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_BLUE_EGG_BUBBLEGLOOP_SWAMP, NULL, 5917, 0, 2497), - RC(RC_BGS_BLUE_EGG_SWAMP_BEHIND_TANKTUP_2, RCTYPE_BLUE_EGG, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_BLUE_EGG_BUBBLEGLOOP_SWAMP, NULL, 5705, 0, 2672), - RC(RC_BGS_BLUE_EGG_SWAMP_BEHIND_TANKTUP_3, RCTYPE_BLUE_EGG, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_BLUE_EGG_BUBBLEGLOOP_SWAMP, NULL, 5283, 0, 3047), - RC(RC_BGS_BLUE_EGG_SWAMP_BEHIND_TANKTUP_4, RCTYPE_BLUE_EGG, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_BLUE_EGG_BUBBLEGLOOP_SWAMP, NULL, 5087, 0, 3251), - RC(RC_BGS_BLUE_EGG_SWAMP_NEAR_HUTS_1, RCTYPE_BLUE_EGG, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_BLUE_EGG_BUBBLEGLOOP_SWAMP, NULL, 1813, 0, -2967), - RC(RC_BGS_BLUE_EGG_SWAMP_NEAR_HUTS_2, RCTYPE_BLUE_EGG, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_BLUE_EGG_BUBBLEGLOOP_SWAMP, NULL, 1857, 0, -3096), - RC(RC_BGS_BLUE_EGG_SWAMP_NEAR_HUTS_3, RCTYPE_BLUE_EGG, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_BLUE_EGG_BUBBLEGLOOP_SWAMP, NULL, 1889, 0, -3228), - RC(RC_BGS_BLUE_EGG_SWAMP_NEAR_MR_VILES_1, RCTYPE_BLUE_EGG, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_BLUE_EGG_BUBBLEGLOOP_SWAMP, NULL, -404, 0, -1715), - RC(RC_BGS_BLUE_EGG_SWAMP_NEAR_MR_VILES_2, RCTYPE_BLUE_EGG, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_BLUE_EGG_BUBBLEGLOOP_SWAMP, NULL, -518, 0, -1728), - RC(RC_BGS_BLUE_EGG_SWAMP_NEAR_MR_VILES_3, RCTYPE_BLUE_EGG, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_BLUE_EGG_BUBBLEGLOOP_SWAMP, NULL, -628, 0, -1744), - RC(RC_BGS_BLUE_EGG_SWAMP_NEAR_MR_VILES_4, RCTYPE_BLUE_EGG, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_BLUE_EGG_BUBBLEGLOOP_SWAMP, NULL, 1497, 0, -3242), - RC(RC_BGS_BLUE_EGG_SWAMP_NEAR_MR_VILES_5, RCTYPE_BLUE_EGG, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_BLUE_EGG_BUBBLEGLOOP_SWAMP, NULL, 1501, 0, -3121), - RC(RC_BGS_BLUE_EGG_SWAMP_NEAR_MR_VILES_6, RCTYPE_BLUE_EGG, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_BLUE_EGG_BUBBLEGLOOP_SWAMP, NULL, 1506, 0, -3005), - RC(RC_BGS_BLUE_EGG_SWAMP_NEAR_SWITCH_1, RCTYPE_BLUE_EGG, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_BLUE_EGG_BUBBLEGLOOP_SWAMP, NULL, -635, 0, -1361), - RC(RC_BGS_BLUE_EGG_SWAMP_NEAR_SWITCH_2, RCTYPE_BLUE_EGG, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_BLUE_EGG_BUBBLEGLOOP_SWAMP, NULL, -528, 0, -1380), - RC(RC_BGS_BLUE_EGG_SWAMP_NEAR_SWITCH_3, RCTYPE_BLUE_EGG, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_BLUE_EGG_BUBBLEGLOOP_SWAMP, NULL, -427, 0, -1398), - RC(RC_BGS_BLUE_EGG_SWAMP_UNDER_HUTS_1, RCTYPE_BLUE_EGG, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_BLUE_EGG_BUBBLEGLOOP_SWAMP, NULL, 4592, 0, -3489), - RC(RC_BGS_BLUE_EGG_SWAMP_UNDER_HUTS_2, RCTYPE_BLUE_EGG, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_BLUE_EGG_BUBBLEGLOOP_SWAMP, NULL, 4586, 0, -3710), - RC(RC_BGS_BLUE_EGG_SWAMP_UNDER_HUTS_3, RCTYPE_BLUE_EGG, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_BLUE_EGG_BUBBLEGLOOP_SWAMP, NULL, 4809, 0, -3711), - RC(RC_BGS_BLUE_EGG_SWAMP_UNDER_HUTS_4, RCTYPE_BLUE_EGG, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_BLUE_EGG_BUBBLEGLOOP_SWAMP, NULL, 4814, 0, -3490), + RC(RC_BGS_BLUE_EGG_BEHIND_ENTRANCE_1, RCTYPE_BLUE_EGG, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_BLUE_EGG, NULL, 4309, 100, 6025), + RC(RC_BGS_BLUE_EGG_BEHIND_ENTRANCE_2, RCTYPE_BLUE_EGG, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_BLUE_EGG, NULL, 4368, 100, 6106), + RC(RC_BGS_BLUE_EGG_BEHIND_ENTRANCE_3, RCTYPE_BLUE_EGG, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_BLUE_EGG, NULL, 4428, 100, 6198), + RC(RC_BGS_BLUE_EGG_BEHIND_ENTRANCE_4, RCTYPE_BLUE_EGG, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_BLUE_EGG, NULL, 4484, 100, 6296), + RC(RC_BGS_BLUE_EGG_BEHIND_ENTRANCE_5, RCTYPE_BLUE_EGG, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_BLUE_EGG, NULL, 4541, 100, 6389), + RC(RC_BGS_BLUE_EGG_ELEVATED_WALKWAY_1, RCTYPE_BLUE_EGG, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_BLUE_EGG, NULL, 4133, 1400, -1304), + RC(RC_BGS_BLUE_EGG_ELEVATED_WALKWAY_2, RCTYPE_BLUE_EGG, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_BLUE_EGG, NULL, 4208, 1400, -1422), + RC(RC_BGS_BLUE_EGG_ELEVATED_WALKWAY_3, RCTYPE_BLUE_EGG, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_BLUE_EGG, NULL, 4343, 1400, -1422), + RC(RC_BGS_BLUE_EGG_ELEVATED_WALKWAY_4, RCTYPE_BLUE_EGG, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_BLUE_EGG, NULL, 4412, 1400, -1304), + RC(RC_BGS_BLUE_EGG_ELEVATED_WALKWAY_5, RCTYPE_BLUE_EGG, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_BLUE_EGG, NULL, 4342, 1400, -1184), + RC(RC_BGS_BLUE_EGG_ELEVATED_WALKWAY_6, RCTYPE_BLUE_EGG, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_BLUE_EGG, NULL, 4207, 1400, -1184), + RC(RC_BGS_BLUE_EGG_INSIDE_MR_VILES_1, RCTYPE_BLUE_EGG, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_BLUE_EGG, NULL, 1185, 0, 0), + RC(RC_BGS_BLUE_EGG_INSIDE_MR_VILES_2, RCTYPE_BLUE_EGG, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_BLUE_EGG, NULL, -1189, 0, 0), + RC(RC_BGS_BLUE_EGG_INSIDE_TANKTUP_1, RCTYPE_BLUE_EGG, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_BLUE_EGG, NULL, 300, 0, -1830), + RC(RC_BGS_BLUE_EGG_INSIDE_TANKTUP_2, RCTYPE_BLUE_EGG, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_BLUE_EGG, NULL, 150, 0, -1829), + RC(RC_BGS_BLUE_EGG_INSIDE_TANKTUP_3, RCTYPE_BLUE_EGG, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_BLUE_EGG, NULL, -150, 0, -1832), + RC(RC_BGS_BLUE_EGG_INSIDE_TANKTUP_4, RCTYPE_BLUE_EGG, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_BLUE_EGG, NULL, -300, 0, -1831), + RC(RC_BGS_BLUE_EGG_MAZE_WALKWAY_1, RCTYPE_BLUE_EGG, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_BLUE_EGG, NULL, -7873, 1000, -6525), + RC(RC_BGS_BLUE_EGG_MAZE_WALKWAY_2, RCTYPE_BLUE_EGG, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_BLUE_EGG, NULL, -7591, 1000, -6568), + RC(RC_BGS_BLUE_EGG_MAZE_WALKWAY_3, RCTYPE_BLUE_EGG, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_BLUE_EGG, NULL, -7309, 1000, -6610), + RC(RC_BGS_BLUE_EGG_MAZE_WALKWAY_4, RCTYPE_BLUE_EGG, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_BLUE_EGG, NULL, -7017, 1000, -6552), + RC(RC_BGS_BLUE_EGG_MAZE_WALKWAY_5, RCTYPE_BLUE_EGG, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_BLUE_EGG, NULL, -6729, 1000, -6507), + RC(RC_BGS_BLUE_EGG_POLE_NEAR_BLUE_JINJO_1, RCTYPE_BLUE_EGG, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_BLUE_EGG, NULL, -3920, 1250, -7549), + RC(RC_BGS_BLUE_EGG_POLE_NEAR_BLUE_JINJO_2, RCTYPE_BLUE_EGG, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_BLUE_EGG, NULL, -3920, 1350, -7549), + RC(RC_BGS_BLUE_EGG_POLE_NEAR_BLUE_JINJO_3, RCTYPE_BLUE_EGG, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_BLUE_EGG, NULL, -3920, 1450, -7549), + RC(RC_BGS_BLUE_EGG_POLE_NEAR_ENTRANCE_1, RCTYPE_BLUE_EGG, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_BLUE_EGG, NULL, 839, 1250, 2740), + RC(RC_BGS_BLUE_EGG_POLE_NEAR_ENTRANCE_2, RCTYPE_BLUE_EGG, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_BLUE_EGG, NULL, 839, 1350, 2740), + RC(RC_BGS_BLUE_EGG_POLE_NEAR_ENTRANCE_3, RCTYPE_BLUE_EGG, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_BLUE_EGG, NULL, 839, 1450, 2740), + RC(RC_BGS_BLUE_EGG_STUMP_NEAR_BIG_EGG_1, RCTYPE_BLUE_EGG, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_BLUE_EGG, NULL, -3209, 150, -253), + RC(RC_BGS_BLUE_EGG_STUMP_NEAR_BIG_EGG_2, RCTYPE_BLUE_EGG, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_BLUE_EGG, NULL, -3403, 150, -761), + RC(RC_BGS_BLUE_EGG_SWAMP_BEHIND_TANKTUP_1, RCTYPE_BLUE_EGG, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_BLUE_EGG, NULL, 5917, 0, 2497), + RC(RC_BGS_BLUE_EGG_SWAMP_BEHIND_TANKTUP_2, RCTYPE_BLUE_EGG, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_BLUE_EGG, NULL, 5705, 0, 2672), + RC(RC_BGS_BLUE_EGG_SWAMP_BEHIND_TANKTUP_3, RCTYPE_BLUE_EGG, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_BLUE_EGG, NULL, 5283, 0, 3047), + RC(RC_BGS_BLUE_EGG_SWAMP_BEHIND_TANKTUP_4, RCTYPE_BLUE_EGG, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_BLUE_EGG, NULL, 5087, 0, 3251), + RC(RC_BGS_BLUE_EGG_SWAMP_NEAR_HUTS_1, RCTYPE_BLUE_EGG, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_BLUE_EGG, NULL, 1813, 0, -2967), + RC(RC_BGS_BLUE_EGG_SWAMP_NEAR_HUTS_2, RCTYPE_BLUE_EGG, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_BLUE_EGG, NULL, 1857, 0, -3096), + RC(RC_BGS_BLUE_EGG_SWAMP_NEAR_HUTS_3, RCTYPE_BLUE_EGG, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_BLUE_EGG, NULL, 1889, 0, -3228), + RC(RC_BGS_BLUE_EGG_SWAMP_NEAR_MR_VILES_1, RCTYPE_BLUE_EGG, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_BLUE_EGG, NULL, -404, 0, -1715), + RC(RC_BGS_BLUE_EGG_SWAMP_NEAR_MR_VILES_2, RCTYPE_BLUE_EGG, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_BLUE_EGG, NULL, -518, 0, -1728), + RC(RC_BGS_BLUE_EGG_SWAMP_NEAR_MR_VILES_3, RCTYPE_BLUE_EGG, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_BLUE_EGG, NULL, -628, 0, -1744), + RC(RC_BGS_BLUE_EGG_SWAMP_NEAR_MR_VILES_4, RCTYPE_BLUE_EGG, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_BLUE_EGG, NULL, 1497, 0, -3242), + RC(RC_BGS_BLUE_EGG_SWAMP_NEAR_MR_VILES_5, RCTYPE_BLUE_EGG, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_BLUE_EGG, NULL, 1501, 0, -3121), + RC(RC_BGS_BLUE_EGG_SWAMP_NEAR_MR_VILES_6, RCTYPE_BLUE_EGG, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_BLUE_EGG, NULL, 1506, 0, -3005), + RC(RC_BGS_BLUE_EGG_SWAMP_NEAR_SWITCH_1, RCTYPE_BLUE_EGG, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_BLUE_EGG, NULL, -635, 0, -1361), + RC(RC_BGS_BLUE_EGG_SWAMP_NEAR_SWITCH_2, RCTYPE_BLUE_EGG, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_BLUE_EGG, NULL, -528, 0, -1380), + RC(RC_BGS_BLUE_EGG_SWAMP_NEAR_SWITCH_3, RCTYPE_BLUE_EGG, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_BLUE_EGG, NULL, -427, 0, -1398), + RC(RC_BGS_BLUE_EGG_SWAMP_UNDER_HUTS_1, RCTYPE_BLUE_EGG, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_BLUE_EGG, NULL, 4592, 0, -3489), + RC(RC_BGS_BLUE_EGG_SWAMP_UNDER_HUTS_2, RCTYPE_BLUE_EGG, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_BLUE_EGG, NULL, 4586, 0, -3710), + RC(RC_BGS_BLUE_EGG_SWAMP_UNDER_HUTS_3, RCTYPE_BLUE_EGG, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_BLUE_EGG, NULL, 4809, 0, -3711), + RC(RC_BGS_BLUE_EGG_SWAMP_UNDER_HUTS_4, RCTYPE_BLUE_EGG, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_BLUE_EGG, NULL, 4814, 0, -3490), RC(RC_BGS_EMPTY_HONEYCOMB_MUMBOS, RCTYPE_EMPTY_HONEYCOMB, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_EMPTY_HONEYCOMB_BUBBLEGLOOP_SWAMP, HONEYCOMB_7_BGS_MUMBOS, 0, 600, 0), RC(RC_BGS_EMPTY_HONEYCOMB_TANKTUP, RCTYPE_EMPTY_HONEYCOMB, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_EMPTY_HONEYCOMB_BUBBLEGLOOP_SWAMP, HONEYCOMB_8_BGS_TANKTUP, 0, 537, -1157), - RC(RC_BGS_EXTRA_LIFE_ABOVE_THE_EGG, RCTYPE_EXTRA_LIFE, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_EXTRA_LIFE_BUBBLEGLOOP_SWAMP, NULL, -4382, 985, 2799), - RC(RC_BGS_EXTRA_LIFE_MR_VILE_1, RCTYPE_EXTRA_LIFE, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_EXTRA_LIFE_BUBBLEGLOOP_SWAMP, NULL, 0, 0, 0), - RC(RC_BGS_EXTRA_LIFE_MR_VILE_2, RCTYPE_EXTRA_LIFE, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_EXTRA_LIFE_BUBBLEGLOOP_SWAMP, NULL, 0, 0, 0), - RC(RC_BGS_EXTRA_LIFE_MR_VILE_3, RCTYPE_EXTRA_LIFE, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_EXTRA_LIFE_BUBBLEGLOOP_SWAMP, NULL, 0, 0, 0), - RC(RC_BGS_EXTRA_LIFE_SWAMP_BY_THE_HUTS, RCTYPE_EXTRA_LIFE, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_EXTRA_LIFE_BUBBLEGLOOP_SWAMP, NULL, 7149, 0, -4353), - RC(RC_BGS_HONEYCOMB_BEEHIVE_ELEVATED_WALKWAY_1, RCTYPE_HONEYCOMB, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_HONEYCOMB_BUBBLEGLOOP_SWAMP, NULL, 0, 0, 0), - RC(RC_BGS_HONEYCOMB_BEEHIVE_ELEVATED_WALKWAY_2, RCTYPE_HONEYCOMB, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_HONEYCOMB_BUBBLEGLOOP_SWAMP, NULL, 0, 0, 0), - RC(RC_BGS_HONEYCOMB_BEEHIVE_ELEVATED_WALKWAY_3, RCTYPE_HONEYCOMB, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_HONEYCOMB_BUBBLEGLOOP_SWAMP, NULL, 0, 0, 0), - RC(RC_BGS_HONEYCOMB_BEEHIVE_NEAR_MAZE_ENTRANCE_1, RCTYPE_HONEYCOMB, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_HONEYCOMB_BUBBLEGLOOP_SWAMP, NULL, 0, 0, 0), - RC(RC_BGS_HONEYCOMB_BEEHIVE_NEAR_MAZE_ENTRANCE_2, RCTYPE_HONEYCOMB, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_HONEYCOMB_BUBBLEGLOOP_SWAMP, NULL, 0, 0, 0), - RC(RC_BGS_HONEYCOMB_BEEHIVE_NEAR_MAZE_ENTRANCE_3, RCTYPE_HONEYCOMB, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_HONEYCOMB_BUBBLEGLOOP_SWAMP, NULL, 0, 0, 0), - RC(RC_BGS_HONEYCOMB_BEEHIVE_NEAR_TANKTUP_1, RCTYPE_HONEYCOMB, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_HONEYCOMB_BUBBLEGLOOP_SWAMP, NULL, 0, 0, 0), - RC(RC_BGS_HONEYCOMB_BEEHIVE_NEAR_TANKTUP_2, RCTYPE_HONEYCOMB, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_HONEYCOMB_BUBBLEGLOOP_SWAMP, NULL, 0, 0, 0), - RC(RC_BGS_HONEYCOMB_BEEHIVE_NEAR_TANKTUP_3, RCTYPE_HONEYCOMB, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_HONEYCOMB_BUBBLEGLOOP_SWAMP, NULL, 0, 0, 0), - RC(RC_BGS_HONEYCOMB_BEEHIVE_NEAR_WARP_PAD_1, RCTYPE_HONEYCOMB, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_HONEYCOMB_BUBBLEGLOOP_SWAMP, NULL, 0, 0, 0), - RC(RC_BGS_HONEYCOMB_BEEHIVE_NEAR_WARP_PAD_2, RCTYPE_HONEYCOMB, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_HONEYCOMB_BUBBLEGLOOP_SWAMP, NULL, 0, 0, 0), - RC(RC_BGS_HONEYCOMB_BEEHIVE_NEAR_WARP_PAD_3, RCTYPE_HONEYCOMB, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_HONEYCOMB_BUBBLEGLOOP_SWAMP, NULL, 0, 0, 0), + RC(RC_BGS_EXTRA_LIFE_ABOVE_THE_EGG, RCTYPE_EXTRA_LIFE, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_EXTRA_LIFE, NULL, -4382, 985, 2799), + RC(RC_BGS_EXTRA_LIFE_MR_VILE_1, RCTYPE_EXTRA_LIFE, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_EXTRA_LIFE, NULL, 0, 0, 0), + RC(RC_BGS_EXTRA_LIFE_MR_VILE_2, RCTYPE_EXTRA_LIFE, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_EXTRA_LIFE, NULL, 0, 0, 0), + RC(RC_BGS_EXTRA_LIFE_MR_VILE_3, RCTYPE_EXTRA_LIFE, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_EXTRA_LIFE, NULL, 0, 0, 0), + RC(RC_BGS_EXTRA_LIFE_SWAMP_BY_THE_HUTS, RCTYPE_EXTRA_LIFE, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_EXTRA_LIFE, NULL, 7149, 0, -4353), + RC(RC_BGS_HONEYCOMB_BEEHIVE_ELEVATED_WALKWAY_1, RCTYPE_HONEYCOMB, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_BGS_HONEYCOMB_BEEHIVE_ELEVATED_WALKWAY_2, RCTYPE_HONEYCOMB, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_BGS_HONEYCOMB_BEEHIVE_ELEVATED_WALKWAY_3, RCTYPE_HONEYCOMB, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_BGS_HONEYCOMB_BEEHIVE_NEAR_MAZE_ENTRANCE_1, RCTYPE_HONEYCOMB, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_BGS_HONEYCOMB_BEEHIVE_NEAR_MAZE_ENTRANCE_2, RCTYPE_HONEYCOMB, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_BGS_HONEYCOMB_BEEHIVE_NEAR_MAZE_ENTRANCE_3, RCTYPE_HONEYCOMB, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_BGS_HONEYCOMB_BEEHIVE_NEAR_TANKTUP_1, RCTYPE_HONEYCOMB, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_BGS_HONEYCOMB_BEEHIVE_NEAR_TANKTUP_2, RCTYPE_HONEYCOMB, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_BGS_HONEYCOMB_BEEHIVE_NEAR_TANKTUP_3, RCTYPE_HONEYCOMB, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_BGS_HONEYCOMB_BEEHIVE_NEAR_WARP_PAD_1, RCTYPE_HONEYCOMB, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_BGS_HONEYCOMB_BEEHIVE_NEAR_WARP_PAD_2, RCTYPE_HONEYCOMB, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_BGS_HONEYCOMB_BEEHIVE_NEAR_WARP_PAD_3, RCTYPE_HONEYCOMB, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_HONEYCOMB, NULL, 0, 0, 0), RC(RC_BGS_JIGGY_CROCTUS, RCTYPE_JIGGY, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_JIGGY_BUBBLEGLOOP_SWAMP, JIGGY_22_CROCTUS, 0, 0, 0), RC(RC_BGS_JIGGY_ELEVATED_WALKWAY, RCTYPE_JIGGY, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_JIGGY_BUBBLEGLOOP_SWAMP, JIGGY_20_BGS_ELEVATED_WALKWAY, 0, 0, 0), RC(RC_BGS_JIGGY_FLIBBITS, RCTYPE_JIGGY, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_JIGGY_BUBBLEGLOOP_SWAMP, JIGGY_24_BGS_FLIBBITS, 0, 0, 0), @@ -219,64 +219,64 @@ std::map Checks = { RC(RC_BGS_NOTE_THIRD_SHORT_SWAMP_LOG_1, RCTYPE_MUSIC_NOTE, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_MUSIC_NOTE_BUBBLEGLOOP_SWAMP, NULL, 2921, 93, -513), RC(RC_BGS_NOTE_THIRD_SHORT_SWAMP_LOG_2, RCTYPE_MUSIC_NOTE, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_MUSIC_NOTE_BUBBLEGLOOP_SWAMP, NULL, 3020, 93, -304), RC(RC_BGS_NOTE_THIRD_SHORT_SWAMP_LOG_3, RCTYPE_MUSIC_NOTE, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_MUSIC_NOTE_BUBBLEGLOOP_SWAMP, NULL, 3114, 93, -86), - RC(RC_CC_BLUE_EGG_ABOVEWATER_PIPE_1, RCTYPE_BLUE_EGG, LEVEL_3_CLANKERS_CAVERN, RI_BLUE_EGG_CLANKERS_CAVERN, NULL, 6379, 5087, 2586), - RC(RC_CC_BLUE_EGG_ABOVEWATER_PIPE_2, RCTYPE_BLUE_EGG, LEVEL_3_CLANKERS_CAVERN, RI_BLUE_EGG_CLANKERS_CAVERN, NULL, 6582, 5047, 2536), - RC(RC_CC_BLUE_EGG_ABOVEWATER_PIPE_3, RCTYPE_BLUE_EGG, LEVEL_3_CLANKERS_CAVERN, RI_BLUE_EGG_CLANKERS_CAVERN, NULL, 6785, 4876, 2454), - RC(RC_CC_BLUE_EGG_ABOVEWATER_PIPE_4, RCTYPE_BLUE_EGG, LEVEL_3_CLANKERS_CAVERN, RI_BLUE_EGG_CLANKERS_CAVERN, NULL, 6989, 4703, 2388), - RC(RC_CC_BLUE_EGG_ABOVEWATER_PIPE_5, RCTYPE_BLUE_EGG, LEVEL_3_CLANKERS_CAVERN, RI_BLUE_EGG_CLANKERS_CAVERN, NULL, 7194, 4526, 2321), - RC(RC_CC_BLUE_EGG_ALCOVE_WITH_OPEN_GRATE_1, RCTYPE_BLUE_EGG, LEVEL_3_CLANKERS_CAVERN, RI_BLUE_EGG_CLANKERS_CAVERN, NULL, 2588, 5456, 2596), - RC(RC_CC_BLUE_EGG_ALCOVE_WITH_OPEN_GRATE_2, RCTYPE_BLUE_EGG, LEVEL_3_CLANKERS_CAVERN, RI_BLUE_EGG_CLANKERS_CAVERN, NULL, 2494, 5456, 2556), - RC(RC_CC_BLUE_EGG_ENTRANCE_1, RCTYPE_BLUE_EGG, LEVEL_3_CLANKERS_CAVERN, RI_BLUE_EGG_CLANKERS_CAVERN, NULL, -5274, 3269, -270), - RC(RC_CC_BLUE_EGG_ENTRANCE_2, RCTYPE_BLUE_EGG, LEVEL_3_CLANKERS_CAVERN, RI_BLUE_EGG_CLANKERS_CAVERN, NULL, -4937, 3221, -597), - RC(RC_CC_BLUE_EGG_ENTRANCE_3, RCTYPE_BLUE_EGG, LEVEL_3_CLANKERS_CAVERN, RI_BLUE_EGG_CLANKERS_CAVERN, NULL, -4492, 3113, -449), - RC(RC_CC_BLUE_EGG_ENTRANCE_4, RCTYPE_BLUE_EGG, LEVEL_3_CLANKERS_CAVERN, RI_BLUE_EGG_CLANKERS_CAVERN, NULL, -4392, 3051, -27), - RC(RC_CC_BLUE_EGG_ENTRANCE_5, RCTYPE_BLUE_EGG, LEVEL_3_CLANKERS_CAVERN, RI_BLUE_EGG_CLANKERS_CAVERN, NULL, -4722, 3104, 299), - RC(RC_CC_BLUE_EGG_ENTRANCE_6, RCTYPE_BLUE_EGG, LEVEL_3_CLANKERS_CAVERN, RI_BLUE_EGG_CLANKERS_CAVERN, NULL, -5159, 3232, 178), - RC(RC_CC_BLUE_EGG_LEDGE_NEAR_CHOMPA_1, RCTYPE_BLUE_EGG, LEVEL_3_CLANKERS_CAVERN, RI_BLUE_EGG_CLANKERS_CAVERN, NULL, 2293, 3662, 2354), - RC(RC_CC_BLUE_EGG_LEDGE_NEAR_CHOMPA_2, RCTYPE_BLUE_EGG, LEVEL_3_CLANKERS_CAVERN, RI_BLUE_EGG_CLANKERS_CAVERN, NULL, 2360, 3662, 2231), - RC(RC_CC_BLUE_EGG_LEDGE_NEAR_CHOMPA_3, RCTYPE_BLUE_EGG, LEVEL_3_CLANKERS_CAVERN, RI_BLUE_EGG_CLANKERS_CAVERN, NULL, 2329, 3662, 2107), - RC(RC_CC_BLUE_EGG_LEDGE_NEAR_CHOMPA_4, RCTYPE_BLUE_EGG, LEVEL_3_CLANKERS_CAVERN, RI_BLUE_EGG_CLANKERS_CAVERN, NULL, 2216, 3662, 2018), - RC(RC_CC_BLUE_EGG_LEDGE_NEAR_CHOMPA_5, RCTYPE_BLUE_EGG, LEVEL_3_CLANKERS_CAVERN, RI_BLUE_EGG_CLANKERS_CAVERN, NULL, 2094, 3662, 1968), - RC(RC_CC_BLUE_EGG_LEDGE_NEAR_CHOMPA_6, RCTYPE_BLUE_EGG, LEVEL_3_CLANKERS_CAVERN, RI_BLUE_EGG_CLANKERS_CAVERN, NULL, 1970, 3662, 1998), - RC(RC_CC_BLUE_EGG_LEDGE_NEAR_CHOMPA_7, RCTYPE_BLUE_EGG, LEVEL_3_CLANKERS_CAVERN, RI_BLUE_EGG_CLANKERS_CAVERN, NULL, 1895, 3662, 2117), - RC(RC_CC_BLUE_EGG_NEAR_RINGS_1, RCTYPE_BLUE_EGG, LEVEL_3_CLANKERS_CAVERN, RI_BLUE_EGG_CLANKERS_CAVERN, NULL, -390, -116, 1316), - RC(RC_CC_BLUE_EGG_NEAR_RINGS_2, RCTYPE_BLUE_EGG, LEVEL_3_CLANKERS_CAVERN, RI_BLUE_EGG_CLANKERS_CAVERN, NULL, -476, -192, 480), - RC(RC_CC_BLUE_EGG_NEAR_RINGS_3, RCTYPE_BLUE_EGG, LEVEL_3_CLANKERS_CAVERN, RI_BLUE_EGG_CLANKERS_CAVERN, NULL, -433, -214, -453), - RC(RC_CC_BLUE_EGG_NEAR_RINGS_4, RCTYPE_BLUE_EGG, LEVEL_3_CLANKERS_CAVERN, RI_BLUE_EGG_CLANKERS_CAVERN, NULL, -390, -160, -1300), - RC(RC_CC_BLUE_EGG_NEAR_RINGS_5, RCTYPE_BLUE_EGG, LEVEL_3_CLANKERS_CAVERN, RI_BLUE_EGG_CLANKERS_CAVERN, NULL, 391, -160, -1300), - RC(RC_CC_BLUE_EGG_NEAR_RINGS_6, RCTYPE_BLUE_EGG, LEVEL_3_CLANKERS_CAVERN, RI_BLUE_EGG_CLANKERS_CAVERN, NULL, 434, -214, -453), - RC(RC_CC_BLUE_EGG_NEAR_RINGS_7, RCTYPE_BLUE_EGG, LEVEL_3_CLANKERS_CAVERN, RI_BLUE_EGG_CLANKERS_CAVERN, NULL, 476, -192, 480), - RC(RC_CC_BLUE_EGG_NEAR_RINGS_8, RCTYPE_BLUE_EGG, LEVEL_3_CLANKERS_CAVERN, RI_BLUE_EGG_CLANKERS_CAVERN, NULL, 389, -116, 1316), - RC(RC_CC_BLUE_EGG_NEAR_SNIPPETS_1, RCTYPE_BLUE_EGG, LEVEL_3_CLANKERS_CAVERN, RI_BLUE_EGG_CLANKERS_CAVERN, NULL, 15075, 3648, -20), - RC(RC_CC_BLUE_EGG_NEAR_SNIPPETS_2, RCTYPE_BLUE_EGG, LEVEL_3_CLANKERS_CAVERN, RI_BLUE_EGG_CLANKERS_CAVERN, NULL, 14862, 3649, -17), - RC(RC_CC_BLUE_EGG_NEAR_SNIPPETS_3, RCTYPE_BLUE_EGG, LEVEL_3_CLANKERS_CAVERN, RI_BLUE_EGG_CLANKERS_CAVERN, NULL, 14651, 3649, -20), - RC(RC_CC_BLUE_EGG_NEAR_SNIPPETS_4, RCTYPE_BLUE_EGG, LEVEL_3_CLANKERS_CAVERN, RI_BLUE_EGG_CLANKERS_CAVERN, NULL, 14437, 3649, -20), - RC(RC_CC_BLUE_EGG_NEAR_SNIPPETS_5, RCTYPE_BLUE_EGG, LEVEL_3_CLANKERS_CAVERN, RI_BLUE_EGG_CLANKERS_CAVERN, NULL, 14225, 3649, -20), - RC(RC_CC_BLUE_EGG_SLOW_SAWBLADES_EXIT_1, RCTYPE_BLUE_EGG, LEVEL_3_CLANKERS_CAVERN, RI_BLUE_EGG_CLANKERS_CAVERN, NULL, 0, 2392, 5200), - RC(RC_CC_BLUE_EGG_SLOW_SAWBLADES_EXIT_2, RCTYPE_BLUE_EGG, LEVEL_3_CLANKERS_CAVERN, RI_BLUE_EGG_CLANKERS_CAVERN, NULL, 0, 2293, 5276), - RC(RC_CC_BLUE_EGG_SLOW_SAWBLADES_EXIT_3, RCTYPE_BLUE_EGG, LEVEL_3_CLANKERS_CAVERN, RI_BLUE_EGG_CLANKERS_CAVERN, NULL, 0, 2197, 5350), - RC(RC_CC_BLUE_EGG_SLOW_SAWBLADES_EXIT_4, RCTYPE_BLUE_EGG, LEVEL_3_CLANKERS_CAVERN, RI_BLUE_EGG_CLANKERS_CAVERN, NULL, 0, 2099, 5425), - RC(RC_CC_BLUE_EGG_UNDERWATER_PIPE_1, RCTYPE_BLUE_EGG, LEVEL_3_CLANKERS_CAVERN, RI_BLUE_EGG_CLANKERS_CAVERN, NULL, 3854, 1202, -532), - RC(RC_CC_BLUE_EGG_UNDERWATER_PIPE_2, RCTYPE_BLUE_EGG, LEVEL_3_CLANKERS_CAVERN, RI_BLUE_EGG_CLANKERS_CAVERN, NULL, 3692, 1202, -356), - RC(RC_CC_BLUE_EGG_UNDERWATER_PIPE_3, RCTYPE_BLUE_EGG, LEVEL_3_CLANKERS_CAVERN, RI_BLUE_EGG_CLANKERS_CAVERN, NULL, 3529, 1202, -182), - RC(RC_CC_BLUE_EGG_UNDERWATER_PIPE_4, RCTYPE_BLUE_EGG, LEVEL_3_CLANKERS_CAVERN, RI_BLUE_EGG_CLANKERS_CAVERN, NULL, 3369, 1207, -10), - RC(RC_CC_BLUE_EGG_UNDERWATER_PIPE_5, RCTYPE_BLUE_EGG, LEVEL_3_CLANKERS_CAVERN, RI_BLUE_EGG_CLANKERS_CAVERN, NULL, 3206, 1202, 165), - RC(RC_CC_BLUE_EGG_YELLOW_GRATE_1, RCTYPE_BLUE_EGG, LEVEL_3_CLANKERS_CAVERN, RI_BLUE_EGG_CLANKERS_CAVERN, NULL, 4271, 5261, -2936), - RC(RC_CC_BLUE_EGG_YELLOW_GRATE_2, RCTYPE_BLUE_EGG, LEVEL_3_CLANKERS_CAVERN, RI_BLUE_EGG_CLANKERS_CAVERN, NULL, 3247, 5262, -2842), + RC(RC_CC_BLUE_EGG_ABOVEWATER_PIPE_1, RCTYPE_BLUE_EGG, LEVEL_3_CLANKERS_CAVERN, RI_BLUE_EGG, NULL, 6379, 5087, 2586), + RC(RC_CC_BLUE_EGG_ABOVEWATER_PIPE_2, RCTYPE_BLUE_EGG, LEVEL_3_CLANKERS_CAVERN, RI_BLUE_EGG, NULL, 6582, 5047, 2536), + RC(RC_CC_BLUE_EGG_ABOVEWATER_PIPE_3, RCTYPE_BLUE_EGG, LEVEL_3_CLANKERS_CAVERN, RI_BLUE_EGG, NULL, 6785, 4876, 2454), + RC(RC_CC_BLUE_EGG_ABOVEWATER_PIPE_4, RCTYPE_BLUE_EGG, LEVEL_3_CLANKERS_CAVERN, RI_BLUE_EGG, NULL, 6989, 4703, 2388), + RC(RC_CC_BLUE_EGG_ABOVEWATER_PIPE_5, RCTYPE_BLUE_EGG, LEVEL_3_CLANKERS_CAVERN, RI_BLUE_EGG, NULL, 7194, 4526, 2321), + RC(RC_CC_BLUE_EGG_ALCOVE_WITH_OPEN_GRATE_1, RCTYPE_BLUE_EGG, LEVEL_3_CLANKERS_CAVERN, RI_BLUE_EGG, NULL, 2588, 5456, 2596), + RC(RC_CC_BLUE_EGG_ALCOVE_WITH_OPEN_GRATE_2, RCTYPE_BLUE_EGG, LEVEL_3_CLANKERS_CAVERN, RI_BLUE_EGG, NULL, 2494, 5456, 2556), + RC(RC_CC_BLUE_EGG_ENTRANCE_1, RCTYPE_BLUE_EGG, LEVEL_3_CLANKERS_CAVERN, RI_BLUE_EGG, NULL, -5274, 3269, -270), + RC(RC_CC_BLUE_EGG_ENTRANCE_2, RCTYPE_BLUE_EGG, LEVEL_3_CLANKERS_CAVERN, RI_BLUE_EGG, NULL, -4937, 3221, -597), + RC(RC_CC_BLUE_EGG_ENTRANCE_3, RCTYPE_BLUE_EGG, LEVEL_3_CLANKERS_CAVERN, RI_BLUE_EGG, NULL, -4492, 3113, -449), + RC(RC_CC_BLUE_EGG_ENTRANCE_4, RCTYPE_BLUE_EGG, LEVEL_3_CLANKERS_CAVERN, RI_BLUE_EGG, NULL, -4392, 3051, -27), + RC(RC_CC_BLUE_EGG_ENTRANCE_5, RCTYPE_BLUE_EGG, LEVEL_3_CLANKERS_CAVERN, RI_BLUE_EGG, NULL, -4722, 3104, 299), + RC(RC_CC_BLUE_EGG_ENTRANCE_6, RCTYPE_BLUE_EGG, LEVEL_3_CLANKERS_CAVERN, RI_BLUE_EGG, NULL, -5159, 3232, 178), + RC(RC_CC_BLUE_EGG_LEDGE_NEAR_CHOMPA_1, RCTYPE_BLUE_EGG, LEVEL_3_CLANKERS_CAVERN, RI_BLUE_EGG, NULL, 2293, 3662, 2354), + RC(RC_CC_BLUE_EGG_LEDGE_NEAR_CHOMPA_2, RCTYPE_BLUE_EGG, LEVEL_3_CLANKERS_CAVERN, RI_BLUE_EGG, NULL, 2360, 3662, 2231), + RC(RC_CC_BLUE_EGG_LEDGE_NEAR_CHOMPA_3, RCTYPE_BLUE_EGG, LEVEL_3_CLANKERS_CAVERN, RI_BLUE_EGG, NULL, 2329, 3662, 2107), + RC(RC_CC_BLUE_EGG_LEDGE_NEAR_CHOMPA_4, RCTYPE_BLUE_EGG, LEVEL_3_CLANKERS_CAVERN, RI_BLUE_EGG, NULL, 2216, 3662, 2018), + RC(RC_CC_BLUE_EGG_LEDGE_NEAR_CHOMPA_5, RCTYPE_BLUE_EGG, LEVEL_3_CLANKERS_CAVERN, RI_BLUE_EGG, NULL, 2094, 3662, 1968), + RC(RC_CC_BLUE_EGG_LEDGE_NEAR_CHOMPA_6, RCTYPE_BLUE_EGG, LEVEL_3_CLANKERS_CAVERN, RI_BLUE_EGG, NULL, 1970, 3662, 1998), + RC(RC_CC_BLUE_EGG_LEDGE_NEAR_CHOMPA_7, RCTYPE_BLUE_EGG, LEVEL_3_CLANKERS_CAVERN, RI_BLUE_EGG, NULL, 1895, 3662, 2117), + RC(RC_CC_BLUE_EGG_NEAR_RINGS_1, RCTYPE_BLUE_EGG, LEVEL_3_CLANKERS_CAVERN, RI_BLUE_EGG, NULL, -390, -116, 1316), + RC(RC_CC_BLUE_EGG_NEAR_RINGS_2, RCTYPE_BLUE_EGG, LEVEL_3_CLANKERS_CAVERN, RI_BLUE_EGG, NULL, -476, -192, 480), + RC(RC_CC_BLUE_EGG_NEAR_RINGS_3, RCTYPE_BLUE_EGG, LEVEL_3_CLANKERS_CAVERN, RI_BLUE_EGG, NULL, -433, -214, -453), + RC(RC_CC_BLUE_EGG_NEAR_RINGS_4, RCTYPE_BLUE_EGG, LEVEL_3_CLANKERS_CAVERN, RI_BLUE_EGG, NULL, -390, -160, -1300), + RC(RC_CC_BLUE_EGG_NEAR_RINGS_5, RCTYPE_BLUE_EGG, LEVEL_3_CLANKERS_CAVERN, RI_BLUE_EGG, NULL, 391, -160, -1300), + RC(RC_CC_BLUE_EGG_NEAR_RINGS_6, RCTYPE_BLUE_EGG, LEVEL_3_CLANKERS_CAVERN, RI_BLUE_EGG, NULL, 434, -214, -453), + RC(RC_CC_BLUE_EGG_NEAR_RINGS_7, RCTYPE_BLUE_EGG, LEVEL_3_CLANKERS_CAVERN, RI_BLUE_EGG, NULL, 476, -192, 480), + RC(RC_CC_BLUE_EGG_NEAR_RINGS_8, RCTYPE_BLUE_EGG, LEVEL_3_CLANKERS_CAVERN, RI_BLUE_EGG, NULL, 389, -116, 1316), + RC(RC_CC_BLUE_EGG_NEAR_SNIPPETS_1, RCTYPE_BLUE_EGG, LEVEL_3_CLANKERS_CAVERN, RI_BLUE_EGG, NULL, 15075, 3648, -20), + RC(RC_CC_BLUE_EGG_NEAR_SNIPPETS_2, RCTYPE_BLUE_EGG, LEVEL_3_CLANKERS_CAVERN, RI_BLUE_EGG, NULL, 14862, 3649, -17), + RC(RC_CC_BLUE_EGG_NEAR_SNIPPETS_3, RCTYPE_BLUE_EGG, LEVEL_3_CLANKERS_CAVERN, RI_BLUE_EGG, NULL, 14651, 3649, -20), + RC(RC_CC_BLUE_EGG_NEAR_SNIPPETS_4, RCTYPE_BLUE_EGG, LEVEL_3_CLANKERS_CAVERN, RI_BLUE_EGG, NULL, 14437, 3649, -20), + RC(RC_CC_BLUE_EGG_NEAR_SNIPPETS_5, RCTYPE_BLUE_EGG, LEVEL_3_CLANKERS_CAVERN, RI_BLUE_EGG, NULL, 14225, 3649, -20), + RC(RC_CC_BLUE_EGG_SLOW_SAWBLADES_EXIT_1, RCTYPE_BLUE_EGG, LEVEL_3_CLANKERS_CAVERN, RI_BLUE_EGG, NULL, 0, 2392, 5200), + RC(RC_CC_BLUE_EGG_SLOW_SAWBLADES_EXIT_2, RCTYPE_BLUE_EGG, LEVEL_3_CLANKERS_CAVERN, RI_BLUE_EGG, NULL, 0, 2293, 5276), + RC(RC_CC_BLUE_EGG_SLOW_SAWBLADES_EXIT_3, RCTYPE_BLUE_EGG, LEVEL_3_CLANKERS_CAVERN, RI_BLUE_EGG, NULL, 0, 2197, 5350), + RC(RC_CC_BLUE_EGG_SLOW_SAWBLADES_EXIT_4, RCTYPE_BLUE_EGG, LEVEL_3_CLANKERS_CAVERN, RI_BLUE_EGG, NULL, 0, 2099, 5425), + RC(RC_CC_BLUE_EGG_UNDERWATER_PIPE_1, RCTYPE_BLUE_EGG, LEVEL_3_CLANKERS_CAVERN, RI_BLUE_EGG, NULL, 3854, 1202, -532), + RC(RC_CC_BLUE_EGG_UNDERWATER_PIPE_2, RCTYPE_BLUE_EGG, LEVEL_3_CLANKERS_CAVERN, RI_BLUE_EGG, NULL, 3692, 1202, -356), + RC(RC_CC_BLUE_EGG_UNDERWATER_PIPE_3, RCTYPE_BLUE_EGG, LEVEL_3_CLANKERS_CAVERN, RI_BLUE_EGG, NULL, 3529, 1202, -182), + RC(RC_CC_BLUE_EGG_UNDERWATER_PIPE_4, RCTYPE_BLUE_EGG, LEVEL_3_CLANKERS_CAVERN, RI_BLUE_EGG, NULL, 3369, 1207, -10), + RC(RC_CC_BLUE_EGG_UNDERWATER_PIPE_5, RCTYPE_BLUE_EGG, LEVEL_3_CLANKERS_CAVERN, RI_BLUE_EGG, NULL, 3206, 1202, 165), + RC(RC_CC_BLUE_EGG_YELLOW_GRATE_1, RCTYPE_BLUE_EGG, LEVEL_3_CLANKERS_CAVERN, RI_BLUE_EGG, NULL, 4271, 5261, -2936), + RC(RC_CC_BLUE_EGG_YELLOW_GRATE_2, RCTYPE_BLUE_EGG, LEVEL_3_CLANKERS_CAVERN, RI_BLUE_EGG, NULL, 3247, 5262, -2842), RC(RC_CC_EMPTY_HONEYCOMB_ABOVEWATER, RCTYPE_EMPTY_HONEYCOMB, LEVEL_3_CLANKERS_CAVERN, RI_EMPTY_HONEYCOMB_CLANKERS_CAVERN, HONEYCOMB_6_CC_ABOVE_WATER, 7886, 4272, 1969), RC(RC_CC_EMPTY_HONEYCOMB_UNDERWATER, RCTYPE_EMPTY_HONEYCOMB, LEVEL_3_CLANKERS_CAVERN, RI_EMPTY_HONEYCOMB_CLANKERS_CAVERN, HONEYCOMB_5_CC_UNDERWATER, 3718, 3311, 2519), - RC(RC_CC_EXTRA_LIFE_CLANKERS_LEFT_FIN, RCTYPE_EXTRA_LIFE, LEVEL_3_CLANKERS_CAVERN, RI_EXTRA_LIFE_CLANKERS_CAVERN, NULL, 4570, 3727, 2783), - RC(RC_CC_EXTRA_LIFE_JINJO_PIPE, RCTYPE_EXTRA_LIFE, LEVEL_3_CLANKERS_CAVERN, RI_EXTRA_LIFE_CLANKERS_CAVERN, NULL, 7309, 4267, 2286), - RC(RC_CC_EXTRA_LIFE_YELLOW_GRATE, RCTYPE_EXTRA_LIFE, LEVEL_3_CLANKERS_CAVERN, RI_EXTRA_LIFE_CLANKERS_CAVERN, NULL, 1752, 5270, -2214), - RC(RC_CC_HONEYCOMB_BEEHIVE_INSIDE_CLANKER_1, RCTYPE_HONEYCOMB, LEVEL_3_CLANKERS_CAVERN, RI_HONEYCOMB_CLANKERS_CAVERN, NULL, 0, 0, 0), - RC(RC_CC_HONEYCOMB_BEEHIVE_INSIDE_CLANKER_2, RCTYPE_HONEYCOMB, LEVEL_3_CLANKERS_CAVERN, RI_HONEYCOMB_CLANKERS_CAVERN, NULL, 0, 0, 0), - RC(RC_CC_HONEYCOMB_BEEHIVE_INSIDE_CLANKER_3, RCTYPE_HONEYCOMB, LEVEL_3_CLANKERS_CAVERN, RI_HONEYCOMB_CLANKERS_CAVERN, NULL, 0, 0, 0), - RC(RC_CC_HONEYCOMB_BEEHIVE_NEAR_THE_ENTRANCE_1, RCTYPE_HONEYCOMB, LEVEL_3_CLANKERS_CAVERN, RI_HONEYCOMB_CLANKERS_CAVERN, NULL, 0, 0, 0), - RC(RC_CC_HONEYCOMB_BEEHIVE_NEAR_THE_ENTRANCE_2, RCTYPE_HONEYCOMB, LEVEL_3_CLANKERS_CAVERN, RI_HONEYCOMB_CLANKERS_CAVERN, NULL, 0, 0, 0), - RC(RC_CC_HONEYCOMB_BEEHIVE_NEAR_THE_ENTRANCE_3, RCTYPE_HONEYCOMB, LEVEL_3_CLANKERS_CAVERN, RI_HONEYCOMB_CLANKERS_CAVERN, NULL, 0, 0, 0), - RC(RC_CC_HONEYCOMB_BEEHIVE_NEAR_THE_YELLOW_GRATES_1, RCTYPE_HONEYCOMB, LEVEL_3_CLANKERS_CAVERN, RI_HONEYCOMB_CLANKERS_CAVERN, NULL, 0, 0, 0), - RC(RC_CC_HONEYCOMB_BEEHIVE_NEAR_THE_YELLOW_GRATES_2, RCTYPE_HONEYCOMB, LEVEL_3_CLANKERS_CAVERN, RI_HONEYCOMB_CLANKERS_CAVERN, NULL, 0, 0, 0), - RC(RC_CC_HONEYCOMB_BEEHIVE_NEAR_THE_YELLOW_GRATES_3, RCTYPE_HONEYCOMB, LEVEL_3_CLANKERS_CAVERN, RI_HONEYCOMB_CLANKERS_CAVERN, NULL, 0, 0, 0), + RC(RC_CC_EXTRA_LIFE_CLANKERS_LEFT_FIN, RCTYPE_EXTRA_LIFE, LEVEL_3_CLANKERS_CAVERN, RI_EXTRA_LIFE, NULL, 4570, 3727, 2783), + RC(RC_CC_EXTRA_LIFE_JINJO_PIPE, RCTYPE_EXTRA_LIFE, LEVEL_3_CLANKERS_CAVERN, RI_EXTRA_LIFE, NULL, 7309, 4267, 2286), + RC(RC_CC_EXTRA_LIFE_YELLOW_GRATE, RCTYPE_EXTRA_LIFE, LEVEL_3_CLANKERS_CAVERN, RI_EXTRA_LIFE, NULL, 1752, 5270, -2214), + RC(RC_CC_HONEYCOMB_BEEHIVE_INSIDE_CLANKER_1, RCTYPE_HONEYCOMB, LEVEL_3_CLANKERS_CAVERN, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_CC_HONEYCOMB_BEEHIVE_INSIDE_CLANKER_2, RCTYPE_HONEYCOMB, LEVEL_3_CLANKERS_CAVERN, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_CC_HONEYCOMB_BEEHIVE_INSIDE_CLANKER_3, RCTYPE_HONEYCOMB, LEVEL_3_CLANKERS_CAVERN, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_CC_HONEYCOMB_BEEHIVE_NEAR_THE_ENTRANCE_1, RCTYPE_HONEYCOMB, LEVEL_3_CLANKERS_CAVERN, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_CC_HONEYCOMB_BEEHIVE_NEAR_THE_ENTRANCE_2, RCTYPE_HONEYCOMB, LEVEL_3_CLANKERS_CAVERN, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_CC_HONEYCOMB_BEEHIVE_NEAR_THE_ENTRANCE_3, RCTYPE_HONEYCOMB, LEVEL_3_CLANKERS_CAVERN, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_CC_HONEYCOMB_BEEHIVE_NEAR_THE_YELLOW_GRATES_1, RCTYPE_HONEYCOMB, LEVEL_3_CLANKERS_CAVERN, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_CC_HONEYCOMB_BEEHIVE_NEAR_THE_YELLOW_GRATES_2, RCTYPE_HONEYCOMB, LEVEL_3_CLANKERS_CAVERN, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_CC_HONEYCOMB_BEEHIVE_NEAR_THE_YELLOW_GRATES_3, RCTYPE_HONEYCOMB, LEVEL_3_CLANKERS_CAVERN, RI_HONEYCOMB, NULL, 0, 0, 0), RC(RC_CC_JIGGY_BOLT, RCTYPE_JIGGY, LEVEL_3_CLANKERS_CAVERN, RI_JIGGY_CLANKERS_CAVERN, JIGGY_18_CC_BOLT, 90, 5962, -12), RC(RC_CC_JIGGY_CLANKER_RAISED, RCTYPE_JIGGY, LEVEL_3_CLANKERS_CAVERN, RI_JIGGY_CLANKERS_CAVERN, JIGGY_17_CC_CLANKER_RAISED, 0, 0, 0), RC(RC_CC_JIGGY_FAST_SAWBLADES, RCTYPE_JIGGY, LEVEL_3_CLANKERS_CAVERN, RI_JIGGY_CLANKERS_CAVERN, JIGGY_1E_CC_FAST_SAWBLADES, 0, -340, -1604), @@ -398,164 +398,164 @@ std::map Checks = { RC(RC_CC_NOTE_UNDERWATER_PIPE_7, RCTYPE_MUSIC_NOTE, LEVEL_3_CLANKERS_CAVERN, RI_MUSIC_NOTE_CLANKERS_CAVERN, NULL, 6804, 1184, 2361), RC(RC_CC_NOTE_YELLOW_GRATE_1, RCTYPE_MUSIC_NOTE, LEVEL_3_CLANKERS_CAVERN, RI_MUSIC_NOTE_CLANKERS_CAVERN, NULL, 2240, 5262, -2473), RC(RC_CC_NOTE_YELLOW_GRATE_2, RCTYPE_MUSIC_NOTE, LEVEL_3_CLANKERS_CAVERN, RI_MUSIC_NOTE_CLANKERS_CAVERN, NULL, 5270, 5261, -2937), - RC(RC_CCW_BLUE_EGG_AUTUMN_GNAWTYS_INTERIOR_1, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG_CLICK_CLOCK_WOOD, NULL, 825, 758, 531), - RC(RC_CCW_BLUE_EGG_AUTUMN_GNAWTYS_INTERIOR_2, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG_CLICK_CLOCK_WOOD, NULL, 682, 758, 583), - RC(RC_CCW_BLUE_EGG_AUTUMN_GNAWTYS_INTERIOR_3, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG_CLICK_CLOCK_WOOD, NULL, 536, 758, 628), - RC(RC_CCW_BLUE_EGG_AUTUMN_LEAF_NEAR_ENTRANCE_1, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG_CLICK_CLOCK_WOOD, NULL, -113, 304, 3001), - RC(RC_CCW_BLUE_EGG_AUTUMN_LEAF_NEAR_ENTRANCE_2, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG_CLICK_CLOCK_WOOD, NULL, 115, 605, 3001), - RC(RC_CCW_BLUE_EGG_AUTUMN_NABNUTS_WINDOW_INTERIOR_1, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG_CLICK_CLOCK_WOOD, NULL, -170, 0, -700), - RC(RC_CCW_BLUE_EGG_AUTUMN_NABNUTS_WINDOW_INTERIOR_2, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG_CLICK_CLOCK_WOOD, NULL, 0, -20, -630), - RC(RC_CCW_BLUE_EGG_AUTUMN_NABNUTS_WINDOW_INTERIOR_3, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG_CLICK_CLOCK_WOOD, NULL, 170, 0, -699), - RC(RC_CCW_BLUE_EGG_AUTUMN_NEAR_EYRIES_NEST_1, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG_CLICK_CLOCK_WOOD, NULL, -1362, 4419, 2014), - RC(RC_CCW_BLUE_EGG_AUTUMN_NEAR_EYRIES_NEST_2, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG_CLICK_CLOCK_WOOD, NULL, -1860, 4469, 1580), - RC(RC_CCW_BLUE_EGG_AUTUMN_NEAR_EYRIES_NEST_3, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG_CLICK_CLOCK_WOOD, NULL, -2181, 4519, 1118), - RC(RC_CCW_BLUE_EGG_AUTUMN_NEAR_MUMBOS_SKULL_1, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG_CLICK_CLOCK_WOOD, NULL, -5700, 40, -1000), - RC(RC_CCW_BLUE_EGG_AUTUMN_NEAR_MUMBOS_SKULL_2, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG_CLICK_CLOCK_WOOD, NULL, -5500, 40, -500), - RC(RC_CCW_BLUE_EGG_AUTUMN_NEAR_MUMBOS_SKULL_3, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG_CLICK_CLOCK_WOOD, NULL, -5350, 40, 0), - RC(RC_CCW_BLUE_EGG_AUTUMN_NEAR_TREEHOUSE_1, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG_CLICK_CLOCK_WOOD, NULL, 3513, 4102, -541), - RC(RC_CCW_BLUE_EGG_AUTUMN_NEAR_TREEHOUSE_2, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG_CLICK_CLOCK_WOOD, NULL, 3595, 4104, 478), - RC(RC_CCW_BLUE_EGG_AUTUMN_TOP_OF_BRANCH_1, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG_CLICK_CLOCK_WOOD, NULL, -3615, 2773, 1411), - RC(RC_CCW_BLUE_EGG_AUTUMN_TOP_OF_BRANCH_2, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG_CLICK_CLOCK_WOOD, NULL, -4356, 2821, 356), - RC(RC_CCW_BLUE_EGG_AUTUMN_TOP_OF_BRANCH_3, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG_CLICK_CLOCK_WOOD, NULL, -4920, 2778, 1222), - RC(RC_CCW_BLUE_EGG_AUTUMN_TOP_OF_BRANCH_4, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG_CLICK_CLOCK_WOOD, NULL, -3735, 2828, -787), - RC(RC_CCW_BLUE_EGG_AUTUMN_TOP_OF_BRANCH_5, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG_CLICK_CLOCK_WOOD, NULL, -4431, 2830, -882), - RC(RC_CCW_BLUE_EGG_AUTUMN_TOP_OF_BRANCH_6, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG_CLICK_CLOCK_WOOD, NULL, -5370, 2882, -787), - RC(RC_CCW_BLUE_EGG_ENTRANCE_HUB_1, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG_CLICK_CLOCK_WOOD, NULL, 3270, 103, -815), - RC(RC_CCW_BLUE_EGG_ENTRANCE_HUB_2, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG_CLICK_CLOCK_WOOD, NULL, 3483, 109, -341), - RC(RC_CCW_BLUE_EGG_ENTRANCE_HUB_3, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG_CLICK_CLOCK_WOOD, NULL, 3483, 99, 342), - RC(RC_CCW_BLUE_EGG_ENTRANCE_HUB_4, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG_CLICK_CLOCK_WOOD, NULL, 3270, 121, 815), - RC(RC_CCW_BLUE_EGG_SPRING_EYRIES_NEST_1, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG_CLICK_CLOCK_WOOD, NULL, -3930, 4900, 316), - RC(RC_CCW_BLUE_EGG_SPRING_EYRIES_NEST_2, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG_CLICK_CLOCK_WOOD, NULL, -4378, 4900, 764), - RC(RC_CCW_BLUE_EGG_SPRING_EYRIES_NEST_3, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG_CLICK_CLOCK_WOOD, NULL, -5018, 4900, 773), - RC(RC_CCW_BLUE_EGG_SPRING_EYRIES_NEST_4, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG_CLICK_CLOCK_WOOD, NULL, -5468, 4900, 314), - RC(RC_CCW_BLUE_EGG_SPRING_EYRIES_NEST_5, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG_CLICK_CLOCK_WOOD, NULL, -5468, 4900, -315), - RC(RC_CCW_BLUE_EGG_SPRING_EYRIES_NEST_6, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG_CLICK_CLOCK_WOOD, NULL, -5018, 4900, -773), - RC(RC_CCW_BLUE_EGG_SPRING_EYRIES_NEST_7, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG_CLICK_CLOCK_WOOD, NULL, -4378, 4900, -764), - RC(RC_CCW_BLUE_EGG_SPRING_EYRIES_NEST_8, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG_CLICK_CLOCK_WOOD, NULL, -3930, 4900, -315), - RC(RC_CCW_BLUE_EGG_SPRING_INSIDE_MUMBOS_SKULL_1, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG_CLICK_CLOCK_WOOD, NULL, 510, 387, 0), - RC(RC_CCW_BLUE_EGG_SPRING_INSIDE_MUMBOS_SKULL_2, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG_CLICK_CLOCK_WOOD, NULL, 0, 398, 520), - RC(RC_CCW_BLUE_EGG_SPRING_INSIDE_MUMBOS_SKULL_3, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG_CLICK_CLOCK_WOOD, NULL, 0, 398, -520), - RC(RC_CCW_BLUE_EGG_SPRING_INSIDE_NABNUTS_HOUSE_1, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG_CLICK_CLOCK_WOOD, NULL, 472, 413, -237), - RC(RC_CCW_BLUE_EGG_SPRING_INSIDE_NABNUTS_HOUSE_2, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG_CLICK_CLOCK_WOOD, NULL, 383, 413, -295), - RC(RC_CCW_BLUE_EGG_SPRING_INSIDE_NABNUTS_HOUSE_3, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG_CLICK_CLOCK_WOOD, NULL, 287, 413, -357), - RC(RC_CCW_BLUE_EGG_SPRING_LOWER_TREE_LEDGE_1, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG_CLICK_CLOCK_WOOD, NULL, 975, 900, 2573), - RC(RC_CCW_BLUE_EGG_SPRING_LOWER_TREE_LEDGE_2, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG_CLICK_CLOCK_WOOD, NULL, 2566, 900, 968), - RC(RC_CCW_BLUE_EGG_SPRING_LOWER_TREE_LEDGE_3, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG_CLICK_CLOCK_WOOD, NULL, 2568, 900, -968), - RC(RC_CCW_BLUE_EGG_SPRING_LOWER_TREE_LEDGE_4, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG_CLICK_CLOCK_WOOD, NULL, 1950, 900, -1949), - RC(RC_CCW_BLUE_EGG_SPRING_LOWER_TREE_LEDGE_5, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG_CLICK_CLOCK_WOOD, NULL, 975, 900, -2574), - RC(RC_CCW_BLUE_EGG_SPRING_LOWER_TREE_LEDGE_6, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG_CLICK_CLOCK_WOOD, NULL, -50, 1050, -2750), - RC(RC_CCW_BLUE_EGG_SPRING_LOWER_TREE_LEDGE_7, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG_CLICK_CLOCK_WOOD, NULL, -975, 900, -2575), - RC(RC_CCW_BLUE_EGG_SPRING_LOWER_TREE_LEDGE_8, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG_CLICK_CLOCK_WOOD, NULL, -2579, 1100, -980), - RC(RC_CCW_BLUE_EGG_SPRING_LOWER_TREE_LEDGE_9, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG_CLICK_CLOCK_WOOD, NULL, -2579, 900, 980), - RC(RC_CCW_BLUE_EGG_SPRING_LOWER_TREE_LEDGE_10, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG_CLICK_CLOCK_WOOD, NULL, -977, 900, 2573), - RC(RC_CCW_BLUE_EGG_SPRING_NEAR_BEEHIVE_1, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG_CLICK_CLOCK_WOOD, NULL, -2140, 2938, -1157), - RC(RC_CCW_BLUE_EGG_SPRING_NEAR_BEEHIVE_2, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG_CLICK_CLOCK_WOOD, NULL, -1696, 3050, -1731), - RC(RC_CCW_BLUE_EGG_SPRING_NEAR_BEEHIVE_3, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG_CLICK_CLOCK_WOOD, NULL, -1072, 3157, -2180), - RC(RC_CCW_BLUE_EGG_SPRING_NEAR_BEEHIVE_4, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG_CLICK_CLOCK_WOOD, NULL, 790, 3300, -2345), - RC(RC_CCW_BLUE_EGG_SPRING_NEAR_BEEHIVE_5, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG_CLICK_CLOCK_WOOD, NULL, 1427, 3300, -1995), - RC(RC_CCW_BLUE_EGG_SPRING_NEAR_BEEHIVE_6, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG_CLICK_CLOCK_WOOD, NULL, 1873, 3899, -1580), - RC(RC_CCW_BLUE_EGG_SPRING_NEAR_BEEHIVE_7, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG_CLICK_CLOCK_WOOD, NULL, 2267, 3963, -1018), - RC(RC_CCW_BLUE_EGG_SPRING_NEAR_BEEHIVE_8, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG_CLICK_CLOCK_WOOD, NULL, 2450, 4019, -394), - RC(RC_CCW_BLUE_EGG_SPRING_NEAR_GNAWTYS_HOUSE_1, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG_CLICK_CLOCK_WOOD, NULL, 4366, -599, -311), - RC(RC_CCW_BLUE_EGG_SPRING_NEAR_GNAWTYS_HOUSE_2, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG_CLICK_CLOCK_WOOD, NULL, 5404, -593, -734), - RC(RC_CCW_BLUE_EGG_SPRING_NEAR_GNAWTYS_HOUSE_3, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG_CLICK_CLOCK_WOOD, NULL, 5831, -589, 301), - RC(RC_CCW_BLUE_EGG_SPRING_NEAR_GNAWTYS_HOUSE_4, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG_CLICK_CLOCK_WOOD, NULL, 4769, -600, 726), - RC(RC_CCW_BLUE_EGG_SPRING_UNFINISHED_BRIDGE_1, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG_CLICK_CLOCK_WOOD, NULL, 4302, 3719, 583), - RC(RC_CCW_BLUE_EGG_SPRING_UNFINISHED_BRIDGE_2, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG_CLICK_CLOCK_WOOD, NULL, 4214, 3719, 1076), - RC(RC_CCW_BLUE_EGG_SPRING_UNFINISHED_BRIDGE_3, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG_CLICK_CLOCK_WOOD, NULL, 3653, 3719, 1587), - RC(RC_CCW_BLUE_EGG_SPRING_UNFINISHED_BRIDGE_4, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG_CLICK_CLOCK_WOOD, NULL, 3080, 3719, 2063), - RC(RC_CCW_BLUE_EGG_SUMMER_NEAR_BIG_FLOWER_1, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG_CLICK_CLOCK_WOOD, NULL, -633, 5, -4826), - RC(RC_CCW_BLUE_EGG_SUMMER_NEAR_BIG_FLOWER_2, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG_CLICK_CLOCK_WOOD, NULL, -727, 5, -5426), - RC(RC_CCW_BLUE_EGG_SUMMER_NEAR_BIG_FLOWER_3, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG_CLICK_CLOCK_WOOD, NULL, -635, 5, -6006), - RC(RC_CCW_BLUE_EGG_SUMMER_NEAR_BIG_FLOWER_4, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG_CLICK_CLOCK_WOOD, NULL, 9, 5, -6099), - RC(RC_CCW_BLUE_EGG_SUMMER_NEAR_BIG_FLOWER_5, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG_CLICK_CLOCK_WOOD, NULL, 634, 5, -6008), - RC(RC_CCW_BLUE_EGG_SUMMER_NEAR_BIG_FLOWER_6, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG_CLICK_CLOCK_WOOD, NULL, 726, 5, -5426), - RC(RC_CCW_BLUE_EGG_SUMMER_NEAR_BIG_FLOWER_7, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG_CLICK_CLOCK_WOOD, NULL, 636, 5, -4834), - RC(RC_CCW_BLUE_EGG_SUMMER_NEAR_BIG_FLOWER_8, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG_CLICK_CLOCK_WOOD, NULL, 9, 5, -4734), - RC(RC_CCW_BLUE_EGG_SUMMER_NEAR_MUMBOS_SKULL_1, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG_CLICK_CLOCK_WOOD, NULL, -4815, 125, 200), - RC(RC_CCW_BLUE_EGG_SUMMER_NEAR_MUMBOS_SKULL_2, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG_CLICK_CLOCK_WOOD, NULL, -4930, 125, 0), - RC(RC_CCW_BLUE_EGG_SUMMER_NEAR_MUMBOS_SKULL_3, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG_CLICK_CLOCK_WOOD, NULL, -4815, 125, -201), - RC(RC_CCW_BLUE_EGG_SUMMER_NEAR_MUMBOS_SKULL_4, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG_CLICK_CLOCK_WOOD, NULL, -4585, 125, -200), - RC(RC_CCW_BLUE_EGG_SUMMER_NEAR_MUMBOS_SKULL_5, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG_CLICK_CLOCK_WOOD, NULL, -4470, 125, 0), - RC(RC_CCW_BLUE_EGG_SUMMER_NEAR_MUMBOS_SKULL_6, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG_CLICK_CLOCK_WOOD, NULL, -4585, 125, 200), - RC(RC_CCW_BLUE_EGG_SUMMER_NEAR_NABNUTS_HOUSE_1, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG_CLICK_CLOCK_WOOD, NULL, -1153, 4019, 4293), - RC(RC_CCW_BLUE_EGG_SUMMER_NEAR_NABNUTS_HOUSE_2, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG_CLICK_CLOCK_WOOD, NULL, -1284, 4019, 4611), - RC(RC_CCW_BLUE_EGG_SUMMER_NEAR_NABNUTS_HOUSE_3, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG_CLICK_CLOCK_WOOD, NULL, -1599, 4019, 4747), - RC(RC_CCW_BLUE_EGG_SUMMER_NEAR_NABNUTS_HOUSE_4, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG_CLICK_CLOCK_WOOD, NULL, -2047, 4019, 4303), - RC(RC_CCW_BLUE_EGG_SUMMER_NEAR_NABNUTS_HOUSE_5, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG_CLICK_CLOCK_WOOD, NULL, -1920, 4019, 3996), - RC(RC_CCW_BLUE_EGG_SUMMER_NEAR_NABNUTS_HOUSE_6, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG_CLICK_CLOCK_WOOD, NULL, -1603, 4019, 3851), - RC(RC_CCW_BLUE_EGG_WINTER_INSIDE_NABNUTS_HOUSE_1, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG_CLICK_CLOCK_WOOD, NULL, -285, 513, -354), - RC(RC_CCW_BLUE_EGG_WINTER_INSIDE_NABNUTS_HOUSE_2, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG_CLICK_CLOCK_WOOD, NULL, -395, 513, -280), - RC(RC_CCW_BLUE_EGG_WINTER_INSIDE_NABNUTS_HOUSE_3, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG_CLICK_CLOCK_WOOD, NULL, -504, 513, -205), - RC(RC_CCW_BLUE_EGG_WINTER_INSIDE_NABNUTS_HOUSE_4, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG_CLICK_CLOCK_WOOD, NULL, -577, 513, -110), - RC(RC_CCW_BLUE_EGG_WINTER_INSIDE_NABNUTS_HOUSE_5, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG_CLICK_CLOCK_WOOD, NULL, -646, 513, -5), - RC(RC_CCW_BLUE_EGG_WINTER_NABNUTS_WINDOW_INTERIOR_1, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG_CLICK_CLOCK_WOOD, NULL, 253, -500, -621), - RC(RC_CCW_BLUE_EGG_WINTER_NABNUTS_WINDOW_INTERIOR_2, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG_CLICK_CLOCK_WOOD, NULL, 617, -499, -263), - RC(RC_CCW_BLUE_EGG_WINTER_NABNUTS_WINDOW_INTERIOR_3, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG_CLICK_CLOCK_WOOD, NULL, 621, -499, 254), - RC(RC_CCW_BLUE_EGG_WINTER_NABNUTS_WINDOW_INTERIOR_4, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG_CLICK_CLOCK_WOOD, NULL, 258, -500, 624), - RC(RC_CCW_BLUE_EGG_WINTER_NABNUTS_WINDOW_INTERIOR_5, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG_CLICK_CLOCK_WOOD, NULL, -254, -500, 621), - RC(RC_CCW_BLUE_EGG_WINTER_NABNUTS_WINDOW_INTERIOR_6, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG_CLICK_CLOCK_WOOD, NULL, -622, -499, 259), - RC(RC_CCW_BLUE_EGG_WINTER_NABNUTS_WINDOW_INTERIOR_7, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG_CLICK_CLOCK_WOOD, NULL, -624, -499, -254), - RC(RC_CCW_BLUE_EGG_WINTER_NABNUTS_WINDOW_INTERIOR_8, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG_CLICK_CLOCK_WOOD, NULL, -262, -500, -619), - RC(RC_CCW_BLUE_EGG_WINTER_WINDOW_ABOVE_NABNUT_1, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG_CLICK_CLOCK_WOOD, NULL, 244, 150, -509), - RC(RC_CCW_BLUE_EGG_WINTER_WINDOW_ABOVE_NABNUT_2, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG_CLICK_CLOCK_WOOD, NULL, 88, 250, 682), - RC(RC_CCW_BLUE_EGG_WINTER_WINDOW_ABOVE_NABNUT_3, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG_CLICK_CLOCK_WOOD, NULL, -531, 450, -430), + RC(RC_CCW_BLUE_EGG_AUTUMN_GNAWTYS_INTERIOR_1, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG, NULL, 825, 758, 531), + RC(RC_CCW_BLUE_EGG_AUTUMN_GNAWTYS_INTERIOR_2, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG, NULL, 682, 758, 583), + RC(RC_CCW_BLUE_EGG_AUTUMN_GNAWTYS_INTERIOR_3, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG, NULL, 536, 758, 628), + RC(RC_CCW_BLUE_EGG_AUTUMN_LEAF_NEAR_ENTRANCE_1, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG, NULL, -113, 304, 3001), + RC(RC_CCW_BLUE_EGG_AUTUMN_LEAF_NEAR_ENTRANCE_2, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG, NULL, 115, 605, 3001), + RC(RC_CCW_BLUE_EGG_AUTUMN_NABNUTS_WINDOW_INTERIOR_1, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG, NULL, -170, 0, -700), + RC(RC_CCW_BLUE_EGG_AUTUMN_NABNUTS_WINDOW_INTERIOR_2, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG, NULL, 0, -20, -630), + RC(RC_CCW_BLUE_EGG_AUTUMN_NABNUTS_WINDOW_INTERIOR_3, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG, NULL, 170, 0, -699), + RC(RC_CCW_BLUE_EGG_AUTUMN_NEAR_EYRIES_NEST_1, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG, NULL, -1362, 4419, 2014), + RC(RC_CCW_BLUE_EGG_AUTUMN_NEAR_EYRIES_NEST_2, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG, NULL, -1860, 4469, 1580), + RC(RC_CCW_BLUE_EGG_AUTUMN_NEAR_EYRIES_NEST_3, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG, NULL, -2181, 4519, 1118), + RC(RC_CCW_BLUE_EGG_AUTUMN_NEAR_MUMBOS_SKULL_1, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG, NULL, -5700, 40, -1000), + RC(RC_CCW_BLUE_EGG_AUTUMN_NEAR_MUMBOS_SKULL_2, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG, NULL, -5500, 40, -500), + RC(RC_CCW_BLUE_EGG_AUTUMN_NEAR_MUMBOS_SKULL_3, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG, NULL, -5350, 40, 0), + RC(RC_CCW_BLUE_EGG_AUTUMN_NEAR_TREEHOUSE_1, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG, NULL, 3513, 4102, -541), + RC(RC_CCW_BLUE_EGG_AUTUMN_NEAR_TREEHOUSE_2, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG, NULL, 3595, 4104, 478), + RC(RC_CCW_BLUE_EGG_AUTUMN_TOP_OF_BRANCH_1, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG, NULL, -3615, 2773, 1411), + RC(RC_CCW_BLUE_EGG_AUTUMN_TOP_OF_BRANCH_2, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG, NULL, -4356, 2821, 356), + RC(RC_CCW_BLUE_EGG_AUTUMN_TOP_OF_BRANCH_3, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG, NULL, -4920, 2778, 1222), + RC(RC_CCW_BLUE_EGG_AUTUMN_TOP_OF_BRANCH_4, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG, NULL, -3735, 2828, -787), + RC(RC_CCW_BLUE_EGG_AUTUMN_TOP_OF_BRANCH_5, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG, NULL, -4431, 2830, -882), + RC(RC_CCW_BLUE_EGG_AUTUMN_TOP_OF_BRANCH_6, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG, NULL, -5370, 2882, -787), + RC(RC_CCW_BLUE_EGG_ENTRANCE_HUB_1, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG, NULL, 3270, 103, -815), + RC(RC_CCW_BLUE_EGG_ENTRANCE_HUB_2, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG, NULL, 3483, 109, -341), + RC(RC_CCW_BLUE_EGG_ENTRANCE_HUB_3, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG, NULL, 3483, 99, 342), + RC(RC_CCW_BLUE_EGG_ENTRANCE_HUB_4, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG, NULL, 3270, 121, 815), + RC(RC_CCW_BLUE_EGG_SPRING_EYRIES_NEST_1, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG, NULL, -3930, 4900, 316), + RC(RC_CCW_BLUE_EGG_SPRING_EYRIES_NEST_2, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG, NULL, -4378, 4900, 764), + RC(RC_CCW_BLUE_EGG_SPRING_EYRIES_NEST_3, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG, NULL, -5018, 4900, 773), + RC(RC_CCW_BLUE_EGG_SPRING_EYRIES_NEST_4, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG, NULL, -5468, 4900, 314), + RC(RC_CCW_BLUE_EGG_SPRING_EYRIES_NEST_5, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG, NULL, -5468, 4900, -315), + RC(RC_CCW_BLUE_EGG_SPRING_EYRIES_NEST_6, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG, NULL, -5018, 4900, -773), + RC(RC_CCW_BLUE_EGG_SPRING_EYRIES_NEST_7, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG, NULL, -4378, 4900, -764), + RC(RC_CCW_BLUE_EGG_SPRING_EYRIES_NEST_8, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG, NULL, -3930, 4900, -315), + RC(RC_CCW_BLUE_EGG_SPRING_INSIDE_MUMBOS_SKULL_1, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG, NULL, 510, 387, 0), + RC(RC_CCW_BLUE_EGG_SPRING_INSIDE_MUMBOS_SKULL_2, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG, NULL, 0, 398, 520), + RC(RC_CCW_BLUE_EGG_SPRING_INSIDE_MUMBOS_SKULL_3, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG, NULL, 0, 398, -520), + RC(RC_CCW_BLUE_EGG_SPRING_INSIDE_NABNUTS_HOUSE_1, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG, NULL, 472, 413, -237), + RC(RC_CCW_BLUE_EGG_SPRING_INSIDE_NABNUTS_HOUSE_2, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG, NULL, 383, 413, -295), + RC(RC_CCW_BLUE_EGG_SPRING_INSIDE_NABNUTS_HOUSE_3, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG, NULL, 287, 413, -357), + RC(RC_CCW_BLUE_EGG_SPRING_LOWER_TREE_LEDGE_1, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG, NULL, 975, 900, 2573), + RC(RC_CCW_BLUE_EGG_SPRING_LOWER_TREE_LEDGE_2, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG, NULL, 2566, 900, 968), + RC(RC_CCW_BLUE_EGG_SPRING_LOWER_TREE_LEDGE_3, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG, NULL, 2568, 900, -968), + RC(RC_CCW_BLUE_EGG_SPRING_LOWER_TREE_LEDGE_4, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG, NULL, 1950, 900, -1949), + RC(RC_CCW_BLUE_EGG_SPRING_LOWER_TREE_LEDGE_5, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG, NULL, 975, 900, -2574), + RC(RC_CCW_BLUE_EGG_SPRING_LOWER_TREE_LEDGE_6, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG, NULL, -50, 1050, -2750), + RC(RC_CCW_BLUE_EGG_SPRING_LOWER_TREE_LEDGE_7, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG, NULL, -975, 900, -2575), + RC(RC_CCW_BLUE_EGG_SPRING_LOWER_TREE_LEDGE_8, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG, NULL, -2579, 1100, -980), + RC(RC_CCW_BLUE_EGG_SPRING_LOWER_TREE_LEDGE_9, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG, NULL, -2579, 900, 980), + RC(RC_CCW_BLUE_EGG_SPRING_LOWER_TREE_LEDGE_10, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG, NULL, -977, 900, 2573), + RC(RC_CCW_BLUE_EGG_SPRING_NEAR_BEEHIVE_1, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG, NULL, -2140, 2938, -1157), + RC(RC_CCW_BLUE_EGG_SPRING_NEAR_BEEHIVE_2, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG, NULL, -1696, 3050, -1731), + RC(RC_CCW_BLUE_EGG_SPRING_NEAR_BEEHIVE_3, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG, NULL, -1072, 3157, -2180), + RC(RC_CCW_BLUE_EGG_SPRING_NEAR_BEEHIVE_4, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG, NULL, 790, 3300, -2345), + RC(RC_CCW_BLUE_EGG_SPRING_NEAR_BEEHIVE_5, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG, NULL, 1427, 3300, -1995), + RC(RC_CCW_BLUE_EGG_SPRING_NEAR_BEEHIVE_6, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG, NULL, 1873, 3899, -1580), + RC(RC_CCW_BLUE_EGG_SPRING_NEAR_BEEHIVE_7, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG, NULL, 2267, 3963, -1018), + RC(RC_CCW_BLUE_EGG_SPRING_NEAR_BEEHIVE_8, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG, NULL, 2450, 4019, -394), + RC(RC_CCW_BLUE_EGG_SPRING_NEAR_GNAWTYS_HOUSE_1, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG, NULL, 4366, -599, -311), + RC(RC_CCW_BLUE_EGG_SPRING_NEAR_GNAWTYS_HOUSE_2, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG, NULL, 5404, -593, -734), + RC(RC_CCW_BLUE_EGG_SPRING_NEAR_GNAWTYS_HOUSE_3, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG, NULL, 5831, -589, 301), + RC(RC_CCW_BLUE_EGG_SPRING_NEAR_GNAWTYS_HOUSE_4, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG, NULL, 4769, -600, 726), + RC(RC_CCW_BLUE_EGG_SPRING_UNFINISHED_BRIDGE_1, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG, NULL, 4302, 3719, 583), + RC(RC_CCW_BLUE_EGG_SPRING_UNFINISHED_BRIDGE_2, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG, NULL, 4214, 3719, 1076), + RC(RC_CCW_BLUE_EGG_SPRING_UNFINISHED_BRIDGE_3, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG, NULL, 3653, 3719, 1587), + RC(RC_CCW_BLUE_EGG_SPRING_UNFINISHED_BRIDGE_4, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG, NULL, 3080, 3719, 2063), + RC(RC_CCW_BLUE_EGG_SUMMER_NEAR_BIG_FLOWER_1, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG, NULL, -633, 5, -4826), + RC(RC_CCW_BLUE_EGG_SUMMER_NEAR_BIG_FLOWER_2, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG, NULL, -727, 5, -5426), + RC(RC_CCW_BLUE_EGG_SUMMER_NEAR_BIG_FLOWER_3, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG, NULL, -635, 5, -6006), + RC(RC_CCW_BLUE_EGG_SUMMER_NEAR_BIG_FLOWER_4, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG, NULL, 9, 5, -6099), + RC(RC_CCW_BLUE_EGG_SUMMER_NEAR_BIG_FLOWER_5, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG, NULL, 634, 5, -6008), + RC(RC_CCW_BLUE_EGG_SUMMER_NEAR_BIG_FLOWER_6, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG, NULL, 726, 5, -5426), + RC(RC_CCW_BLUE_EGG_SUMMER_NEAR_BIG_FLOWER_7, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG, NULL, 636, 5, -4834), + RC(RC_CCW_BLUE_EGG_SUMMER_NEAR_BIG_FLOWER_8, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG, NULL, 9, 5, -4734), + RC(RC_CCW_BLUE_EGG_SUMMER_NEAR_MUMBOS_SKULL_1, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG, NULL, -4815, 125, 200), + RC(RC_CCW_BLUE_EGG_SUMMER_NEAR_MUMBOS_SKULL_2, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG, NULL, -4930, 125, 0), + RC(RC_CCW_BLUE_EGG_SUMMER_NEAR_MUMBOS_SKULL_3, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG, NULL, -4815, 125, -201), + RC(RC_CCW_BLUE_EGG_SUMMER_NEAR_MUMBOS_SKULL_4, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG, NULL, -4585, 125, -200), + RC(RC_CCW_BLUE_EGG_SUMMER_NEAR_MUMBOS_SKULL_5, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG, NULL, -4470, 125, 0), + RC(RC_CCW_BLUE_EGG_SUMMER_NEAR_MUMBOS_SKULL_6, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG, NULL, -4585, 125, 200), + RC(RC_CCW_BLUE_EGG_SUMMER_NEAR_NABNUTS_HOUSE_1, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG, NULL, -1153, 4019, 4293), + RC(RC_CCW_BLUE_EGG_SUMMER_NEAR_NABNUTS_HOUSE_2, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG, NULL, -1284, 4019, 4611), + RC(RC_CCW_BLUE_EGG_SUMMER_NEAR_NABNUTS_HOUSE_3, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG, NULL, -1599, 4019, 4747), + RC(RC_CCW_BLUE_EGG_SUMMER_NEAR_NABNUTS_HOUSE_4, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG, NULL, -2047, 4019, 4303), + RC(RC_CCW_BLUE_EGG_SUMMER_NEAR_NABNUTS_HOUSE_5, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG, NULL, -1920, 4019, 3996), + RC(RC_CCW_BLUE_EGG_SUMMER_NEAR_NABNUTS_HOUSE_6, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG, NULL, -1603, 4019, 3851), + RC(RC_CCW_BLUE_EGG_WINTER_INSIDE_NABNUTS_HOUSE_1, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG, NULL, -285, 513, -354), + RC(RC_CCW_BLUE_EGG_WINTER_INSIDE_NABNUTS_HOUSE_2, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG, NULL, -395, 513, -280), + RC(RC_CCW_BLUE_EGG_WINTER_INSIDE_NABNUTS_HOUSE_3, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG, NULL, -504, 513, -205), + RC(RC_CCW_BLUE_EGG_WINTER_INSIDE_NABNUTS_HOUSE_4, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG, NULL, -577, 513, -110), + RC(RC_CCW_BLUE_EGG_WINTER_INSIDE_NABNUTS_HOUSE_5, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG, NULL, -646, 513, -5), + RC(RC_CCW_BLUE_EGG_WINTER_NABNUTS_WINDOW_INTERIOR_1, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG, NULL, 253, -500, -621), + RC(RC_CCW_BLUE_EGG_WINTER_NABNUTS_WINDOW_INTERIOR_2, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG, NULL, 617, -499, -263), + RC(RC_CCW_BLUE_EGG_WINTER_NABNUTS_WINDOW_INTERIOR_3, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG, NULL, 621, -499, 254), + RC(RC_CCW_BLUE_EGG_WINTER_NABNUTS_WINDOW_INTERIOR_4, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG, NULL, 258, -500, 624), + RC(RC_CCW_BLUE_EGG_WINTER_NABNUTS_WINDOW_INTERIOR_5, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG, NULL, -254, -500, 621), + RC(RC_CCW_BLUE_EGG_WINTER_NABNUTS_WINDOW_INTERIOR_6, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG, NULL, -622, -499, 259), + RC(RC_CCW_BLUE_EGG_WINTER_NABNUTS_WINDOW_INTERIOR_7, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG, NULL, -624, -499, -254), + RC(RC_CCW_BLUE_EGG_WINTER_NABNUTS_WINDOW_INTERIOR_8, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG, NULL, -262, -500, -619), + RC(RC_CCW_BLUE_EGG_WINTER_WINDOW_ABOVE_NABNUT_1, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG, NULL, 244, 150, -509), + RC(RC_CCW_BLUE_EGG_WINTER_WINDOW_ABOVE_NABNUT_2, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG, NULL, 88, 250, 682), + RC(RC_CCW_BLUE_EGG_WINTER_WINDOW_ABOVE_NABNUT_3, RCTYPE_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD, RI_BLUE_EGG, NULL, -531, 450, -430), RC(RC_CCW_EMPTY_HONEYCOMB_GNAWTYS, RCTYPE_EMPTY_HONEYCOMB, LEVEL_8_CLICK_CLOCK_WOOD, RI_EMPTY_HONEYCOMB_CLICK_CLOCK_WOOD, HONEYCOMB_D_CCW_GNAWTYS, 694, 998, 632), RC(RC_CCW_EMPTY_HONEYCOMB_NABNUTS, RCTYPE_EMPTY_HONEYCOMB, LEVEL_8_CLICK_CLOCK_WOOD, RI_EMPTY_HONEYCOMB_CLICK_CLOCK_WOOD, HONEYCOMB_E_CCW_NABNUTS, 640, 513, -202), - RC(RC_CCW_EXTRA_LIFE_AUTUMN_BEHIND_GNAWTYS_FIRE, RCTYPE_EXTRA_LIFE, LEVEL_8_CLICK_CLOCK_WOOD, RI_EXTRA_LIFE_CLICK_CLOCK_WOOD, NULL, -225, 640, 506), - RC(RC_CCW_EXTRA_LIFE_AUTUMN_SNAREBEAR_NEAR_TREEHOUSE, RCTYPE_EXTRA_LIFE, LEVEL_8_CLICK_CLOCK_WOOD, RI_EXTRA_LIFE_CLICK_CLOCK_WOOD, NULL, 4050, 4284, 1010), - RC(RC_CCW_EXTRA_LIFE_AUTUMN_TOP_ROOM, RCTYPE_EXTRA_LIFE, LEVEL_8_CLICK_CLOCK_WOOD, RI_EXTRA_LIFE_CLICK_CLOCK_WOOD, NULL, -310, 730, -856), - RC(RC_CCW_EXTRA_LIFE_SPRING_BRANCHES_ABOVE_MUMBOS_SKULL, RCTYPE_EXTRA_LIFE, LEVEL_8_CLICK_CLOCK_WOOD, RI_EXTRA_LIFE_CLICK_CLOCK_WOOD, NULL, -4993, 2896, -944), - RC(RC_CCW_EXTRA_LIFE_SPRING_SNAREBEAR_IN_THE_LAKE, RCTYPE_EXTRA_LIFE, LEVEL_8_CLICK_CLOCK_WOOD, RI_EXTRA_LIFE_CLICK_CLOCK_WOOD, NULL, 5100, 425, 0), - RC(RC_CCW_EXTRA_LIFE_SPRING_TOP_ROOM_BY_THE_JIGGY, RCTYPE_EXTRA_LIFE, LEVEL_8_CLICK_CLOCK_WOOD, RI_EXTRA_LIFE_CLICK_CLOCK_WOOD, NULL, -693, 2, 528), - RC(RC_CCW_EXTRA_LIFE_SPRING_TOP_ROOM_IN_THE_BRANCHES, RCTYPE_EXTRA_LIFE, LEVEL_8_CLICK_CLOCK_WOOD, RI_EXTRA_LIFE_CLICK_CLOCK_WOOD, NULL, -310, 730, -855), - RC(RC_CCW_EXTRA_LIFE_SUMMER_NEAR_THE_BIG_FLOWER, RCTYPE_EXTRA_LIFE, LEVEL_8_CLICK_CLOCK_WOOD, RI_EXTRA_LIFE_CLICK_CLOCK_WOOD, NULL, 3604, 22, -4012), - RC(RC_CCW_EXTRA_LIFE_SUMMER_TREEHOUSE, RCTYPE_EXTRA_LIFE, LEVEL_8_CLICK_CLOCK_WOOD, RI_EXTRA_LIFE_CLICK_CLOCK_WOOD, NULL, 5848, 4244, 612), - RC(RC_CCW_EXTRA_LIFE_SUMMER_TOP_ROOM, RCTYPE_EXTRA_LIFE, LEVEL_8_CLICK_CLOCK_WOOD, RI_EXTRA_LIFE_CLICK_CLOCK_WOOD, NULL, 833, 441, 133), - RC(RC_CCW_EXTRA_LIFE_WINTER_BENEATH_SIR_SLUSH, RCTYPE_EXTRA_LIFE, LEVEL_8_CLICK_CLOCK_WOOD, RI_EXTRA_LIFE_CLICK_CLOCK_WOOD, NULL, -3157, 300, -3149), - RC(RC_CCW_EXTRA_LIFE_WINTER_UNDER_THE_ICY_LAKE, RCTYPE_EXTRA_LIFE, LEVEL_8_CLICK_CLOCK_WOOD, RI_EXTRA_LIFE_CLICK_CLOCK_WOOD, NULL, 3078, -338, 3076), - RC(RC_CCW_HONEYCOMB_BEEHIVE_AUTUMN_ABOVE_THE_LAKE_1, RCTYPE_HONEYCOMB, LEVEL_8_CLICK_CLOCK_WOOD, RI_HONEYCOMB_CLICK_CLOCK_WOOD, NULL, 0, 0, 0), - RC(RC_CCW_HONEYCOMB_BEEHIVE_AUTUMN_ABOVE_THE_LAKE_2, RCTYPE_HONEYCOMB, LEVEL_8_CLICK_CLOCK_WOOD, RI_HONEYCOMB_CLICK_CLOCK_WOOD, NULL, 0, 0, 0), - RC(RC_CCW_HONEYCOMB_BEEHIVE_AUTUMN_ABOVE_THE_LAKE_3, RCTYPE_HONEYCOMB, LEVEL_8_CLICK_CLOCK_WOOD, RI_HONEYCOMB_CLICK_CLOCK_WOOD, NULL, 0, 0, 0), - RC(RC_CCW_HONEYCOMB_BEEHIVE_AUTUMN_GRASS_NEAR_THE_ENTRANCE_1, RCTYPE_HONEYCOMB, LEVEL_8_CLICK_CLOCK_WOOD, RI_HONEYCOMB_CLICK_CLOCK_WOOD, NULL, 0, 0, 0), - RC(RC_CCW_HONEYCOMB_BEEHIVE_AUTUMN_GRASS_NEAR_THE_ENTRANCE_2, RCTYPE_HONEYCOMB, LEVEL_8_CLICK_CLOCK_WOOD, RI_HONEYCOMB_CLICK_CLOCK_WOOD, NULL, 0, 0, 0), - RC(RC_CCW_HONEYCOMB_BEEHIVE_AUTUMN_GRASS_NEAR_THE_ENTRANCE_3, RCTYPE_HONEYCOMB, LEVEL_8_CLICK_CLOCK_WOOD, RI_HONEYCOMB_CLICK_CLOCK_WOOD, NULL, 0, 0, 0), - RC(RC_CCW_HONEYCOMB_BEEHIVE_AUTUMN_IN_THE_TREEHOUSE_1, RCTYPE_HONEYCOMB, LEVEL_8_CLICK_CLOCK_WOOD, RI_HONEYCOMB_CLICK_CLOCK_WOOD, NULL, 0, 0, 0), - RC(RC_CCW_HONEYCOMB_BEEHIVE_AUTUMN_IN_THE_TREEHOUSE_2, RCTYPE_HONEYCOMB, LEVEL_8_CLICK_CLOCK_WOOD, RI_HONEYCOMB_CLICK_CLOCK_WOOD, NULL, 0, 0, 0), - RC(RC_CCW_HONEYCOMB_BEEHIVE_AUTUMN_IN_THE_TREEHOUSE_3, RCTYPE_HONEYCOMB, LEVEL_8_CLICK_CLOCK_WOOD, RI_HONEYCOMB_CLICK_CLOCK_WOOD, NULL, 0, 0, 0), - RC(RC_CCW_HONEYCOMB_BEEHIVE_ENTRANCE_LEFT_OF_SUMMER_DOOR_1, RCTYPE_HONEYCOMB, LEVEL_8_CLICK_CLOCK_WOOD, RI_HONEYCOMB_CLICK_CLOCK_WOOD, NULL, 0, 0, 0), - RC(RC_CCW_HONEYCOMB_BEEHIVE_ENTRANCE_LEFT_OF_SUMMER_DOOR_2, RCTYPE_HONEYCOMB, LEVEL_8_CLICK_CLOCK_WOOD, RI_HONEYCOMB_CLICK_CLOCK_WOOD, NULL, 0, 0, 0), - RC(RC_CCW_HONEYCOMB_BEEHIVE_ENTRANCE_LEFT_OF_SUMMER_DOOR_3, RCTYPE_HONEYCOMB, LEVEL_8_CLICK_CLOCK_WOOD, RI_HONEYCOMB_CLICK_CLOCK_WOOD, NULL, 0, 0, 0), - RC(RC_CCW_HONEYCOMB_BEEHIVE_ENTRANCE_RIGHT_OF_SUMMER_DOOR_1, RCTYPE_HONEYCOMB, LEVEL_8_CLICK_CLOCK_WOOD, RI_HONEYCOMB_CLICK_CLOCK_WOOD, NULL, 0, 0, 0), - RC(RC_CCW_HONEYCOMB_BEEHIVE_ENTRANCE_RIGHT_OF_SUMMER_DOOR_2, RCTYPE_HONEYCOMB, LEVEL_8_CLICK_CLOCK_WOOD, RI_HONEYCOMB_CLICK_CLOCK_WOOD, NULL, 0, 0, 0), - RC(RC_CCW_HONEYCOMB_BEEHIVE_ENTRANCE_RIGHT_OF_SUMMER_DOOR_3, RCTYPE_HONEYCOMB, LEVEL_8_CLICK_CLOCK_WOOD, RI_HONEYCOMB_CLICK_CLOCK_WOOD, NULL, 0, 0, 0), - RC(RC_CCW_HONEYCOMB_BEEHIVE_SPRING_BY_THE_BIG_FLOWER_1, RCTYPE_HONEYCOMB, LEVEL_8_CLICK_CLOCK_WOOD, RI_HONEYCOMB_CLICK_CLOCK_WOOD, NULL, 0, 0, 0), - RC(RC_CCW_HONEYCOMB_BEEHIVE_SPRING_BY_THE_BIG_FLOWER_2, RCTYPE_HONEYCOMB, LEVEL_8_CLICK_CLOCK_WOOD, RI_HONEYCOMB_CLICK_CLOCK_WOOD, NULL, 0, 0, 0), - RC(RC_CCW_HONEYCOMB_BEEHIVE_SPRING_BY_THE_BIG_FLOWER_3, RCTYPE_HONEYCOMB, LEVEL_8_CLICK_CLOCK_WOOD, RI_HONEYCOMB_CLICK_CLOCK_WOOD, NULL, 0, 0, 0), - RC(RC_CCW_HONEYCOMB_BEEHIVE_SPRING_GRASS_NEAR_THE_ENTRANCE_1, RCTYPE_HONEYCOMB, LEVEL_8_CLICK_CLOCK_WOOD, RI_HONEYCOMB_CLICK_CLOCK_WOOD, NULL, 0, 0, 0), - RC(RC_CCW_HONEYCOMB_BEEHIVE_SPRING_GRASS_NEAR_THE_ENTRANCE_2, RCTYPE_HONEYCOMB, LEVEL_8_CLICK_CLOCK_WOOD, RI_HONEYCOMB_CLICK_CLOCK_WOOD, NULL, 0, 0, 0), - RC(RC_CCW_HONEYCOMB_BEEHIVE_SPRING_GRASS_NEAR_THE_ENTRANCE_3, RCTYPE_HONEYCOMB, LEVEL_8_CLICK_CLOCK_WOOD, RI_HONEYCOMB_CLICK_CLOCK_WOOD, NULL, 0, 0, 0), - RC(RC_CCW_HONEYCOMB_BEEHIVE_SPRING_UNDER_THE_TREEHOUSE_1, RCTYPE_HONEYCOMB, LEVEL_8_CLICK_CLOCK_WOOD, RI_HONEYCOMB_CLICK_CLOCK_WOOD, NULL, 0, 0, 0), - RC(RC_CCW_HONEYCOMB_BEEHIVE_SPRING_UNDER_THE_TREEHOUSE_2, RCTYPE_HONEYCOMB, LEVEL_8_CLICK_CLOCK_WOOD, RI_HONEYCOMB_CLICK_CLOCK_WOOD, NULL, 0, 0, 0), - RC(RC_CCW_HONEYCOMB_BEEHIVE_SPRING_UNDER_THE_TREEHOUSE_3, RCTYPE_HONEYCOMB, LEVEL_8_CLICK_CLOCK_WOOD, RI_HONEYCOMB_CLICK_CLOCK_WOOD, NULL, 0, 0, 0), - RC(RC_CCW_HONEYCOMB_BEEHIVE_SUMMER_DRIED_UP_LAKE_1, RCTYPE_HONEYCOMB, LEVEL_8_CLICK_CLOCK_WOOD, RI_HONEYCOMB_CLICK_CLOCK_WOOD, NULL, 0, 0, 0), - RC(RC_CCW_HONEYCOMB_BEEHIVE_SUMMER_DRIED_UP_LAKE_2, RCTYPE_HONEYCOMB, LEVEL_8_CLICK_CLOCK_WOOD, RI_HONEYCOMB_CLICK_CLOCK_WOOD, NULL, 0, 0, 0), - RC(RC_CCW_HONEYCOMB_BEEHIVE_SUMMER_DRIED_UP_LAKE_3, RCTYPE_HONEYCOMB, LEVEL_8_CLICK_CLOCK_WOOD, RI_HONEYCOMB_CLICK_CLOCK_WOOD, NULL, 0, 0, 0), - RC(RC_CCW_HONEYCOMB_BEEHIVE_SUMMER_GRASS_NEAR_THE_ENTRANCE_1, RCTYPE_HONEYCOMB, LEVEL_8_CLICK_CLOCK_WOOD, RI_HONEYCOMB_CLICK_CLOCK_WOOD, NULL, 0, 0, 0), - RC(RC_CCW_HONEYCOMB_BEEHIVE_SUMMER_GRASS_NEAR_THE_ENTRANCE_2, RCTYPE_HONEYCOMB, LEVEL_8_CLICK_CLOCK_WOOD, RI_HONEYCOMB_CLICK_CLOCK_WOOD, NULL, 0, 0, 0), - RC(RC_CCW_HONEYCOMB_BEEHIVE_SUMMER_GRASS_NEAR_THE_ENTRANCE_3, RCTYPE_HONEYCOMB, LEVEL_8_CLICK_CLOCK_WOOD, RI_HONEYCOMB_CLICK_CLOCK_WOOD, NULL, 0, 0, 0), - RC(RC_CCW_HONEYCOMB_BEEHIVE_SUMMER_OUTSIDE_NABNUTS_1, RCTYPE_HONEYCOMB, LEVEL_8_CLICK_CLOCK_WOOD, RI_HONEYCOMB_CLICK_CLOCK_WOOD, NULL, 0, 0, 0), - RC(RC_CCW_HONEYCOMB_BEEHIVE_SUMMER_OUTSIDE_NABNUTS_2, RCTYPE_HONEYCOMB, LEVEL_8_CLICK_CLOCK_WOOD, RI_HONEYCOMB_CLICK_CLOCK_WOOD, NULL, 0, 0, 0), - RC(RC_CCW_HONEYCOMB_BEEHIVE_SUMMER_OUTSIDE_NABNUTS_3, RCTYPE_HONEYCOMB, LEVEL_8_CLICK_CLOCK_WOOD, RI_HONEYCOMB_CLICK_CLOCK_WOOD, NULL, 0, 0, 0), - RC(RC_CCW_HONEYCOMB_BEEHIVE_WINTER_AROUND_THE_TREE_BASE_1, RCTYPE_HONEYCOMB, LEVEL_8_CLICK_CLOCK_WOOD, RI_HONEYCOMB_CLICK_CLOCK_WOOD, NULL, 0, 0, 0), - RC(RC_CCW_HONEYCOMB_BEEHIVE_WINTER_AROUND_THE_TREE_BASE_2, RCTYPE_HONEYCOMB, LEVEL_8_CLICK_CLOCK_WOOD, RI_HONEYCOMB_CLICK_CLOCK_WOOD, NULL, 0, 0, 0), - RC(RC_CCW_HONEYCOMB_BEEHIVE_WINTER_AROUND_THE_TREE_BASE_3, RCTYPE_HONEYCOMB, LEVEL_8_CLICK_CLOCK_WOOD, RI_HONEYCOMB_CLICK_CLOCK_WOOD, NULL, 0, 0, 0), - RC(RC_CCW_HONEYCOMB_BEEHIVE_WINTER_INSIDE_MUMBOS_SKULL_1, RCTYPE_HONEYCOMB, LEVEL_8_CLICK_CLOCK_WOOD, RI_HONEYCOMB_CLICK_CLOCK_WOOD, NULL, 0, 0, 0), - RC(RC_CCW_HONEYCOMB_BEEHIVE_WINTER_INSIDE_MUMBOS_SKULL_2, RCTYPE_HONEYCOMB, LEVEL_8_CLICK_CLOCK_WOOD, RI_HONEYCOMB_CLICK_CLOCK_WOOD, NULL, 0, 0, 0), - RC(RC_CCW_HONEYCOMB_BEEHIVE_WINTER_INSIDE_MUMBOS_SKULL_3, RCTYPE_HONEYCOMB, LEVEL_8_CLICK_CLOCK_WOOD, RI_HONEYCOMB_CLICK_CLOCK_WOOD, NULL, 0, 0, 0), - RC(RC_CCW_HONEYCOMB_BEEHIVE_WINTER_OUTSIDE_THE_TREEHOUSE_1, RCTYPE_HONEYCOMB, LEVEL_8_CLICK_CLOCK_WOOD, RI_HONEYCOMB_CLICK_CLOCK_WOOD, NULL, 0, 0, 0), - RC(RC_CCW_HONEYCOMB_BEEHIVE_WINTER_OUTSIDE_THE_TREEHOUSE_2, RCTYPE_HONEYCOMB, LEVEL_8_CLICK_CLOCK_WOOD, RI_HONEYCOMB_CLICK_CLOCK_WOOD, NULL, 0, 0, 0), - RC(RC_CCW_HONEYCOMB_BEEHIVE_WINTER_OUTSIDE_THE_TREEHOUSE_3, RCTYPE_HONEYCOMB, LEVEL_8_CLICK_CLOCK_WOOD, RI_HONEYCOMB_CLICK_CLOCK_WOOD, NULL, 0, 0, 0), + RC(RC_CCW_EXTRA_LIFE_AUTUMN_BEHIND_GNAWTYS_FIRE, RCTYPE_EXTRA_LIFE, LEVEL_8_CLICK_CLOCK_WOOD, RI_EXTRA_LIFE, NULL, -225, 640, 506), + RC(RC_CCW_EXTRA_LIFE_AUTUMN_SNAREBEAR_NEAR_TREEHOUSE, RCTYPE_EXTRA_LIFE, LEVEL_8_CLICK_CLOCK_WOOD, RI_EXTRA_LIFE, NULL, 4050, 4284, 1010), + RC(RC_CCW_EXTRA_LIFE_AUTUMN_TOP_ROOM, RCTYPE_EXTRA_LIFE, LEVEL_8_CLICK_CLOCK_WOOD, RI_EXTRA_LIFE, NULL, -310, 730, -856), + RC(RC_CCW_EXTRA_LIFE_SPRING_BRANCHES_ABOVE_MUMBOS_SKULL, RCTYPE_EXTRA_LIFE, LEVEL_8_CLICK_CLOCK_WOOD, RI_EXTRA_LIFE, NULL, -4993, 2896, -944), + RC(RC_CCW_EXTRA_LIFE_SPRING_SNAREBEAR_IN_THE_LAKE, RCTYPE_EXTRA_LIFE, LEVEL_8_CLICK_CLOCK_WOOD, RI_EXTRA_LIFE, NULL, 5100, 425, 0), + RC(RC_CCW_EXTRA_LIFE_SPRING_TOP_ROOM_BY_THE_JIGGY, RCTYPE_EXTRA_LIFE, LEVEL_8_CLICK_CLOCK_WOOD, RI_EXTRA_LIFE, NULL, -693, 2, 528), + RC(RC_CCW_EXTRA_LIFE_SPRING_TOP_ROOM_IN_THE_BRANCHES, RCTYPE_EXTRA_LIFE, LEVEL_8_CLICK_CLOCK_WOOD, RI_EXTRA_LIFE, NULL, -310, 730, -855), + RC(RC_CCW_EXTRA_LIFE_SUMMER_NEAR_THE_BIG_FLOWER, RCTYPE_EXTRA_LIFE, LEVEL_8_CLICK_CLOCK_WOOD, RI_EXTRA_LIFE, NULL, 3604, 22, -4012), + RC(RC_CCW_EXTRA_LIFE_SUMMER_TREEHOUSE, RCTYPE_EXTRA_LIFE, LEVEL_8_CLICK_CLOCK_WOOD, RI_EXTRA_LIFE, NULL, 5848, 4244, 612), + RC(RC_CCW_EXTRA_LIFE_SUMMER_TOP_ROOM, RCTYPE_EXTRA_LIFE, LEVEL_8_CLICK_CLOCK_WOOD, RI_EXTRA_LIFE, NULL, 833, 441, 133), + RC(RC_CCW_EXTRA_LIFE_WINTER_BENEATH_SIR_SLUSH, RCTYPE_EXTRA_LIFE, LEVEL_8_CLICK_CLOCK_WOOD, RI_EXTRA_LIFE, NULL, -3157, 300, -3149), + RC(RC_CCW_EXTRA_LIFE_WINTER_UNDER_THE_ICY_LAKE, RCTYPE_EXTRA_LIFE, LEVEL_8_CLICK_CLOCK_WOOD, RI_EXTRA_LIFE, NULL, 3078, -338, 3076), + RC(RC_CCW_HONEYCOMB_BEEHIVE_AUTUMN_ABOVE_THE_LAKE_1, RCTYPE_HONEYCOMB, LEVEL_8_CLICK_CLOCK_WOOD, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_CCW_HONEYCOMB_BEEHIVE_AUTUMN_ABOVE_THE_LAKE_2, RCTYPE_HONEYCOMB, LEVEL_8_CLICK_CLOCK_WOOD, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_CCW_HONEYCOMB_BEEHIVE_AUTUMN_ABOVE_THE_LAKE_3, RCTYPE_HONEYCOMB, LEVEL_8_CLICK_CLOCK_WOOD, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_CCW_HONEYCOMB_BEEHIVE_AUTUMN_GRASS_NEAR_THE_ENTRANCE_1, RCTYPE_HONEYCOMB, LEVEL_8_CLICK_CLOCK_WOOD, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_CCW_HONEYCOMB_BEEHIVE_AUTUMN_GRASS_NEAR_THE_ENTRANCE_2, RCTYPE_HONEYCOMB, LEVEL_8_CLICK_CLOCK_WOOD, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_CCW_HONEYCOMB_BEEHIVE_AUTUMN_GRASS_NEAR_THE_ENTRANCE_3, RCTYPE_HONEYCOMB, LEVEL_8_CLICK_CLOCK_WOOD, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_CCW_HONEYCOMB_BEEHIVE_AUTUMN_IN_THE_TREEHOUSE_1, RCTYPE_HONEYCOMB, LEVEL_8_CLICK_CLOCK_WOOD, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_CCW_HONEYCOMB_BEEHIVE_AUTUMN_IN_THE_TREEHOUSE_2, RCTYPE_HONEYCOMB, LEVEL_8_CLICK_CLOCK_WOOD, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_CCW_HONEYCOMB_BEEHIVE_AUTUMN_IN_THE_TREEHOUSE_3, RCTYPE_HONEYCOMB, LEVEL_8_CLICK_CLOCK_WOOD, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_CCW_HONEYCOMB_BEEHIVE_ENTRANCE_LEFT_OF_SUMMER_DOOR_1, RCTYPE_HONEYCOMB, LEVEL_8_CLICK_CLOCK_WOOD, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_CCW_HONEYCOMB_BEEHIVE_ENTRANCE_LEFT_OF_SUMMER_DOOR_2, RCTYPE_HONEYCOMB, LEVEL_8_CLICK_CLOCK_WOOD, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_CCW_HONEYCOMB_BEEHIVE_ENTRANCE_LEFT_OF_SUMMER_DOOR_3, RCTYPE_HONEYCOMB, LEVEL_8_CLICK_CLOCK_WOOD, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_CCW_HONEYCOMB_BEEHIVE_ENTRANCE_RIGHT_OF_SUMMER_DOOR_1, RCTYPE_HONEYCOMB, LEVEL_8_CLICK_CLOCK_WOOD, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_CCW_HONEYCOMB_BEEHIVE_ENTRANCE_RIGHT_OF_SUMMER_DOOR_2, RCTYPE_HONEYCOMB, LEVEL_8_CLICK_CLOCK_WOOD, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_CCW_HONEYCOMB_BEEHIVE_ENTRANCE_RIGHT_OF_SUMMER_DOOR_3, RCTYPE_HONEYCOMB, LEVEL_8_CLICK_CLOCK_WOOD, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_CCW_HONEYCOMB_BEEHIVE_SPRING_BY_THE_BIG_FLOWER_1, RCTYPE_HONEYCOMB, LEVEL_8_CLICK_CLOCK_WOOD, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_CCW_HONEYCOMB_BEEHIVE_SPRING_BY_THE_BIG_FLOWER_2, RCTYPE_HONEYCOMB, LEVEL_8_CLICK_CLOCK_WOOD, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_CCW_HONEYCOMB_BEEHIVE_SPRING_BY_THE_BIG_FLOWER_3, RCTYPE_HONEYCOMB, LEVEL_8_CLICK_CLOCK_WOOD, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_CCW_HONEYCOMB_BEEHIVE_SPRING_GRASS_NEAR_THE_ENTRANCE_1, RCTYPE_HONEYCOMB, LEVEL_8_CLICK_CLOCK_WOOD, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_CCW_HONEYCOMB_BEEHIVE_SPRING_GRASS_NEAR_THE_ENTRANCE_2, RCTYPE_HONEYCOMB, LEVEL_8_CLICK_CLOCK_WOOD, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_CCW_HONEYCOMB_BEEHIVE_SPRING_GRASS_NEAR_THE_ENTRANCE_3, RCTYPE_HONEYCOMB, LEVEL_8_CLICK_CLOCK_WOOD, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_CCW_HONEYCOMB_BEEHIVE_SPRING_UNDER_THE_TREEHOUSE_1, RCTYPE_HONEYCOMB, LEVEL_8_CLICK_CLOCK_WOOD, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_CCW_HONEYCOMB_BEEHIVE_SPRING_UNDER_THE_TREEHOUSE_2, RCTYPE_HONEYCOMB, LEVEL_8_CLICK_CLOCK_WOOD, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_CCW_HONEYCOMB_BEEHIVE_SPRING_UNDER_THE_TREEHOUSE_3, RCTYPE_HONEYCOMB, LEVEL_8_CLICK_CLOCK_WOOD, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_CCW_HONEYCOMB_BEEHIVE_SUMMER_DRIED_UP_LAKE_1, RCTYPE_HONEYCOMB, LEVEL_8_CLICK_CLOCK_WOOD, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_CCW_HONEYCOMB_BEEHIVE_SUMMER_DRIED_UP_LAKE_2, RCTYPE_HONEYCOMB, LEVEL_8_CLICK_CLOCK_WOOD, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_CCW_HONEYCOMB_BEEHIVE_SUMMER_DRIED_UP_LAKE_3, RCTYPE_HONEYCOMB, LEVEL_8_CLICK_CLOCK_WOOD, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_CCW_HONEYCOMB_BEEHIVE_SUMMER_GRASS_NEAR_THE_ENTRANCE_1, RCTYPE_HONEYCOMB, LEVEL_8_CLICK_CLOCK_WOOD, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_CCW_HONEYCOMB_BEEHIVE_SUMMER_GRASS_NEAR_THE_ENTRANCE_2, RCTYPE_HONEYCOMB, LEVEL_8_CLICK_CLOCK_WOOD, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_CCW_HONEYCOMB_BEEHIVE_SUMMER_GRASS_NEAR_THE_ENTRANCE_3, RCTYPE_HONEYCOMB, LEVEL_8_CLICK_CLOCK_WOOD, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_CCW_HONEYCOMB_BEEHIVE_SUMMER_OUTSIDE_NABNUTS_1, RCTYPE_HONEYCOMB, LEVEL_8_CLICK_CLOCK_WOOD, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_CCW_HONEYCOMB_BEEHIVE_SUMMER_OUTSIDE_NABNUTS_2, RCTYPE_HONEYCOMB, LEVEL_8_CLICK_CLOCK_WOOD, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_CCW_HONEYCOMB_BEEHIVE_SUMMER_OUTSIDE_NABNUTS_3, RCTYPE_HONEYCOMB, LEVEL_8_CLICK_CLOCK_WOOD, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_CCW_HONEYCOMB_BEEHIVE_WINTER_AROUND_THE_TREE_BASE_1, RCTYPE_HONEYCOMB, LEVEL_8_CLICK_CLOCK_WOOD, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_CCW_HONEYCOMB_BEEHIVE_WINTER_AROUND_THE_TREE_BASE_2, RCTYPE_HONEYCOMB, LEVEL_8_CLICK_CLOCK_WOOD, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_CCW_HONEYCOMB_BEEHIVE_WINTER_AROUND_THE_TREE_BASE_3, RCTYPE_HONEYCOMB, LEVEL_8_CLICK_CLOCK_WOOD, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_CCW_HONEYCOMB_BEEHIVE_WINTER_INSIDE_MUMBOS_SKULL_1, RCTYPE_HONEYCOMB, LEVEL_8_CLICK_CLOCK_WOOD, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_CCW_HONEYCOMB_BEEHIVE_WINTER_INSIDE_MUMBOS_SKULL_2, RCTYPE_HONEYCOMB, LEVEL_8_CLICK_CLOCK_WOOD, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_CCW_HONEYCOMB_BEEHIVE_WINTER_INSIDE_MUMBOS_SKULL_3, RCTYPE_HONEYCOMB, LEVEL_8_CLICK_CLOCK_WOOD, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_CCW_HONEYCOMB_BEEHIVE_WINTER_OUTSIDE_THE_TREEHOUSE_1, RCTYPE_HONEYCOMB, LEVEL_8_CLICK_CLOCK_WOOD, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_CCW_HONEYCOMB_BEEHIVE_WINTER_OUTSIDE_THE_TREEHOUSE_2, RCTYPE_HONEYCOMB, LEVEL_8_CLICK_CLOCK_WOOD, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_CCW_HONEYCOMB_BEEHIVE_WINTER_OUTSIDE_THE_TREEHOUSE_3, RCTYPE_HONEYCOMB, LEVEL_8_CLICK_CLOCK_WOOD, RI_HONEYCOMB, NULL, 0, 0, 0), RC(RC_CCW_JIGGY_EYRIE, RCTYPE_JIGGY, LEVEL_8_CLICK_CLOCK_WOOD, RI_JIGGY_CLICK_CLOCK_WOOD, JIGGY_49_CCW_EYRIE, 0, 0, 0), RC(RC_CCW_JIGGY_FLOWER, RCTYPE_JIGGY, LEVEL_8_CLICK_CLOCK_WOOD, RI_JIGGY_CLICK_CLOCK_WOOD, JIGGY_4D_CCW_FLOWER, 0, 0, 0), RC(RC_CCW_JIGGY_GNAWTY, RCTYPE_JIGGY, LEVEL_8_CLICK_CLOCK_WOOD, RI_JIGGY_CLICK_CLOCK_WOOD, JIGGY_4B_CCW_GNAWTY, 240, 600, 75), @@ -697,73 +697,73 @@ std::map Checks = { RC(RC_CCW_NOTE_WINTER_TREETOP_PLATFORMS_3, RCTYPE_MUSIC_NOTE, LEVEL_8_CLICK_CLOCK_WOOD, RI_MUSIC_NOTE_CLICK_CLOCK_WOOD, NULL, -1691, 5210, -2199), RC(RC_CCW_NOTE_WINTER_TREETOP_PLATFORMS_4, RCTYPE_MUSIC_NOTE, LEVEL_8_CLICK_CLOCK_WOOD, RI_MUSIC_NOTE_CLICK_CLOCK_WOOD, NULL, -764, 5590, -2634), RC(RC_CCW_SNS_YELLOW_EGG, RCTYPE_STOP_N_SWOP, LEVEL_8_CLICK_CLOCK_WOOD, RI_STOP_N_SWOP_EGG_YELLOW, SNS_ITEM_EGG_YELLOW, 556, 150, 47), - RC(RC_FP_BLUE_EGG_BEHIND_IGLOO_1, RCTYPE_BLUE_EGG, LEVEL_5_FREEZEEZY_PEAK, RI_BLUE_EGG_FREEZEEZY_PEAK, NULL, 1536, 3505, 9857), - RC(RC_FP_BLUE_EGG_BEHIND_IGLOO_2, RCTYPE_BLUE_EGG, LEVEL_5_FREEZEEZY_PEAK, RI_BLUE_EGG_FREEZEEZY_PEAK, NULL, 1606, 3505, 9635), - RC(RC_FP_BLUE_EGG_BEHIND_IGLOO_3, RCTYPE_BLUE_EGG, LEVEL_5_FREEZEEZY_PEAK, RI_BLUE_EGG_FREEZEEZY_PEAK, NULL, 1674, 3505, 9422), - RC(RC_FP_BLUE_EGG_BEHIND_IGLOO_4, RCTYPE_BLUE_EGG, LEVEL_5_FREEZEEZY_PEAK, RI_BLUE_EGG_FREEZEEZY_PEAK, NULL, 1610, 3505, 9197), - RC(RC_FP_BLUE_EGG_BEHIND_IGLOO_5, RCTYPE_BLUE_EGG, LEVEL_5_FREEZEEZY_PEAK, RI_BLUE_EGG_FREEZEEZY_PEAK, NULL, 1545, 3505, 8981), - RC(RC_FP_BLUE_EGG_NEAR_GREEN_PRESENT_1, RCTYPE_BLUE_EGG, LEVEL_5_FREEZEEZY_PEAK, RI_BLUE_EGG_FREEZEEZY_PEAK, NULL, 404, 18, -2625), - RC(RC_FP_BLUE_EGG_NEAR_GREEN_PRESENT_2, RCTYPE_BLUE_EGG, LEVEL_5_FREEZEEZY_PEAK, RI_BLUE_EGG_FREEZEEZY_PEAK, NULL, 654, 18, -3169), - RC(RC_FP_BLUE_EGG_NEAR_GREEN_PRESENT_3, RCTYPE_BLUE_EGG, LEVEL_5_FREEZEEZY_PEAK, RI_BLUE_EGG_FREEZEEZY_PEAK, NULL, 1410, 17, -2859), - RC(RC_FP_BLUE_EGG_NEAR_GREEN_PRESENT_4, RCTYPE_BLUE_EGG, LEVEL_5_FREEZEEZY_PEAK, RI_BLUE_EGG_FREEZEEZY_PEAK, NULL, 1185, 18, -2295), - RC(RC_FP_BLUE_EGG_POTTED_TREE_INTERIOR_1, RCTYPE_BLUE_EGG, LEVEL_5_FREEZEEZY_PEAK, RI_BLUE_EGG_FREEZEEZY_PEAK, NULL, -344, 2110, -200), - RC(RC_FP_BLUE_EGG_POTTED_TREE_INTERIOR_2, RCTYPE_BLUE_EGG, LEVEL_5_FREEZEEZY_PEAK, RI_BLUE_EGG_FREEZEEZY_PEAK, NULL, -195, 2110, -343), - RC(RC_FP_BLUE_EGG_POTTED_TREE_INTERIOR_3, RCTYPE_BLUE_EGG, LEVEL_5_FREEZEEZY_PEAK, RI_BLUE_EGG_FREEZEEZY_PEAK, NULL, -1, 2110, -399), - RC(RC_FP_BLUE_EGG_POTTED_TREE_INTERIOR_4, RCTYPE_BLUE_EGG, LEVEL_5_FREEZEEZY_PEAK, RI_BLUE_EGG_FREEZEEZY_PEAK, NULL, 199, 2110, -346), - RC(RC_FP_BLUE_EGG_POTTED_TREE_INTERIOR_5, RCTYPE_BLUE_EGG, LEVEL_5_FREEZEEZY_PEAK, RI_BLUE_EGG_FREEZEEZY_PEAK, NULL, 345, 2110, -199), - RC(RC_FP_BLUE_EGG_POTTED_TREE_INTERIOR_6, RCTYPE_BLUE_EGG, LEVEL_5_FREEZEEZY_PEAK, RI_BLUE_EGG_FREEZEEZY_PEAK, NULL, 395, 2110, 1), - RC(RC_FP_BLUE_EGG_POTTED_TREE_INTERIOR_7, RCTYPE_BLUE_EGG, LEVEL_5_FREEZEEZY_PEAK, RI_BLUE_EGG_FREEZEEZY_PEAK, NULL, 341, 2110, 196), - RC(RC_FP_BLUE_EGG_POTTED_TREE_INTERIOR_8, RCTYPE_BLUE_EGG, LEVEL_5_FREEZEEZY_PEAK, RI_BLUE_EGG_FREEZEEZY_PEAK, NULL, 199, 2110, 340), - RC(RC_FP_BLUE_EGG_POTTED_TREE_INTERIOR_9, RCTYPE_BLUE_EGG, LEVEL_5_FREEZEEZY_PEAK, RI_BLUE_EGG_FREEZEEZY_PEAK, NULL, 0, 2110, 393), - RC(RC_FP_BLUE_EGG_POTTED_TREE_INTERIOR_10, RCTYPE_BLUE_EGG, LEVEL_5_FREEZEEZY_PEAK, RI_BLUE_EGG_FREEZEEZY_PEAK, NULL, -198, 2110, 347), - RC(RC_FP_BLUE_EGG_POTTED_TREE_INTERIOR_11, RCTYPE_BLUE_EGG, LEVEL_5_FREEZEEZY_PEAK, RI_BLUE_EGG_FREEZEEZY_PEAK, NULL, -344, 2110, 198), - RC(RC_FP_BLUE_EGG_POTTED_TREE_INTERIOR_12, RCTYPE_BLUE_EGG, LEVEL_5_FREEZEEZY_PEAK, RI_BLUE_EGG_FREEZEEZY_PEAK, NULL, -396, 2110, 0), - RC(RC_FP_BLUE_EGG_SNOWMANS_HAT_1, RCTYPE_BLUE_EGG, LEVEL_5_FREEZEEZY_PEAK, RI_BLUE_EGG_FREEZEEZY_PEAK, NULL, -1465, 7354, 1066), - RC(RC_FP_BLUE_EGG_SNOWMANS_HAT_2, RCTYPE_BLUE_EGG, LEVEL_5_FREEZEEZY_PEAK, RI_BLUE_EGG_FREEZEEZY_PEAK, NULL, -1961, 7227, 248), - RC(RC_FP_BLUE_EGG_SNOWMANS_HAT_3, RCTYPE_BLUE_EGG, LEVEL_5_FREEZEEZY_PEAK, RI_BLUE_EGG_FREEZEEZY_PEAK, NULL, -1734, 7166, -667), - RC(RC_FP_BLUE_EGG_SNOWMANS_HAT_4, RCTYPE_BLUE_EGG, LEVEL_5_FREEZEEZY_PEAK, RI_BLUE_EGG_FREEZEEZY_PEAK, NULL, -948, 7201, -1175), - RC(RC_FP_BLUE_EGG_SNOWMANS_HAT_5, RCTYPE_BLUE_EGG, LEVEL_5_FREEZEEZY_PEAK, RI_BLUE_EGG_FREEZEEZY_PEAK, NULL, -33, 7313, -984), - RC(RC_FP_BLUE_EGG_SNOWMANS_HAT_6, RCTYPE_BLUE_EGG, LEVEL_5_FREEZEEZY_PEAK, RI_BLUE_EGG_FREEZEEZY_PEAK, NULL, 496, 7442, -179), - RC(RC_FP_BLUE_EGG_SNOWMANS_HAT_7, RCTYPE_BLUE_EGG, LEVEL_5_FREEZEEZY_PEAK, RI_BLUE_EGG_FREEZEEZY_PEAK, NULL, 278, 7505, 757), - RC(RC_FP_BLUE_EGG_WATER_BEHIND_SNOWMAN_1, RCTYPE_BLUE_EGG, LEVEL_5_FREEZEEZY_PEAK, RI_BLUE_EGG_FREEZEEZY_PEAK, NULL, -3128, -168, -4645), - RC(RC_FP_BLUE_EGG_WATER_BEHIND_SNOWMAN_2, RCTYPE_BLUE_EGG, LEVEL_5_FREEZEEZY_PEAK, RI_BLUE_EGG_FREEZEEZY_PEAK, NULL, -2939, -168, -4791), - RC(RC_FP_BLUE_EGG_WATER_BEHIND_SNOWMAN_3, RCTYPE_BLUE_EGG, LEVEL_5_FREEZEEZY_PEAK, RI_BLUE_EGG_FREEZEEZY_PEAK, NULL, -2759, -168, -4928), - RC(RC_FP_BLUE_EGG_WATER_BEHIND_SNOWMAN_4, RCTYPE_BLUE_EGG, LEVEL_5_FREEZEEZY_PEAK, RI_BLUE_EGG_FREEZEEZY_PEAK, NULL, -2552, -168, -5061), - RC(RC_FP_BLUE_EGG_WATER_BEHIND_SNOWMAN_5, RCTYPE_BLUE_EGG, LEVEL_5_FREEZEEZY_PEAK, RI_BLUE_EGG_FREEZEEZY_PEAK, NULL, -2367, -168, -5166), - RC(RC_FP_BLUE_EGG_WATER_BEHIND_SNOWMAN_6, RCTYPE_BLUE_EGG, LEVEL_5_FREEZEEZY_PEAK, RI_BLUE_EGG_FREEZEEZY_PEAK, NULL, -2165, -168, -5146), - RC(RC_FP_BLUE_EGG_WATER_BEHIND_SNOWMAN_7, RCTYPE_BLUE_EGG, LEVEL_5_FREEZEEZY_PEAK, RI_BLUE_EGG_FREEZEEZY_PEAK, NULL, -1979, -168, -5120), - RC(RC_FP_BLUE_EGG_WATER_BEHIND_SNOWMAN_8, RCTYPE_BLUE_EGG, LEVEL_5_FREEZEEZY_PEAK, RI_BLUE_EGG_FREEZEEZY_PEAK, NULL, -1897, -168, -4931), - RC(RC_FP_BLUE_EGG_WATER_BEHIND_SNOWMAN_9, RCTYPE_BLUE_EGG, LEVEL_5_FREEZEEZY_PEAK, RI_BLUE_EGG_FREEZEEZY_PEAK, NULL, -1824, -168, -4732), - RC(RC_FP_BLUE_EGG_WATER_BEHIND_SNOWMAN_10, RCTYPE_BLUE_EGG, LEVEL_5_FREEZEEZY_PEAK, RI_BLUE_EGG_FREEZEEZY_PEAK, NULL, -1758, -168, -4514), - RC(RC_FP_BLUE_EGG_WATER_POTTED_TREE_1, RCTYPE_BLUE_EGG, LEVEL_5_FREEZEEZY_PEAK, RI_BLUE_EGG_FREEZEEZY_PEAK, NULL, -4112, -168, 5604), - RC(RC_FP_BLUE_EGG_WATER_POTTED_TREE_2, RCTYPE_BLUE_EGG, LEVEL_5_FREEZEEZY_PEAK, RI_BLUE_EGG_FREEZEEZY_PEAK, NULL, -3753, -168, 6126), - RC(RC_FP_BLUE_EGG_WATER_POTTED_TREE_3, RCTYPE_BLUE_EGG, LEVEL_5_FREEZEEZY_PEAK, RI_BLUE_EGG_FREEZEEZY_PEAK, NULL, -3887, -168, 6767), - RC(RC_FP_BLUE_EGG_WATER_POTTED_TREE_4, RCTYPE_BLUE_EGG, LEVEL_5_FREEZEEZY_PEAK, RI_BLUE_EGG_FREEZEEZY_PEAK, NULL, -4440, -168, 7130), - RC(RC_FP_BLUE_EGG_WATER_POTTED_TREE_5, RCTYPE_BLUE_EGG, LEVEL_5_FREEZEEZY_PEAK, RI_BLUE_EGG_FREEZEEZY_PEAK, NULL, -5069, -168, 6990), - RC(RC_FP_BLUE_EGG_WATER_POTTED_TREE_6, RCTYPE_BLUE_EGG, LEVEL_5_FREEZEEZY_PEAK, RI_BLUE_EGG_FREEZEEZY_PEAK, NULL, -5424, -168, 6438), - RC(RC_FP_BLUE_EGG_WATER_POTTED_TREE_7, RCTYPE_BLUE_EGG, LEVEL_5_FREEZEEZY_PEAK, RI_BLUE_EGG_FREEZEEZY_PEAK, NULL, -5280, -168, 5810), - RC(RC_FP_BLUE_EGG_WATER_POTTED_TREE_8, RCTYPE_BLUE_EGG, LEVEL_5_FREEZEEZY_PEAK, RI_BLUE_EGG_FREEZEEZY_PEAK, NULL, -4753, -168, 5455), - RC(RC_FP_BLUE_EGG_WOZZAS_CAVE_1, RCTYPE_BLUE_EGG, LEVEL_5_FREEZEEZY_PEAK, RI_BLUE_EGG_FREEZEEZY_PEAK, NULL, -6559, 0, -291), - RC(RC_FP_BLUE_EGG_WOZZAS_CAVE_2, RCTYPE_BLUE_EGG, LEVEL_5_FREEZEEZY_PEAK, RI_BLUE_EGG_FREEZEEZY_PEAK, NULL, -7119, 0, -113), - RC(RC_FP_BLUE_EGG_WOZZAS_CAVE_3, RCTYPE_BLUE_EGG, LEVEL_5_FREEZEEZY_PEAK, RI_BLUE_EGG_FREEZEEZY_PEAK, NULL, -7166, 0, 926), - RC(RC_FP_BLUE_EGG_WOZZAS_CAVE_4, RCTYPE_BLUE_EGG, LEVEL_5_FREEZEEZY_PEAK, RI_BLUE_EGG_FREEZEEZY_PEAK, NULL, -6599, 0, 1184), + RC(RC_FP_BLUE_EGG_BEHIND_IGLOO_1, RCTYPE_BLUE_EGG, LEVEL_5_FREEZEEZY_PEAK, RI_BLUE_EGG, NULL, 1536, 3505, 9857), + RC(RC_FP_BLUE_EGG_BEHIND_IGLOO_2, RCTYPE_BLUE_EGG, LEVEL_5_FREEZEEZY_PEAK, RI_BLUE_EGG, NULL, 1606, 3505, 9635), + RC(RC_FP_BLUE_EGG_BEHIND_IGLOO_3, RCTYPE_BLUE_EGG, LEVEL_5_FREEZEEZY_PEAK, RI_BLUE_EGG, NULL, 1674, 3505, 9422), + RC(RC_FP_BLUE_EGG_BEHIND_IGLOO_4, RCTYPE_BLUE_EGG, LEVEL_5_FREEZEEZY_PEAK, RI_BLUE_EGG, NULL, 1610, 3505, 9197), + RC(RC_FP_BLUE_EGG_BEHIND_IGLOO_5, RCTYPE_BLUE_EGG, LEVEL_5_FREEZEEZY_PEAK, RI_BLUE_EGG, NULL, 1545, 3505, 8981), + RC(RC_FP_BLUE_EGG_NEAR_GREEN_PRESENT_1, RCTYPE_BLUE_EGG, LEVEL_5_FREEZEEZY_PEAK, RI_BLUE_EGG, NULL, 404, 18, -2625), + RC(RC_FP_BLUE_EGG_NEAR_GREEN_PRESENT_2, RCTYPE_BLUE_EGG, LEVEL_5_FREEZEEZY_PEAK, RI_BLUE_EGG, NULL, 654, 18, -3169), + RC(RC_FP_BLUE_EGG_NEAR_GREEN_PRESENT_3, RCTYPE_BLUE_EGG, LEVEL_5_FREEZEEZY_PEAK, RI_BLUE_EGG, NULL, 1410, 17, -2859), + RC(RC_FP_BLUE_EGG_NEAR_GREEN_PRESENT_4, RCTYPE_BLUE_EGG, LEVEL_5_FREEZEEZY_PEAK, RI_BLUE_EGG, NULL, 1185, 18, -2295), + RC(RC_FP_BLUE_EGG_POTTED_TREE_INTERIOR_1, RCTYPE_BLUE_EGG, LEVEL_5_FREEZEEZY_PEAK, RI_BLUE_EGG, NULL, -344, 2110, -200), + RC(RC_FP_BLUE_EGG_POTTED_TREE_INTERIOR_2, RCTYPE_BLUE_EGG, LEVEL_5_FREEZEEZY_PEAK, RI_BLUE_EGG, NULL, -195, 2110, -343), + RC(RC_FP_BLUE_EGG_POTTED_TREE_INTERIOR_3, RCTYPE_BLUE_EGG, LEVEL_5_FREEZEEZY_PEAK, RI_BLUE_EGG, NULL, -1, 2110, -399), + RC(RC_FP_BLUE_EGG_POTTED_TREE_INTERIOR_4, RCTYPE_BLUE_EGG, LEVEL_5_FREEZEEZY_PEAK, RI_BLUE_EGG, NULL, 199, 2110, -346), + RC(RC_FP_BLUE_EGG_POTTED_TREE_INTERIOR_5, RCTYPE_BLUE_EGG, LEVEL_5_FREEZEEZY_PEAK, RI_BLUE_EGG, NULL, 345, 2110, -199), + RC(RC_FP_BLUE_EGG_POTTED_TREE_INTERIOR_6, RCTYPE_BLUE_EGG, LEVEL_5_FREEZEEZY_PEAK, RI_BLUE_EGG, NULL, 395, 2110, 1), + RC(RC_FP_BLUE_EGG_POTTED_TREE_INTERIOR_7, RCTYPE_BLUE_EGG, LEVEL_5_FREEZEEZY_PEAK, RI_BLUE_EGG, NULL, 341, 2110, 196), + RC(RC_FP_BLUE_EGG_POTTED_TREE_INTERIOR_8, RCTYPE_BLUE_EGG, LEVEL_5_FREEZEEZY_PEAK, RI_BLUE_EGG, NULL, 199, 2110, 340), + RC(RC_FP_BLUE_EGG_POTTED_TREE_INTERIOR_9, RCTYPE_BLUE_EGG, LEVEL_5_FREEZEEZY_PEAK, RI_BLUE_EGG, NULL, 0, 2110, 393), + RC(RC_FP_BLUE_EGG_POTTED_TREE_INTERIOR_10, RCTYPE_BLUE_EGG, LEVEL_5_FREEZEEZY_PEAK, RI_BLUE_EGG, NULL, -198, 2110, 347), + RC(RC_FP_BLUE_EGG_POTTED_TREE_INTERIOR_11, RCTYPE_BLUE_EGG, LEVEL_5_FREEZEEZY_PEAK, RI_BLUE_EGG, NULL, -344, 2110, 198), + RC(RC_FP_BLUE_EGG_POTTED_TREE_INTERIOR_12, RCTYPE_BLUE_EGG, LEVEL_5_FREEZEEZY_PEAK, RI_BLUE_EGG, NULL, -396, 2110, 0), + RC(RC_FP_BLUE_EGG_SNOWMANS_HAT_1, RCTYPE_BLUE_EGG, LEVEL_5_FREEZEEZY_PEAK, RI_BLUE_EGG, NULL, -1465, 7354, 1066), + RC(RC_FP_BLUE_EGG_SNOWMANS_HAT_2, RCTYPE_BLUE_EGG, LEVEL_5_FREEZEEZY_PEAK, RI_BLUE_EGG, NULL, -1961, 7227, 248), + RC(RC_FP_BLUE_EGG_SNOWMANS_HAT_3, RCTYPE_BLUE_EGG, LEVEL_5_FREEZEEZY_PEAK, RI_BLUE_EGG, NULL, -1734, 7166, -667), + RC(RC_FP_BLUE_EGG_SNOWMANS_HAT_4, RCTYPE_BLUE_EGG, LEVEL_5_FREEZEEZY_PEAK, RI_BLUE_EGG, NULL, -948, 7201, -1175), + RC(RC_FP_BLUE_EGG_SNOWMANS_HAT_5, RCTYPE_BLUE_EGG, LEVEL_5_FREEZEEZY_PEAK, RI_BLUE_EGG, NULL, -33, 7313, -984), + RC(RC_FP_BLUE_EGG_SNOWMANS_HAT_6, RCTYPE_BLUE_EGG, LEVEL_5_FREEZEEZY_PEAK, RI_BLUE_EGG, NULL, 496, 7442, -179), + RC(RC_FP_BLUE_EGG_SNOWMANS_HAT_7, RCTYPE_BLUE_EGG, LEVEL_5_FREEZEEZY_PEAK, RI_BLUE_EGG, NULL, 278, 7505, 757), + RC(RC_FP_BLUE_EGG_WATER_BEHIND_SNOWMAN_1, RCTYPE_BLUE_EGG, LEVEL_5_FREEZEEZY_PEAK, RI_BLUE_EGG, NULL, -3128, -168, -4645), + RC(RC_FP_BLUE_EGG_WATER_BEHIND_SNOWMAN_2, RCTYPE_BLUE_EGG, LEVEL_5_FREEZEEZY_PEAK, RI_BLUE_EGG, NULL, -2939, -168, -4791), + RC(RC_FP_BLUE_EGG_WATER_BEHIND_SNOWMAN_3, RCTYPE_BLUE_EGG, LEVEL_5_FREEZEEZY_PEAK, RI_BLUE_EGG, NULL, -2759, -168, -4928), + RC(RC_FP_BLUE_EGG_WATER_BEHIND_SNOWMAN_4, RCTYPE_BLUE_EGG, LEVEL_5_FREEZEEZY_PEAK, RI_BLUE_EGG, NULL, -2552, -168, -5061), + RC(RC_FP_BLUE_EGG_WATER_BEHIND_SNOWMAN_5, RCTYPE_BLUE_EGG, LEVEL_5_FREEZEEZY_PEAK, RI_BLUE_EGG, NULL, -2367, -168, -5166), + RC(RC_FP_BLUE_EGG_WATER_BEHIND_SNOWMAN_6, RCTYPE_BLUE_EGG, LEVEL_5_FREEZEEZY_PEAK, RI_BLUE_EGG, NULL, -2165, -168, -5146), + RC(RC_FP_BLUE_EGG_WATER_BEHIND_SNOWMAN_7, RCTYPE_BLUE_EGG, LEVEL_5_FREEZEEZY_PEAK, RI_BLUE_EGG, NULL, -1979, -168, -5120), + RC(RC_FP_BLUE_EGG_WATER_BEHIND_SNOWMAN_8, RCTYPE_BLUE_EGG, LEVEL_5_FREEZEEZY_PEAK, RI_BLUE_EGG, NULL, -1897, -168, -4931), + RC(RC_FP_BLUE_EGG_WATER_BEHIND_SNOWMAN_9, RCTYPE_BLUE_EGG, LEVEL_5_FREEZEEZY_PEAK, RI_BLUE_EGG, NULL, -1824, -168, -4732), + RC(RC_FP_BLUE_EGG_WATER_BEHIND_SNOWMAN_10, RCTYPE_BLUE_EGG, LEVEL_5_FREEZEEZY_PEAK, RI_BLUE_EGG, NULL, -1758, -168, -4514), + RC(RC_FP_BLUE_EGG_WATER_POTTED_TREE_1, RCTYPE_BLUE_EGG, LEVEL_5_FREEZEEZY_PEAK, RI_BLUE_EGG, NULL, -4112, -168, 5604), + RC(RC_FP_BLUE_EGG_WATER_POTTED_TREE_2, RCTYPE_BLUE_EGG, LEVEL_5_FREEZEEZY_PEAK, RI_BLUE_EGG, NULL, -3753, -168, 6126), + RC(RC_FP_BLUE_EGG_WATER_POTTED_TREE_3, RCTYPE_BLUE_EGG, LEVEL_5_FREEZEEZY_PEAK, RI_BLUE_EGG, NULL, -3887, -168, 6767), + RC(RC_FP_BLUE_EGG_WATER_POTTED_TREE_4, RCTYPE_BLUE_EGG, LEVEL_5_FREEZEEZY_PEAK, RI_BLUE_EGG, NULL, -4440, -168, 7130), + RC(RC_FP_BLUE_EGG_WATER_POTTED_TREE_5, RCTYPE_BLUE_EGG, LEVEL_5_FREEZEEZY_PEAK, RI_BLUE_EGG, NULL, -5069, -168, 6990), + RC(RC_FP_BLUE_EGG_WATER_POTTED_TREE_6, RCTYPE_BLUE_EGG, LEVEL_5_FREEZEEZY_PEAK, RI_BLUE_EGG, NULL, -5424, -168, 6438), + RC(RC_FP_BLUE_EGG_WATER_POTTED_TREE_7, RCTYPE_BLUE_EGG, LEVEL_5_FREEZEEZY_PEAK, RI_BLUE_EGG, NULL, -5280, -168, 5810), + RC(RC_FP_BLUE_EGG_WATER_POTTED_TREE_8, RCTYPE_BLUE_EGG, LEVEL_5_FREEZEEZY_PEAK, RI_BLUE_EGG, NULL, -4753, -168, 5455), + RC(RC_FP_BLUE_EGG_WOZZAS_CAVE_1, RCTYPE_BLUE_EGG, LEVEL_5_FREEZEEZY_PEAK, RI_BLUE_EGG, NULL, -6559, 0, -291), + RC(RC_FP_BLUE_EGG_WOZZAS_CAVE_2, RCTYPE_BLUE_EGG, LEVEL_5_FREEZEEZY_PEAK, RI_BLUE_EGG, NULL, -7119, 0, -113), + RC(RC_FP_BLUE_EGG_WOZZAS_CAVE_3, RCTYPE_BLUE_EGG, LEVEL_5_FREEZEEZY_PEAK, RI_BLUE_EGG, NULL, -7166, 0, 926), + RC(RC_FP_BLUE_EGG_WOZZAS_CAVE_4, RCTYPE_BLUE_EGG, LEVEL_5_FREEZEEZY_PEAK, RI_BLUE_EGG, NULL, -6599, 0, 1184), RC(RC_FP_EMPTY_HONEYCOMB_UNDER_SIR_SLUSH, RCTYPE_EMPTY_HONEYCOMB, LEVEL_5_FREEZEEZY_PEAK, RI_EMPTY_HONEYCOMB_FREEZEEZY_PEAK, HONEYCOMB_A_FP_SIR_SLUSH, 4295, 441, 1268), RC(RC_FP_EMPTY_HONEYCOMB_WOZZAS_CAVE, RCTYPE_EMPTY_HONEYCOMB, LEVEL_5_FREEZEEZY_PEAK, RI_EMPTY_HONEYCOMB_FREEZEEZY_PEAK, HONEYCOMB_9_FP_WOZZAS_CAVE, -6531, 135, 422), - RC(RC_FP_EXTRA_LIFE_ABOVE_MUMBOS_SKULL, RCTYPE_EXTRA_LIFE, LEVEL_5_FREEZEEZY_PEAK, RI_EXTRA_LIFE_FREEZEEZY_PEAK, NULL, 6992, 1390, -3159), - RC(RC_FP_EXTRA_LIFE_RACE_FINISH_LINE, RCTYPE_EXTRA_LIFE, LEVEL_5_FREEZEEZY_PEAK, RI_EXTRA_LIFE_FREEZEEZY_PEAK, NULL, -4450, 1591, -7407), - RC(RC_FP_EXTRA_LIFE_WOZZAS_CAVE, RCTYPE_EXTRA_LIFE, LEVEL_5_FREEZEEZY_PEAK, RI_EXTRA_LIFE_FREEZEEZY_PEAK, NULL, -7322, 0, 391), - RC(RC_FP_HONEYCOMB_BEEHIVE_NEAR_RACE_START_1, RCTYPE_HONEYCOMB, LEVEL_5_FREEZEEZY_PEAK, RI_HONEYCOMB_FREEZEEZY_PEAK, NULL, 0, 0, 0), - RC(RC_FP_HONEYCOMB_BEEHIVE_NEAR_RACE_START_2, RCTYPE_HONEYCOMB, LEVEL_5_FREEZEEZY_PEAK, RI_HONEYCOMB_FREEZEEZY_PEAK, NULL, 0, 0, 0), - RC(RC_FP_HONEYCOMB_BEEHIVE_NEAR_RACE_START_3, RCTYPE_HONEYCOMB, LEVEL_5_FREEZEEZY_PEAK, RI_HONEYCOMB_FREEZEEZY_PEAK, NULL, 0, 0, 0), - RC(RC_FP_HONEYCOMB_BEEHIVE_PRESENT_STACK_1, RCTYPE_HONEYCOMB, LEVEL_5_FREEZEEZY_PEAK, RI_HONEYCOMB_FREEZEEZY_PEAK, NULL, 0, 0, 0), - RC(RC_FP_HONEYCOMB_BEEHIVE_PRESENT_STACK_2, RCTYPE_HONEYCOMB, LEVEL_5_FREEZEEZY_PEAK, RI_HONEYCOMB_FREEZEEZY_PEAK, NULL, 0, 0, 0), - RC(RC_FP_HONEYCOMB_BEEHIVE_PRESENT_STACK_3, RCTYPE_HONEYCOMB, LEVEL_5_FREEZEEZY_PEAK, RI_HONEYCOMB_FREEZEEZY_PEAK, NULL, 0, 0, 0), - RC(RC_FP_HONEYCOMB_BEEHIVE_SCARF_START_1, RCTYPE_HONEYCOMB, LEVEL_5_FREEZEEZY_PEAK, RI_HONEYCOMB_FREEZEEZY_PEAK, NULL, 0, 0, 0), - RC(RC_FP_HONEYCOMB_BEEHIVE_SCARF_START_2, RCTYPE_HONEYCOMB, LEVEL_5_FREEZEEZY_PEAK, RI_HONEYCOMB_FREEZEEZY_PEAK, NULL, 0, 0, 0), - RC(RC_FP_HONEYCOMB_BEEHIVE_SCARF_START_3, RCTYPE_HONEYCOMB, LEVEL_5_FREEZEEZY_PEAK, RI_HONEYCOMB_FREEZEEZY_PEAK, NULL, 0, 0, 0), - RC(RC_FP_HONEYCOMB_BEEHIVE_SCARF_END_1, RCTYPE_HONEYCOMB, LEVEL_5_FREEZEEZY_PEAK, RI_HONEYCOMB_FREEZEEZY_PEAK, NULL, 0, 0, 0), - RC(RC_FP_HONEYCOMB_BEEHIVE_SCARF_END_2, RCTYPE_HONEYCOMB, LEVEL_5_FREEZEEZY_PEAK, RI_HONEYCOMB_FREEZEEZY_PEAK, NULL, 0, 0, 0), - RC(RC_FP_HONEYCOMB_BEEHIVE_SCARF_END_3, RCTYPE_HONEYCOMB, LEVEL_5_FREEZEEZY_PEAK, RI_HONEYCOMB_FREEZEEZY_PEAK, NULL, 0, 0, 0), + RC(RC_FP_EXTRA_LIFE_ABOVE_MUMBOS_SKULL, RCTYPE_EXTRA_LIFE, LEVEL_5_FREEZEEZY_PEAK, RI_EXTRA_LIFE, NULL, 6992, 1390, -3159), + RC(RC_FP_EXTRA_LIFE_RACE_FINISH_LINE, RCTYPE_EXTRA_LIFE, LEVEL_5_FREEZEEZY_PEAK, RI_EXTRA_LIFE, NULL, -4450, 1591, -7407), + RC(RC_FP_EXTRA_LIFE_WOZZAS_CAVE, RCTYPE_EXTRA_LIFE, LEVEL_5_FREEZEEZY_PEAK, RI_EXTRA_LIFE, NULL, -7322, 0, 391), + RC(RC_FP_HONEYCOMB_BEEHIVE_NEAR_RACE_START_1, RCTYPE_HONEYCOMB, LEVEL_5_FREEZEEZY_PEAK, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_FP_HONEYCOMB_BEEHIVE_NEAR_RACE_START_2, RCTYPE_HONEYCOMB, LEVEL_5_FREEZEEZY_PEAK, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_FP_HONEYCOMB_BEEHIVE_NEAR_RACE_START_3, RCTYPE_HONEYCOMB, LEVEL_5_FREEZEEZY_PEAK, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_FP_HONEYCOMB_BEEHIVE_PRESENT_STACK_1, RCTYPE_HONEYCOMB, LEVEL_5_FREEZEEZY_PEAK, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_FP_HONEYCOMB_BEEHIVE_PRESENT_STACK_2, RCTYPE_HONEYCOMB, LEVEL_5_FREEZEEZY_PEAK, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_FP_HONEYCOMB_BEEHIVE_PRESENT_STACK_3, RCTYPE_HONEYCOMB, LEVEL_5_FREEZEEZY_PEAK, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_FP_HONEYCOMB_BEEHIVE_SCARF_START_1, RCTYPE_HONEYCOMB, LEVEL_5_FREEZEEZY_PEAK, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_FP_HONEYCOMB_BEEHIVE_SCARF_START_2, RCTYPE_HONEYCOMB, LEVEL_5_FREEZEEZY_PEAK, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_FP_HONEYCOMB_BEEHIVE_SCARF_START_3, RCTYPE_HONEYCOMB, LEVEL_5_FREEZEEZY_PEAK, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_FP_HONEYCOMB_BEEHIVE_SCARF_END_1, RCTYPE_HONEYCOMB, LEVEL_5_FREEZEEZY_PEAK, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_FP_HONEYCOMB_BEEHIVE_SCARF_END_2, RCTYPE_HONEYCOMB, LEVEL_5_FREEZEEZY_PEAK, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_FP_HONEYCOMB_BEEHIVE_SCARF_END_3, RCTYPE_HONEYCOMB, LEVEL_5_FREEZEEZY_PEAK, RI_HONEYCOMB, NULL, 0, 0, 0), RC(RC_FP_JIGGY_BEAT_ALL_SIR_SLUSH, RCTYPE_JIGGY, LEVEL_5_FREEZEEZY_PEAK, RI_JIGGY_FREEZEEZY_PEAK, JIGGY_31_FP_SIR_SLUSH, 0, 0 ,0), RC(RC_FP_JIGGY_BOGGY_RACE_1, RCTYPE_JIGGY, LEVEL_5_FREEZEEZY_PEAK, RI_JIGGY_FREEZEEZY_PEAK, JIGGY_30_FP_BOGGY_2, 0, 0 ,0), RC(RC_FP_JIGGY_BOGGY_RACE_2, RCTYPE_JIGGY, LEVEL_5_FREEZEEZY_PEAK, RI_JIGGY_FREEZEEZY_PEAK, JIGGY_2C_FP_BOGGY_3, 0, 0 ,0), @@ -891,109 +891,109 @@ std::map Checks = { RC(RC_FP_NOTE_SNOWMAN_SCARF_18, RCTYPE_MUSIC_NOTE, LEVEL_5_FREEZEEZY_PEAK, RI_MUSIC_NOTE_FREEZEEZY_PEAK, NULL, -941, 5605, 844), RC(RC_FP_NOTE_SNOWMAN_SCARF_19, RCTYPE_MUSIC_NOTE, LEVEL_5_FREEZEEZY_PEAK, RI_MUSIC_NOTE_FREEZEEZY_PEAK, NULL, 17, 5605, 266), RC(RC_FP_SNS_ICE_KEY, RCTYPE_STOP_N_SWOP, LEVEL_5_FREEZEEZY_PEAK, RI_STOP_N_SWOP_ICE_KEY, SNS_ITEM_ICE_KEY, 1567, 583, 2416), - RC(RC_GL_BLUE_EGG_ABOVE_350_NOTE_DOOR_1, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG_GRUNTILDAS_LAIR, NULL, 50, 2009, -1065), - RC(RC_GL_BLUE_EGG_ABOVE_350_NOTE_DOOR_2, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG_GRUNTILDAS_LAIR, NULL, 50, 2009, -605), - RC(RC_GL_BLUE_EGG_ABOVE_350_NOTE_DOOR_3, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG_GRUNTILDAS_LAIR, NULL, 50, 2009, -145), - RC(RC_GL_BLUE_EGG_ABOVE_350_NOTE_DOOR_4, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG_GRUNTILDAS_LAIR, NULL, 50, 2009, 315), - RC(RC_GL_BLUE_EGG_ABOVE_350_NOTE_DOOR_5, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG_GRUNTILDAS_LAIR, NULL, 50, 2009, 775), - RC(RC_GL_BLUE_EGG_ABOVE_350_NOTE_DOOR_6, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG_GRUNTILDAS_LAIR, NULL, 50, 2009, 1235), - RC(RC_GL_BLUE_EGG_BEFORE_GOBIS_VALLEY_ENTRANCE_1, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG_GRUNTILDAS_LAIR, NULL, 2799, 0, -2071), - RC(RC_GL_BLUE_EGG_BEFORE_GOBIS_VALLEY_ENTRANCE_2, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG_GRUNTILDAS_LAIR, NULL, 2911, 0, -1907), - RC(RC_GL_BLUE_EGG_BEFORE_GOBIS_VALLEY_ENTRANCE_3, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG_GRUNTILDAS_LAIR, NULL, 3016, 0, -1764), - RC(RC_GL_BLUE_EGG_BEFORE_GOBIS_VALLEY_ENTRANCE_4, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG_GRUNTILDAS_LAIR, NULL, 3120, 0, -1616), - RC(RC_GL_BLUE_EGG_BEFORE_SECOND_NOTE_DOOR_1, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG_GRUNTILDAS_LAIR, NULL, -9, -1395, 1178), - RC(RC_GL_BLUE_EGG_BEFORE_SECOND_NOTE_DOOR_2, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG_GRUNTILDAS_LAIR, NULL, 382, -1395, 1090), - RC(RC_GL_BLUE_EGG_BEFORE_SECOND_NOTE_DOOR_3, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG_GRUNTILDAS_LAIR, NULL, 820, -1395, 1183), - RC(RC_GL_BLUE_EGG_BEFORE_SECOND_NOTE_DOOR_4, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG_GRUNTILDAS_LAIR, NULL, 820, -1395, 1692), - RC(RC_GL_BLUE_EGG_BEFORE_SECOND_NOTE_DOOR_5, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG_GRUNTILDAS_LAIR, NULL, 445, -1395, 1832), - RC(RC_GL_BLUE_EGG_BEFORE_SECOND_NOTE_DOOR_6, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG_GRUNTILDAS_LAIR, NULL, 27, -1395, 1781), - RC(RC_GL_BLUE_EGG_BEFORE_SECOND_NOTE_DOOR_7, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG_GRUNTILDAS_LAIR, NULL, -185, -1395, 1477), - RC(RC_GL_BLUE_EGG_CCW_ENTRANCE_UPPER_TUNNEL_1, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG_GRUNTILDAS_LAIR, NULL, 0, 800, 3600), - RC(RC_GL_BLUE_EGG_CCW_ENTRANCE_UPPER_TUNNEL_2, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG_GRUNTILDAS_LAIR, NULL, 0, 800, 4001), - RC(RC_GL_BLUE_EGG_CCW_ENTRANCE_UPPER_TUNNEL_3, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG_GRUNTILDAS_LAIR, NULL, 0, 800, 4400), - RC(RC_GL_BLUE_EGG_CCW_ENTRANCE_UPPER_TUNNEL_4, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG_GRUNTILDAS_LAIR, NULL, 0, 800, 4800), - RC(RC_GL_BLUE_EGG_BGS_PUZZLE_BOARD_1, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG_GRUNTILDAS_LAIR, NULL, -6392, 122, 744), - RC(RC_GL_BLUE_EGG_BGS_PUZZLE_BOARD_2, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG_GRUNTILDAS_LAIR, NULL, -6732, 277, 765), - RC(RC_GL_BLUE_EGG_BGS_PUZZLE_BOARD_3, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG_GRUNTILDAS_LAIR, NULL, -7018, 426, 641), - RC(RC_GL_BLUE_EGG_BGS_PUZZLE_BOARD_4, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG_GRUNTILDAS_LAIR, NULL, -7264, 495, 389), - RC(RC_GL_BLUE_EGG_BGS_PUZZLE_BOARD_5, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG_GRUNTILDAS_LAIR, NULL, -7264, 496, -1392), - RC(RC_GL_BLUE_EGG_BGS_PUZZLE_BOARD_6, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG_GRUNTILDAS_LAIR, NULL, -7018, 426, -1640), - RC(RC_GL_BLUE_EGG_BGS_PUZZLE_BOARD_7, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG_GRUNTILDAS_LAIR, NULL, -6732, 277, -1767), - RC(RC_GL_BLUE_EGG_BGS_PUZZLE_BOARD_8, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG_GRUNTILDAS_LAIR, NULL, -6392, 122, -1749), - RC(RC_GL_BLUE_EGG_FP_PUZZLE_BOARD_1, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG_GRUNTILDAS_LAIR, NULL, 2726, -176, -6393), - RC(RC_GL_BLUE_EGG_FP_PUZZLE_BOARD_2, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG_GRUNTILDAS_LAIR, NULL, 2986, -176, -6339), - RC(RC_GL_BLUE_EGG_FP_PUZZLE_BOARD_3, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG_GRUNTILDAS_LAIR, NULL, 3277, -176, -6332), - RC(RC_GL_BLUE_EGG_FP_PUZZLE_BOARD_4, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG_GRUNTILDAS_LAIR, NULL, 3552, -176, -6394), - RC(RC_GL_BLUE_EGG_MMM_ENTRANCE_1, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG_GRUNTILDAS_LAIR, NULL, 1004, -800, 6827), - RC(RC_GL_BLUE_EGG_MMM_ENTRANCE_2, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG_GRUNTILDAS_LAIR, NULL, 888, -802, 6826), - RC(RC_GL_BLUE_EGG_MMM_ENTRANCE_3, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG_GRUNTILDAS_LAIR, NULL, -300, -792, 6800), - RC(RC_GL_BLUE_EGG_MMM_ENTRANCE_4, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG_GRUNTILDAS_LAIR, NULL, -458, -768, 6764), - RC(RC_GL_BLUE_EGG_MMM_PUZZLE_BOARD_1, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG_GRUNTILDAS_LAIR, NULL, -1335, -1482, 1349), - RC(RC_GL_BLUE_EGG_MMM_PUZZLE_BOARD_2, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG_GRUNTILDAS_LAIR, NULL, -1835, -1486, 485), - RC(RC_GL_BLUE_EGG_MMM_PUZZLE_BOARD_3, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG_GRUNTILDAS_LAIR, NULL, -1832, -1486, -499), - RC(RC_GL_BLUE_EGG_MMM_PUZZLE_BOARD_4, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG_GRUNTILDAS_LAIR, NULL, -1344, -1492, -1346), - RC(RC_GL_BLUE_EGG_MMM_PUZZLE_BOARD_5, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG_GRUNTILDAS_LAIR, NULL, -499, -1492, -1836), - RC(RC_GL_BLUE_EGG_MMM_PUZZLE_BOARD_6, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG_GRUNTILDAS_LAIR, NULL, 491, -1490, -1832), - RC(RC_GL_BLUE_EGG_MMM_PUZZLE_BOARD_7, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG_GRUNTILDAS_LAIR, NULL, 1342, -1486, -1349), - RC(RC_GL_BLUE_EGG_MMM_PUZZLE_BOARD_8, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG_GRUNTILDAS_LAIR, NULL, 1833, -1492, -491), - RC(RC_GL_BLUE_EGG_MMM_PUZZLE_BOARD_9, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG_GRUNTILDAS_LAIR, NULL, 1846, -1492, 503), - RC(RC_GL_BLUE_EGG_MMM_PUZZLE_BOARD_10, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG_GRUNTILDAS_LAIR, NULL, 1341, -1492, 1361), - RC(RC_GL_BLUE_EGG_NEAR_PURPLE_CAULDRON_1, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG_GRUNTILDAS_LAIR, NULL, -885, -749, 3037), - RC(RC_GL_BLUE_EGG_NEAR_PURPLE_CAULDRON_2, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG_GRUNTILDAS_LAIR, NULL, -98, -749, 3041), - RC(RC_GL_BLUE_EGG_NEAR_PURPLE_CAULDRON_3, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG_GRUNTILDAS_LAIR, NULL, 418, -750, 3577), - RC(RC_GL_BLUE_EGG_NEAR_PURPLE_CAULDRON_4, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG_GRUNTILDAS_LAIR, NULL, 422, -750, 4333), - RC(RC_GL_BLUE_EGG_NEAR_PURPLE_CAULDRON_5, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG_GRUNTILDAS_LAIR, NULL, -114, -750, 4871), - RC(RC_GL_BLUE_EGG_NEAR_PURPLE_CAULDRON_6, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG_GRUNTILDAS_LAIR, NULL, -864, -750, 4881), - RC(RC_GL_BLUE_EGG_NEAR_PURPLE_CAULDRON_7, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG_GRUNTILDAS_LAIR, NULL, -1412, -750, 4335), - RC(RC_GL_BLUE_EGG_NEAR_PURPLE_CAULDRON_8, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG_GRUNTILDAS_LAIR, NULL, -1410, -749, 3551), - RC(RC_GL_BLUE_EGG_RBB_ENTRANCE_1, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG_GRUNTILDAS_LAIR, NULL, -1499, 0, 310), - RC(RC_GL_BLUE_EGG_RBB_ENTRANCE_2, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG_GRUNTILDAS_LAIR, NULL, -1630, 0, 310), - RC(RC_GL_BLUE_EGG_RBB_ENTRANCE_3, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG_GRUNTILDAS_LAIR, NULL, -1630, 0, 180), - RC(RC_GL_BLUE_EGG_RBB_ENTRANCE_4, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG_GRUNTILDAS_LAIR, NULL, -1499, 0, 180), - RC(RC_GL_BLUE_EGG_RBB_PUZZLE_BOARD_1, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG_GRUNTILDAS_LAIR, NULL, 7900, 1750, -1445), - RC(RC_GL_BLUE_EGG_RBB_PUZZLE_BOARD_2, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG_GRUNTILDAS_LAIR, NULL, 7900, 1750, -1358), - RC(RC_GL_BLUE_EGG_WATER_SWITCH_1_ROOM_1, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG_GRUNTILDAS_LAIR, NULL, -898, 0, -630), - RC(RC_GL_BLUE_EGG_WATER_SWITCH_1_ROOM_2, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG_GRUNTILDAS_LAIR, NULL, -126, 0, -637), - RC(RC_GL_BLUE_EGG_WATER_SWITCH_1_ROOM_3, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG_GRUNTILDAS_LAIR, NULL, 671, 0, -637), - RC(RC_GL_BLUE_EGG_WATER_SWITCH_1_ROOM_4, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG_GRUNTILDAS_LAIR, NULL, 671, 0, 631), - RC(RC_GL_BLUE_EGG_WATER_SWITCH_1_ROOM_5, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG_GRUNTILDAS_LAIR, NULL, -112, 0, 630), - RC(RC_GL_BLUE_EGG_WATER_SWITCH_1_ROOM_6, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG_GRUNTILDAS_LAIR, NULL, -899, 0, 630), - RC(RC_GL_EXTRA_LIFE_ABOVE_CLICK_CLOCK_WOODS_ENTRANCE, RCTYPE_EXTRA_LIFE, LEVEL_6_LAIR, RI_EXTRA_LIFE_GRUNTILDAS_LAIR, NULL, 0, 1600, -3700), - RC(RC_GL_EXTRA_LIFE_ABOVE_THE_LOG_NEAR_BUBBLEGLOOP, RCTYPE_EXTRA_LIFE, LEVEL_6_LAIR, RI_EXTRA_LIFE_GRUNTILDAS_LAIR, NULL, -1992, 878, -3052), - RC(RC_GL_EXTRA_LIFE_BACK_OF_GRUNTY_STATUES_HAT, RCTYPE_EXTRA_LIFE, LEVEL_6_LAIR, RI_EXTRA_LIFE_GRUNTILDAS_LAIR, NULL, 2954, 1247, 100), - RC(RC_GL_EXTRA_LIFE_BEHIND_MUMBOS_SHACK, RCTYPE_EXTRA_LIFE, LEVEL_6_LAIR, RI_EXTRA_LIFE_GRUNTILDAS_LAIR, NULL, -8689, -1781, -3192), - RC(RC_GL_EXTRA_LIFE_CLICK_CLOCK_WOODS_PUZZLE_ROOM, RCTYPE_EXTRA_LIFE, LEVEL_6_LAIR, RI_EXTRA_LIFE_GRUNTILDAS_LAIR, NULL, 3599, -478, 2424), - RC(RC_GL_EXTRA_LIFE_MAD_MONSTER_MANSION_PUZZLE_ROOM, RCTYPE_EXTRA_LIFE, LEVEL_6_LAIR, RI_EXTRA_LIFE_GRUNTILDAS_LAIR, NULL, -838, 1950, 835), - RC(RC_GL_HONEYCOMB_BEEHIVE_BEHIND_BGS_ENTRANCE_1, RCTYPE_HONEYCOMB, LEVEL_6_LAIR, RI_HONEYCOMB_GRUNTILDAS_LAIR, NULL, 0, 0, 0), - RC(RC_GL_HONEYCOMB_BEEHIVE_BEHIND_BGS_ENTRANCE_2, RCTYPE_HONEYCOMB, LEVEL_6_LAIR, RI_HONEYCOMB_GRUNTILDAS_LAIR, NULL, 0, 0, 0), - RC(RC_GL_HONEYCOMB_BEEHIVE_BEHIND_BGS_ENTRANCE_3, RCTYPE_HONEYCOMB, LEVEL_6_LAIR, RI_HONEYCOMB_GRUNTILDAS_LAIR, NULL, 0, 0, 0), - RC(RC_GL_HONEYCOMB_BEEHIVE_BEHIND_MMM_ENTRANCE_1, RCTYPE_HONEYCOMB, LEVEL_6_LAIR, RI_HONEYCOMB_GRUNTILDAS_LAIR, NULL, 0, 0, 0), - RC(RC_GL_HONEYCOMB_BEEHIVE_BEHIND_MMM_ENTRANCE_2, RCTYPE_HONEYCOMB, LEVEL_6_LAIR, RI_HONEYCOMB_GRUNTILDAS_LAIR, NULL, 0, 0, 0), - RC(RC_GL_HONEYCOMB_BEEHIVE_BEHIND_MMM_ENTRANCE_3, RCTYPE_HONEYCOMB, LEVEL_6_LAIR, RI_HONEYCOMB_GRUNTILDAS_LAIR, NULL, 0, 0, 0), - RC(RC_GL_HONEYCOMB_BEEHIVE_BIG_GRUNTY_STATUE_LEFT_1, RCTYPE_HONEYCOMB, LEVEL_6_LAIR, RI_HONEYCOMB_GRUNTILDAS_LAIR, NULL, 0, 0, 0), - RC(RC_GL_HONEYCOMB_BEEHIVE_BIG_GRUNTY_STATUE_LEFT_2, RCTYPE_HONEYCOMB, LEVEL_6_LAIR, RI_HONEYCOMB_GRUNTILDAS_LAIR, NULL, 0, 0, 0), - RC(RC_GL_HONEYCOMB_BEEHIVE_BIG_GRUNTY_STATUE_LEFT_3, RCTYPE_HONEYCOMB, LEVEL_6_LAIR, RI_HONEYCOMB_GRUNTILDAS_LAIR, NULL, 0, 0, 0), - RC(RC_GL_HONEYCOMB_BEEHIVE_BIG_GRUNTY_STATUE_RIGHT_1, RCTYPE_HONEYCOMB, LEVEL_6_LAIR, RI_HONEYCOMB_GRUNTILDAS_LAIR, NULL, 0, 0, 0), - RC(RC_GL_HONEYCOMB_BEEHIVE_BIG_GRUNTY_STATUE_RIGHT_2, RCTYPE_HONEYCOMB, LEVEL_6_LAIR, RI_HONEYCOMB_GRUNTILDAS_LAIR, NULL, 0, 0, 0), - RC(RC_GL_HONEYCOMB_BEEHIVE_BIG_GRUNTY_STATUE_RIGHT_3, RCTYPE_HONEYCOMB, LEVEL_6_LAIR, RI_HONEYCOMB_GRUNTILDAS_LAIR, NULL, 0, 0, 0), - RC(RC_GL_HONEYCOMB_BEEHIVE_NEAR_50_NOTE_DOOR_1, RCTYPE_HONEYCOMB, LEVEL_6_LAIR, RI_HONEYCOMB_GRUNTILDAS_LAIR, NULL, 0, 0, 0), - RC(RC_GL_HONEYCOMB_BEEHIVE_NEAR_50_NOTE_DOOR_2, RCTYPE_HONEYCOMB, LEVEL_6_LAIR, RI_HONEYCOMB_GRUNTILDAS_LAIR, NULL, 0, 0, 0), - RC(RC_GL_HONEYCOMB_BEEHIVE_NEAR_50_NOTE_DOOR_3, RCTYPE_HONEYCOMB, LEVEL_6_LAIR, RI_HONEYCOMB_GRUNTILDAS_LAIR, NULL, 0, 0, 0), - RC(RC_GL_HONEYCOMB_BEEHIVE_NEAR_CCW_PUZZLE_SWITCH_1, RCTYPE_HONEYCOMB, LEVEL_6_LAIR, RI_HONEYCOMB_GRUNTILDAS_LAIR, NULL, 0, 0, 0), - RC(RC_GL_HONEYCOMB_BEEHIVE_NEAR_CCW_PUZZLE_SWITCH_2, RCTYPE_HONEYCOMB, LEVEL_6_LAIR, RI_HONEYCOMB_GRUNTILDAS_LAIR, NULL, 0, 0, 0), - RC(RC_GL_HONEYCOMB_BEEHIVE_NEAR_CCW_PUZZLE_SWITCH_3, RCTYPE_HONEYCOMB, LEVEL_6_LAIR, RI_HONEYCOMB_GRUNTILDAS_LAIR, NULL, 0, 0, 0), - RC(RC_GL_HONEYCOMB_BEEHIVE_NEAR_FIRST_GRUNTY_STATUE_1, RCTYPE_HONEYCOMB, LEVEL_6_LAIR, RI_HONEYCOMB_GRUNTILDAS_LAIR, NULL, 0, 0, 0), - RC(RC_GL_HONEYCOMB_BEEHIVE_NEAR_FIRST_GRUNTY_STATUE_2, RCTYPE_HONEYCOMB, LEVEL_6_LAIR, RI_HONEYCOMB_GRUNTILDAS_LAIR, NULL, 0, 0, 0), - RC(RC_GL_HONEYCOMB_BEEHIVE_NEAR_FIRST_GRUNTY_STATUE_3, RCTYPE_HONEYCOMB, LEVEL_6_LAIR, RI_HONEYCOMB_GRUNTILDAS_LAIR, NULL, 0, 0, 0), - RC(RC_GL_HONEYCOMB_BEEHIVE_NEAR_CC_ENTRANCE_1, RCTYPE_HONEYCOMB, LEVEL_6_LAIR, RI_HONEYCOMB_GRUNTILDAS_LAIR, NULL, 0, 0, 0), - RC(RC_GL_HONEYCOMB_BEEHIVE_NEAR_CC_ENTRANCE_2, RCTYPE_HONEYCOMB, LEVEL_6_LAIR, RI_HONEYCOMB_GRUNTILDAS_LAIR, NULL, 0, 0, 0), - RC(RC_GL_HONEYCOMB_BEEHIVE_NEAR_CC_ENTRANCE_3, RCTYPE_HONEYCOMB, LEVEL_6_LAIR, RI_HONEYCOMB_GRUNTILDAS_LAIR, NULL, 0, 0, 0), - RC(RC_GL_HONEYCOMB_BEEHIVE_NEAR_TTC_ENTRANCE_1, RCTYPE_HONEYCOMB, LEVEL_6_LAIR, RI_HONEYCOMB_GRUNTILDAS_LAIR, NULL, 0, 0, 0), - RC(RC_GL_HONEYCOMB_BEEHIVE_NEAR_TTC_ENTRANCE_2, RCTYPE_HONEYCOMB, LEVEL_6_LAIR, RI_HONEYCOMB_GRUNTILDAS_LAIR, NULL, 0, 0, 0), - RC(RC_GL_HONEYCOMB_BEEHIVE_NEAR_TTC_ENTRANCE_3, RCTYPE_HONEYCOMB, LEVEL_6_LAIR, RI_HONEYCOMB_GRUNTILDAS_LAIR, NULL, 0, 0, 0), - RC(RC_GL_HONEYCOMB_BEEHIVE_NEAR_RBB_PUZZLE_1, RCTYPE_HONEYCOMB, LEVEL_6_LAIR, RI_HONEYCOMB_GRUNTILDAS_LAIR, NULL, 0, 0, 0), - RC(RC_GL_HONEYCOMB_BEEHIVE_NEAR_RBB_PUZZLE_2, RCTYPE_HONEYCOMB, LEVEL_6_LAIR, RI_HONEYCOMB_GRUNTILDAS_LAIR, NULL, 0, 0, 0), - RC(RC_GL_HONEYCOMB_BEEHIVE_NEAR_RBB_PUZZLE_3, RCTYPE_HONEYCOMB, LEVEL_6_LAIR, RI_HONEYCOMB_GRUNTILDAS_LAIR, NULL, 0, 0, 0), + RC(RC_GL_BLUE_EGG_ABOVE_350_NOTE_DOOR_1, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG, NULL, 50, 2009, -1065), + RC(RC_GL_BLUE_EGG_ABOVE_350_NOTE_DOOR_2, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG, NULL, 50, 2009, -605), + RC(RC_GL_BLUE_EGG_ABOVE_350_NOTE_DOOR_3, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG, NULL, 50, 2009, -145), + RC(RC_GL_BLUE_EGG_ABOVE_350_NOTE_DOOR_4, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG, NULL, 50, 2009, 315), + RC(RC_GL_BLUE_EGG_ABOVE_350_NOTE_DOOR_5, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG, NULL, 50, 2009, 775), + RC(RC_GL_BLUE_EGG_ABOVE_350_NOTE_DOOR_6, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG, NULL, 50, 2009, 1235), + RC(RC_GL_BLUE_EGG_BEFORE_GOBIS_VALLEY_ENTRANCE_1, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG, NULL, 2799, 0, -2071), + RC(RC_GL_BLUE_EGG_BEFORE_GOBIS_VALLEY_ENTRANCE_2, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG, NULL, 2911, 0, -1907), + RC(RC_GL_BLUE_EGG_BEFORE_GOBIS_VALLEY_ENTRANCE_3, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG, NULL, 3016, 0, -1764), + RC(RC_GL_BLUE_EGG_BEFORE_GOBIS_VALLEY_ENTRANCE_4, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG, NULL, 3120, 0, -1616), + RC(RC_GL_BLUE_EGG_BEFORE_SECOND_NOTE_DOOR_1, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG, NULL, -9, -1395, 1178), + RC(RC_GL_BLUE_EGG_BEFORE_SECOND_NOTE_DOOR_2, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG, NULL, 382, -1395, 1090), + RC(RC_GL_BLUE_EGG_BEFORE_SECOND_NOTE_DOOR_3, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG, NULL, 820, -1395, 1183), + RC(RC_GL_BLUE_EGG_BEFORE_SECOND_NOTE_DOOR_4, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG, NULL, 820, -1395, 1692), + RC(RC_GL_BLUE_EGG_BEFORE_SECOND_NOTE_DOOR_5, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG, NULL, 445, -1395, 1832), + RC(RC_GL_BLUE_EGG_BEFORE_SECOND_NOTE_DOOR_6, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG, NULL, 27, -1395, 1781), + RC(RC_GL_BLUE_EGG_BEFORE_SECOND_NOTE_DOOR_7, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG, NULL, -185, -1395, 1477), + RC(RC_GL_BLUE_EGG_CCW_ENTRANCE_UPPER_TUNNEL_1, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG, NULL, 0, 800, 3600), + RC(RC_GL_BLUE_EGG_CCW_ENTRANCE_UPPER_TUNNEL_2, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG, NULL, 0, 800, 4001), + RC(RC_GL_BLUE_EGG_CCW_ENTRANCE_UPPER_TUNNEL_3, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG, NULL, 0, 800, 4400), + RC(RC_GL_BLUE_EGG_CCW_ENTRANCE_UPPER_TUNNEL_4, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG, NULL, 0, 800, 4800), + RC(RC_GL_BLUE_EGG_BGS_PUZZLE_BOARD_1, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG, NULL, -6392, 122, 744), + RC(RC_GL_BLUE_EGG_BGS_PUZZLE_BOARD_2, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG, NULL, -6732, 277, 765), + RC(RC_GL_BLUE_EGG_BGS_PUZZLE_BOARD_3, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG, NULL, -7018, 426, 641), + RC(RC_GL_BLUE_EGG_BGS_PUZZLE_BOARD_4, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG, NULL, -7264, 495, 389), + RC(RC_GL_BLUE_EGG_BGS_PUZZLE_BOARD_5, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG, NULL, -7264, 496, -1392), + RC(RC_GL_BLUE_EGG_BGS_PUZZLE_BOARD_6, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG, NULL, -7018, 426, -1640), + RC(RC_GL_BLUE_EGG_BGS_PUZZLE_BOARD_7, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG, NULL, -6732, 277, -1767), + RC(RC_GL_BLUE_EGG_BGS_PUZZLE_BOARD_8, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG, NULL, -6392, 122, -1749), + RC(RC_GL_BLUE_EGG_FP_PUZZLE_BOARD_1, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG, NULL, 2726, -176, -6393), + RC(RC_GL_BLUE_EGG_FP_PUZZLE_BOARD_2, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG, NULL, 2986, -176, -6339), + RC(RC_GL_BLUE_EGG_FP_PUZZLE_BOARD_3, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG, NULL, 3277, -176, -6332), + RC(RC_GL_BLUE_EGG_FP_PUZZLE_BOARD_4, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG, NULL, 3552, -176, -6394), + RC(RC_GL_BLUE_EGG_MMM_ENTRANCE_1, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG, NULL, 1004, -800, 6827), + RC(RC_GL_BLUE_EGG_MMM_ENTRANCE_2, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG, NULL, 888, -802, 6826), + RC(RC_GL_BLUE_EGG_MMM_ENTRANCE_3, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG, NULL, -300, -792, 6800), + RC(RC_GL_BLUE_EGG_MMM_ENTRANCE_4, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG, NULL, -458, -768, 6764), + RC(RC_GL_BLUE_EGG_MMM_PUZZLE_BOARD_1, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG, NULL, -1335, -1482, 1349), + RC(RC_GL_BLUE_EGG_MMM_PUZZLE_BOARD_2, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG, NULL, -1835, -1486, 485), + RC(RC_GL_BLUE_EGG_MMM_PUZZLE_BOARD_3, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG, NULL, -1832, -1486, -499), + RC(RC_GL_BLUE_EGG_MMM_PUZZLE_BOARD_4, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG, NULL, -1344, -1492, -1346), + RC(RC_GL_BLUE_EGG_MMM_PUZZLE_BOARD_5, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG, NULL, -499, -1492, -1836), + RC(RC_GL_BLUE_EGG_MMM_PUZZLE_BOARD_6, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG, NULL, 491, -1490, -1832), + RC(RC_GL_BLUE_EGG_MMM_PUZZLE_BOARD_7, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG, NULL, 1342, -1486, -1349), + RC(RC_GL_BLUE_EGG_MMM_PUZZLE_BOARD_8, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG, NULL, 1833, -1492, -491), + RC(RC_GL_BLUE_EGG_MMM_PUZZLE_BOARD_9, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG, NULL, 1846, -1492, 503), + RC(RC_GL_BLUE_EGG_MMM_PUZZLE_BOARD_10, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG, NULL, 1341, -1492, 1361), + RC(RC_GL_BLUE_EGG_NEAR_PURPLE_CAULDRON_1, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG, NULL, -885, -749, 3037), + RC(RC_GL_BLUE_EGG_NEAR_PURPLE_CAULDRON_2, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG, NULL, -98, -749, 3041), + RC(RC_GL_BLUE_EGG_NEAR_PURPLE_CAULDRON_3, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG, NULL, 418, -750, 3577), + RC(RC_GL_BLUE_EGG_NEAR_PURPLE_CAULDRON_4, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG, NULL, 422, -750, 4333), + RC(RC_GL_BLUE_EGG_NEAR_PURPLE_CAULDRON_5, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG, NULL, -114, -750, 4871), + RC(RC_GL_BLUE_EGG_NEAR_PURPLE_CAULDRON_6, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG, NULL, -864, -750, 4881), + RC(RC_GL_BLUE_EGG_NEAR_PURPLE_CAULDRON_7, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG, NULL, -1412, -750, 4335), + RC(RC_GL_BLUE_EGG_NEAR_PURPLE_CAULDRON_8, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG, NULL, -1410, -749, 3551), + RC(RC_GL_BLUE_EGG_RBB_ENTRANCE_1, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG, NULL, -1499, 0, 310), + RC(RC_GL_BLUE_EGG_RBB_ENTRANCE_2, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG, NULL, -1630, 0, 310), + RC(RC_GL_BLUE_EGG_RBB_ENTRANCE_3, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG, NULL, -1630, 0, 180), + RC(RC_GL_BLUE_EGG_RBB_ENTRANCE_4, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG, NULL, -1499, 0, 180), + RC(RC_GL_BLUE_EGG_RBB_PUZZLE_BOARD_1, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG, NULL, 7900, 1750, -1445), + RC(RC_GL_BLUE_EGG_RBB_PUZZLE_BOARD_2, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG, NULL, 7900, 1750, -1358), + RC(RC_GL_BLUE_EGG_WATER_SWITCH_1_ROOM_1, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG, NULL, -898, 0, -630), + RC(RC_GL_BLUE_EGG_WATER_SWITCH_1_ROOM_2, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG, NULL, -126, 0, -637), + RC(RC_GL_BLUE_EGG_WATER_SWITCH_1_ROOM_3, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG, NULL, 671, 0, -637), + RC(RC_GL_BLUE_EGG_WATER_SWITCH_1_ROOM_4, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG, NULL, 671, 0, 631), + RC(RC_GL_BLUE_EGG_WATER_SWITCH_1_ROOM_5, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG, NULL, -112, 0, 630), + RC(RC_GL_BLUE_EGG_WATER_SWITCH_1_ROOM_6, RCTYPE_BLUE_EGG, LEVEL_6_LAIR, RI_BLUE_EGG, NULL, -899, 0, 630), + RC(RC_GL_EXTRA_LIFE_ABOVE_CLICK_CLOCK_WOODS_ENTRANCE, RCTYPE_EXTRA_LIFE, LEVEL_6_LAIR, RI_EXTRA_LIFE, NULL, 0, 1600, -3700), + RC(RC_GL_EXTRA_LIFE_ABOVE_THE_LOG_NEAR_BUBBLEGLOOP, RCTYPE_EXTRA_LIFE, LEVEL_6_LAIR, RI_EXTRA_LIFE, NULL, -1992, 878, -3052), + RC(RC_GL_EXTRA_LIFE_BACK_OF_GRUNTY_STATUES_HAT, RCTYPE_EXTRA_LIFE, LEVEL_6_LAIR, RI_EXTRA_LIFE, NULL, 2954, 1247, 100), + RC(RC_GL_EXTRA_LIFE_BEHIND_MUMBOS_SHACK, RCTYPE_EXTRA_LIFE, LEVEL_6_LAIR, RI_EXTRA_LIFE, NULL, -8689, -1781, -3192), + RC(RC_GL_EXTRA_LIFE_CLICK_CLOCK_WOODS_PUZZLE_ROOM, RCTYPE_EXTRA_LIFE, LEVEL_6_LAIR, RI_EXTRA_LIFE, NULL, 3599, -478, 2424), + RC(RC_GL_EXTRA_LIFE_MAD_MONSTER_MANSION_PUZZLE_ROOM, RCTYPE_EXTRA_LIFE, LEVEL_6_LAIR, RI_EXTRA_LIFE, NULL, -838, 1950, 835), + RC(RC_GL_HONEYCOMB_BEEHIVE_BEHIND_BGS_ENTRANCE_1, RCTYPE_HONEYCOMB, LEVEL_6_LAIR, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_GL_HONEYCOMB_BEEHIVE_BEHIND_BGS_ENTRANCE_2, RCTYPE_HONEYCOMB, LEVEL_6_LAIR, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_GL_HONEYCOMB_BEEHIVE_BEHIND_BGS_ENTRANCE_3, RCTYPE_HONEYCOMB, LEVEL_6_LAIR, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_GL_HONEYCOMB_BEEHIVE_BEHIND_MMM_ENTRANCE_1, RCTYPE_HONEYCOMB, LEVEL_6_LAIR, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_GL_HONEYCOMB_BEEHIVE_BEHIND_MMM_ENTRANCE_2, RCTYPE_HONEYCOMB, LEVEL_6_LAIR, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_GL_HONEYCOMB_BEEHIVE_BEHIND_MMM_ENTRANCE_3, RCTYPE_HONEYCOMB, LEVEL_6_LAIR, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_GL_HONEYCOMB_BEEHIVE_BIG_GRUNTY_STATUE_LEFT_1, RCTYPE_HONEYCOMB, LEVEL_6_LAIR, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_GL_HONEYCOMB_BEEHIVE_BIG_GRUNTY_STATUE_LEFT_2, RCTYPE_HONEYCOMB, LEVEL_6_LAIR, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_GL_HONEYCOMB_BEEHIVE_BIG_GRUNTY_STATUE_LEFT_3, RCTYPE_HONEYCOMB, LEVEL_6_LAIR, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_GL_HONEYCOMB_BEEHIVE_BIG_GRUNTY_STATUE_RIGHT_1, RCTYPE_HONEYCOMB, LEVEL_6_LAIR, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_GL_HONEYCOMB_BEEHIVE_BIG_GRUNTY_STATUE_RIGHT_2, RCTYPE_HONEYCOMB, LEVEL_6_LAIR, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_GL_HONEYCOMB_BEEHIVE_BIG_GRUNTY_STATUE_RIGHT_3, RCTYPE_HONEYCOMB, LEVEL_6_LAIR, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_GL_HONEYCOMB_BEEHIVE_NEAR_50_NOTE_DOOR_1, RCTYPE_HONEYCOMB, LEVEL_6_LAIR, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_GL_HONEYCOMB_BEEHIVE_NEAR_50_NOTE_DOOR_2, RCTYPE_HONEYCOMB, LEVEL_6_LAIR, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_GL_HONEYCOMB_BEEHIVE_NEAR_50_NOTE_DOOR_3, RCTYPE_HONEYCOMB, LEVEL_6_LAIR, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_GL_HONEYCOMB_BEEHIVE_NEAR_CCW_PUZZLE_SWITCH_1, RCTYPE_HONEYCOMB, LEVEL_6_LAIR, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_GL_HONEYCOMB_BEEHIVE_NEAR_CCW_PUZZLE_SWITCH_2, RCTYPE_HONEYCOMB, LEVEL_6_LAIR, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_GL_HONEYCOMB_BEEHIVE_NEAR_CCW_PUZZLE_SWITCH_3, RCTYPE_HONEYCOMB, LEVEL_6_LAIR, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_GL_HONEYCOMB_BEEHIVE_NEAR_FIRST_GRUNTY_STATUE_1, RCTYPE_HONEYCOMB, LEVEL_6_LAIR, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_GL_HONEYCOMB_BEEHIVE_NEAR_FIRST_GRUNTY_STATUE_2, RCTYPE_HONEYCOMB, LEVEL_6_LAIR, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_GL_HONEYCOMB_BEEHIVE_NEAR_FIRST_GRUNTY_STATUE_3, RCTYPE_HONEYCOMB, LEVEL_6_LAIR, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_GL_HONEYCOMB_BEEHIVE_NEAR_CC_ENTRANCE_1, RCTYPE_HONEYCOMB, LEVEL_6_LAIR, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_GL_HONEYCOMB_BEEHIVE_NEAR_CC_ENTRANCE_2, RCTYPE_HONEYCOMB, LEVEL_6_LAIR, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_GL_HONEYCOMB_BEEHIVE_NEAR_CC_ENTRANCE_3, RCTYPE_HONEYCOMB, LEVEL_6_LAIR, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_GL_HONEYCOMB_BEEHIVE_NEAR_TTC_ENTRANCE_1, RCTYPE_HONEYCOMB, LEVEL_6_LAIR, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_GL_HONEYCOMB_BEEHIVE_NEAR_TTC_ENTRANCE_2, RCTYPE_HONEYCOMB, LEVEL_6_LAIR, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_GL_HONEYCOMB_BEEHIVE_NEAR_TTC_ENTRANCE_3, RCTYPE_HONEYCOMB, LEVEL_6_LAIR, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_GL_HONEYCOMB_BEEHIVE_NEAR_RBB_PUZZLE_1, RCTYPE_HONEYCOMB, LEVEL_6_LAIR, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_GL_HONEYCOMB_BEEHIVE_NEAR_RBB_PUZZLE_2, RCTYPE_HONEYCOMB, LEVEL_6_LAIR, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_GL_HONEYCOMB_BEEHIVE_NEAR_RBB_PUZZLE_3, RCTYPE_HONEYCOMB, LEVEL_6_LAIR, RI_HONEYCOMB, NULL, 0, 0, 0), RC(RC_GL_JIGGY_LOBBY, RCTYPE_JIGGY, LEVEL_6_LAIR, RI_JIGGY_GRUNTILDAS_LAIR, JIGGY_33_LAIR_1ST_JIGGY, -1505, 600, 123), RC(RC_GL_JIGGY_WITCH_SWITCH_BUBBLEGLOOP_SWAMP, RCTYPE_JIGGY, LEVEL_6_LAIR, RI_JIGGY_GRUNTILDAS_LAIR, JIGGY_37_LAIR_BGS_WITCH_SWITCH, 0, 0, -20), RC(RC_GL_JIGGY_WITCH_SWITCH_CLANKERS_CAVERN, RCTYPE_JIGGY, LEVEL_6_LAIR, RI_JIGGY_GRUNTILDAS_LAIR, JIGGY_35_LAIR_CC_WITCH_SWITCH, 0, 75, 156), @@ -1014,75 +1014,75 @@ std::map Checks = { RC(RC_GL_MUMBO_TOKEN_WHIPCRACK_NEAR_MMM_JIGGY_PODIUM, RCTYPE_MUMBO_TOKEN, LEVEL_6_LAIR, RI_MUMBO_TOKEN_GRUNTILDAS_LAIR, MUMBOTOKEN_5A_LAIR_WHIPCRACK_NEAR_MMM_JIGGY_PODIUM, -1140, 707, 1973), RC(RC_GL_MUMBO_TOKEN_BEHIND_MUMBO_IN_CRYPT, RCTYPE_MUMBO_TOKEN, LEVEL_6_LAIR, RI_MUMBO_TOKEN_GRUNTILDAS_LAIR, MUMBOTOKEN_57_LAIR_BEHIND_MUMBO_IN_CRYPT, 1488, 249, 0), RC(RC_GL_MUMBO_TOKEN_ABOVE_NOTE_DOOR_WATER_AREA, RCTYPE_MUMBO_TOKEN, LEVEL_6_LAIR, RI_MUMBO_TOKEN_GRUNTILDAS_LAIR, MUMBOTOKEN_58_LAIR_ABOVE_NOTE_DOOR_WATER_AREA, 1256, 2582, 0), - RC(RC_GV_BLUE_EGG_BEHIND_WATER_PYRAMID_1, RCTYPE_BLUE_EGG, LEVEL_7_GOBIS_VALLEY, RI_BLUE_EGG_GOBIS_VALLEY, NULL, 387, 2730, -6645), - RC(RC_GV_BLUE_EGG_BEHIND_WATER_PYRAMID_2, RCTYPE_BLUE_EGG, LEVEL_7_GOBIS_VALLEY, RI_BLUE_EGG_GOBIS_VALLEY, NULL, 17, 2730, -6645), - RC(RC_GV_BLUE_EGG_BEHIND_WATER_PYRAMID_3, RCTYPE_BLUE_EGG, LEVEL_7_GOBIS_VALLEY, RI_BLUE_EGG_GOBIS_VALLEY, NULL, -342, 2730, -6645), - RC(RC_GV_BLUE_EGG_ENTRANCE_1, RCTYPE_BLUE_EGG, LEVEL_7_GOBIS_VALLEY, RI_BLUE_EGG_GOBIS_VALLEY, NULL, 1325, -59, 9447), - RC(RC_GV_BLUE_EGG_ENTRANCE_2, RCTYPE_BLUE_EGG, LEVEL_7_GOBIS_VALLEY, RI_BLUE_EGG_GOBIS_VALLEY, NULL, 845, -55, 9275), - RC(RC_GV_BLUE_EGG_ENTRANCE_3, RCTYPE_BLUE_EGG, LEVEL_7_GOBIS_VALLEY, RI_BLUE_EGG_GOBIS_VALLEY, NULL, 781, -51, 8805), - RC(RC_GV_BLUE_EGG_ENTRANCE_4, RCTYPE_BLUE_EGG, LEVEL_7_GOBIS_VALLEY, RI_BLUE_EGG_GOBIS_VALLEY, NULL, 1214, -51, 8493), - RC(RC_GV_BLUE_EGG_ENTRANCE_5, RCTYPE_BLUE_EGG, LEVEL_7_GOBIS_VALLEY, RI_BLUE_EGG_GOBIS_VALLEY, NULL, 1647, -56, 8820), - RC(RC_GV_BLUE_EGG_MAZE_PYRAMID_INTERIOR_1, RCTYPE_BLUE_EGG, LEVEL_7_GOBIS_VALLEY, RI_BLUE_EGG_GOBIS_VALLEY, NULL, 712, 20, -1636), - RC(RC_GV_BLUE_EGG_MAZE_PYRAMID_INTERIOR_2, RCTYPE_BLUE_EGG, LEVEL_7_GOBIS_VALLEY, RI_BLUE_EGG_GOBIS_VALLEY, NULL, 612, 20, -1636), - RC(RC_GV_BLUE_EGG_MAZE_PYRAMID_INTERIOR_3, RCTYPE_BLUE_EGG, LEVEL_7_GOBIS_VALLEY, RI_BLUE_EGG_GOBIS_VALLEY, NULL, 511, 20, -1636), - RC(RC_GV_BLUE_EGG_MAZE_PYRAMID_INTERIOR_4, RCTYPE_BLUE_EGG, LEVEL_7_GOBIS_VALLEY, RI_BLUE_EGG_GOBIS_VALLEY, NULL, 517, 22, -1502), - RC(RC_GV_BLUE_EGG_MAZE_PYRAMID_INTERIOR_5, RCTYPE_BLUE_EGG, LEVEL_7_GOBIS_VALLEY, RI_BLUE_EGG_GOBIS_VALLEY, NULL, 612, 22, -1502), - RC(RC_GV_BLUE_EGG_MAZE_PYRAMID_INTERIOR_6, RCTYPE_BLUE_EGG, LEVEL_7_GOBIS_VALLEY, RI_BLUE_EGG_GOBIS_VALLEY, NULL, 712, 22, -1502), - RC(RC_GV_BLUE_EGG_MAZE_PYRAMID_INTERIOR_7, RCTYPE_BLUE_EGG, LEVEL_7_GOBIS_VALLEY, RI_BLUE_EGG_GOBIS_VALLEY, NULL, -856, 25, -1243), - RC(RC_GV_BLUE_EGG_MAZE_PYRAMID_INTERIOR_8, RCTYPE_BLUE_EGG, LEVEL_7_GOBIS_VALLEY, RI_BLUE_EGG_GOBIS_VALLEY, NULL, -775, 25, -1243), - RC(RC_GV_BLUE_EGG_MAZE_PYRAMID_INTERIOR_9, RCTYPE_BLUE_EGG, LEVEL_7_GOBIS_VALLEY, RI_BLUE_EGG_GOBIS_VALLEY, NULL, -775, 25, -1140), - RC(RC_GV_BLUE_EGG_MAZE_PYRAMID_INTERIOR_10, RCTYPE_BLUE_EGG, LEVEL_7_GOBIS_VALLEY, RI_BLUE_EGG_GOBIS_VALLEY, NULL, -855, 25, -1140), - RC(RC_GV_BLUE_EGG_MAZE_PYRAMID_INTERIOR_11, RCTYPE_BLUE_EGG, LEVEL_7_GOBIS_VALLEY, RI_BLUE_EGG_GOBIS_VALLEY, NULL, -1139, 25, 880), - RC(RC_GV_BLUE_EGG_MAZE_PYRAMID_INTERIOR_12, RCTYPE_BLUE_EGG, LEVEL_7_GOBIS_VALLEY, RI_BLUE_EGG_GOBIS_VALLEY, NULL, -1139, 25, 961), - RC(RC_GV_BLUE_EGG_MAZE_PYRAMID_INTERIOR_13, RCTYPE_BLUE_EGG, LEVEL_7_GOBIS_VALLEY, RI_BLUE_EGG_GOBIS_VALLEY, NULL, -1240, 25, 964), - RC(RC_GV_BLUE_EGG_MAZE_PYRAMID_INTERIOR_14, RCTYPE_BLUE_EGG, LEVEL_7_GOBIS_VALLEY, RI_BLUE_EGG_GOBIS_VALLEY, NULL, -1240, 24, 884), - RC(RC_GV_BLUE_EGG_NEAR_MAZE_PYRAMID_1, RCTYPE_BLUE_EGG, LEVEL_7_GOBIS_VALLEY, RI_BLUE_EGG_GOBIS_VALLEY, NULL, -985, 2432, 994), - RC(RC_GV_BLUE_EGG_NEAR_MAZE_PYRAMID_2, RCTYPE_BLUE_EGG, LEVEL_7_GOBIS_VALLEY, RI_BLUE_EGG_GOBIS_VALLEY, NULL, -1056, 2432, 466), - RC(RC_GV_BLUE_EGG_NEAR_MAZE_PYRAMID_3, RCTYPE_BLUE_EGG, LEVEL_7_GOBIS_VALLEY, RI_BLUE_EGG_GOBIS_VALLEY, NULL, -1137, 2432, -58), - RC(RC_GV_BLUE_EGG_NEAR_MAZE_PYRAMID_4, RCTYPE_BLUE_EGG, LEVEL_7_GOBIS_VALLEY, RI_BLUE_EGG_GOBIS_VALLEY, NULL, -814, 2431, -394), - RC(RC_GV_BLUE_EGG_NEAR_MAZE_PYRAMID_5, RCTYPE_BLUE_EGG, LEVEL_7_GOBIS_VALLEY, RI_BLUE_EGG_GOBIS_VALLEY, NULL, -472, 2432, -752), - RC(RC_GV_BLUE_EGG_NEAR_MAZE_PYRAMID_6, RCTYPE_BLUE_EGG, LEVEL_7_GOBIS_VALLEY, RI_BLUE_EGG_GOBIS_VALLEY, NULL, 129, 2432, -740), - RC(RC_GV_BLUE_EGG_NEAR_MAZE_PYRAMID_7, RCTYPE_BLUE_EGG, LEVEL_7_GOBIS_VALLEY, RI_BLUE_EGG_GOBIS_VALLEY, NULL, 740, 2432, -729), - RC(RC_GV_BLUE_EGG_NEAR_MAZE_PYRAMID_8, RCTYPE_BLUE_EGG, LEVEL_7_GOBIS_VALLEY, RI_BLUE_EGG_GOBIS_VALLEY, NULL, 945, 2432, -392), - RC(RC_GV_BLUE_EGG_NEAR_MAZE_PYRAMID_9, RCTYPE_BLUE_EGG, LEVEL_7_GOBIS_VALLEY, RI_BLUE_EGG_GOBIS_VALLEY, NULL, 1151, 2431, -43), - RC(RC_GV_BLUE_EGG_NEAR_MAZE_PYRAMID_10, RCTYPE_BLUE_EGG, LEVEL_7_GOBIS_VALLEY, RI_BLUE_EGG_GOBIS_VALLEY, NULL, 1099, 2432, 473), - RC(RC_GV_BLUE_EGG_NEAR_MAZE_PYRAMID_11, RCTYPE_BLUE_EGG, LEVEL_7_GOBIS_VALLEY, RI_BLUE_EGG_GOBIS_VALLEY, NULL, 1039, 2432, 970), - RC(RC_GV_BLUE_EGG_SPHYNX_INTERIOR_1, RCTYPE_BLUE_EGG, LEVEL_7_GOBIS_VALLEY, RI_BLUE_EGG_GOBIS_VALLEY, NULL, -2251, 0, -50), - RC(RC_GV_BLUE_EGG_SPHYNX_INTERIOR_2, RCTYPE_BLUE_EGG, LEVEL_7_GOBIS_VALLEY, RI_BLUE_EGG_GOBIS_VALLEY, NULL, -2347, 0, 159), - RC(RC_GV_BLUE_EGG_SPHYNX_INTERIOR_3, RCTYPE_BLUE_EGG, LEVEL_7_GOBIS_VALLEY, RI_BLUE_EGG_GOBIS_VALLEY, NULL, -2550, 0, 251), - RC(RC_GV_BLUE_EGG_SPHYNX_INTERIOR_4, RCTYPE_BLUE_EGG, LEVEL_7_GOBIS_VALLEY, RI_BLUE_EGG_GOBIS_VALLEY, NULL, -2757, 0, 137), - RC(RC_GV_BLUE_EGG_SPHYNX_INTERIOR_5, RCTYPE_BLUE_EGG, LEVEL_7_GOBIS_VALLEY, RI_BLUE_EGG_GOBIS_VALLEY, NULL, -2850, 0, -50), - RC(RC_GV_BLUE_EGG_SPHYNX_INTERIOR_6, RCTYPE_BLUE_EGG, LEVEL_7_GOBIS_VALLEY, RI_BLUE_EGG_GOBIS_VALLEY, NULL, -2756, 0, -272), - RC(RC_GV_BLUE_EGG_SPHYNX_INTERIOR_7, RCTYPE_BLUE_EGG, LEVEL_7_GOBIS_VALLEY, RI_BLUE_EGG_GOBIS_VALLEY, NULL, -2550, 0, -349), - RC(RC_GV_BLUE_EGG_SPHYNX_INTERIOR_8, RCTYPE_BLUE_EGG, LEVEL_7_GOBIS_VALLEY, RI_BLUE_EGG_GOBIS_VALLEY, NULL, -2359, 0, -293), - RC(RC_GV_BLUE_EGG_SPHYNX_LEFT_1, RCTYPE_BLUE_EGG, LEVEL_7_GOBIS_VALLEY, RI_BLUE_EGG_GOBIS_VALLEY, NULL, -4379, 1623, 6824), - RC(RC_GV_BLUE_EGG_SPHYNX_LEFT_2, RCTYPE_BLUE_EGG, LEVEL_7_GOBIS_VALLEY, RI_BLUE_EGG_GOBIS_VALLEY, NULL, -4674, 1659, 6885), - RC(RC_GV_BLUE_EGG_SPHYNX_LEFT_3, RCTYPE_BLUE_EGG, LEVEL_7_GOBIS_VALLEY, RI_BLUE_EGG_GOBIS_VALLEY, NULL, -4530, 1665, 6538), - RC(RC_GV_BLUE_EGG_SPHYNX_RIGHT_1, RCTYPE_BLUE_EGG, LEVEL_7_GOBIS_VALLEY, RI_BLUE_EGG_GOBIS_VALLEY, NULL, -4402, 1618, 5076), - RC(RC_GV_BLUE_EGG_SPHYNX_RIGHT_2, RCTYPE_BLUE_EGG, LEVEL_7_GOBIS_VALLEY, RI_BLUE_EGG_GOBIS_VALLEY, NULL, -4551, 1663, 5336), - RC(RC_GV_BLUE_EGG_SPHYNX_RIGHT_3, RCTYPE_BLUE_EGG, LEVEL_7_GOBIS_VALLEY, RI_BLUE_EGG_GOBIS_VALLEY, NULL, -4689, 1662, 5017), - RC(RC_GV_BLUE_EGG_WATER_PYRAMID_INTERIOR_1, RCTYPE_BLUE_EGG, LEVEL_7_GOBIS_VALLEY, RI_BLUE_EGG_GOBIS_VALLEY, NULL, -671, 13, -369), - RC(RC_GV_BLUE_EGG_WATER_PYRAMID_INTERIOR_2, RCTYPE_BLUE_EGG, LEVEL_7_GOBIS_VALLEY, RI_BLUE_EGG_GOBIS_VALLEY, NULL, -390, 13, 655), - RC(RC_GV_BLUE_EGG_WATER_PYRAMID_INTERIOR_3, RCTYPE_BLUE_EGG, LEVEL_7_GOBIS_VALLEY, RI_BLUE_EGG_GOBIS_VALLEY, NULL, 354, 13, -645), - RC(RC_GV_BLUE_EGG_WATER_PYRAMID_INTERIOR_4, RCTYPE_BLUE_EGG, LEVEL_7_GOBIS_VALLEY, RI_BLUE_EGG_GOBIS_VALLEY, NULL, 645, 13, 384), - RC(RC_GV_BLUE_EGG_WATER_PYRAMID_TOP_1, RCTYPE_BLUE_EGG, LEVEL_7_GOBIS_VALLEY, RI_BLUE_EGG_GOBIS_VALLEY, NULL, -1168, 3325, -5619), - RC(RC_GV_BLUE_EGG_WATER_PYRAMID_TOP_2, RCTYPE_BLUE_EGG, LEVEL_7_GOBIS_VALLEY, RI_BLUE_EGG_GOBIS_VALLEY, NULL, 861, 3821, -5292), - RC(RC_GV_BLUE_EGG_WATER_PYRAMID_TOP_3, RCTYPE_BLUE_EGG, LEVEL_7_GOBIS_VALLEY, RI_BLUE_EGG_GOBIS_VALLEY, NULL, 526, 4316, -3580), - RC(RC_GV_BLUE_EGG_WATER_PYRAMID_TOP_4, RCTYPE_BLUE_EGG, LEVEL_7_GOBIS_VALLEY, RI_BLUE_EGG_GOBIS_VALLEY, NULL, 523, 4316, -4952), + RC(RC_GV_BLUE_EGG_BEHIND_WATER_PYRAMID_1, RCTYPE_BLUE_EGG, LEVEL_7_GOBIS_VALLEY, RI_BLUE_EGG, NULL, 387, 2730, -6645), + RC(RC_GV_BLUE_EGG_BEHIND_WATER_PYRAMID_2, RCTYPE_BLUE_EGG, LEVEL_7_GOBIS_VALLEY, RI_BLUE_EGG, NULL, 17, 2730, -6645), + RC(RC_GV_BLUE_EGG_BEHIND_WATER_PYRAMID_3, RCTYPE_BLUE_EGG, LEVEL_7_GOBIS_VALLEY, RI_BLUE_EGG, NULL, -342, 2730, -6645), + RC(RC_GV_BLUE_EGG_ENTRANCE_1, RCTYPE_BLUE_EGG, LEVEL_7_GOBIS_VALLEY, RI_BLUE_EGG, NULL, 1325, -59, 9447), + RC(RC_GV_BLUE_EGG_ENTRANCE_2, RCTYPE_BLUE_EGG, LEVEL_7_GOBIS_VALLEY, RI_BLUE_EGG, NULL, 845, -55, 9275), + RC(RC_GV_BLUE_EGG_ENTRANCE_3, RCTYPE_BLUE_EGG, LEVEL_7_GOBIS_VALLEY, RI_BLUE_EGG, NULL, 781, -51, 8805), + RC(RC_GV_BLUE_EGG_ENTRANCE_4, RCTYPE_BLUE_EGG, LEVEL_7_GOBIS_VALLEY, RI_BLUE_EGG, NULL, 1214, -51, 8493), + RC(RC_GV_BLUE_EGG_ENTRANCE_5, RCTYPE_BLUE_EGG, LEVEL_7_GOBIS_VALLEY, RI_BLUE_EGG, NULL, 1647, -56, 8820), + RC(RC_GV_BLUE_EGG_MAZE_PYRAMID_INTERIOR_1, RCTYPE_BLUE_EGG, LEVEL_7_GOBIS_VALLEY, RI_BLUE_EGG, NULL, 712, 20, -1636), + RC(RC_GV_BLUE_EGG_MAZE_PYRAMID_INTERIOR_2, RCTYPE_BLUE_EGG, LEVEL_7_GOBIS_VALLEY, RI_BLUE_EGG, NULL, 612, 20, -1636), + RC(RC_GV_BLUE_EGG_MAZE_PYRAMID_INTERIOR_3, RCTYPE_BLUE_EGG, LEVEL_7_GOBIS_VALLEY, RI_BLUE_EGG, NULL, 511, 20, -1636), + RC(RC_GV_BLUE_EGG_MAZE_PYRAMID_INTERIOR_4, RCTYPE_BLUE_EGG, LEVEL_7_GOBIS_VALLEY, RI_BLUE_EGG, NULL, 517, 22, -1502), + RC(RC_GV_BLUE_EGG_MAZE_PYRAMID_INTERIOR_5, RCTYPE_BLUE_EGG, LEVEL_7_GOBIS_VALLEY, RI_BLUE_EGG, NULL, 612, 22, -1502), + RC(RC_GV_BLUE_EGG_MAZE_PYRAMID_INTERIOR_6, RCTYPE_BLUE_EGG, LEVEL_7_GOBIS_VALLEY, RI_BLUE_EGG, NULL, 712, 22, -1502), + RC(RC_GV_BLUE_EGG_MAZE_PYRAMID_INTERIOR_7, RCTYPE_BLUE_EGG, LEVEL_7_GOBIS_VALLEY, RI_BLUE_EGG, NULL, -856, 25, -1243), + RC(RC_GV_BLUE_EGG_MAZE_PYRAMID_INTERIOR_8, RCTYPE_BLUE_EGG, LEVEL_7_GOBIS_VALLEY, RI_BLUE_EGG, NULL, -775, 25, -1243), + RC(RC_GV_BLUE_EGG_MAZE_PYRAMID_INTERIOR_9, RCTYPE_BLUE_EGG, LEVEL_7_GOBIS_VALLEY, RI_BLUE_EGG, NULL, -775, 25, -1140), + RC(RC_GV_BLUE_EGG_MAZE_PYRAMID_INTERIOR_10, RCTYPE_BLUE_EGG, LEVEL_7_GOBIS_VALLEY, RI_BLUE_EGG, NULL, -855, 25, -1140), + RC(RC_GV_BLUE_EGG_MAZE_PYRAMID_INTERIOR_11, RCTYPE_BLUE_EGG, LEVEL_7_GOBIS_VALLEY, RI_BLUE_EGG, NULL, -1139, 25, 880), + RC(RC_GV_BLUE_EGG_MAZE_PYRAMID_INTERIOR_12, RCTYPE_BLUE_EGG, LEVEL_7_GOBIS_VALLEY, RI_BLUE_EGG, NULL, -1139, 25, 961), + RC(RC_GV_BLUE_EGG_MAZE_PYRAMID_INTERIOR_13, RCTYPE_BLUE_EGG, LEVEL_7_GOBIS_VALLEY, RI_BLUE_EGG, NULL, -1240, 25, 964), + RC(RC_GV_BLUE_EGG_MAZE_PYRAMID_INTERIOR_14, RCTYPE_BLUE_EGG, LEVEL_7_GOBIS_VALLEY, RI_BLUE_EGG, NULL, -1240, 24, 884), + RC(RC_GV_BLUE_EGG_NEAR_MAZE_PYRAMID_1, RCTYPE_BLUE_EGG, LEVEL_7_GOBIS_VALLEY, RI_BLUE_EGG, NULL, -985, 2432, 994), + RC(RC_GV_BLUE_EGG_NEAR_MAZE_PYRAMID_2, RCTYPE_BLUE_EGG, LEVEL_7_GOBIS_VALLEY, RI_BLUE_EGG, NULL, -1056, 2432, 466), + RC(RC_GV_BLUE_EGG_NEAR_MAZE_PYRAMID_3, RCTYPE_BLUE_EGG, LEVEL_7_GOBIS_VALLEY, RI_BLUE_EGG, NULL, -1137, 2432, -58), + RC(RC_GV_BLUE_EGG_NEAR_MAZE_PYRAMID_4, RCTYPE_BLUE_EGG, LEVEL_7_GOBIS_VALLEY, RI_BLUE_EGG, NULL, -814, 2431, -394), + RC(RC_GV_BLUE_EGG_NEAR_MAZE_PYRAMID_5, RCTYPE_BLUE_EGG, LEVEL_7_GOBIS_VALLEY, RI_BLUE_EGG, NULL, -472, 2432, -752), + RC(RC_GV_BLUE_EGG_NEAR_MAZE_PYRAMID_6, RCTYPE_BLUE_EGG, LEVEL_7_GOBIS_VALLEY, RI_BLUE_EGG, NULL, 129, 2432, -740), + RC(RC_GV_BLUE_EGG_NEAR_MAZE_PYRAMID_7, RCTYPE_BLUE_EGG, LEVEL_7_GOBIS_VALLEY, RI_BLUE_EGG, NULL, 740, 2432, -729), + RC(RC_GV_BLUE_EGG_NEAR_MAZE_PYRAMID_8, RCTYPE_BLUE_EGG, LEVEL_7_GOBIS_VALLEY, RI_BLUE_EGG, NULL, 945, 2432, -392), + RC(RC_GV_BLUE_EGG_NEAR_MAZE_PYRAMID_9, RCTYPE_BLUE_EGG, LEVEL_7_GOBIS_VALLEY, RI_BLUE_EGG, NULL, 1151, 2431, -43), + RC(RC_GV_BLUE_EGG_NEAR_MAZE_PYRAMID_10, RCTYPE_BLUE_EGG, LEVEL_7_GOBIS_VALLEY, RI_BLUE_EGG, NULL, 1099, 2432, 473), + RC(RC_GV_BLUE_EGG_NEAR_MAZE_PYRAMID_11, RCTYPE_BLUE_EGG, LEVEL_7_GOBIS_VALLEY, RI_BLUE_EGG, NULL, 1039, 2432, 970), + RC(RC_GV_BLUE_EGG_SPHYNX_INTERIOR_1, RCTYPE_BLUE_EGG, LEVEL_7_GOBIS_VALLEY, RI_BLUE_EGG, NULL, -2251, 0, -50), + RC(RC_GV_BLUE_EGG_SPHYNX_INTERIOR_2, RCTYPE_BLUE_EGG, LEVEL_7_GOBIS_VALLEY, RI_BLUE_EGG, NULL, -2347, 0, 159), + RC(RC_GV_BLUE_EGG_SPHYNX_INTERIOR_3, RCTYPE_BLUE_EGG, LEVEL_7_GOBIS_VALLEY, RI_BLUE_EGG, NULL, -2550, 0, 251), + RC(RC_GV_BLUE_EGG_SPHYNX_INTERIOR_4, RCTYPE_BLUE_EGG, LEVEL_7_GOBIS_VALLEY, RI_BLUE_EGG, NULL, -2757, 0, 137), + RC(RC_GV_BLUE_EGG_SPHYNX_INTERIOR_5, RCTYPE_BLUE_EGG, LEVEL_7_GOBIS_VALLEY, RI_BLUE_EGG, NULL, -2850, 0, -50), + RC(RC_GV_BLUE_EGG_SPHYNX_INTERIOR_6, RCTYPE_BLUE_EGG, LEVEL_7_GOBIS_VALLEY, RI_BLUE_EGG, NULL, -2756, 0, -272), + RC(RC_GV_BLUE_EGG_SPHYNX_INTERIOR_7, RCTYPE_BLUE_EGG, LEVEL_7_GOBIS_VALLEY, RI_BLUE_EGG, NULL, -2550, 0, -349), + RC(RC_GV_BLUE_EGG_SPHYNX_INTERIOR_8, RCTYPE_BLUE_EGG, LEVEL_7_GOBIS_VALLEY, RI_BLUE_EGG, NULL, -2359, 0, -293), + RC(RC_GV_BLUE_EGG_SPHYNX_LEFT_1, RCTYPE_BLUE_EGG, LEVEL_7_GOBIS_VALLEY, RI_BLUE_EGG, NULL, -4379, 1623, 6824), + RC(RC_GV_BLUE_EGG_SPHYNX_LEFT_2, RCTYPE_BLUE_EGG, LEVEL_7_GOBIS_VALLEY, RI_BLUE_EGG, NULL, -4674, 1659, 6885), + RC(RC_GV_BLUE_EGG_SPHYNX_LEFT_3, RCTYPE_BLUE_EGG, LEVEL_7_GOBIS_VALLEY, RI_BLUE_EGG, NULL, -4530, 1665, 6538), + RC(RC_GV_BLUE_EGG_SPHYNX_RIGHT_1, RCTYPE_BLUE_EGG, LEVEL_7_GOBIS_VALLEY, RI_BLUE_EGG, NULL, -4402, 1618, 5076), + RC(RC_GV_BLUE_EGG_SPHYNX_RIGHT_2, RCTYPE_BLUE_EGG, LEVEL_7_GOBIS_VALLEY, RI_BLUE_EGG, NULL, -4551, 1663, 5336), + RC(RC_GV_BLUE_EGG_SPHYNX_RIGHT_3, RCTYPE_BLUE_EGG, LEVEL_7_GOBIS_VALLEY, RI_BLUE_EGG, NULL, -4689, 1662, 5017), + RC(RC_GV_BLUE_EGG_WATER_PYRAMID_INTERIOR_1, RCTYPE_BLUE_EGG, LEVEL_7_GOBIS_VALLEY, RI_BLUE_EGG, NULL, -671, 13, -369), + RC(RC_GV_BLUE_EGG_WATER_PYRAMID_INTERIOR_2, RCTYPE_BLUE_EGG, LEVEL_7_GOBIS_VALLEY, RI_BLUE_EGG, NULL, -390, 13, 655), + RC(RC_GV_BLUE_EGG_WATER_PYRAMID_INTERIOR_3, RCTYPE_BLUE_EGG, LEVEL_7_GOBIS_VALLEY, RI_BLUE_EGG, NULL, 354, 13, -645), + RC(RC_GV_BLUE_EGG_WATER_PYRAMID_INTERIOR_4, RCTYPE_BLUE_EGG, LEVEL_7_GOBIS_VALLEY, RI_BLUE_EGG, NULL, 645, 13, 384), + RC(RC_GV_BLUE_EGG_WATER_PYRAMID_TOP_1, RCTYPE_BLUE_EGG, LEVEL_7_GOBIS_VALLEY, RI_BLUE_EGG, NULL, -1168, 3325, -5619), + RC(RC_GV_BLUE_EGG_WATER_PYRAMID_TOP_2, RCTYPE_BLUE_EGG, LEVEL_7_GOBIS_VALLEY, RI_BLUE_EGG, NULL, 861, 3821, -5292), + RC(RC_GV_BLUE_EGG_WATER_PYRAMID_TOP_3, RCTYPE_BLUE_EGG, LEVEL_7_GOBIS_VALLEY, RI_BLUE_EGG, NULL, 526, 4316, -3580), + RC(RC_GV_BLUE_EGG_WATER_PYRAMID_TOP_4, RCTYPE_BLUE_EGG, LEVEL_7_GOBIS_VALLEY, RI_BLUE_EGG, NULL, 523, 4316, -4952), RC(RC_GV_EMPTY_HONEYCOMB_CACTUS, RCTYPE_EMPTY_HONEYCOMB, LEVEL_7_GOBIS_VALLEY, RI_EMPTY_HONEYCOMB_GOBIS_VALLEY, HONEYCOMB_B_GV_CACTUS, 2911, 3292, -3307), RC(RC_GV_EMPTY_HONEYCOMB_GOBI, RCTYPE_EMPTY_HONEYCOMB, LEVEL_7_GOBIS_VALLEY, RI_EMPTY_HONEYCOMB_GOBIS_VALLEY, HONEYCOMB_C_GV_GOBI_3, -6885, 2383, 1335), - RC(RC_GV_EXTRA_LIFE_BEHIND_JINXY, RCTYPE_EXTRA_LIFE, LEVEL_7_GOBIS_VALLEY, RI_EXTRA_LIFE_GOBIS_VALLEY, NULL, -8948, 1332, 5500), - RC(RC_GV_EXTRA_LIFE_INSIDE_SANDYBUTTS_TOMB, RCTYPE_EXTRA_LIFE, LEVEL_7_GOBIS_VALLEY, RI_EXTRA_LIFE_GOBIS_VALLEY, NULL, 1282, 18, 1971), - RC(RC_GV_EXTRA_LIFE_ON_TOP_OF_WATER_PYRAMID, RCTYPE_EXTRA_LIFE, LEVEL_7_GOBIS_VALLEY, RI_EXTRA_LIFE_GOBIS_VALLEY, NULL, -230, 4820, -4421), - RC(RC_GV_HONEYCOMB_BEEHIVE_BEHIND_WATER_PYRAMID_1, RCTYPE_HONEYCOMB, LEVEL_7_GOBIS_VALLEY, RI_HONEYCOMB_GOBIS_VALLEY, NULL, 0, 0, 0), - RC(RC_GV_HONEYCOMB_BEEHIVE_BEHIND_WATER_PYRAMID_2, RCTYPE_HONEYCOMB, LEVEL_7_GOBIS_VALLEY, RI_HONEYCOMB_GOBIS_VALLEY, NULL, 0, 0, 0), - RC(RC_GV_HONEYCOMB_BEEHIVE_BEHIND_WATER_PYRAMID_3, RCTYPE_HONEYCOMB, LEVEL_7_GOBIS_VALLEY, RI_HONEYCOMB_GOBIS_VALLEY, NULL, 0, 0, 0), - RC(RC_GV_HONEYCOMB_BEEHIVE_NEAR_PUZZLE_PYRAMID_1, RCTYPE_HONEYCOMB, LEVEL_7_GOBIS_VALLEY, RI_HONEYCOMB_GOBIS_VALLEY, NULL, 0, 0, 0), - RC(RC_GV_HONEYCOMB_BEEHIVE_NEAR_PUZZLE_PYRAMID_2, RCTYPE_HONEYCOMB, LEVEL_7_GOBIS_VALLEY, RI_HONEYCOMB_GOBIS_VALLEY, NULL, 0, 0, 0), - RC(RC_GV_HONEYCOMB_BEEHIVE_NEAR_PUZZLE_PYRAMID_3, RCTYPE_HONEYCOMB, LEVEL_7_GOBIS_VALLEY, RI_HONEYCOMB_GOBIS_VALLEY, NULL, 0, 0, 0), - RC(RC_GV_HONEYCOMB_BEEHIVE_NEAR_WARP_PAD_1, RCTYPE_HONEYCOMB, LEVEL_7_GOBIS_VALLEY, RI_HONEYCOMB_GOBIS_VALLEY, NULL, 0, 0, 0), - RC(RC_GV_HONEYCOMB_BEEHIVE_NEAR_WARP_PAD_2, RCTYPE_HONEYCOMB, LEVEL_7_GOBIS_VALLEY, RI_HONEYCOMB_GOBIS_VALLEY, NULL, 0, 0, 0), - RC(RC_GV_HONEYCOMB_BEEHIVE_NEAR_WARP_PAD_3, RCTYPE_HONEYCOMB, LEVEL_7_GOBIS_VALLEY, RI_HONEYCOMB_GOBIS_VALLEY, NULL, 0, 0, 0), + RC(RC_GV_EXTRA_LIFE_BEHIND_JINXY, RCTYPE_EXTRA_LIFE, LEVEL_7_GOBIS_VALLEY, RI_EXTRA_LIFE, NULL, -8948, 1332, 5500), + RC(RC_GV_EXTRA_LIFE_INSIDE_SANDYBUTTS_TOMB, RCTYPE_EXTRA_LIFE, LEVEL_7_GOBIS_VALLEY, RI_EXTRA_LIFE, NULL, 1282, 18, 1971), + RC(RC_GV_EXTRA_LIFE_ON_TOP_OF_WATER_PYRAMID, RCTYPE_EXTRA_LIFE, LEVEL_7_GOBIS_VALLEY, RI_EXTRA_LIFE, NULL, -230, 4820, -4421), + RC(RC_GV_HONEYCOMB_BEEHIVE_BEHIND_WATER_PYRAMID_1, RCTYPE_HONEYCOMB, LEVEL_7_GOBIS_VALLEY, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_GV_HONEYCOMB_BEEHIVE_BEHIND_WATER_PYRAMID_2, RCTYPE_HONEYCOMB, LEVEL_7_GOBIS_VALLEY, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_GV_HONEYCOMB_BEEHIVE_BEHIND_WATER_PYRAMID_3, RCTYPE_HONEYCOMB, LEVEL_7_GOBIS_VALLEY, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_GV_HONEYCOMB_BEEHIVE_NEAR_PUZZLE_PYRAMID_1, RCTYPE_HONEYCOMB, LEVEL_7_GOBIS_VALLEY, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_GV_HONEYCOMB_BEEHIVE_NEAR_PUZZLE_PYRAMID_2, RCTYPE_HONEYCOMB, LEVEL_7_GOBIS_VALLEY, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_GV_HONEYCOMB_BEEHIVE_NEAR_PUZZLE_PYRAMID_3, RCTYPE_HONEYCOMB, LEVEL_7_GOBIS_VALLEY, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_GV_HONEYCOMB_BEEHIVE_NEAR_WARP_PAD_1, RCTYPE_HONEYCOMB, LEVEL_7_GOBIS_VALLEY, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_GV_HONEYCOMB_BEEHIVE_NEAR_WARP_PAD_2, RCTYPE_HONEYCOMB, LEVEL_7_GOBIS_VALLEY, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_GV_HONEYCOMB_BEEHIVE_NEAR_WARP_PAD_3, RCTYPE_HONEYCOMB, LEVEL_7_GOBIS_VALLEY, RI_HONEYCOMB, NULL, 0, 0, 0), RC(RC_GV_JIGGY_ANCIENT_ONES, RCTYPE_JIGGY, LEVEL_7_GOBIS_VALLEY, RI_JIGGY_GOBIS_VALLEY, JIGGY_46_GV_ANCIENT_ONES, 0, 0, 0), RC(RC_GV_JIGGY_GOBI_1, RCTYPE_JIGGY, LEVEL_7_GOBIS_VALLEY, RI_JIGGY_GOBIS_VALLEY, JIGGY_44_GV_GOBI_1, 0, 0, 0), RC(RC_GV_JIGGY_GOBI_2, RCTYPE_JIGGY, LEVEL_7_GOBIS_VALLEY, RI_JIGGY_GOBIS_VALLEY, JIGGY_45_GV_GOBI_2, 0, 0, 0), @@ -1210,56 +1210,56 @@ std::map Checks = { RC(RC_GV_NOTE_WATER_PYRAMID_TOP_3, RCTYPE_MUSIC_NOTE, LEVEL_7_GOBIS_VALLEY, RI_MUSIC_NOTE_GOBIS_VALLEY, NULL, -828, 3821, -3580), RC(RC_GV_NOTE_WATER_PYRAMID_TOP_4, RCTYPE_MUSIC_NOTE, LEVEL_7_GOBIS_VALLEY, RI_MUSIC_NOTE_GOBIS_VALLEY, NULL, -489, 4316, -4946), RC(RC_GV_SNS_BLUE_EGG, RCTYPE_STOP_N_SWOP, LEVEL_7_GOBIS_VALLEY, RI_STOP_N_SWOP_EGG_BLUE, SNS_ITEM_EGG_BLUE, 8, 470, -4141), - RC(RC_MM_BLUE_EGG_HUT_BUNDLE_1, RCTYPE_BLUE_EGG, LEVEL_1_MUMBOS_MOUNTAIN, RI_BLUE_EGG_MUMBOS_MOUNTAIN, NULL, 0, 0, 0), - RC(RC_MM_BLUE_EGG_HUT_BUNDLE_2, RCTYPE_BLUE_EGG, LEVEL_1_MUMBOS_MOUNTAIN, RI_BLUE_EGG_MUMBOS_MOUNTAIN, NULL, 0, 0, 0), - RC(RC_MM_BLUE_EGG_HUT_BUNDLE_3, RCTYPE_BLUE_EGG, LEVEL_1_MUMBOS_MOUNTAIN, RI_BLUE_EGG_MUMBOS_MOUNTAIN, NULL, 0, 0, 0), - RC(RC_MM_BLUE_EGG_HUT_BUNDLE_4, RCTYPE_BLUE_EGG, LEVEL_1_MUMBOS_MOUNTAIN, RI_BLUE_EGG_MUMBOS_MOUNTAIN, NULL, 0, 0, 0), - RC(RC_MM_BLUE_EGG_HUT_BUNDLE_5, RCTYPE_BLUE_EGG, LEVEL_1_MUMBOS_MOUNTAIN, RI_BLUE_EGG_MUMBOS_MOUNTAIN, NULL, 0, 0, 0), - RC(RC_MM_BLUE_EGG_INSIDE_MUMBOS_SKULL_1, RCTYPE_BLUE_EGG, LEVEL_1_MUMBOS_MOUNTAIN, RI_BLUE_EGG_MUMBOS_MOUNTAIN, NULL, -131, 398, -496), - RC(RC_MM_BLUE_EGG_INSIDE_MUMBOS_SKULL_2, RCTYPE_BLUE_EGG, LEVEL_1_MUMBOS_MOUNTAIN, RI_BLUE_EGG_MUMBOS_MOUNTAIN, NULL, -362, 378, -362), - RC(RC_MM_BLUE_EGG_INSIDE_MUMBOS_SKULL_3, RCTYPE_BLUE_EGG, LEVEL_1_MUMBOS_MOUNTAIN, RI_BLUE_EGG_MUMBOS_MOUNTAIN, NULL, -487, 398, -146), - RC(RC_MM_BLUE_EGG_INSIDE_MUMBOS_SKULL_4, RCTYPE_BLUE_EGG, LEVEL_1_MUMBOS_MOUNTAIN, RI_BLUE_EGG_MUMBOS_MOUNTAIN, NULL, -493, 398, 101), - RC(RC_MM_BLUE_EGG_INSIDE_MUMBOS_SKULL_5, RCTYPE_BLUE_EGG, LEVEL_1_MUMBOS_MOUNTAIN, RI_BLUE_EGG_MUMBOS_MOUNTAIN, NULL, -352, 398, 371), - RC(RC_MM_BLUE_EGG_INSIDE_MUMBOS_SKULL_6, RCTYPE_BLUE_EGG, LEVEL_1_MUMBOS_MOUNTAIN, RI_BLUE_EGG_MUMBOS_MOUNTAIN, NULL, -131, 398, 496), - RC(RC_MM_BLUE_EGG_INSIDE_MUMBOS_SKULL_7, RCTYPE_BLUE_EGG, LEVEL_1_MUMBOS_MOUNTAIN, RI_BLUE_EGG_MUMBOS_MOUNTAIN, NULL, 136, 398, -499), - RC(RC_MM_BLUE_EGG_INSIDE_MUMBOS_SKULL_8, RCTYPE_BLUE_EGG, LEVEL_1_MUMBOS_MOUNTAIN, RI_BLUE_EGG_MUMBOS_MOUNTAIN, NULL, 361, 379, -363), - RC(RC_MM_BLUE_EGG_INSIDE_MUMBOS_SKULL_9, RCTYPE_BLUE_EGG, LEVEL_1_MUMBOS_MOUNTAIN, RI_BLUE_EGG_MUMBOS_MOUNTAIN, NULL, 498, 394, -129), - RC(RC_MM_BLUE_EGG_INSIDE_MUMBOS_SKULL_10, RCTYPE_BLUE_EGG, LEVEL_1_MUMBOS_MOUNTAIN, RI_BLUE_EGG_MUMBOS_MOUNTAIN, NULL, 495, 398, 133), - RC(RC_MM_BLUE_EGG_INSIDE_MUMBOS_SKULL_11, RCTYPE_BLUE_EGG, LEVEL_1_MUMBOS_MOUNTAIN, RI_BLUE_EGG_MUMBOS_MOUNTAIN, NULL, 359, 398, 362), - RC(RC_MM_BLUE_EGG_INSIDE_MUMBOS_SKULL_12, RCTYPE_BLUE_EGG, LEVEL_1_MUMBOS_MOUNTAIN, RI_BLUE_EGG_MUMBOS_MOUNTAIN, NULL, 134, 379, 497), - RC(RC_MM_BLUE_EGG_INSIDE_TICKERS_TOWER_1, RCTYPE_BLUE_EGG, LEVEL_1_MUMBOS_MOUNTAIN, RI_BLUE_EGG_MUMBOS_MOUNTAIN, NULL, -10, 1507, -125), - RC(RC_MM_BLUE_EGG_INSIDE_TICKERS_TOWER_2, RCTYPE_BLUE_EGG, LEVEL_1_MUMBOS_MOUNTAIN, RI_BLUE_EGG_MUMBOS_MOUNTAIN, NULL, -80, 1503, -71), - RC(RC_MM_BLUE_EGG_INSIDE_TICKERS_TOWER_3, RCTYPE_BLUE_EGG, LEVEL_1_MUMBOS_MOUNTAIN, RI_BLUE_EGG_MUMBOS_MOUNTAIN, NULL, -74, 1521, 19), - RC(RC_MM_BLUE_EGG_INSIDE_TICKERS_TOWER_4, RCTYPE_BLUE_EGG, LEVEL_1_MUMBOS_MOUNTAIN, RI_BLUE_EGG_MUMBOS_MOUNTAIN, NULL, -3, 1510, 52), - RC(RC_MM_BLUE_EGG_INSIDE_TICKERS_TOWER_5, RCTYPE_BLUE_EGG, LEVEL_1_MUMBOS_MOUNTAIN, RI_BLUE_EGG_MUMBOS_MOUNTAIN, NULL, 60, 1510, -87), - RC(RC_MM_BLUE_EGG_INSIDE_TICKERS_TOWER_6, RCTYPE_BLUE_EGG, LEVEL_1_MUMBOS_MOUNTAIN, RI_BLUE_EGG_MUMBOS_MOUNTAIN, NULL, 67, 1510, 0), - RC(RC_MM_BLUE_EGG_NEAR_CONGA_LOWER_LEDGE_1, RCTYPE_BLUE_EGG, LEVEL_1_MUMBOS_MOUNTAIN, RI_BLUE_EGG_MUMBOS_MOUNTAIN, NULL, -5548, 200, 5984), - RC(RC_MM_BLUE_EGG_NEAR_CONGA_LOWER_LEDGE_2, RCTYPE_BLUE_EGG, LEVEL_1_MUMBOS_MOUNTAIN, RI_BLUE_EGG_MUMBOS_MOUNTAIN, NULL, -5706, 200, 5962), - RC(RC_MM_BLUE_EGG_NEAR_CONGA_LOWER_LEDGE_3, RCTYPE_BLUE_EGG, LEVEL_1_MUMBOS_MOUNTAIN, RI_BLUE_EGG_MUMBOS_MOUNTAIN, NULL, -5835, 201, 5896), - RC(RC_MM_BLUE_EGG_NEAR_CONGA_LOWER_LEDGE_4, RCTYPE_BLUE_EGG, LEVEL_1_MUMBOS_MOUNTAIN, RI_BLUE_EGG_MUMBOS_MOUNTAIN, NULL, -5911, 200, 5764), - RC(RC_MM_BLUE_EGG_NEAR_CONGA_LOWER_LEDGE_5, RCTYPE_BLUE_EGG, LEVEL_1_MUMBOS_MOUNTAIN, RI_BLUE_EGG_MUMBOS_MOUNTAIN, NULL, -5967, 200, 5615), - RC(RC_MM_BLUE_EGG_NEAR_CONGA_LOWER_LEDGE_6, RCTYPE_BLUE_EGG, LEVEL_1_MUMBOS_MOUNTAIN, RI_BLUE_EGG_MUMBOS_MOUNTAIN, NULL, -5927, 200, 5471), - RC(RC_MM_BLUE_EGG_NEAR_CONGA_LOWER_LEDGE_7, RCTYPE_BLUE_EGG, LEVEL_1_MUMBOS_MOUNTAIN, RI_BLUE_EGG_MUMBOS_MOUNTAIN, NULL, -5858, 200, 5343), - RC(RC_MM_BLUE_EGG_NEAR_CONGA_LOWER_LEDGE_8, RCTYPE_BLUE_EGG, LEVEL_1_MUMBOS_MOUNTAIN, RI_BLUE_EGG_MUMBOS_MOUNTAIN, NULL, -5732, 200, 5272), - RC(RC_MM_BLUE_EGG_NEAR_CONGA_MIDDLE_LEDGE_1, RCTYPE_BLUE_EGG, LEVEL_1_MUMBOS_MOUNTAIN, RI_BLUE_EGG_MUMBOS_MOUNTAIN, NULL, -5061, 298, 6090), - RC(RC_MM_BLUE_EGG_NEAR_CONGA_MIDDLE_LEDGE_2, RCTYPE_BLUE_EGG, LEVEL_1_MUMBOS_MOUNTAIN, RI_BLUE_EGG_MUMBOS_MOUNTAIN, NULL, -4881, 299, 6135), - RC(RC_MM_BLUE_EGG_NEAR_CONGA_UPPER_LEDGE_1, RCTYPE_BLUE_EGG, LEVEL_1_MUMBOS_MOUNTAIN, RI_BLUE_EGG_MUMBOS_MOUNTAIN, NULL, -3958, 600, 6084), - RC(RC_MM_BLUE_EGG_NEAR_CONGA_UPPER_LEDGE_2, RCTYPE_BLUE_EGG, LEVEL_1_MUMBOS_MOUNTAIN, RI_BLUE_EGG_MUMBOS_MOUNTAIN, NULL, -3827, 600, 5997), - RC(RC_MM_BLUE_EGG_UNDER_RUINS_1, RCTYPE_BLUE_EGG, LEVEL_1_MUMBOS_MOUNTAIN, RI_BLUE_EGG_MUMBOS_MOUNTAIN, NULL, -2840, 2355, -2408), - RC(RC_MM_BLUE_EGG_UNDER_RUINS_2, RCTYPE_BLUE_EGG, LEVEL_1_MUMBOS_MOUNTAIN, RI_BLUE_EGG_MUMBOS_MOUNTAIN, NULL, -2811, 2355, -2445), - RC(RC_MM_BLUE_EGG_UNDER_RUINS_3, RCTYPE_BLUE_EGG, LEVEL_1_MUMBOS_MOUNTAIN, RI_BLUE_EGG_MUMBOS_MOUNTAIN, NULL, -2776, 2355, -2494), - RC(RC_MM_BLUE_EGG_UNDER_RUINS_4, RCTYPE_BLUE_EGG, LEVEL_1_MUMBOS_MOUNTAIN, RI_BLUE_EGG_MUMBOS_MOUNTAIN, NULL, -2743, 2355, -2538), - RC(RC_MM_BLUE_EGG_UNDER_RUINS_5, RCTYPE_BLUE_EGG, LEVEL_1_MUMBOS_MOUNTAIN, RI_BLUE_EGG_MUMBOS_MOUNTAIN, NULL, -2713, 2355, -2576), + RC(RC_MM_BLUE_EGG_HUT_BUNDLE_1, RCTYPE_BLUE_EGG, LEVEL_1_MUMBOS_MOUNTAIN, RI_BLUE_EGG, NULL, 0, 0, 0), + RC(RC_MM_BLUE_EGG_HUT_BUNDLE_2, RCTYPE_BLUE_EGG, LEVEL_1_MUMBOS_MOUNTAIN, RI_BLUE_EGG, NULL, 0, 0, 0), + RC(RC_MM_BLUE_EGG_HUT_BUNDLE_3, RCTYPE_BLUE_EGG, LEVEL_1_MUMBOS_MOUNTAIN, RI_BLUE_EGG, NULL, 0, 0, 0), + RC(RC_MM_BLUE_EGG_HUT_BUNDLE_4, RCTYPE_BLUE_EGG, LEVEL_1_MUMBOS_MOUNTAIN, RI_BLUE_EGG, NULL, 0, 0, 0), + RC(RC_MM_BLUE_EGG_HUT_BUNDLE_5, RCTYPE_BLUE_EGG, LEVEL_1_MUMBOS_MOUNTAIN, RI_BLUE_EGG, NULL, 0, 0, 0), + RC(RC_MM_BLUE_EGG_INSIDE_MUMBOS_SKULL_1, RCTYPE_BLUE_EGG, LEVEL_1_MUMBOS_MOUNTAIN, RI_BLUE_EGG, NULL, -131, 398, -496), + RC(RC_MM_BLUE_EGG_INSIDE_MUMBOS_SKULL_2, RCTYPE_BLUE_EGG, LEVEL_1_MUMBOS_MOUNTAIN, RI_BLUE_EGG, NULL, -362, 378, -362), + RC(RC_MM_BLUE_EGG_INSIDE_MUMBOS_SKULL_3, RCTYPE_BLUE_EGG, LEVEL_1_MUMBOS_MOUNTAIN, RI_BLUE_EGG, NULL, -487, 398, -146), + RC(RC_MM_BLUE_EGG_INSIDE_MUMBOS_SKULL_4, RCTYPE_BLUE_EGG, LEVEL_1_MUMBOS_MOUNTAIN, RI_BLUE_EGG, NULL, -493, 398, 101), + RC(RC_MM_BLUE_EGG_INSIDE_MUMBOS_SKULL_5, RCTYPE_BLUE_EGG, LEVEL_1_MUMBOS_MOUNTAIN, RI_BLUE_EGG, NULL, -352, 398, 371), + RC(RC_MM_BLUE_EGG_INSIDE_MUMBOS_SKULL_6, RCTYPE_BLUE_EGG, LEVEL_1_MUMBOS_MOUNTAIN, RI_BLUE_EGG, NULL, -131, 398, 496), + RC(RC_MM_BLUE_EGG_INSIDE_MUMBOS_SKULL_7, RCTYPE_BLUE_EGG, LEVEL_1_MUMBOS_MOUNTAIN, RI_BLUE_EGG, NULL, 136, 398, -499), + RC(RC_MM_BLUE_EGG_INSIDE_MUMBOS_SKULL_8, RCTYPE_BLUE_EGG, LEVEL_1_MUMBOS_MOUNTAIN, RI_BLUE_EGG, NULL, 361, 379, -363), + RC(RC_MM_BLUE_EGG_INSIDE_MUMBOS_SKULL_9, RCTYPE_BLUE_EGG, LEVEL_1_MUMBOS_MOUNTAIN, RI_BLUE_EGG, NULL, 498, 394, -129), + RC(RC_MM_BLUE_EGG_INSIDE_MUMBOS_SKULL_10, RCTYPE_BLUE_EGG, LEVEL_1_MUMBOS_MOUNTAIN, RI_BLUE_EGG, NULL, 495, 398, 133), + RC(RC_MM_BLUE_EGG_INSIDE_MUMBOS_SKULL_11, RCTYPE_BLUE_EGG, LEVEL_1_MUMBOS_MOUNTAIN, RI_BLUE_EGG, NULL, 359, 398, 362), + RC(RC_MM_BLUE_EGG_INSIDE_MUMBOS_SKULL_12, RCTYPE_BLUE_EGG, LEVEL_1_MUMBOS_MOUNTAIN, RI_BLUE_EGG, NULL, 134, 379, 497), + RC(RC_MM_BLUE_EGG_INSIDE_TICKERS_TOWER_1, RCTYPE_BLUE_EGG, LEVEL_1_MUMBOS_MOUNTAIN, RI_BLUE_EGG, NULL, -10, 1507, -125), + RC(RC_MM_BLUE_EGG_INSIDE_TICKERS_TOWER_2, RCTYPE_BLUE_EGG, LEVEL_1_MUMBOS_MOUNTAIN, RI_BLUE_EGG, NULL, -80, 1503, -71), + RC(RC_MM_BLUE_EGG_INSIDE_TICKERS_TOWER_3, RCTYPE_BLUE_EGG, LEVEL_1_MUMBOS_MOUNTAIN, RI_BLUE_EGG, NULL, -74, 1521, 19), + RC(RC_MM_BLUE_EGG_INSIDE_TICKERS_TOWER_4, RCTYPE_BLUE_EGG, LEVEL_1_MUMBOS_MOUNTAIN, RI_BLUE_EGG, NULL, -3, 1510, 52), + RC(RC_MM_BLUE_EGG_INSIDE_TICKERS_TOWER_5, RCTYPE_BLUE_EGG, LEVEL_1_MUMBOS_MOUNTAIN, RI_BLUE_EGG, NULL, 60, 1510, -87), + RC(RC_MM_BLUE_EGG_INSIDE_TICKERS_TOWER_6, RCTYPE_BLUE_EGG, LEVEL_1_MUMBOS_MOUNTAIN, RI_BLUE_EGG, NULL, 67, 1510, 0), + RC(RC_MM_BLUE_EGG_NEAR_CONGA_LOWER_LEDGE_1, RCTYPE_BLUE_EGG, LEVEL_1_MUMBOS_MOUNTAIN, RI_BLUE_EGG, NULL, -5548, 200, 5984), + RC(RC_MM_BLUE_EGG_NEAR_CONGA_LOWER_LEDGE_2, RCTYPE_BLUE_EGG, LEVEL_1_MUMBOS_MOUNTAIN, RI_BLUE_EGG, NULL, -5706, 200, 5962), + RC(RC_MM_BLUE_EGG_NEAR_CONGA_LOWER_LEDGE_3, RCTYPE_BLUE_EGG, LEVEL_1_MUMBOS_MOUNTAIN, RI_BLUE_EGG, NULL, -5835, 201, 5896), + RC(RC_MM_BLUE_EGG_NEAR_CONGA_LOWER_LEDGE_4, RCTYPE_BLUE_EGG, LEVEL_1_MUMBOS_MOUNTAIN, RI_BLUE_EGG, NULL, -5911, 200, 5764), + RC(RC_MM_BLUE_EGG_NEAR_CONGA_LOWER_LEDGE_5, RCTYPE_BLUE_EGG, LEVEL_1_MUMBOS_MOUNTAIN, RI_BLUE_EGG, NULL, -5967, 200, 5615), + RC(RC_MM_BLUE_EGG_NEAR_CONGA_LOWER_LEDGE_6, RCTYPE_BLUE_EGG, LEVEL_1_MUMBOS_MOUNTAIN, RI_BLUE_EGG, NULL, -5927, 200, 5471), + RC(RC_MM_BLUE_EGG_NEAR_CONGA_LOWER_LEDGE_7, RCTYPE_BLUE_EGG, LEVEL_1_MUMBOS_MOUNTAIN, RI_BLUE_EGG, NULL, -5858, 200, 5343), + RC(RC_MM_BLUE_EGG_NEAR_CONGA_LOWER_LEDGE_8, RCTYPE_BLUE_EGG, LEVEL_1_MUMBOS_MOUNTAIN, RI_BLUE_EGG, NULL, -5732, 200, 5272), + RC(RC_MM_BLUE_EGG_NEAR_CONGA_MIDDLE_LEDGE_1, RCTYPE_BLUE_EGG, LEVEL_1_MUMBOS_MOUNTAIN, RI_BLUE_EGG, NULL, -5061, 298, 6090), + RC(RC_MM_BLUE_EGG_NEAR_CONGA_MIDDLE_LEDGE_2, RCTYPE_BLUE_EGG, LEVEL_1_MUMBOS_MOUNTAIN, RI_BLUE_EGG, NULL, -4881, 299, 6135), + RC(RC_MM_BLUE_EGG_NEAR_CONGA_UPPER_LEDGE_1, RCTYPE_BLUE_EGG, LEVEL_1_MUMBOS_MOUNTAIN, RI_BLUE_EGG, NULL, -3958, 600, 6084), + RC(RC_MM_BLUE_EGG_NEAR_CONGA_UPPER_LEDGE_2, RCTYPE_BLUE_EGG, LEVEL_1_MUMBOS_MOUNTAIN, RI_BLUE_EGG, NULL, -3827, 600, 5997), + RC(RC_MM_BLUE_EGG_UNDER_RUINS_1, RCTYPE_BLUE_EGG, LEVEL_1_MUMBOS_MOUNTAIN, RI_BLUE_EGG, NULL, -2840, 2355, -2408), + RC(RC_MM_BLUE_EGG_UNDER_RUINS_2, RCTYPE_BLUE_EGG, LEVEL_1_MUMBOS_MOUNTAIN, RI_BLUE_EGG, NULL, -2811, 2355, -2445), + RC(RC_MM_BLUE_EGG_UNDER_RUINS_3, RCTYPE_BLUE_EGG, LEVEL_1_MUMBOS_MOUNTAIN, RI_BLUE_EGG, NULL, -2776, 2355, -2494), + RC(RC_MM_BLUE_EGG_UNDER_RUINS_4, RCTYPE_BLUE_EGG, LEVEL_1_MUMBOS_MOUNTAIN, RI_BLUE_EGG, NULL, -2743, 2355, -2538), + RC(RC_MM_BLUE_EGG_UNDER_RUINS_5, RCTYPE_BLUE_EGG, LEVEL_1_MUMBOS_MOUNTAIN, RI_BLUE_EGG, NULL, -2713, 2355, -2576), RC(RC_MM_EMPTY_HONEYCOMB_HILL, RCTYPE_EMPTY_HONEYCOMB, LEVEL_1_MUMBOS_MOUNTAIN, RI_EMPTY_HONEYCOMB_MUMBOS_MOUNTAIN, HONEYCOMB_1_MM_HILL, 985, 484, 1681), RC(RC_MM_EMPTY_HONEYCOMB_JUJU, RCTYPE_EMPTY_HONEYCOMB, LEVEL_1_MUMBOS_MOUNTAIN, RI_EMPTY_HONEYCOMB_MUMBOS_MOUNTAIN, HONEYCOMB_2_MM_JUJU, 4302, 2900, -1490), - RC(RC_MM_EXTRA_LIFE_HUT, RCTYPE_EXTRA_LIFE, LEVEL_1_MUMBOS_MOUNTAIN, RI_EXTRA_LIFE_MUMBOS_MOUNTAIN, NULL, 0, 0, 0), - RC(RC_MM_EXTRA_LIFE_TICKERS_TOWER, RCTYPE_EXTRA_LIFE, LEVEL_1_MUMBOS_MOUNTAIN, RI_EXTRA_LIFE_MUMBOS_MOUNTAIN, NULL, 223, 3563, -382), - RC(RC_MM_HONEYCOMB_BEEHIVE_BY_BIG_BUTT_1, RCTYPE_HONEYCOMB, LEVEL_1_MUMBOS_MOUNTAIN, RI_HONEYCOMB_MUMBOS_MOUNTAIN, NULL, 0, 0, 0), - RC(RC_MM_HONEYCOMB_BEEHIVE_BY_BIG_BUTT_2, RCTYPE_HONEYCOMB, LEVEL_1_MUMBOS_MOUNTAIN, RI_HONEYCOMB_MUMBOS_MOUNTAIN, NULL, 0, 0, 0), - RC(RC_MM_HONEYCOMB_BEEHIVE_BY_BIG_BUTT_3, RCTYPE_HONEYCOMB, LEVEL_1_MUMBOS_MOUNTAIN, RI_HONEYCOMB_MUMBOS_MOUNTAIN, NULL, 0, 0, 0), - RC(RC_MM_HONEYCOMB_BEEHIVE_BY_THE_HUTS_1, RCTYPE_HONEYCOMB, LEVEL_1_MUMBOS_MOUNTAIN, RI_HONEYCOMB_MUMBOS_MOUNTAIN, NULL, 0, 0, 0), - RC(RC_MM_HONEYCOMB_BEEHIVE_BY_THE_HUTS_2, RCTYPE_HONEYCOMB, LEVEL_1_MUMBOS_MOUNTAIN, RI_HONEYCOMB_MUMBOS_MOUNTAIN, NULL, 0, 0, 0), - RC(RC_MM_HONEYCOMB_BEEHIVE_BY_THE_HUTS_3, RCTYPE_HONEYCOMB, LEVEL_1_MUMBOS_MOUNTAIN, RI_HONEYCOMB_MUMBOS_MOUNTAIN, NULL, 0, 0, 0), + RC(RC_MM_EXTRA_LIFE_HUT, RCTYPE_EXTRA_LIFE, LEVEL_1_MUMBOS_MOUNTAIN, RI_EXTRA_LIFE, NULL, 0, 0, 0), + RC(RC_MM_EXTRA_LIFE_TICKERS_TOWER, RCTYPE_EXTRA_LIFE, LEVEL_1_MUMBOS_MOUNTAIN, RI_EXTRA_LIFE, NULL, 223, 3563, -382), + RC(RC_MM_HONEYCOMB_BEEHIVE_BY_BIG_BUTT_1, RCTYPE_HONEYCOMB, LEVEL_1_MUMBOS_MOUNTAIN, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_MM_HONEYCOMB_BEEHIVE_BY_BIG_BUTT_2, RCTYPE_HONEYCOMB, LEVEL_1_MUMBOS_MOUNTAIN, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_MM_HONEYCOMB_BEEHIVE_BY_BIG_BUTT_3, RCTYPE_HONEYCOMB, LEVEL_1_MUMBOS_MOUNTAIN, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_MM_HONEYCOMB_BEEHIVE_BY_THE_HUTS_1, RCTYPE_HONEYCOMB, LEVEL_1_MUMBOS_MOUNTAIN, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_MM_HONEYCOMB_BEEHIVE_BY_THE_HUTS_2, RCTYPE_HONEYCOMB, LEVEL_1_MUMBOS_MOUNTAIN, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_MM_HONEYCOMB_BEEHIVE_BY_THE_HUTS_3, RCTYPE_HONEYCOMB, LEVEL_1_MUMBOS_MOUNTAIN, RI_HONEYCOMB, NULL, 0, 0, 0), RC(RC_MM_JIGGY_CHIMPY, RCTYPE_JIGGY, LEVEL_1_MUMBOS_MOUNTAIN, RI_JIGGY_MUMBOS_MOUNTAIN, JIGGY_9_MM_CHIMPY, 0, 0, 0), RC(RC_MM_JIGGY_CONGA, RCTYPE_JIGGY, LEVEL_1_MUMBOS_MOUNTAIN, RI_JIGGY_MUMBOS_MOUNTAIN, JIGGY_A_MM_CONGA, 0, 0, 0), RC(RC_MM_JIGGY_HILL, RCTYPE_JIGGY, LEVEL_1_MUMBOS_MOUNTAIN, RI_JIGGY_MUMBOS_MOUNTAIN, JIGGY_07_MM_HILL, 4335, 1485, 794), @@ -1383,100 +1383,100 @@ std::map Checks = { RC(RC_MM_NOTE_INSIDE_TICKERS_TOWER_4, RCTYPE_MUSIC_NOTE, LEVEL_1_MUMBOS_MOUNTAIN, RI_MUSIC_NOTE_MUMBOS_MOUNTAIN, NULL, 60, 817, -87), RC(RC_MM_NOTE_INSIDE_TICKERS_TOWER_5, RCTYPE_MUSIC_NOTE, LEVEL_1_MUMBOS_MOUNTAIN, RI_MUSIC_NOTE_MUMBOS_MOUNTAIN, NULL, -10, 817, -125), RC(RC_MM_NOTE_INSIDE_TICKERS_TOWER_6, RCTYPE_MUSIC_NOTE, LEVEL_1_MUMBOS_MOUNTAIN, RI_MUSIC_NOTE_MUMBOS_MOUNTAIN, NULL, -80, 817, -71), - RC(RC_MMM_BLUE_EGG_BEDROOM_1, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG_MAD_MONSTER_MANSION, NULL, -650, 175, 450), - RC(RC_MMM_BLUE_EGG_BEDROOM_2, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG_MAD_MONSTER_MANSION, NULL, -650, 175, 300), - RC(RC_MMM_BLUE_EGG_BEDROOM_3, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG_MAD_MONSTER_MANSION, NULL, -650, 175, 150), - RC(RC_MMM_BLUE_EGG_CELLAR_1, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG_MAD_MONSTER_MANSION, NULL, -464, 40, -473), - RC(RC_MMM_BLUE_EGG_CELLAR_2, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG_MAD_MONSTER_MANSION, NULL, -495, 40, -474), - RC(RC_MMM_BLUE_EGG_CELLAR_3, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG_MAD_MONSTER_MANSION, NULL, -524, 40, -473), - RC(RC_MMM_BLUE_EGG_CHURCH_PEW_NORTHEAST_1, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG_MAD_MONSTER_MANSION, NULL, 950, 588, 819), - RC(RC_MMM_BLUE_EGG_CHURCH_PEW_NORTHEAST_2, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG_MAD_MONSTER_MANSION, NULL, 2300, 588, 819), - RC(RC_MMM_BLUE_EGG_CHURCH_PEW_NORTHWEST_1, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG_MAD_MONSTER_MANSION, NULL, -2299, 588, 820), - RC(RC_MMM_BLUE_EGG_CHURCH_PEW_NORTHWEST_2, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG_MAD_MONSTER_MANSION, NULL, -949, 588, 820), - RC(RC_MMM_BLUE_EGG_CHURCH_PEW_SOUTHEAST_1, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG_MAD_MONSTER_MANSION, NULL, 2300, 588, 2369), - RC(RC_MMM_BLUE_EGG_CHURCH_PEW_SOUTHEAST_2, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG_MAD_MONSTER_MANSION, NULL, 950, 588, 2369), - RC(RC_MMM_BLUE_EGG_CHURCH_PEW_SOUTHWEST_1, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG_MAD_MONSTER_MANSION, NULL, -949, 588, 2370), - RC(RC_MMM_BLUE_EGG_CHURCH_PEW_SOUTHWEST_2, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG_MAD_MONSTER_MANSION, NULL, -2299, 588, 2370), - RC(RC_MMM_BLUE_EGG_CHURCH_RAFTERS_1, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG_MAD_MONSTER_MANSION, NULL, 2070, 4885, -2065), - RC(RC_MMM_BLUE_EGG_CHURCH_RAFTERS_2, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG_MAD_MONSTER_MANSION, NULL, 2069, 4885, -1765), - RC(RC_MMM_BLUE_EGG_CHURCH_RAFTERS_3, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG_MAD_MONSTER_MANSION, NULL, 2069, 4885, -1464), - RC(RC_MMM_BLUE_EGG_CHURCH_RAFTERS_4, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG_MAD_MONSTER_MANSION, NULL, -2100, 4839, -2065), - RC(RC_MMM_BLUE_EGG_CHURCH_RAFTERS_5, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG_MAD_MONSTER_MANSION, NULL, -2100, 4838, -1764), - RC(RC_MMM_BLUE_EGG_CHURCH_RAFTERS_6, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG_MAD_MONSTER_MANSION, NULL, -2100, 4839, -1465), - RC(RC_MMM_BLUE_EGG_CHURCH_RAFTERS_7, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG_MAD_MONSTER_MANSION, NULL, -2100, 4813, 2730), - RC(RC_MMM_BLUE_EGG_CHURCH_RAFTERS_8, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG_MAD_MONSTER_MANSION, NULL, -2100, 4813, 2430), - RC(RC_MMM_BLUE_EGG_CHURCH_RAFTERS_9, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG_MAD_MONSTER_MANSION, NULL, -2100, 4813, 2129), - RC(RC_MMM_BLUE_EGG_CHURCH_RAFTERS_10, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG_MAD_MONSTER_MANSION, NULL, 2070, 4768, 2720), - RC(RC_MMM_BLUE_EGG_CHURCH_RAFTERS_11, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG_MAD_MONSTER_MANSION, NULL, 2070, 4768, 2420), - RC(RC_MMM_BLUE_EGG_CHURCH_RAFTERS_12, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG_MAD_MONSTER_MANSION, NULL, 2070, 4768, 2119), - RC(RC_MMM_BLUE_EGG_CHURCH_WINDOW_1, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG_MAD_MONSTER_MANSION, NULL, -700, 0, -480), - RC(RC_MMM_BLUE_EGG_CHURCH_WINDOW_2, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG_MAD_MONSTER_MANSION, NULL, -700, 0, -280), - RC(RC_MMM_BLUE_EGG_CHURCH_WINDOW_3, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG_MAD_MONSTER_MANSION, NULL, -701, 0, -80), - RC(RC_MMM_BLUE_EGG_CHURCH_WINDOW_4, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG_MAD_MONSTER_MANSION, NULL, -700, 0, 121), - RC(RC_MMM_BLUE_EGG_CHURCH_WINDOW_5, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG_MAD_MONSTER_MANSION, NULL, -700, 0, 320), - RC(RC_MMM_BLUE_EGG_CHURCH_WINDOW_6, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG_MAD_MONSTER_MANSION, NULL, -700, 0, 520), - RC(RC_MMM_BLUE_EGG_CHURCH_WINDOW_7, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG_MAD_MONSTER_MANSION, NULL, -600, 0, 619), - RC(RC_MMM_BLUE_EGG_CHURCH_WINDOW_8, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG_MAD_MONSTER_MANSION, NULL, -400, 0, 620), - RC(RC_MMM_BLUE_EGG_CHURCH_WINDOW_9, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG_MAD_MONSTER_MANSION, NULL, -199, 0, 621), - RC(RC_MMM_BLUE_EGG_CHURCH_WINDOW_10, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG_MAD_MONSTER_MANSION, NULL, 200, 0, 620), - RC(RC_MMM_BLUE_EGG_CHURCH_WINDOW_11, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG_MAD_MONSTER_MANSION, NULL, 401, 0, 620), - RC(RC_MMM_BLUE_EGG_CHURCH_WINDOW_12, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG_MAD_MONSTER_MANSION, NULL, 600, 0, 620), - RC(RC_MMM_BLUE_EGG_CHURCH_WINDOW_13, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG_MAD_MONSTER_MANSION, NULL, 700, 0, 519), - RC(RC_MMM_BLUE_EGG_CHURCH_WINDOW_14, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG_MAD_MONSTER_MANSION, NULL, 700, 0, 320), - RC(RC_MMM_BLUE_EGG_CHURCH_WINDOW_15, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG_MAD_MONSTER_MANSION, NULL, 700, 0, 120), - RC(RC_MMM_BLUE_EGG_CHURCH_WINDOW_16, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG_MAD_MONSTER_MANSION, NULL, 700, 0, -78), - RC(RC_MMM_BLUE_EGG_CHURCH_WINDOW_17, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG_MAD_MONSTER_MANSION, NULL, 700, 0, -279), - RC(RC_MMM_BLUE_EGG_CHURCH_WINDOW_18, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG_MAD_MONSTER_MANSION, NULL, 700, 0, -481), - RC(RC_MMM_BLUE_EGG_DINING_ROOM_MANTLE_1, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG_MAD_MONSTER_MANSION, NULL, -350, 550, -2499), - RC(RC_MMM_BLUE_EGG_DINING_ROOM_MANTLE_2, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG_MAD_MONSTER_MANSION, NULL, -176, 550, -2499), - RC(RC_MMM_BLUE_EGG_DINING_ROOM_MANTLE_3, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG_MAD_MONSTER_MANSION, NULL, 0, 550, -2500), - RC(RC_MMM_BLUE_EGG_DINING_ROOM_MANTLE_4, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG_MAD_MONSTER_MANSION, NULL, 174, 550, -2500), - RC(RC_MMM_BLUE_EGG_DINING_ROOM_MANTLE_5, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG_MAD_MONSTER_MANSION, NULL, 349, 550, -2500), - RC(RC_MMM_BLUE_EGG_EGG_ROOM_1, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG_MAD_MONSTER_MANSION, NULL, 446, 135, -339), - RC(RC_MMM_BLUE_EGG_EGG_ROOM_2, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG_MAD_MONSTER_MANSION, NULL, 450, 0, -35), - RC(RC_MMM_BLUE_EGG_EGG_ROOM_3, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG_MAD_MONSTER_MANSION, NULL, 450, 0, 36), - RC(RC_MMM_BLUE_EGG_EGG_ROOM_4, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG_MAD_MONSTER_MANSION, NULL, 35, 0, 351), - RC(RC_MMM_BLUE_EGG_EGG_ROOM_5, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG_MAD_MONSTER_MANSION, NULL, -36, 0, 350), - RC(RC_MMM_BLUE_EGG_EGG_ROOM_6, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG_MAD_MONSTER_MANSION, NULL, -442, 160, 331), - RC(RC_MMM_BLUE_EGG_EGG_ROOM_7, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG_MAD_MONSTER_MANSION, NULL, -437, 150, -336), - RC(RC_MMM_BLUE_EGG_EGG_ROOM_8, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG_MAD_MONSTER_MANSION, NULL, -302, 150, -336), - RC(RC_MMM_BLUE_EGG_HONEYCOMB_ROOM_1, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG_MAD_MONSTER_MANSION, NULL, 225, -135, -390), - RC(RC_MMM_BLUE_EGG_HONEYCOMB_ROOM_2, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG_MAD_MONSTER_MANSION, NULL, 61, -135, -390), - RC(RC_MMM_BLUE_EGG_HONEYCOMB_ROOM_3, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG_MAD_MONSTER_MANSION, NULL, -103, -135, -390), - RC(RC_MMM_BLUE_EGG_HONEYCOMB_ROOM_4, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG_MAD_MONSTER_MANSION, NULL, -268, -135, -390), - RC(RC_MMM_BLUE_EGG_HONEYCOMB_ROOM_5, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG_MAD_MONSTER_MANSION, NULL, -442, -135, -390), - RC(RC_MMM_BLUE_EGG_MANSION_AWNING_1, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG_MAD_MONSTER_MANSION, NULL, 50, 1100, -760), - RC(RC_MMM_BLUE_EGG_MANSION_AWNING_2, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG_MAD_MONSTER_MANSION, NULL, 50, 1100, 1255), - RC(RC_MMM_BLUE_EGG_MANSION_AWNING_3, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG_MAD_MONSTER_MANSION, NULL, 1942, 1100, 1255), - RC(RC_MMM_BLUE_EGG_MANSION_AWNING_4, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG_MAD_MONSTER_MANSION, NULL, 1950, 1099, -758), - RC(RC_MMM_BLUE_EGG_MAZE_1, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG_MAD_MONSTER_MANSION, NULL, -1750, 0, 2410), - RC(RC_MMM_BLUE_EGG_MAZE_2, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG_MAD_MONSTER_MANSION, NULL, -1951, 0, 2655), - RC(RC_MMM_BLUE_EGG_MAZE_3, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG_MAD_MONSTER_MANSION, NULL, -2446, 0, 760), - RC(RC_MMM_BLUE_EGG_NEAR_FOUNTAIN_1, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG_MAD_MONSTER_MANSION, NULL, 7173, -175, -103), - RC(RC_MMM_BLUE_EGG_NEAR_FOUNTAIN_2, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG_MAD_MONSTER_MANSION, NULL, 7173, -175, 452), - RC(RC_MMM_BLUE_EGG_NEAR_FOUNTAIN_3, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG_MAD_MONSTER_MANSION, NULL, 7173, -175, 1008), - RC(RC_MMM_BLUE_EGG_NEAR_FOUNTAIN_4, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG_MAD_MONSTER_MANSION, NULL, 7174, -175, 1564), - RC(RC_MMM_BLUE_EGG_NEAR_WELL_1, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG_MAD_MONSTER_MANSION, NULL, 4200, -275, -2324), - RC(RC_MMM_BLUE_EGG_NEAR_WELL_2, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG_MAD_MONSTER_MANSION, NULL, 4200, -275, -2474), - RC(RC_MMM_BLUE_EGG_NEAR_WELL_3, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG_MAD_MONSTER_MANSION, NULL, 7150, -273, -2383), - RC(RC_MMM_BLUE_EGG_NEAR_WELL_4, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG_MAD_MONSTER_MANSION, NULL, 7149, -273, -2233), + RC(RC_MMM_BLUE_EGG_BEDROOM_1, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG, NULL, -650, 175, 450), + RC(RC_MMM_BLUE_EGG_BEDROOM_2, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG, NULL, -650, 175, 300), + RC(RC_MMM_BLUE_EGG_BEDROOM_3, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG, NULL, -650, 175, 150), + RC(RC_MMM_BLUE_EGG_CELLAR_1, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG, NULL, -464, 40, -473), + RC(RC_MMM_BLUE_EGG_CELLAR_2, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG, NULL, -495, 40, -474), + RC(RC_MMM_BLUE_EGG_CELLAR_3, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG, NULL, -524, 40, -473), + RC(RC_MMM_BLUE_EGG_CHURCH_PEW_NORTHEAST_1, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG, NULL, 950, 588, 819), + RC(RC_MMM_BLUE_EGG_CHURCH_PEW_NORTHEAST_2, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG, NULL, 2300, 588, 819), + RC(RC_MMM_BLUE_EGG_CHURCH_PEW_NORTHWEST_1, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG, NULL, -2299, 588, 820), + RC(RC_MMM_BLUE_EGG_CHURCH_PEW_NORTHWEST_2, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG, NULL, -949, 588, 820), + RC(RC_MMM_BLUE_EGG_CHURCH_PEW_SOUTHEAST_1, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG, NULL, 2300, 588, 2369), + RC(RC_MMM_BLUE_EGG_CHURCH_PEW_SOUTHEAST_2, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG, NULL, 950, 588, 2369), + RC(RC_MMM_BLUE_EGG_CHURCH_PEW_SOUTHWEST_1, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG, NULL, -949, 588, 2370), + RC(RC_MMM_BLUE_EGG_CHURCH_PEW_SOUTHWEST_2, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG, NULL, -2299, 588, 2370), + RC(RC_MMM_BLUE_EGG_CHURCH_RAFTERS_1, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG, NULL, 2070, 4885, -2065), + RC(RC_MMM_BLUE_EGG_CHURCH_RAFTERS_2, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG, NULL, 2069, 4885, -1765), + RC(RC_MMM_BLUE_EGG_CHURCH_RAFTERS_3, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG, NULL, 2069, 4885, -1464), + RC(RC_MMM_BLUE_EGG_CHURCH_RAFTERS_4, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG, NULL, -2100, 4839, -2065), + RC(RC_MMM_BLUE_EGG_CHURCH_RAFTERS_5, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG, NULL, -2100, 4838, -1764), + RC(RC_MMM_BLUE_EGG_CHURCH_RAFTERS_6, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG, NULL, -2100, 4839, -1465), + RC(RC_MMM_BLUE_EGG_CHURCH_RAFTERS_7, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG, NULL, -2100, 4813, 2730), + RC(RC_MMM_BLUE_EGG_CHURCH_RAFTERS_8, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG, NULL, -2100, 4813, 2430), + RC(RC_MMM_BLUE_EGG_CHURCH_RAFTERS_9, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG, NULL, -2100, 4813, 2129), + RC(RC_MMM_BLUE_EGG_CHURCH_RAFTERS_10, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG, NULL, 2070, 4768, 2720), + RC(RC_MMM_BLUE_EGG_CHURCH_RAFTERS_11, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG, NULL, 2070, 4768, 2420), + RC(RC_MMM_BLUE_EGG_CHURCH_RAFTERS_12, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG, NULL, 2070, 4768, 2119), + RC(RC_MMM_BLUE_EGG_CHURCH_WINDOW_1, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG, NULL, -700, 0, -480), + RC(RC_MMM_BLUE_EGG_CHURCH_WINDOW_2, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG, NULL, -700, 0, -280), + RC(RC_MMM_BLUE_EGG_CHURCH_WINDOW_3, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG, NULL, -701, 0, -80), + RC(RC_MMM_BLUE_EGG_CHURCH_WINDOW_4, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG, NULL, -700, 0, 121), + RC(RC_MMM_BLUE_EGG_CHURCH_WINDOW_5, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG, NULL, -700, 0, 320), + RC(RC_MMM_BLUE_EGG_CHURCH_WINDOW_6, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG, NULL, -700, 0, 520), + RC(RC_MMM_BLUE_EGG_CHURCH_WINDOW_7, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG, NULL, -600, 0, 619), + RC(RC_MMM_BLUE_EGG_CHURCH_WINDOW_8, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG, NULL, -400, 0, 620), + RC(RC_MMM_BLUE_EGG_CHURCH_WINDOW_9, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG, NULL, -199, 0, 621), + RC(RC_MMM_BLUE_EGG_CHURCH_WINDOW_10, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG, NULL, 200, 0, 620), + RC(RC_MMM_BLUE_EGG_CHURCH_WINDOW_11, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG, NULL, 401, 0, 620), + RC(RC_MMM_BLUE_EGG_CHURCH_WINDOW_12, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG, NULL, 600, 0, 620), + RC(RC_MMM_BLUE_EGG_CHURCH_WINDOW_13, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG, NULL, 700, 0, 519), + RC(RC_MMM_BLUE_EGG_CHURCH_WINDOW_14, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG, NULL, 700, 0, 320), + RC(RC_MMM_BLUE_EGG_CHURCH_WINDOW_15, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG, NULL, 700, 0, 120), + RC(RC_MMM_BLUE_EGG_CHURCH_WINDOW_16, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG, NULL, 700, 0, -78), + RC(RC_MMM_BLUE_EGG_CHURCH_WINDOW_17, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG, NULL, 700, 0, -279), + RC(RC_MMM_BLUE_EGG_CHURCH_WINDOW_18, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG, NULL, 700, 0, -481), + RC(RC_MMM_BLUE_EGG_DINING_ROOM_MANTLE_1, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG, NULL, -350, 550, -2499), + RC(RC_MMM_BLUE_EGG_DINING_ROOM_MANTLE_2, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG, NULL, -176, 550, -2499), + RC(RC_MMM_BLUE_EGG_DINING_ROOM_MANTLE_3, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG, NULL, 0, 550, -2500), + RC(RC_MMM_BLUE_EGG_DINING_ROOM_MANTLE_4, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG, NULL, 174, 550, -2500), + RC(RC_MMM_BLUE_EGG_DINING_ROOM_MANTLE_5, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG, NULL, 349, 550, -2500), + RC(RC_MMM_BLUE_EGG_EGG_ROOM_1, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG, NULL, 446, 135, -339), + RC(RC_MMM_BLUE_EGG_EGG_ROOM_2, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG, NULL, 450, 0, -35), + RC(RC_MMM_BLUE_EGG_EGG_ROOM_3, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG, NULL, 450, 0, 36), + RC(RC_MMM_BLUE_EGG_EGG_ROOM_4, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG, NULL, 35, 0, 351), + RC(RC_MMM_BLUE_EGG_EGG_ROOM_5, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG, NULL, -36, 0, 350), + RC(RC_MMM_BLUE_EGG_EGG_ROOM_6, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG, NULL, -442, 160, 331), + RC(RC_MMM_BLUE_EGG_EGG_ROOM_7, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG, NULL, -437, 150, -336), + RC(RC_MMM_BLUE_EGG_EGG_ROOM_8, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG, NULL, -302, 150, -336), + RC(RC_MMM_BLUE_EGG_HONEYCOMB_ROOM_1, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG, NULL, 225, -135, -390), + RC(RC_MMM_BLUE_EGG_HONEYCOMB_ROOM_2, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG, NULL, 61, -135, -390), + RC(RC_MMM_BLUE_EGG_HONEYCOMB_ROOM_3, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG, NULL, -103, -135, -390), + RC(RC_MMM_BLUE_EGG_HONEYCOMB_ROOM_4, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG, NULL, -268, -135, -390), + RC(RC_MMM_BLUE_EGG_HONEYCOMB_ROOM_5, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG, NULL, -442, -135, -390), + RC(RC_MMM_BLUE_EGG_MANSION_AWNING_1, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG, NULL, 50, 1100, -760), + RC(RC_MMM_BLUE_EGG_MANSION_AWNING_2, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG, NULL, 50, 1100, 1255), + RC(RC_MMM_BLUE_EGG_MANSION_AWNING_3, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG, NULL, 1942, 1100, 1255), + RC(RC_MMM_BLUE_EGG_MANSION_AWNING_4, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG, NULL, 1950, 1099, -758), + RC(RC_MMM_BLUE_EGG_MAZE_1, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG, NULL, -1750, 0, 2410), + RC(RC_MMM_BLUE_EGG_MAZE_2, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG, NULL, -1951, 0, 2655), + RC(RC_MMM_BLUE_EGG_MAZE_3, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG, NULL, -2446, 0, 760), + RC(RC_MMM_BLUE_EGG_NEAR_FOUNTAIN_1, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG, NULL, 7173, -175, -103), + RC(RC_MMM_BLUE_EGG_NEAR_FOUNTAIN_2, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG, NULL, 7173, -175, 452), + RC(RC_MMM_BLUE_EGG_NEAR_FOUNTAIN_3, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG, NULL, 7173, -175, 1008), + RC(RC_MMM_BLUE_EGG_NEAR_FOUNTAIN_4, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG, NULL, 7174, -175, 1564), + RC(RC_MMM_BLUE_EGG_NEAR_WELL_1, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG, NULL, 4200, -275, -2324), + RC(RC_MMM_BLUE_EGG_NEAR_WELL_2, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG, NULL, 4200, -275, -2474), + RC(RC_MMM_BLUE_EGG_NEAR_WELL_3, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG, NULL, 7150, -273, -2383), + RC(RC_MMM_BLUE_EGG_NEAR_WELL_4, RCTYPE_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION, RI_BLUE_EGG, NULL, 7149, -273, -2233), RC(RC_MMM_EMPTY_HONEYCOMB_BENEATH_THE_FLOORBOARDS, RCTYPE_EMPTY_HONEYCOMB, LEVEL_A_MAD_MONSTER_MANSION, RI_EMPTY_HONEYCOMB_MAD_MONSTER_MANSION, HONEYCOMB_12_MMM_FLOORBOARD, -51, -135, 52), RC(RC_MMM_EMPTY_HONEYCOMB_CHURCH_RAFTERS, RCTYPE_EMPTY_HONEYCOMB, LEVEL_A_MAD_MONSTER_MANSION, RI_EMPTY_HONEYCOMB_MAD_MONSTER_MANSION, HONEYCOMB_11_MMM_CHURCH_RAFTERS, 0, 5163, 2400), - RC(RC_MMM_EXTRA_LIFE_CHURCH_PIPES, RCTYPE_EXTRA_LIFE, LEVEL_A_MAD_MONSTER_MANSION, RI_EXTRA_LIFE_MAD_MONSTER_MANSION, NULL, -1, 2263, -3465), - RC(RC_MMM_EXTRA_LIFE_CHURCH_WINDOW, RCTYPE_EXTRA_LIFE, LEVEL_A_MAD_MONSTER_MANSION, RI_EXTRA_LIFE_MAD_MONSTER_MANSION, NULL, 0, 13, 6), - RC(RC_MMM_EXTRA_LIFE_DINING_ROOM_CHANDELIER, RCTYPE_EXTRA_LIFE, LEVEL_A_MAD_MONSTER_MANSION, RI_EXTRA_LIFE_MAD_MONSTER_MANSION, NULL, 0, 1326, 145), - RC(RC_MMM_HONEYCOMB_BEEHIVE_CHURCH_ORGAN_LEFT_1, RCTYPE_HONEYCOMB, LEVEL_A_MAD_MONSTER_MANSION, RI_HONEYCOMB_MAD_MONSTER_MANSION, NULL, 0, 0, 0), - RC(RC_MMM_HONEYCOMB_BEEHIVE_CHURCH_ORGAN_LEFT_2, RCTYPE_HONEYCOMB, LEVEL_A_MAD_MONSTER_MANSION, RI_HONEYCOMB_MAD_MONSTER_MANSION, NULL, 0, 0, 0), - RC(RC_MMM_HONEYCOMB_BEEHIVE_CHURCH_ORGAN_LEFT_3, RCTYPE_HONEYCOMB, LEVEL_A_MAD_MONSTER_MANSION, RI_HONEYCOMB_MAD_MONSTER_MANSION, NULL, 0, 0, 0), - RC(RC_MMM_HONEYCOMB_BEEHIVE_CHURCH_ORGAN_RIGHT_1, RCTYPE_HONEYCOMB, LEVEL_A_MAD_MONSTER_MANSION, RI_HONEYCOMB_MAD_MONSTER_MANSION, NULL, 0, 0, 0), - RC(RC_MMM_HONEYCOMB_BEEHIVE_CHURCH_ORGAN_RIGHT_2, RCTYPE_HONEYCOMB, LEVEL_A_MAD_MONSTER_MANSION, RI_HONEYCOMB_MAD_MONSTER_MANSION, NULL, 0, 0, 0), - RC(RC_MMM_HONEYCOMB_BEEHIVE_CHURCH_ORGAN_RIGHT_3, RCTYPE_HONEYCOMB, LEVEL_A_MAD_MONSTER_MANSION, RI_HONEYCOMB_MAD_MONSTER_MANSION, NULL, 0, 0, 0), - RC(RC_MMM_HONEYCOMB_BEEHIVE_IN_THE_MAZE_1, RCTYPE_HONEYCOMB, LEVEL_A_MAD_MONSTER_MANSION, RI_HONEYCOMB_MAD_MONSTER_MANSION, NULL, 0, 0, 0), - RC(RC_MMM_HONEYCOMB_BEEHIVE_IN_THE_MAZE_2, RCTYPE_HONEYCOMB, LEVEL_A_MAD_MONSTER_MANSION, RI_HONEYCOMB_MAD_MONSTER_MANSION, NULL, 0, 0, 0), - RC(RC_MMM_HONEYCOMB_BEEHIVE_IN_THE_MAZE_3, RCTYPE_HONEYCOMB, LEVEL_A_MAD_MONSTER_MANSION, RI_HONEYCOMB_MAD_MONSTER_MANSION, NULL, 0, 0, 0), - RC(RC_MMM_HONEYCOMB_BEEHIVE_IN_THE_TALL_GRASS_1, RCTYPE_HONEYCOMB, LEVEL_A_MAD_MONSTER_MANSION, RI_HONEYCOMB_MAD_MONSTER_MANSION, NULL, 0, 0, 0), - RC(RC_MMM_HONEYCOMB_BEEHIVE_IN_THE_TALL_GRASS_2, RCTYPE_HONEYCOMB, LEVEL_A_MAD_MONSTER_MANSION, RI_HONEYCOMB_MAD_MONSTER_MANSION, NULL, 0, 0, 0), - RC(RC_MMM_HONEYCOMB_BEEHIVE_IN_THE_TALL_GRASS_3, RCTYPE_HONEYCOMB, LEVEL_A_MAD_MONSTER_MANSION, RI_HONEYCOMB_MAD_MONSTER_MANSION, NULL, 0, 0, 0), + RC(RC_MMM_EXTRA_LIFE_CHURCH_PIPES, RCTYPE_EXTRA_LIFE, LEVEL_A_MAD_MONSTER_MANSION, RI_EXTRA_LIFE, NULL, -1, 2263, -3465), + RC(RC_MMM_EXTRA_LIFE_CHURCH_WINDOW, RCTYPE_EXTRA_LIFE, LEVEL_A_MAD_MONSTER_MANSION, RI_EXTRA_LIFE, NULL, 0, 13, 6), + RC(RC_MMM_EXTRA_LIFE_DINING_ROOM_CHANDELIER, RCTYPE_EXTRA_LIFE, LEVEL_A_MAD_MONSTER_MANSION, RI_EXTRA_LIFE, NULL, 0, 1326, 145), + RC(RC_MMM_HONEYCOMB_BEEHIVE_CHURCH_ORGAN_LEFT_1, RCTYPE_HONEYCOMB, LEVEL_A_MAD_MONSTER_MANSION, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_MMM_HONEYCOMB_BEEHIVE_CHURCH_ORGAN_LEFT_2, RCTYPE_HONEYCOMB, LEVEL_A_MAD_MONSTER_MANSION, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_MMM_HONEYCOMB_BEEHIVE_CHURCH_ORGAN_LEFT_3, RCTYPE_HONEYCOMB, LEVEL_A_MAD_MONSTER_MANSION, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_MMM_HONEYCOMB_BEEHIVE_CHURCH_ORGAN_RIGHT_1, RCTYPE_HONEYCOMB, LEVEL_A_MAD_MONSTER_MANSION, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_MMM_HONEYCOMB_BEEHIVE_CHURCH_ORGAN_RIGHT_2, RCTYPE_HONEYCOMB, LEVEL_A_MAD_MONSTER_MANSION, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_MMM_HONEYCOMB_BEEHIVE_CHURCH_ORGAN_RIGHT_3, RCTYPE_HONEYCOMB, LEVEL_A_MAD_MONSTER_MANSION, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_MMM_HONEYCOMB_BEEHIVE_IN_THE_MAZE_1, RCTYPE_HONEYCOMB, LEVEL_A_MAD_MONSTER_MANSION, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_MMM_HONEYCOMB_BEEHIVE_IN_THE_MAZE_2, RCTYPE_HONEYCOMB, LEVEL_A_MAD_MONSTER_MANSION, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_MMM_HONEYCOMB_BEEHIVE_IN_THE_MAZE_3, RCTYPE_HONEYCOMB, LEVEL_A_MAD_MONSTER_MANSION, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_MMM_HONEYCOMB_BEEHIVE_IN_THE_TALL_GRASS_1, RCTYPE_HONEYCOMB, LEVEL_A_MAD_MONSTER_MANSION, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_MMM_HONEYCOMB_BEEHIVE_IN_THE_TALL_GRASS_2, RCTYPE_HONEYCOMB, LEVEL_A_MAD_MONSTER_MANSION, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_MMM_HONEYCOMB_BEEHIVE_IN_THE_TALL_GRASS_3, RCTYPE_HONEYCOMB, LEVEL_A_MAD_MONSTER_MANSION, RI_HONEYCOMB, NULL, 0, 0, 0), RC(RC_MMM_JIGGY_BARREL_INTERIOR, RCTYPE_JIGGY, LEVEL_A_MAD_MONSTER_MANSION, RI_JIGGY_MAD_MONSTER_MANSION, JIGGY_61_MMM_RAIN_BARREL, 2, 288, -4), RC(RC_MMM_JIGGY_CELLAR, RCTYPE_JIGGY, LEVEL_A_MAD_MONSTER_MANSION, RI_JIGGY_MAD_MONSTER_MANSION, JIGGY_5E_MMM_CELLAR, -516, 30, 477), RC(RC_MMM_JIGGY_CEMETARY_POTS, RCTYPE_JIGGY, LEVEL_A_MAD_MONSTER_MANSION, RI_JIGGY_MAD_MONSTER_MANSION, JIGGY_63_MMM_FLOWER_POTS, 0, 0, 0), @@ -1610,79 +1610,79 @@ std::map Checks = { RC(RC_MMM_NOTE_WELL_INTERIOR_7, RCTYPE_MUSIC_NOTE, LEVEL_A_MAD_MONSTER_MANSION, RI_MUSIC_NOTE_MAD_MONSTER_MANSION, NULL, 681, 0, 182), RC(RC_MMM_SNS_CYAN_EGG, RCTYPE_STOP_N_SWOP, LEVEL_A_MAD_MONSTER_MANSION, RI_STOP_N_SWOP_EGG_CYAN, SNS_ITEM_EGG_CYAN, 1995, 100, -476), RC(RC_MMM_SNS_GREEN_EGG, RCTYPE_STOP_N_SWOP, LEVEL_A_MAD_MONSTER_MANSION, RI_STOP_N_SWOP_EGG_GREEN, SNS_ITEM_EGG_GREEN, 517, 350, -241), - RC(RC_RBB_BLUE_EGG_ANCHOR_ROOM_1, RCTYPE_BLUE_EGG, LEVEL_9_RUSTY_BUCKET_BAY, RI_BLUE_EGG_RUSTY_BUCKET_BAY, NULL, -450, 0, -750), - RC(RC_RBB_BLUE_EGG_ANCHOR_ROOM_2, RCTYPE_BLUE_EGG, LEVEL_9_RUSTY_BUCKET_BAY, RI_BLUE_EGG_RUSTY_BUCKET_BAY, NULL, 450, 0, -751), - RC(RC_RBB_BLUE_EGG_ANCHOR_ROOM_3, RCTYPE_BLUE_EGG, LEVEL_9_RUSTY_BUCKET_BAY, RI_BLUE_EGG_RUSTY_BUCKET_BAY, NULL, 450, 0, 750), - RC(RC_RBB_BLUE_EGG_ANCHOR_ROOM_4, RCTYPE_BLUE_EGG, LEVEL_9_RUSTY_BUCKET_BAY, RI_BLUE_EGG_RUSTY_BUCKET_BAY, NULL, -450, 0, 750), - RC(RC_RBB_BLUE_EGG_BETWEEN_SHIPPING_CONTAINERS_1, RCTYPE_BLUE_EGG, LEVEL_9_RUSTY_BUCKET_BAY, RI_BLUE_EGG_RUSTY_BUCKET_BAY, NULL, -750, -800, -3651), - RC(RC_RBB_BLUE_EGG_BETWEEN_SHIPPING_CONTAINERS_2, RCTYPE_BLUE_EGG, LEVEL_9_RUSTY_BUCKET_BAY, RI_BLUE_EGG_RUSTY_BUCKET_BAY, NULL, -750, -800, -3726), - RC(RC_RBB_BLUE_EGG_BETWEEN_SHIPPING_CONTAINERS_3, RCTYPE_BLUE_EGG, LEVEL_9_RUSTY_BUCKET_BAY, RI_BLUE_EGG_RUSTY_BUCKET_BAY, NULL, -50, -800, -3651), - RC(RC_RBB_BLUE_EGG_BETWEEN_SHIPPING_CONTAINERS_4, RCTYPE_BLUE_EGG, LEVEL_9_RUSTY_BUCKET_BAY, RI_BLUE_EGG_RUSTY_BUCKET_BAY, NULL, -49, -800, -3726), - RC(RC_RBB_BLUE_EGG_ENGING_ROOM_1, RCTYPE_BLUE_EGG, LEVEL_9_RUSTY_BUCKET_BAY, RI_BLUE_EGG_RUSTY_BUCKET_BAY, NULL, -2550, 1059, -3001), - RC(RC_RBB_BLUE_EGG_ENGING_ROOM_2, RCTYPE_BLUE_EGG, LEVEL_9_RUSTY_BUCKET_BAY, RI_BLUE_EGG_RUSTY_BUCKET_BAY, NULL, -2550, 1059, -2300), - RC(RC_RBB_BLUE_EGG_ENGING_ROOM_3, RCTYPE_BLUE_EGG, LEVEL_9_RUSTY_BUCKET_BAY, RI_BLUE_EGG_RUSTY_BUCKET_BAY, NULL, -2550, 1059, -2475), - RC(RC_RBB_BLUE_EGG_ENGING_ROOM_4, RCTYPE_BLUE_EGG, LEVEL_9_RUSTY_BUCKET_BAY, RI_BLUE_EGG_RUSTY_BUCKET_BAY, NULL, -2550, 1059, -2825), - RC(RC_RRB_BLUE_EGG_ENTRANCE_1, RCTYPE_BLUE_EGG, LEVEL_9_RUSTY_BUCKET_BAY, RI_BLUE_EGG_RUSTY_BUCKET_BAY, NULL, -550, -650, 3549), - RC(RC_RRB_BLUE_EGG_ENTRANCE_2, RCTYPE_BLUE_EGG, LEVEL_9_RUSTY_BUCKET_BAY, RI_BLUE_EGG_RUSTY_BUCKET_BAY, NULL, -1200, -450, 3899), - RC(RC_RRB_BLUE_EGG_ENTRANCE_3, RCTYPE_BLUE_EGG, LEVEL_9_RUSTY_BUCKET_BAY, RI_BLUE_EGG_RUSTY_BUCKET_BAY, NULL, -1750, -650, 3300), - RC(RC_RRB_BLUE_EGG_ENTRANCE_4, RCTYPE_BLUE_EGG, LEVEL_9_RUSTY_BUCKET_BAY, RI_BLUE_EGG_RUSTY_BUCKET_BAY, NULL, 1549, -500, 3250), - RC(RC_RRB_BLUE_EGG_ENTRANCE_5, RCTYPE_BLUE_EGG, LEVEL_9_RUSTY_BUCKET_BAY, RI_BLUE_EGG_RUSTY_BUCKET_BAY, NULL, 1900, -200, 3800), - RC(RC_RBB_BLUE_EGG_KITCHEN_1, RCTYPE_BLUE_EGG, LEVEL_9_RUSTY_BUCKET_BAY, RI_BLUE_EGG_RUSTY_BUCKET_BAY, NULL, 702, 213, -596), - RC(RC_RBB_BLUE_EGG_KITCHEN_2, RCTYPE_BLUE_EGG, LEVEL_9_RUSTY_BUCKET_BAY, RI_BLUE_EGG_RUSTY_BUCKET_BAY, NULL, 758, 213, -600), - RC(RC_RBB_BLUE_EGG_KITCHEN_3, RCTYPE_BLUE_EGG, LEVEL_9_RUSTY_BUCKET_BAY, RI_BLUE_EGG_RUSTY_BUCKET_BAY, NULL, 647, 213, -601), - RC(RC_RBB_BLUE_EGG_KITCHEN_4, RCTYPE_BLUE_EGG, LEVEL_9_RUSTY_BUCKET_BAY, RI_BLUE_EGG_RUSTY_BUCKET_BAY, NULL, 645, 213, -501), - RC(RC_RBB_BLUE_EGG_KITCHEN_5, RCTYPE_BLUE_EGG, LEVEL_9_RUSTY_BUCKET_BAY, RI_BLUE_EGG_RUSTY_BUCKET_BAY, NULL, 705, 213, -503), - RC(RC_RBB_BLUE_EGG_KITCHEN_6, RCTYPE_BLUE_EGG, LEVEL_9_RUSTY_BUCKET_BAY, RI_BLUE_EGG_RUSTY_BUCKET_BAY, NULL, 758, 213, -503), - RC(RC_RBB_BLUE_EGG_KITCHEN_7, RCTYPE_BLUE_EGG, LEVEL_9_RUSTY_BUCKET_BAY, RI_BLUE_EGG_RUSTY_BUCKET_BAY, NULL, 760, 213, -408), - RC(RC_RBB_BLUE_EGG_KITCHEN_8, RCTYPE_BLUE_EGG, LEVEL_9_RUSTY_BUCKET_BAY, RI_BLUE_EGG_RUSTY_BUCKET_BAY, NULL, 700, 213, -407), - RC(RC_RBB_BLUE_EGG_KITCHEN_9, RCTYPE_BLUE_EGG, LEVEL_9_RUSTY_BUCKET_BAY, RI_BLUE_EGG_RUSTY_BUCKET_BAY, NULL, 646, 213, -404), - RC(RC_RBB_BLUE_EGG_NAVIGATION_ROOM_1, RCTYPE_BLUE_EGG, LEVEL_9_RUSTY_BUCKET_BAY, RI_BLUE_EGG_RUSTY_BUCKET_BAY, NULL, -740, 340, 590), - RC(RC_RBB_BLUE_EGG_NAVIGATION_ROOM_2, RCTYPE_BLUE_EGG, LEVEL_9_RUSTY_BUCKET_BAY, RI_BLUE_EGG_RUSTY_BUCKET_BAY, NULL, -740, 340, 409), - RC(RC_RBB_BLUE_EGG_NAVIGATION_ROOM_3, RCTYPE_BLUE_EGG, LEVEL_9_RUSTY_BUCKET_BAY, RI_BLUE_EGG_RUSTY_BUCKET_BAY, NULL, -740, 340, 230), - RC(RC_RBB_BLUE_EGG_NAVIGATION_ROOM_4, RCTYPE_BLUE_EGG, LEVEL_9_RUSTY_BUCKET_BAY, RI_BLUE_EGG_RUSTY_BUCKET_BAY, NULL, -740, 340, 50), - RC(RC_RBB_BLUE_EGG_NEAR_PINK_JINJO_1, RCTYPE_BLUE_EGG, LEVEL_9_RUSTY_BUCKET_BAY, RI_BLUE_EGG_RUSTY_BUCKET_BAY, NULL, 8726, -2613, 3075), - RC(RC_RBB_BLUE_EGG_NEAR_PINK_JINJO_2, RCTYPE_BLUE_EGG, LEVEL_9_RUSTY_BUCKET_BAY, RI_BLUE_EGG_RUSTY_BUCKET_BAY, NULL, 8726, -2613, 3550), - RC(RC_RBB_BLUE_EGG_NEAR_PINK_JINJO_3, RCTYPE_BLUE_EGG, LEVEL_9_RUSTY_BUCKET_BAY, RI_BLUE_EGG_RUSTY_BUCKET_BAY, NULL, 8726, -2613, 4025), - RC(RC_RBB_BLUE_EGG_NEAR_PINK_JINJO_4, RCTYPE_BLUE_EGG, LEVEL_9_RUSTY_BUCKET_BAY, RI_BLUE_EGG_RUSTY_BUCKET_BAY, NULL, 6976, -2613, 3075), - RC(RC_RBB_BLUE_EGG_NEAR_PINK_JINJO_5, RCTYPE_BLUE_EGG, LEVEL_9_RUSTY_BUCKET_BAY, RI_BLUE_EGG_RUSTY_BUCKET_BAY, NULL, 6976, -2613, 3550), - RC(RC_RBB_BLUE_EGG_NEAR_PINK_JINJO_6, RCTYPE_BLUE_EGG, LEVEL_9_RUSTY_BUCKET_BAY, RI_BLUE_EGG_RUSTY_BUCKET_BAY, NULL, 6975, -2613, 4025), - RC(RC_RBB_BLUE_EGG_ON_LIFE_BOAT_1, RCTYPE_BLUE_EGG, LEVEL_9_RUSTY_BUCKET_BAY, RI_BLUE_EGG_RUSTY_BUCKET_BAY, NULL, -3721, -185, -1677), - RC(RC_RBB_BLUE_EGG_ON_LIFE_BOAT_2, RCTYPE_BLUE_EGG, LEVEL_9_RUSTY_BUCKET_BAY, RI_BLUE_EGG_RUSTY_BUCKET_BAY, NULL, -3953, -185, -1677), - RC(RC_RBB_BLUE_EGG_ON_LIFE_BOAT_3, RCTYPE_BLUE_EGG, LEVEL_9_RUSTY_BUCKET_BAY, RI_BLUE_EGG_RUSTY_BUCKET_BAY, NULL, -4185, -185, -1678), - RC(RC_RBB_BLUE_EGG_SHIPPING_CONTAINER_INTERIOR_THIRD_1, RCTYPE_BLUE_EGG, LEVEL_9_RUSTY_BUCKET_BAY, RI_BLUE_EGG_RUSTY_BUCKET_BAY, NULL, -651, 140, -959), - RC(RC_RBB_BLUE_EGG_SHIPPING_CONTAINER_INTERIOR_THIRD_2, RCTYPE_BLUE_EGG, LEVEL_9_RUSTY_BUCKET_BAY, RI_BLUE_EGG_RUSTY_BUCKET_BAY, NULL, -651, 140, -1064), - RC(RC_RBB_BLUE_EGG_SHIPPING_CONTAINER_INTERIOR_THIRD_3, RCTYPE_BLUE_EGG, LEVEL_9_RUSTY_BUCKET_BAY, RI_BLUE_EGG_RUSTY_BUCKET_BAY, NULL, -520, 140, -1064), - RC(RC_RBB_BLUE_EGG_SHIPPING_CONTAINER_INTERIOR_THIRD_4, RCTYPE_BLUE_EGG, LEVEL_9_RUSTY_BUCKET_BAY, RI_BLUE_EGG_RUSTY_BUCKET_BAY, NULL, -390, 140, -1064), - RC(RC_RBB_BLUE_EGG_SHIPPING_CONTAINER_INTERIOR_THIRD_5, RCTYPE_BLUE_EGG, LEVEL_9_RUSTY_BUCKET_BAY, RI_BLUE_EGG_RUSTY_BUCKET_BAY, NULL, -389, 140, -959), - RC(RC_RBB_BLUE_EGG_SHIPPING_CONTAINER_INTERIOR_THIRD_6, RCTYPE_BLUE_EGG, LEVEL_9_RUSTY_BUCKET_BAY, RI_BLUE_EGG_RUSTY_BUCKET_BAY, NULL, -520, 140, -959), - RC(RC_RBB_BLUE_EGG_TNT_ROOM_1, RCTYPE_BLUE_EGG, LEVEL_9_RUSTY_BUCKET_BAY, RI_BLUE_EGG_RUSTY_BUCKET_BAY, NULL, -400, 400, 450), - RC(RC_RBB_BLUE_EGG_TNT_ROOM_2, RCTYPE_BLUE_EGG, LEVEL_9_RUSTY_BUCKET_BAY, RI_BLUE_EGG_RUSTY_BUCKET_BAY, NULL, -400, 400, 324), - RC(RC_RBB_BLUE_EGG_TNT_ROOM_3, RCTYPE_BLUE_EGG, LEVEL_9_RUSTY_BUCKET_BAY, RI_BLUE_EGG_RUSTY_BUCKET_BAY, NULL, -400, 400, 199), - RC(RC_RBB_BLUE_EGG_TNT_ROOM_4, RCTYPE_BLUE_EGG, LEVEL_9_RUSTY_BUCKET_BAY, RI_BLUE_EGG_RUSTY_BUCKET_BAY, NULL, -399, 400, 74), - RC(RC_RBB_BLUE_EGG_TNT_ROOM_5, RCTYPE_BLUE_EGG, LEVEL_9_RUSTY_BUCKET_BAY, RI_BLUE_EGG_RUSTY_BUCKET_BAY, NULL, -400, 400, -49), - RC(RC_RBB_BLUE_EGG_TOP_OF_SHIP_1, RCTYPE_BLUE_EGG, LEVEL_9_RUSTY_BUCKET_BAY, RI_BLUE_EGG_RUSTY_BUCKET_BAY, NULL, 4500, -250, -1150), - RC(RC_RBB_BLUE_EGG_TOP_OF_SHIP_2, RCTYPE_BLUE_EGG, LEVEL_9_RUSTY_BUCKET_BAY, RI_BLUE_EGG_RUSTY_BUCKET_BAY, NULL, 5050, 50, -1050), - RC(RC_RBB_BLUE_EGG_TOP_OF_SHIP_3, RCTYPE_BLUE_EGG, LEVEL_9_RUSTY_BUCKET_BAY, RI_BLUE_EGG_RUSTY_BUCKET_BAY, NULL, 4100, -250, 1150), - RC(RC_RBB_BLUE_EGG_TOP_OF_SHIP_4, RCTYPE_BLUE_EGG, LEVEL_9_RUSTY_BUCKET_BAY, RI_BLUE_EGG_RUSTY_BUCKET_BAY, NULL, 4650, 150, 1050), - RC(RC_RBB_BLUE_EGG_WAREHOUSE_INTERIOR_1, RCTYPE_BLUE_EGG, LEVEL_9_RUSTY_BUCKET_BAY, RI_BLUE_EGG_RUSTY_BUCKET_BAY, NULL, -726, 575, 125), - RC(RC_RBB_BLUE_EGG_WAREHOUSE_INTERIOR_2, RCTYPE_BLUE_EGG, LEVEL_9_RUSTY_BUCKET_BAY, RI_BLUE_EGG_RUSTY_BUCKET_BAY, NULL, -537, 575, 125), - RC(RC_RBB_BLUE_EGG_WAREHOUSE_INTERIOR_3, RCTYPE_BLUE_EGG, LEVEL_9_RUSTY_BUCKET_BAY, RI_BLUE_EGG_RUSTY_BUCKET_BAY, NULL, -350, 575, 125), - RC(RC_RBB_BLUE_EGG_WAREHOUSE_INTERIOR_4, RCTYPE_BLUE_EGG, LEVEL_9_RUSTY_BUCKET_BAY, RI_BLUE_EGG_RUSTY_BUCKET_BAY, NULL, -163, 575, 125), - RC(RC_RBB_BLUE_EGG_WAREHOUSE_INTERIOR_5, RCTYPE_BLUE_EGG, LEVEL_9_RUSTY_BUCKET_BAY, RI_BLUE_EGG_RUSTY_BUCKET_BAY, NULL, 25, 575, 124), + RC(RC_RBB_BLUE_EGG_ANCHOR_ROOM_1, RCTYPE_BLUE_EGG, LEVEL_9_RUSTY_BUCKET_BAY, RI_BLUE_EGG, NULL, -450, 0, -750), + RC(RC_RBB_BLUE_EGG_ANCHOR_ROOM_2, RCTYPE_BLUE_EGG, LEVEL_9_RUSTY_BUCKET_BAY, RI_BLUE_EGG, NULL, 450, 0, -751), + RC(RC_RBB_BLUE_EGG_ANCHOR_ROOM_3, RCTYPE_BLUE_EGG, LEVEL_9_RUSTY_BUCKET_BAY, RI_BLUE_EGG, NULL, 450, 0, 750), + RC(RC_RBB_BLUE_EGG_ANCHOR_ROOM_4, RCTYPE_BLUE_EGG, LEVEL_9_RUSTY_BUCKET_BAY, RI_BLUE_EGG, NULL, -450, 0, 750), + RC(RC_RBB_BLUE_EGG_BETWEEN_SHIPPING_CONTAINERS_1, RCTYPE_BLUE_EGG, LEVEL_9_RUSTY_BUCKET_BAY, RI_BLUE_EGG, NULL, -750, -800, -3651), + RC(RC_RBB_BLUE_EGG_BETWEEN_SHIPPING_CONTAINERS_2, RCTYPE_BLUE_EGG, LEVEL_9_RUSTY_BUCKET_BAY, RI_BLUE_EGG, NULL, -750, -800, -3726), + RC(RC_RBB_BLUE_EGG_BETWEEN_SHIPPING_CONTAINERS_3, RCTYPE_BLUE_EGG, LEVEL_9_RUSTY_BUCKET_BAY, RI_BLUE_EGG, NULL, -50, -800, -3651), + RC(RC_RBB_BLUE_EGG_BETWEEN_SHIPPING_CONTAINERS_4, RCTYPE_BLUE_EGG, LEVEL_9_RUSTY_BUCKET_BAY, RI_BLUE_EGG, NULL, -49, -800, -3726), + RC(RC_RBB_BLUE_EGG_ENGING_ROOM_1, RCTYPE_BLUE_EGG, LEVEL_9_RUSTY_BUCKET_BAY, RI_BLUE_EGG, NULL, -2550, 1059, -3001), + RC(RC_RBB_BLUE_EGG_ENGING_ROOM_2, RCTYPE_BLUE_EGG, LEVEL_9_RUSTY_BUCKET_BAY, RI_BLUE_EGG, NULL, -2550, 1059, -2300), + RC(RC_RBB_BLUE_EGG_ENGING_ROOM_3, RCTYPE_BLUE_EGG, LEVEL_9_RUSTY_BUCKET_BAY, RI_BLUE_EGG, NULL, -2550, 1059, -2475), + RC(RC_RBB_BLUE_EGG_ENGING_ROOM_4, RCTYPE_BLUE_EGG, LEVEL_9_RUSTY_BUCKET_BAY, RI_BLUE_EGG, NULL, -2550, 1059, -2825), + RC(RC_RRB_BLUE_EGG_ENTRANCE_1, RCTYPE_BLUE_EGG, LEVEL_9_RUSTY_BUCKET_BAY, RI_BLUE_EGG, NULL, -550, -650, 3549), + RC(RC_RRB_BLUE_EGG_ENTRANCE_2, RCTYPE_BLUE_EGG, LEVEL_9_RUSTY_BUCKET_BAY, RI_BLUE_EGG, NULL, -1200, -450, 3899), + RC(RC_RRB_BLUE_EGG_ENTRANCE_3, RCTYPE_BLUE_EGG, LEVEL_9_RUSTY_BUCKET_BAY, RI_BLUE_EGG, NULL, -1750, -650, 3300), + RC(RC_RRB_BLUE_EGG_ENTRANCE_4, RCTYPE_BLUE_EGG, LEVEL_9_RUSTY_BUCKET_BAY, RI_BLUE_EGG, NULL, 1549, -500, 3250), + RC(RC_RRB_BLUE_EGG_ENTRANCE_5, RCTYPE_BLUE_EGG, LEVEL_9_RUSTY_BUCKET_BAY, RI_BLUE_EGG, NULL, 1900, -200, 3800), + RC(RC_RBB_BLUE_EGG_KITCHEN_1, RCTYPE_BLUE_EGG, LEVEL_9_RUSTY_BUCKET_BAY, RI_BLUE_EGG, NULL, 702, 213, -596), + RC(RC_RBB_BLUE_EGG_KITCHEN_2, RCTYPE_BLUE_EGG, LEVEL_9_RUSTY_BUCKET_BAY, RI_BLUE_EGG, NULL, 758, 213, -600), + RC(RC_RBB_BLUE_EGG_KITCHEN_3, RCTYPE_BLUE_EGG, LEVEL_9_RUSTY_BUCKET_BAY, RI_BLUE_EGG, NULL, 647, 213, -601), + RC(RC_RBB_BLUE_EGG_KITCHEN_4, RCTYPE_BLUE_EGG, LEVEL_9_RUSTY_BUCKET_BAY, RI_BLUE_EGG, NULL, 645, 213, -501), + RC(RC_RBB_BLUE_EGG_KITCHEN_5, RCTYPE_BLUE_EGG, LEVEL_9_RUSTY_BUCKET_BAY, RI_BLUE_EGG, NULL, 705, 213, -503), + RC(RC_RBB_BLUE_EGG_KITCHEN_6, RCTYPE_BLUE_EGG, LEVEL_9_RUSTY_BUCKET_BAY, RI_BLUE_EGG, NULL, 758, 213, -503), + RC(RC_RBB_BLUE_EGG_KITCHEN_7, RCTYPE_BLUE_EGG, LEVEL_9_RUSTY_BUCKET_BAY, RI_BLUE_EGG, NULL, 760, 213, -408), + RC(RC_RBB_BLUE_EGG_KITCHEN_8, RCTYPE_BLUE_EGG, LEVEL_9_RUSTY_BUCKET_BAY, RI_BLUE_EGG, NULL, 700, 213, -407), + RC(RC_RBB_BLUE_EGG_KITCHEN_9, RCTYPE_BLUE_EGG, LEVEL_9_RUSTY_BUCKET_BAY, RI_BLUE_EGG, NULL, 646, 213, -404), + RC(RC_RBB_BLUE_EGG_NAVIGATION_ROOM_1, RCTYPE_BLUE_EGG, LEVEL_9_RUSTY_BUCKET_BAY, RI_BLUE_EGG, NULL, -740, 340, 590), + RC(RC_RBB_BLUE_EGG_NAVIGATION_ROOM_2, RCTYPE_BLUE_EGG, LEVEL_9_RUSTY_BUCKET_BAY, RI_BLUE_EGG, NULL, -740, 340, 409), + RC(RC_RBB_BLUE_EGG_NAVIGATION_ROOM_3, RCTYPE_BLUE_EGG, LEVEL_9_RUSTY_BUCKET_BAY, RI_BLUE_EGG, NULL, -740, 340, 230), + RC(RC_RBB_BLUE_EGG_NAVIGATION_ROOM_4, RCTYPE_BLUE_EGG, LEVEL_9_RUSTY_BUCKET_BAY, RI_BLUE_EGG, NULL, -740, 340, 50), + RC(RC_RBB_BLUE_EGG_NEAR_PINK_JINJO_1, RCTYPE_BLUE_EGG, LEVEL_9_RUSTY_BUCKET_BAY, RI_BLUE_EGG, NULL, 8726, -2613, 3075), + RC(RC_RBB_BLUE_EGG_NEAR_PINK_JINJO_2, RCTYPE_BLUE_EGG, LEVEL_9_RUSTY_BUCKET_BAY, RI_BLUE_EGG, NULL, 8726, -2613, 3550), + RC(RC_RBB_BLUE_EGG_NEAR_PINK_JINJO_3, RCTYPE_BLUE_EGG, LEVEL_9_RUSTY_BUCKET_BAY, RI_BLUE_EGG, NULL, 8726, -2613, 4025), + RC(RC_RBB_BLUE_EGG_NEAR_PINK_JINJO_4, RCTYPE_BLUE_EGG, LEVEL_9_RUSTY_BUCKET_BAY, RI_BLUE_EGG, NULL, 6976, -2613, 3075), + RC(RC_RBB_BLUE_EGG_NEAR_PINK_JINJO_5, RCTYPE_BLUE_EGG, LEVEL_9_RUSTY_BUCKET_BAY, RI_BLUE_EGG, NULL, 6976, -2613, 3550), + RC(RC_RBB_BLUE_EGG_NEAR_PINK_JINJO_6, RCTYPE_BLUE_EGG, LEVEL_9_RUSTY_BUCKET_BAY, RI_BLUE_EGG, NULL, 6975, -2613, 4025), + RC(RC_RBB_BLUE_EGG_ON_LIFE_BOAT_1, RCTYPE_BLUE_EGG, LEVEL_9_RUSTY_BUCKET_BAY, RI_BLUE_EGG, NULL, -3721, -185, -1677), + RC(RC_RBB_BLUE_EGG_ON_LIFE_BOAT_2, RCTYPE_BLUE_EGG, LEVEL_9_RUSTY_BUCKET_BAY, RI_BLUE_EGG, NULL, -3953, -185, -1677), + RC(RC_RBB_BLUE_EGG_ON_LIFE_BOAT_3, RCTYPE_BLUE_EGG, LEVEL_9_RUSTY_BUCKET_BAY, RI_BLUE_EGG, NULL, -4185, -185, -1678), + RC(RC_RBB_BLUE_EGG_SHIPPING_CONTAINER_INTERIOR_THIRD_1, RCTYPE_BLUE_EGG, LEVEL_9_RUSTY_BUCKET_BAY, RI_BLUE_EGG, NULL, -651, 140, -959), + RC(RC_RBB_BLUE_EGG_SHIPPING_CONTAINER_INTERIOR_THIRD_2, RCTYPE_BLUE_EGG, LEVEL_9_RUSTY_BUCKET_BAY, RI_BLUE_EGG, NULL, -651, 140, -1064), + RC(RC_RBB_BLUE_EGG_SHIPPING_CONTAINER_INTERIOR_THIRD_3, RCTYPE_BLUE_EGG, LEVEL_9_RUSTY_BUCKET_BAY, RI_BLUE_EGG, NULL, -520, 140, -1064), + RC(RC_RBB_BLUE_EGG_SHIPPING_CONTAINER_INTERIOR_THIRD_4, RCTYPE_BLUE_EGG, LEVEL_9_RUSTY_BUCKET_BAY, RI_BLUE_EGG, NULL, -390, 140, -1064), + RC(RC_RBB_BLUE_EGG_SHIPPING_CONTAINER_INTERIOR_THIRD_5, RCTYPE_BLUE_EGG, LEVEL_9_RUSTY_BUCKET_BAY, RI_BLUE_EGG, NULL, -389, 140, -959), + RC(RC_RBB_BLUE_EGG_SHIPPING_CONTAINER_INTERIOR_THIRD_6, RCTYPE_BLUE_EGG, LEVEL_9_RUSTY_BUCKET_BAY, RI_BLUE_EGG, NULL, -520, 140, -959), + RC(RC_RBB_BLUE_EGG_TNT_ROOM_1, RCTYPE_BLUE_EGG, LEVEL_9_RUSTY_BUCKET_BAY, RI_BLUE_EGG, NULL, -400, 400, 450), + RC(RC_RBB_BLUE_EGG_TNT_ROOM_2, RCTYPE_BLUE_EGG, LEVEL_9_RUSTY_BUCKET_BAY, RI_BLUE_EGG, NULL, -400, 400, 324), + RC(RC_RBB_BLUE_EGG_TNT_ROOM_3, RCTYPE_BLUE_EGG, LEVEL_9_RUSTY_BUCKET_BAY, RI_BLUE_EGG, NULL, -400, 400, 199), + RC(RC_RBB_BLUE_EGG_TNT_ROOM_4, RCTYPE_BLUE_EGG, LEVEL_9_RUSTY_BUCKET_BAY, RI_BLUE_EGG, NULL, -399, 400, 74), + RC(RC_RBB_BLUE_EGG_TNT_ROOM_5, RCTYPE_BLUE_EGG, LEVEL_9_RUSTY_BUCKET_BAY, RI_BLUE_EGG, NULL, -400, 400, -49), + RC(RC_RBB_BLUE_EGG_TOP_OF_SHIP_1, RCTYPE_BLUE_EGG, LEVEL_9_RUSTY_BUCKET_BAY, RI_BLUE_EGG, NULL, 4500, -250, -1150), + RC(RC_RBB_BLUE_EGG_TOP_OF_SHIP_2, RCTYPE_BLUE_EGG, LEVEL_9_RUSTY_BUCKET_BAY, RI_BLUE_EGG, NULL, 5050, 50, -1050), + RC(RC_RBB_BLUE_EGG_TOP_OF_SHIP_3, RCTYPE_BLUE_EGG, LEVEL_9_RUSTY_BUCKET_BAY, RI_BLUE_EGG, NULL, 4100, -250, 1150), + RC(RC_RBB_BLUE_EGG_TOP_OF_SHIP_4, RCTYPE_BLUE_EGG, LEVEL_9_RUSTY_BUCKET_BAY, RI_BLUE_EGG, NULL, 4650, 150, 1050), + RC(RC_RBB_BLUE_EGG_WAREHOUSE_INTERIOR_1, RCTYPE_BLUE_EGG, LEVEL_9_RUSTY_BUCKET_BAY, RI_BLUE_EGG, NULL, -726, 575, 125), + RC(RC_RBB_BLUE_EGG_WAREHOUSE_INTERIOR_2, RCTYPE_BLUE_EGG, LEVEL_9_RUSTY_BUCKET_BAY, RI_BLUE_EGG, NULL, -537, 575, 125), + RC(RC_RBB_BLUE_EGG_WAREHOUSE_INTERIOR_3, RCTYPE_BLUE_EGG, LEVEL_9_RUSTY_BUCKET_BAY, RI_BLUE_EGG, NULL, -350, 575, 125), + RC(RC_RBB_BLUE_EGG_WAREHOUSE_INTERIOR_4, RCTYPE_BLUE_EGG, LEVEL_9_RUSTY_BUCKET_BAY, RI_BLUE_EGG, NULL, -163, 575, 125), + RC(RC_RBB_BLUE_EGG_WAREHOUSE_INTERIOR_5, RCTYPE_BLUE_EGG, LEVEL_9_RUSTY_BUCKET_BAY, RI_BLUE_EGG, NULL, 25, 575, 124), RC(RC_RBB_EMPTY_HONEYCOMB_BOAT_HOUSE, RCTYPE_EMPTY_HONEYCOMB, LEVEL_9_RUSTY_BUCKET_BAY, RI_EMPTY_HONEYCOMB_RUSTY_BUCKET_BAY, HONEYCOMB_F_RBB_BOAT_HOUSE, 0, 1000, 0), RC(RC_RBB_EMPTY_HONEYCOMB_ENGINE_ROOM, RCTYPE_EMPTY_HONEYCOMB, LEVEL_9_RUSTY_BUCKET_BAY, RI_EMPTY_HONEYCOMB_RUSTY_BUCKET_BAY, HONEYCOMB_10_RBB_ENGINE_ROOM, 0, 360, 3541), - RC(RC_RBB_EXTRA_LIFE_BOOM_BOXES, RCTYPE_EXTRA_LIFE, LEVEL_9_RUSTY_BUCKET_BAY, RI_EXTRA_LIFE_RUSTY_BUCKET_BAY, NULL, -626, 140, -351), - RC(RC_RBB_EXTRA_LIFE_ENGINE_ROOM, RCTYPE_EXTRA_LIFE, LEVEL_9_RUSTY_BUCKET_BAY, RI_EXTRA_LIFE_RUSTY_BUCKET_BAY, NULL, -2551, 1065, -2650), - RC(RC_RBB_EXTRA_LIFE_WAREHOUSE, RCTYPE_EXTRA_LIFE, LEVEL_9_RUSTY_BUCKET_BAY, RI_EXTRA_LIFE_RUSTY_BUCKET_BAY, NULL, -950, 1045, -50), - RC(RC_RBB_HONEYCOMB_BEEHIVE_ENGINE_ROOM_ENTRANCE_1, RCTYPE_HONEYCOMB, LEVEL_9_RUSTY_BUCKET_BAY, RI_HONEYCOMB_RUSTY_BUCKET_BAY, NULL, 0, 0, 0), - RC(RC_RBB_HONEYCOMB_BEEHIVE_ENGINE_ROOM_ENTRANCE_2, RCTYPE_HONEYCOMB, LEVEL_9_RUSTY_BUCKET_BAY, RI_HONEYCOMB_RUSTY_BUCKET_BAY, NULL, 0, 0, 0), - RC(RC_RBB_HONEYCOMB_BEEHIVE_ENGINE_ROOM_ENTRANCE_3, RCTYPE_HONEYCOMB, LEVEL_9_RUSTY_BUCKET_BAY, RI_HONEYCOMB_RUSTY_BUCKET_BAY, NULL, 0, 0, 0), - RC(RC_RBB_HONEYCOMB_BEEHIVE_FIRST_SHIPPING_CONTAINER_1, RCTYPE_HONEYCOMB, LEVEL_9_RUSTY_BUCKET_BAY, RI_HONEYCOMB_RUSTY_BUCKET_BAY, NULL, 0, 0, 0), - RC(RC_RBB_HONEYCOMB_BEEHIVE_FIRST_SHIPPING_CONTAINER_2, RCTYPE_HONEYCOMB, LEVEL_9_RUSTY_BUCKET_BAY, RI_HONEYCOMB_RUSTY_BUCKET_BAY, NULL, 0, 0, 0), - RC(RC_RBB_HONEYCOMB_BEEHIVE_FIRST_SHIPPING_CONTAINER_3, RCTYPE_HONEYCOMB, LEVEL_9_RUSTY_BUCKET_BAY, RI_HONEYCOMB_RUSTY_BUCKET_BAY, NULL, 0, 0, 0), - RC(RC_RBB_HONEYCOMB_BEEHIVE_GRATE_ABOVE_PINK_JINJO_1, RCTYPE_HONEYCOMB, LEVEL_9_RUSTY_BUCKET_BAY, RI_HONEYCOMB_RUSTY_BUCKET_BAY, NULL, 0, 0, 0), - RC(RC_RBB_HONEYCOMB_BEEHIVE_GRATE_ABOVE_PINK_JINJO_2, RCTYPE_HONEYCOMB, LEVEL_9_RUSTY_BUCKET_BAY, RI_HONEYCOMB_RUSTY_BUCKET_BAY, NULL, 0, 0, 0), - RC(RC_RBB_HONEYCOMB_BEEHIVE_GRATE_ABOVE_PINK_JINJO_3, RCTYPE_HONEYCOMB, LEVEL_9_RUSTY_BUCKET_BAY, RI_HONEYCOMB_RUSTY_BUCKET_BAY, NULL, 0, 0, 0), + RC(RC_RBB_EXTRA_LIFE_BOOM_BOXES, RCTYPE_EXTRA_LIFE, LEVEL_9_RUSTY_BUCKET_BAY, RI_EXTRA_LIFE, NULL, -626, 140, -351), + RC(RC_RBB_EXTRA_LIFE_ENGINE_ROOM, RCTYPE_EXTRA_LIFE, LEVEL_9_RUSTY_BUCKET_BAY, RI_EXTRA_LIFE, NULL, -2551, 1065, -2650), + RC(RC_RBB_EXTRA_LIFE_WAREHOUSE, RCTYPE_EXTRA_LIFE, LEVEL_9_RUSTY_BUCKET_BAY, RI_EXTRA_LIFE, NULL, -950, 1045, -50), + RC(RC_RBB_HONEYCOMB_BEEHIVE_ENGINE_ROOM_ENTRANCE_1, RCTYPE_HONEYCOMB, LEVEL_9_RUSTY_BUCKET_BAY, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_RBB_HONEYCOMB_BEEHIVE_ENGINE_ROOM_ENTRANCE_2, RCTYPE_HONEYCOMB, LEVEL_9_RUSTY_BUCKET_BAY, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_RBB_HONEYCOMB_BEEHIVE_ENGINE_ROOM_ENTRANCE_3, RCTYPE_HONEYCOMB, LEVEL_9_RUSTY_BUCKET_BAY, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_RBB_HONEYCOMB_BEEHIVE_FIRST_SHIPPING_CONTAINER_1, RCTYPE_HONEYCOMB, LEVEL_9_RUSTY_BUCKET_BAY, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_RBB_HONEYCOMB_BEEHIVE_FIRST_SHIPPING_CONTAINER_2, RCTYPE_HONEYCOMB, LEVEL_9_RUSTY_BUCKET_BAY, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_RBB_HONEYCOMB_BEEHIVE_FIRST_SHIPPING_CONTAINER_3, RCTYPE_HONEYCOMB, LEVEL_9_RUSTY_BUCKET_BAY, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_RBB_HONEYCOMB_BEEHIVE_GRATE_ABOVE_PINK_JINJO_1, RCTYPE_HONEYCOMB, LEVEL_9_RUSTY_BUCKET_BAY, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_RBB_HONEYCOMB_BEEHIVE_GRATE_ABOVE_PINK_JINJO_2, RCTYPE_HONEYCOMB, LEVEL_9_RUSTY_BUCKET_BAY, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_RBB_HONEYCOMB_BEEHIVE_GRATE_ABOVE_PINK_JINJO_3, RCTYPE_HONEYCOMB, LEVEL_9_RUSTY_BUCKET_BAY, RI_HONEYCOMB, NULL, 0, 0, 0), RC(RC_RBB_JIGGY_BOSS_BOOM_BOX, RCTYPE_JIGGY, LEVEL_9_RUSTY_BUCKET_BAY, RI_JIGGY_RUSTY_BUCKET_BAY, JIGGY_56_RBB_BOSS_BOOM_BOX, 0, 0, 0), RC(RC_RBB_JIGGY_CAPTAINS_CABIN, RCTYPE_JIGGY, LEVEL_9_RUSTY_BUCKET_BAY, RI_JIGGY_RUSTY_BUCKET_BAY, JIGGY_58_RBB_CAPTAINS_CABIN, -997, 273, 355), RC(RC_RBB_JIGGY_CRANE_CAGE, RCTYPE_JIGGY, LEVEL_9_RUSTY_BUCKET_BAY, RI_JIGGY_RUSTY_BUCKET_BAY, JIGGY_59_RBB_CRANE_CAGE, -4900, 0, 0), @@ -1820,81 +1820,81 @@ std::map Checks = { RC(RC_SM_EMPTY_HONEYCOMB_TREE, RCTYPE_EMPTY_HONEYCOMB, LEVEL_B_SPIRAL_MOUNTAIN, RI_EMPTY_HONEYCOMB_SPIRAL_MOUNTAIN, HONEYCOMB_16_SM_TREE, -2752, 1299, 37), RC(RC_SM_EMPTY_HONEYCOMB_UNDERWATER, RCTYPE_EMPTY_HONEYCOMB, LEVEL_B_SPIRAL_MOUNTAIN, RI_EMPTY_HONEYCOMB_SPIRAL_MOUNTAIN, HONEYCOMB_15_SM_UNDERWATER, -264, -442, -651), RC(RC_SM_EMPTY_HONEYCOMB_WATERFALL, RCTYPE_EMPTY_HONEYCOMB, LEVEL_B_SPIRAL_MOUNTAIN, RI_EMPTY_HONEYCOMB_SPIRAL_MOUNTAIN, HONEYCOMB_14_SM_WATERFALL, -6725, 1300, -1803), - RC(RC_SM_EXTRA_LIFE_ABOVE_BANJOS_HOUSE, RCTYPE_EXTRA_LIFE, LEVEL_B_SPIRAL_MOUNTAIN, RI_EXTRA_LIFE_SPIRAL_MOUNTAIN, NULL, 3656, 339, 6552), - RC(RC_SM_EXTRA_LIFE_WATERFALL, RCTYPE_EXTRA_LIFE, LEVEL_B_SPIRAL_MOUNTAIN, RI_EXTRA_LIFE_SPIRAL_MOUNTAIN, NULL, -7108, 1200, -3079), + RC(RC_SM_EXTRA_LIFE_ABOVE_BANJOS_HOUSE, RCTYPE_EXTRA_LIFE, LEVEL_B_SPIRAL_MOUNTAIN, RI_EXTRA_LIFE, NULL, 3656, 339, 6552), + RC(RC_SM_EXTRA_LIFE_WATERFALL, RCTYPE_EXTRA_LIFE, LEVEL_B_SPIRAL_MOUNTAIN, RI_EXTRA_LIFE, NULL, -7108, 1200, -3079), RC(RC_SM_MOLEHILL_ATTACK, RCTYPE_MOLEHILL, LEVEL_B_SPIRAL_MOUNTAIN, RI_MOLEHILL_CLAW_SWIPE, ABILITY_4_CLAW_SWIPE, 4675, 400, 511), RC(RC_SM_MOLEHILL_BEAK_BARGE, RCTYPE_MOLEHILL, LEVEL_B_SPIRAL_MOUNTAIN, RI_MOLEHILL_BARGE, ABILITY_0_BARGE, 3271, -110, -2673), RC(RC_SM_MOLEHILL_CAMERA_CONTROL, RCTYPE_MOLEHILL, LEVEL_B_SPIRAL_MOUNTAIN, RI_MOLEHILL_CAMERA_CONTROL, ABILITY_3_CAMERA_CONTROL, 2250, -34, 2774 ), RC(RC_SM_MOLEHILL_CLIMB, RCTYPE_MOLEHILL, LEVEL_B_SPIRAL_MOUNTAIN, RI_MOLEHILL_CLIMB, ABILITY_5_CLIMB, -1999, 342, -2545), RC(RC_SM_MOLEHILL_DIVE, RCTYPE_MOLEHILL, LEVEL_B_SPIRAL_MOUNTAIN, RI_MOLEHILL_DIVE, ABILITY_F_DIVE, -2336, 302, 973), RC(RC_SM_MOLEHILL_JUMP, RCTYPE_MOLEHILL, LEVEL_B_SPIRAL_MOUNTAIN, RI_MOLEHILL_FLAP_FLIP, ABILITY_8_FLAP_FLIP, -164, -190, 3313), - RC(RC_TTC_BLUE_EGG_ABOVE_SHOCK_PAD_1, RCTYPE_BLUE_EGG, LEVEL_2_TREASURE_TROVE_COVE, RI_BLUE_EGG_TREASURE_TROVE_COVE, NULL, 4539, 1667, 1639), - RC(RC_TTC_BLUE_EGG_ABOVE_SHOCK_PAD_2, RCTYPE_BLUE_EGG, LEVEL_2_TREASURE_TROVE_COVE, RI_BLUE_EGG_TREASURE_TROVE_COVE, NULL, 4539, 1792, 1639), - RC(RC_TTC_BLUE_EGG_ABOVE_SHOCK_PAD_3, RCTYPE_BLUE_EGG, LEVEL_2_TREASURE_TROVE_COVE, RI_BLUE_EGG_TREASURE_TROVE_COVE, NULL, 4539, 1917, 1639), - RC(RC_TTC_BLUE_EGG_ALCOVE_LEDGE_1, RCTYPE_BLUE_EGG, LEVEL_2_TREASURE_TROVE_COVE, RI_BLUE_EGG_TREASURE_TROVE_COVE, NULL, -2906, 1012, -6249), - RC(RC_TTC_BLUE_EGG_ALCOVE_LEDGE_2, RCTYPE_BLUE_EGG, LEVEL_2_TREASURE_TROVE_COVE, RI_BLUE_EGG_TREASURE_TROVE_COVE, NULL, -2941, 1011, -6045), - RC(RC_TTC_BLUE_EGG_ALCOVE_LEDGE_3, RCTYPE_BLUE_EGG, LEVEL_2_TREASURE_TROVE_COVE, RI_BLUE_EGG_TREASURE_TROVE_COVE, NULL, -3580, 1062, -5526), - RC(RC_TTC_BLUE_EGG_ALCOVE_LEDGE_4, RCTYPE_BLUE_EGG, LEVEL_2_TREASURE_TROVE_COVE, RI_BLUE_EGG_TREASURE_TROVE_COVE, NULL, -3808, 1062, -5389), - RC(RC_TTC_BLUE_EGG_ALCOVE_LEDGE_5, RCTYPE_BLUE_EGG, LEVEL_2_TREASURE_TROVE_COVE, RI_BLUE_EGG_TREASURE_TROVE_COVE, NULL, -3978, 1312, -5163), - RC(RC_TTC_BLUE_EGG_ALCOVE_LEDGE_6, RCTYPE_BLUE_EGG, LEVEL_2_TREASURE_TROVE_COVE, RI_BLUE_EGG_TREASURE_TROVE_COVE, NULL, -3995, 1312, -4990), - RC(RC_TTC_BLUE_EGG_ALCOVE_LEDGE_7, RCTYPE_BLUE_EGG, LEVEL_2_TREASURE_TROVE_COVE, RI_BLUE_EGG_TREASURE_TROVE_COVE, NULL, -4215, 1411, -4547), - RC(RC_TTC_BLUE_EGG_ALCOVE_LEDGE_8, RCTYPE_BLUE_EGG, LEVEL_2_TREASURE_TROVE_COVE, RI_BLUE_EGG_TREASURE_TROVE_COVE, NULL, -4413, 1412, -4482), - RC(RC_TTC_BLUE_EGG_INSIDE_NIPPER_1, RCTYPE_BLUE_EGG, LEVEL_2_TREASURE_TROVE_COVE, RI_BLUE_EGG_TREASURE_TROVE_COVE, NULL, -106, -23, 186), - RC(RC_TTC_BLUE_EGG_INSIDE_NIPPER_2, RCTYPE_BLUE_EGG, LEVEL_2_TREASURE_TROVE_COVE, RI_BLUE_EGG_TREASURE_TROVE_COVE, NULL, -142, -23, 315), - RC(RC_TTC_BLUE_EGG_INSIDE_NIPPER_3, RCTYPE_BLUE_EGG, LEVEL_2_TREASURE_TROVE_COVE, RI_BLUE_EGG_TREASURE_TROVE_COVE, NULL, -267, -23, 318), - RC(RC_TTC_BLUE_EGG_INSIDE_NIPPER_4, RCTYPE_BLUE_EGG, LEVEL_2_TREASURE_TROVE_COVE, RI_BLUE_EGG_TREASURE_TROVE_COVE, NULL, -306, -23, 212), - RC(RC_TTC_BLUE_EGG_INSIDE_NIPPER_5, RCTYPE_BLUE_EGG, LEVEL_2_TREASURE_TROVE_COVE, RI_BLUE_EGG_TREASURE_TROVE_COVE, NULL, -215, -23, 117), - RC(RC_TTC_BLUE_EGG_LIGHTHOUSE_LEDGE_1, RCTYPE_BLUE_EGG, LEVEL_2_TREASURE_TROVE_COVE, RI_BLUE_EGG_TREASURE_TROVE_COVE, NULL, 1012, 5782, -2017), - RC(RC_TTC_BLUE_EGG_LIGHTHOUSE_LEDGE_2, RCTYPE_BLUE_EGG, LEVEL_2_TREASURE_TROVE_COVE, RI_BLUE_EGG_TREASURE_TROVE_COVE, NULL, 864, 5826, -1874), - RC(RC_TTC_BLUE_EGG_LIGHTHOUSE_LEDGE_3, RCTYPE_BLUE_EGG, LEVEL_2_TREASURE_TROVE_COVE, RI_BLUE_EGG_TREASURE_TROVE_COVE, NULL, 648, 5857, -1874), - RC(RC_TTC_BLUE_EGG_LIGHTHOUSE_LEDGE_4, RCTYPE_BLUE_EGG, LEVEL_2_TREASURE_TROVE_COVE, RI_BLUE_EGG_TREASURE_TROVE_COVE, NULL, 743, 6580, -3494), - RC(RC_TTC_BLUE_EGG_LIGHTHOUSE_LEDGE_5, RCTYPE_BLUE_EGG, LEVEL_2_TREASURE_TROVE_COVE, RI_BLUE_EGG_TREASURE_TROVE_COVE, NULL, 944, 6625, -3436), - RC(RC_TTC_BLUE_EGG_LIGHTHOUSE_LEDGE_6, RCTYPE_BLUE_EGG, LEVEL_2_TREASURE_TROVE_COVE, RI_BLUE_EGG_TREASURE_TROVE_COVE, NULL, 1077, 6667, -3226), - RC(RC_TTC_BLUE_EGG_LIGHTHOUSE_TREE_1, RCTYPE_BLUE_EGG, LEVEL_2_TREASURE_TROVE_COVE, RI_BLUE_EGG_TREASURE_TROVE_COVE, NULL, 2475, 5793, -2303), - RC(RC_TTC_BLUE_EGG_LIGHTHOUSE_TREE_2, RCTYPE_BLUE_EGG, LEVEL_2_TREASURE_TROVE_COVE, RI_BLUE_EGG_TREASURE_TROVE_COVE, NULL, 2357, 5791, -2182), - RC(RC_TTC_BLUE_EGG_LIGHTHOUSE_TREE_3, RCTYPE_BLUE_EGG, LEVEL_2_TREASURE_TROVE_COVE, RI_BLUE_EGG_TREASURE_TROVE_COVE, NULL, 2351, 5822, -2417), - RC(RC_TTC_BLUE_EGG_LIGHTHOUSE_TREE_4, RCTYPE_BLUE_EGG, LEVEL_2_TREASURE_TROVE_COVE, RI_BLUE_EGG_TREASURE_TROVE_COVE, NULL, 2241, 5819, -2305), - RC(RC_TTC_BLUE_EGG_LIGHTHOUSE_TREE_5, RCTYPE_BLUE_EGG, LEVEL_2_TREASURE_TROVE_COVE, RI_BLUE_EGG_TREASURE_TROVE_COVE, NULL, 720, 5819, -4297), - RC(RC_TTC_BLUE_EGG_LIGHTHOUSE_TREE_6, RCTYPE_BLUE_EGG, LEVEL_2_TREASURE_TROVE_COVE, RI_BLUE_EGG_TREASURE_TROVE_COVE, NULL, 869, 5820, -4332), - RC(RC_TTC_BLUE_EGG_LIGHTHOUSE_TREE_7, RCTYPE_BLUE_EGG, LEVEL_2_TREASURE_TROVE_COVE, RI_BLUE_EGG_TREASURE_TROVE_COVE, NULL, 750, 5791, -4131), - RC(RC_TTC_BLUE_EGG_LIGHTHOUSE_TREE_8, RCTYPE_BLUE_EGG, LEVEL_2_TREASURE_TROVE_COVE, RI_BLUE_EGG_TREASURE_TROVE_COVE, NULL, 918, 5793, -4172), - RC(RC_TTC_BLUE_EGG_LIGHTHOUSE_TREE_9, RCTYPE_BLUE_EGG, LEVEL_2_TREASURE_TROVE_COVE, RI_BLUE_EGG_TREASURE_TROVE_COVE, NULL, -1269, 5795, -2811), - RC(RC_TTC_BLUE_EGG_LIGHTHOUSE_TREE_10, RCTYPE_BLUE_EGG, LEVEL_2_TREASURE_TROVE_COVE, RI_BLUE_EGG_TREASURE_TROVE_COVE, NULL, -1147, 5822, -2700), - RC(RC_TTC_BLUE_EGG_LIGHTHOUSE_TREE_11, RCTYPE_BLUE_EGG, LEVEL_2_TREASURE_TROVE_COVE, RI_BLUE_EGG_TREASURE_TROVE_COVE, NULL, -1145, 5792, -2928), - RC(RC_TTC_BLUE_EGG_LIGHTHOUSE_TREE_12, RCTYPE_BLUE_EGG, LEVEL_2_TREASURE_TROVE_COVE, RI_BLUE_EGG_TREASURE_TROVE_COVE, NULL, -1037, 5818, -2802), - RC(RC_TTC_BLUE_EGG_LIGHTHOUSE_TREE_13, RCTYPE_BLUE_EGG, LEVEL_2_TREASURE_TROVE_COVE, RI_BLUE_EGG_TREASURE_TROVE_COVE, NULL, 687, 5822, -1177), - RC(RC_TTC_BLUE_EGG_LIGHTHOUSE_TREE_14, RCTYPE_BLUE_EGG, LEVEL_2_TREASURE_TROVE_COVE, RI_BLUE_EGG_TREASURE_TROVE_COVE, NULL, 843, 5819, -1172), - RC(RC_TTC_BLUE_EGG_LIGHTHOUSE_TREE_15, RCTYPE_BLUE_EGG, LEVEL_2_TREASURE_TROVE_COVE, RI_BLUE_EGG_TREASURE_TROVE_COVE, NULL, 857, 5793, -1336), - RC(RC_TTC_BLUE_EGG_LIGHTHOUSE_TREE_16, RCTYPE_BLUE_EGG, LEVEL_2_TREASURE_TROVE_COVE, RI_BLUE_EGG_TREASURE_TROVE_COVE, NULL, 689, 5794, -1347), - RC(RC_TTC_BLUE_EGG_LOCKUP_1, RCTYPE_BLUE_EGG, LEVEL_2_TREASURE_TROVE_COVE, RI_BLUE_EGG_TREASURE_TROVE_COVE, NULL, -3966, 1190, 1747), - RC(RC_TTC_BLUE_EGG_LOCKUP_2, RCTYPE_BLUE_EGG, LEVEL_2_TREASURE_TROVE_COVE, RI_BLUE_EGG_TREASURE_TROVE_COVE, NULL, -4051, 1190, 1793), - RC(RC_TTC_BLUE_EGG_LOCKUP_3, RCTYPE_BLUE_EGG, LEVEL_2_TREASURE_TROVE_COVE, RI_BLUE_EGG_TREASURE_TROVE_COVE, NULL, -4051, 1190, 1706), - RC(RC_TTC_BLUE_EGG_LOCKUP_4, RCTYPE_BLUE_EGG, LEVEL_2_TREASURE_TROVE_COVE, RI_BLUE_EGG_TREASURE_TROVE_COVE, NULL, -3882, 1190, 1795), - RC(RC_TTC_BLUE_EGG_LOCKUP_5, RCTYPE_BLUE_EGG, LEVEL_2_TREASURE_TROVE_COVE, RI_BLUE_EGG_TREASURE_TROVE_COVE, NULL, -3882, 1190, 1707), - RC(RC_TTC_BLUE_EGG_UPPER_POOL_1, RCTYPE_BLUE_EGG, LEVEL_2_TREASURE_TROVE_COVE, RI_BLUE_EGG_TREASURE_TROVE_COVE, NULL, -5319, 2470, -2929), - RC(RC_TTC_BLUE_EGG_UPPER_POOL_2, RCTYPE_BLUE_EGG, LEVEL_2_TREASURE_TROVE_COVE, RI_BLUE_EGG_TREASURE_TROVE_COVE, NULL, -5154, 2470, -3256), - RC(RC_TTC_BLUE_EGG_UPPER_POOL_3, RCTYPE_BLUE_EGG, LEVEL_2_TREASURE_TROVE_COVE, RI_BLUE_EGG_TREASURE_TROVE_COVE, NULL, -4975, 2470, -3543), - RC(RC_TTC_BLUE_EGG_UPPER_POOL_4, RCTYPE_BLUE_EGG, LEVEL_2_TREASURE_TROVE_COVE, RI_BLUE_EGG_TREASURE_TROVE_COVE, NULL, -4749, 2470, -3780), - RC(RC_TTC_BLUE_EGG_UPPER_POOL_5, RCTYPE_BLUE_EGG, LEVEL_2_TREASURE_TROVE_COVE, RI_BLUE_EGG_TREASURE_TROVE_COVE, NULL, -4410, 2470, -3814), - RC(RC_TTC_BLUE_EGG_UPPER_POOL_6, RCTYPE_BLUE_EGG, LEVEL_2_TREASURE_TROVE_COVE, RI_BLUE_EGG_TREASURE_TROVE_COVE, NULL, -4092, 2470, -3826), - RC(RC_TTC_BLUE_EGG_UPPER_POOL_7, RCTYPE_BLUE_EGG, LEVEL_2_TREASURE_TROVE_COVE, RI_BLUE_EGG_TREASURE_TROVE_COVE, NULL, -3957, 2470, -3586), + RC(RC_TTC_BLUE_EGG_ABOVE_SHOCK_PAD_1, RCTYPE_BLUE_EGG, LEVEL_2_TREASURE_TROVE_COVE, RI_BLUE_EGG, NULL, 4539, 1667, 1639), + RC(RC_TTC_BLUE_EGG_ABOVE_SHOCK_PAD_2, RCTYPE_BLUE_EGG, LEVEL_2_TREASURE_TROVE_COVE, RI_BLUE_EGG, NULL, 4539, 1792, 1639), + RC(RC_TTC_BLUE_EGG_ABOVE_SHOCK_PAD_3, RCTYPE_BLUE_EGG, LEVEL_2_TREASURE_TROVE_COVE, RI_BLUE_EGG, NULL, 4539, 1917, 1639), + RC(RC_TTC_BLUE_EGG_ALCOVE_LEDGE_1, RCTYPE_BLUE_EGG, LEVEL_2_TREASURE_TROVE_COVE, RI_BLUE_EGG, NULL, -2906, 1012, -6249), + RC(RC_TTC_BLUE_EGG_ALCOVE_LEDGE_2, RCTYPE_BLUE_EGG, LEVEL_2_TREASURE_TROVE_COVE, RI_BLUE_EGG, NULL, -2941, 1011, -6045), + RC(RC_TTC_BLUE_EGG_ALCOVE_LEDGE_3, RCTYPE_BLUE_EGG, LEVEL_2_TREASURE_TROVE_COVE, RI_BLUE_EGG, NULL, -3580, 1062, -5526), + RC(RC_TTC_BLUE_EGG_ALCOVE_LEDGE_4, RCTYPE_BLUE_EGG, LEVEL_2_TREASURE_TROVE_COVE, RI_BLUE_EGG, NULL, -3808, 1062, -5389), + RC(RC_TTC_BLUE_EGG_ALCOVE_LEDGE_5, RCTYPE_BLUE_EGG, LEVEL_2_TREASURE_TROVE_COVE, RI_BLUE_EGG, NULL, -3978, 1312, -5163), + RC(RC_TTC_BLUE_EGG_ALCOVE_LEDGE_6, RCTYPE_BLUE_EGG, LEVEL_2_TREASURE_TROVE_COVE, RI_BLUE_EGG, NULL, -3995, 1312, -4990), + RC(RC_TTC_BLUE_EGG_ALCOVE_LEDGE_7, RCTYPE_BLUE_EGG, LEVEL_2_TREASURE_TROVE_COVE, RI_BLUE_EGG, NULL, -4215, 1411, -4547), + RC(RC_TTC_BLUE_EGG_ALCOVE_LEDGE_8, RCTYPE_BLUE_EGG, LEVEL_2_TREASURE_TROVE_COVE, RI_BLUE_EGG, NULL, -4413, 1412, -4482), + RC(RC_TTC_BLUE_EGG_INSIDE_NIPPER_1, RCTYPE_BLUE_EGG, LEVEL_2_TREASURE_TROVE_COVE, RI_BLUE_EGG, NULL, -106, -23, 186), + RC(RC_TTC_BLUE_EGG_INSIDE_NIPPER_2, RCTYPE_BLUE_EGG, LEVEL_2_TREASURE_TROVE_COVE, RI_BLUE_EGG, NULL, -142, -23, 315), + RC(RC_TTC_BLUE_EGG_INSIDE_NIPPER_3, RCTYPE_BLUE_EGG, LEVEL_2_TREASURE_TROVE_COVE, RI_BLUE_EGG, NULL, -267, -23, 318), + RC(RC_TTC_BLUE_EGG_INSIDE_NIPPER_4, RCTYPE_BLUE_EGG, LEVEL_2_TREASURE_TROVE_COVE, RI_BLUE_EGG, NULL, -306, -23, 212), + RC(RC_TTC_BLUE_EGG_INSIDE_NIPPER_5, RCTYPE_BLUE_EGG, LEVEL_2_TREASURE_TROVE_COVE, RI_BLUE_EGG, NULL, -215, -23, 117), + RC(RC_TTC_BLUE_EGG_LIGHTHOUSE_LEDGE_1, RCTYPE_BLUE_EGG, LEVEL_2_TREASURE_TROVE_COVE, RI_BLUE_EGG, NULL, 1012, 5782, -2017), + RC(RC_TTC_BLUE_EGG_LIGHTHOUSE_LEDGE_2, RCTYPE_BLUE_EGG, LEVEL_2_TREASURE_TROVE_COVE, RI_BLUE_EGG, NULL, 864, 5826, -1874), + RC(RC_TTC_BLUE_EGG_LIGHTHOUSE_LEDGE_3, RCTYPE_BLUE_EGG, LEVEL_2_TREASURE_TROVE_COVE, RI_BLUE_EGG, NULL, 648, 5857, -1874), + RC(RC_TTC_BLUE_EGG_LIGHTHOUSE_LEDGE_4, RCTYPE_BLUE_EGG, LEVEL_2_TREASURE_TROVE_COVE, RI_BLUE_EGG, NULL, 743, 6580, -3494), + RC(RC_TTC_BLUE_EGG_LIGHTHOUSE_LEDGE_5, RCTYPE_BLUE_EGG, LEVEL_2_TREASURE_TROVE_COVE, RI_BLUE_EGG, NULL, 944, 6625, -3436), + RC(RC_TTC_BLUE_EGG_LIGHTHOUSE_LEDGE_6, RCTYPE_BLUE_EGG, LEVEL_2_TREASURE_TROVE_COVE, RI_BLUE_EGG, NULL, 1077, 6667, -3226), + RC(RC_TTC_BLUE_EGG_LIGHTHOUSE_TREE_1, RCTYPE_BLUE_EGG, LEVEL_2_TREASURE_TROVE_COVE, RI_BLUE_EGG, NULL, 2475, 5793, -2303), + RC(RC_TTC_BLUE_EGG_LIGHTHOUSE_TREE_2, RCTYPE_BLUE_EGG, LEVEL_2_TREASURE_TROVE_COVE, RI_BLUE_EGG, NULL, 2357, 5791, -2182), + RC(RC_TTC_BLUE_EGG_LIGHTHOUSE_TREE_3, RCTYPE_BLUE_EGG, LEVEL_2_TREASURE_TROVE_COVE, RI_BLUE_EGG, NULL, 2351, 5822, -2417), + RC(RC_TTC_BLUE_EGG_LIGHTHOUSE_TREE_4, RCTYPE_BLUE_EGG, LEVEL_2_TREASURE_TROVE_COVE, RI_BLUE_EGG, NULL, 2241, 5819, -2305), + RC(RC_TTC_BLUE_EGG_LIGHTHOUSE_TREE_5, RCTYPE_BLUE_EGG, LEVEL_2_TREASURE_TROVE_COVE, RI_BLUE_EGG, NULL, 720, 5819, -4297), + RC(RC_TTC_BLUE_EGG_LIGHTHOUSE_TREE_6, RCTYPE_BLUE_EGG, LEVEL_2_TREASURE_TROVE_COVE, RI_BLUE_EGG, NULL, 869, 5820, -4332), + RC(RC_TTC_BLUE_EGG_LIGHTHOUSE_TREE_7, RCTYPE_BLUE_EGG, LEVEL_2_TREASURE_TROVE_COVE, RI_BLUE_EGG, NULL, 750, 5791, -4131), + RC(RC_TTC_BLUE_EGG_LIGHTHOUSE_TREE_8, RCTYPE_BLUE_EGG, LEVEL_2_TREASURE_TROVE_COVE, RI_BLUE_EGG, NULL, 918, 5793, -4172), + RC(RC_TTC_BLUE_EGG_LIGHTHOUSE_TREE_9, RCTYPE_BLUE_EGG, LEVEL_2_TREASURE_TROVE_COVE, RI_BLUE_EGG, NULL, -1269, 5795, -2811), + RC(RC_TTC_BLUE_EGG_LIGHTHOUSE_TREE_10, RCTYPE_BLUE_EGG, LEVEL_2_TREASURE_TROVE_COVE, RI_BLUE_EGG, NULL, -1147, 5822, -2700), + RC(RC_TTC_BLUE_EGG_LIGHTHOUSE_TREE_11, RCTYPE_BLUE_EGG, LEVEL_2_TREASURE_TROVE_COVE, RI_BLUE_EGG, NULL, -1145, 5792, -2928), + RC(RC_TTC_BLUE_EGG_LIGHTHOUSE_TREE_12, RCTYPE_BLUE_EGG, LEVEL_2_TREASURE_TROVE_COVE, RI_BLUE_EGG, NULL, -1037, 5818, -2802), + RC(RC_TTC_BLUE_EGG_LIGHTHOUSE_TREE_13, RCTYPE_BLUE_EGG, LEVEL_2_TREASURE_TROVE_COVE, RI_BLUE_EGG, NULL, 687, 5822, -1177), + RC(RC_TTC_BLUE_EGG_LIGHTHOUSE_TREE_14, RCTYPE_BLUE_EGG, LEVEL_2_TREASURE_TROVE_COVE, RI_BLUE_EGG, NULL, 843, 5819, -1172), + RC(RC_TTC_BLUE_EGG_LIGHTHOUSE_TREE_15, RCTYPE_BLUE_EGG, LEVEL_2_TREASURE_TROVE_COVE, RI_BLUE_EGG, NULL, 857, 5793, -1336), + RC(RC_TTC_BLUE_EGG_LIGHTHOUSE_TREE_16, RCTYPE_BLUE_EGG, LEVEL_2_TREASURE_TROVE_COVE, RI_BLUE_EGG, NULL, 689, 5794, -1347), + RC(RC_TTC_BLUE_EGG_LOCKUP_1, RCTYPE_BLUE_EGG, LEVEL_2_TREASURE_TROVE_COVE, RI_BLUE_EGG, NULL, -3966, 1190, 1747), + RC(RC_TTC_BLUE_EGG_LOCKUP_2, RCTYPE_BLUE_EGG, LEVEL_2_TREASURE_TROVE_COVE, RI_BLUE_EGG, NULL, -4051, 1190, 1793), + RC(RC_TTC_BLUE_EGG_LOCKUP_3, RCTYPE_BLUE_EGG, LEVEL_2_TREASURE_TROVE_COVE, RI_BLUE_EGG, NULL, -4051, 1190, 1706), + RC(RC_TTC_BLUE_EGG_LOCKUP_4, RCTYPE_BLUE_EGG, LEVEL_2_TREASURE_TROVE_COVE, RI_BLUE_EGG, NULL, -3882, 1190, 1795), + RC(RC_TTC_BLUE_EGG_LOCKUP_5, RCTYPE_BLUE_EGG, LEVEL_2_TREASURE_TROVE_COVE, RI_BLUE_EGG, NULL, -3882, 1190, 1707), + RC(RC_TTC_BLUE_EGG_UPPER_POOL_1, RCTYPE_BLUE_EGG, LEVEL_2_TREASURE_TROVE_COVE, RI_BLUE_EGG, NULL, -5319, 2470, -2929), + RC(RC_TTC_BLUE_EGG_UPPER_POOL_2, RCTYPE_BLUE_EGG, LEVEL_2_TREASURE_TROVE_COVE, RI_BLUE_EGG, NULL, -5154, 2470, -3256), + RC(RC_TTC_BLUE_EGG_UPPER_POOL_3, RCTYPE_BLUE_EGG, LEVEL_2_TREASURE_TROVE_COVE, RI_BLUE_EGG, NULL, -4975, 2470, -3543), + RC(RC_TTC_BLUE_EGG_UPPER_POOL_4, RCTYPE_BLUE_EGG, LEVEL_2_TREASURE_TROVE_COVE, RI_BLUE_EGG, NULL, -4749, 2470, -3780), + RC(RC_TTC_BLUE_EGG_UPPER_POOL_5, RCTYPE_BLUE_EGG, LEVEL_2_TREASURE_TROVE_COVE, RI_BLUE_EGG, NULL, -4410, 2470, -3814), + RC(RC_TTC_BLUE_EGG_UPPER_POOL_6, RCTYPE_BLUE_EGG, LEVEL_2_TREASURE_TROVE_COVE, RI_BLUE_EGG, NULL, -4092, 2470, -3826), + RC(RC_TTC_BLUE_EGG_UPPER_POOL_7, RCTYPE_BLUE_EGG, LEVEL_2_TREASURE_TROVE_COVE, RI_BLUE_EGG, NULL, -3957, 2470, -3586), RC(RC_TTC_EMPTY_HONEYCOMB_FLOATING_BOX, RCTYPE_EMPTY_HONEYCOMB, LEVEL_2_TREASURE_TROVE_COVE, RI_EMPTY_HONEYCOMB_TREASURE_TROVE_COVE, HONEYCOMB_4_TTC_FLOATING_BOX, 8473, 844, -2684), RC(RC_TTC_EMPTY_HONEYCOMB_UNDERWATER, RCTYPE_EMPTY_HONEYCOMB, LEVEL_2_TREASURE_TROVE_COVE, RI_EMPTY_HONEYCOMB_TREASURE_TROVE_COVE, HONEYCOMB_3_TTC_UNDERWATER, -4303, 46, 115), - RC(RC_TTC_EXTRA_LIFE_CLIFFSIDE_POOL, RCTYPE_EXTRA_LIFE, LEVEL_2_TREASURE_TROVE_COVE, RI_EXTRA_LIFE_TREASURE_TROVE_COVE, NULL, -2442, 3158, -1706), - RC(RC_TTC_EXTRA_LIFE_SHARKFOOD_ISLAND_SIGN, RCTYPE_EXTRA_LIFE, LEVEL_2_TREASURE_TROVE_COVE, RI_EXTRA_LIFE_TREASURE_TROVE_COVE, NULL, 5864, 677, 7898), - RC(RC_TTC_EXTRA_LIFE_SPIRAL_PATH, RCTYPE_EXTRA_LIFE, LEVEL_2_TREASURE_TROVE_COVE, RI_EXTRA_LIFE_TREASURE_TROVE_COVE, NULL, 4710, 323, -6007), - RC(RC_TTC_HONEYCOMB_BEEHIVE_NEAR_BLUBBERS_SHIP_1, RCTYPE_HONEYCOMB, LEVEL_2_TREASURE_TROVE_COVE, RI_HONEYCOMB_TREASURE_TROVE_COVE, NULL, 0, 0, 0), - RC(RC_TTC_HONEYCOMB_BEEHIVE_NEAR_BLUBBERS_SHIP_2, RCTYPE_HONEYCOMB, LEVEL_2_TREASURE_TROVE_COVE, RI_HONEYCOMB_TREASURE_TROVE_COVE, NULL, 0, 0, 0), - RC(RC_TTC_HONEYCOMB_BEEHIVE_NEAR_BLUBBERS_SHIP_3, RCTYPE_HONEYCOMB, LEVEL_2_TREASURE_TROVE_COVE, RI_HONEYCOMB_TREASURE_TROVE_COVE, NULL, 0, 0, 0), - RC(RC_TTC_HONEYCOMB_BEEHIVE_NEAR_THE_BACK_STAIRS_1, RCTYPE_HONEYCOMB, LEVEL_2_TREASURE_TROVE_COVE, RI_HONEYCOMB_TREASURE_TROVE_COVE, NULL, 0, 0, 0), - RC(RC_TTC_HONEYCOMB_BEEHIVE_NEAR_THE_BACK_STAIRS_2, RCTYPE_HONEYCOMB, LEVEL_2_TREASURE_TROVE_COVE, RI_HONEYCOMB_TREASURE_TROVE_COVE, NULL, 0, 0, 0), - RC(RC_TTC_HONEYCOMB_BEEHIVE_NEAR_THE_BACK_STAIRS_3, RCTYPE_HONEYCOMB, LEVEL_2_TREASURE_TROVE_COVE, RI_HONEYCOMB_TREASURE_TROVE_COVE, NULL, 0, 0, 0), - RC(RC_TTC_HONEYCOMB_BEEHIVE_IN_THE_CLIFFSIDE_POOL_1, RCTYPE_HONEYCOMB, LEVEL_2_TREASURE_TROVE_COVE, RI_HONEYCOMB_TREASURE_TROVE_COVE, NULL, 0, 0, 0), - RC(RC_TTC_HONEYCOMB_BEEHIVE_IN_THE_CLIFFSIDE_POOL_2, RCTYPE_HONEYCOMB, LEVEL_2_TREASURE_TROVE_COVE, RI_HONEYCOMB_TREASURE_TROVE_COVE, NULL, 0, 0, 0), - RC(RC_TTC_HONEYCOMB_BEEHIVE_IN_THE_CLIFFSIDE_POOL_3, RCTYPE_HONEYCOMB, LEVEL_2_TREASURE_TROVE_COVE, RI_HONEYCOMB_TREASURE_TROVE_COVE, NULL, 0, 0, 0), - RC(RC_TTC_HONEYCOMB_BEEHIVE_ON_THE_BEACH_1, RCTYPE_HONEYCOMB, LEVEL_2_TREASURE_TROVE_COVE, RI_HONEYCOMB_TREASURE_TROVE_COVE, NULL, 0, 0, 0), - RC(RC_TTC_HONEYCOMB_BEEHIVE_ON_THE_BEACH_2, RCTYPE_HONEYCOMB, LEVEL_2_TREASURE_TROVE_COVE, RI_HONEYCOMB_TREASURE_TROVE_COVE, NULL, 0, 0, 0), - RC(RC_TTC_HONEYCOMB_BEEHIVE_ON_THE_BEACH_3, RCTYPE_HONEYCOMB, LEVEL_2_TREASURE_TROVE_COVE, RI_HONEYCOMB_TREASURE_TROVE_COVE, NULL, 0, 0, 0), + RC(RC_TTC_EXTRA_LIFE_CLIFFSIDE_POOL, RCTYPE_EXTRA_LIFE, LEVEL_2_TREASURE_TROVE_COVE, RI_EXTRA_LIFE, NULL, -2442, 3158, -1706), + RC(RC_TTC_EXTRA_LIFE_SHARKFOOD_ISLAND_SIGN, RCTYPE_EXTRA_LIFE, LEVEL_2_TREASURE_TROVE_COVE, RI_EXTRA_LIFE, NULL, 5864, 677, 7898), + RC(RC_TTC_EXTRA_LIFE_SPIRAL_PATH, RCTYPE_EXTRA_LIFE, LEVEL_2_TREASURE_TROVE_COVE, RI_EXTRA_LIFE, NULL, 4710, 323, -6007), + RC(RC_TTC_HONEYCOMB_BEEHIVE_NEAR_BLUBBERS_SHIP_1, RCTYPE_HONEYCOMB, LEVEL_2_TREASURE_TROVE_COVE, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_TTC_HONEYCOMB_BEEHIVE_NEAR_BLUBBERS_SHIP_2, RCTYPE_HONEYCOMB, LEVEL_2_TREASURE_TROVE_COVE, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_TTC_HONEYCOMB_BEEHIVE_NEAR_BLUBBERS_SHIP_3, RCTYPE_HONEYCOMB, LEVEL_2_TREASURE_TROVE_COVE, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_TTC_HONEYCOMB_BEEHIVE_NEAR_THE_BACK_STAIRS_1, RCTYPE_HONEYCOMB, LEVEL_2_TREASURE_TROVE_COVE, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_TTC_HONEYCOMB_BEEHIVE_NEAR_THE_BACK_STAIRS_2, RCTYPE_HONEYCOMB, LEVEL_2_TREASURE_TROVE_COVE, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_TTC_HONEYCOMB_BEEHIVE_NEAR_THE_BACK_STAIRS_3, RCTYPE_HONEYCOMB, LEVEL_2_TREASURE_TROVE_COVE, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_TTC_HONEYCOMB_BEEHIVE_IN_THE_CLIFFSIDE_POOL_1, RCTYPE_HONEYCOMB, LEVEL_2_TREASURE_TROVE_COVE, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_TTC_HONEYCOMB_BEEHIVE_IN_THE_CLIFFSIDE_POOL_2, RCTYPE_HONEYCOMB, LEVEL_2_TREASURE_TROVE_COVE, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_TTC_HONEYCOMB_BEEHIVE_IN_THE_CLIFFSIDE_POOL_3, RCTYPE_HONEYCOMB, LEVEL_2_TREASURE_TROVE_COVE, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_TTC_HONEYCOMB_BEEHIVE_ON_THE_BEACH_1, RCTYPE_HONEYCOMB, LEVEL_2_TREASURE_TROVE_COVE, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_TTC_HONEYCOMB_BEEHIVE_ON_THE_BEACH_2, RCTYPE_HONEYCOMB, LEVEL_2_TREASURE_TROVE_COVE, RI_HONEYCOMB, NULL, 0, 0, 0), + RC(RC_TTC_HONEYCOMB_BEEHIVE_ON_THE_BEACH_3, RCTYPE_HONEYCOMB, LEVEL_2_TREASURE_TROVE_COVE, RI_HONEYCOMB, NULL, 0, 0, 0), RC(RC_TTC_JIGGY_ALCOVE1, RCTYPE_JIGGY, LEVEL_2_TREASURE_TROVE_COVE, RI_JIGGY_TREASURE_TROVE_COVE, JIGGY_0D_TTC_ALCOVE_1, 2832, 2152, -1797), RC(RC_TTC_JIGGY_ALCOVE2, RCTYPE_JIGGY, LEVEL_2_TREASURE_TROVE_COVE, RI_JIGGY_TREASURE_TROVE_COVE, JIGGY_0E_TTC_ALCOVE_2, -5116, 1417, -3915), RC(RC_TTC_JIGGY_BLUBBER, RCTYPE_JIGGY, LEVEL_2_TREASURE_TROVE_COVE, RI_JIGGY_TREASURE_TROVE_COVE, JIGGY_14_TTC_BLUBBER, 0, 0, 0), diff --git a/src/port/Rando/StaticData/Items.cpp b/src/port/Rando/StaticData/Items.cpp index 825f0e965..c50326121 100644 --- a/src/port/Rando/StaticData/Items.cpp +++ b/src/port/Rando/StaticData/Items.cpp @@ -10,59 +10,29 @@ namespace Rando { namespace StaticData { -#define RI(id, article, name, type, actorId) \ +#define RI(id, article, name, type, actorId, worldId) \ { \ id, { \ - id, #id, article, name, type, actorId \ + id, #id, article, name, type, actorId, worldId \ } \ } // clang-format off std::map Items = { RI(RI_UNKNOWN, "", "Unknown", RITYPE_UNKNOWN, ACTOR_1_UNKNOWN, LEVEL_D_CUTSCENE), - RI(RI_BLUE_EGG_BUBBLEGLOOP_SWAMP, "a", "Blue Egg - BGS", RITYPE_BLUE_EGG, ACTOR_52_BLUE_EGG, LEVEL_4_BUBBLEGLOOP_SWAMP), - RI(RI_BLUE_EGG_CLANKERS_CAVERN, "a", "Blue Egg - CC", RITYPE_BLUE_EGG, ACTOR_52_BLUE_EGG, LEVEL_3_CLANKERS_CAVERN), - RI(RI_BLUE_EGG_CLICK_CLOCK_WOOD, "a", "Blue Egg - CCW", RITYPE_BLUE_EGG, ACTOR_52_BLUE_EGG, LEVEL_8_CLICK_CLOCK_WOOD), - RI(RI_BLUE_EGG_FREEZEEZY_PEAK, "a", "Blue Egg - FP", RITYPE_BLUE_EGG, ACTOR_52_BLUE_EGG, LEVEL_5_FREEZEEZY_PEAK), - RI(RI_BLUE_EGG_GOBIS_VALLEY, "a", "Blue Egg - GV", RITYPE_BLUE_EGG, ACTOR_52_BLUE_EGG, LEVEL_7_GOBIS_VALLEY), - RI(RI_BLUE_EGG_GRUNTILDAS_LAIR, "a", "Blue Egg - Gl", RITYPE_BLUE_EGG, ACTOR_52_BLUE_EGG, LEVEL_6_LAIR), - RI(RI_BLUE_EGG_MAD_MONSTER_MANSION, "a", "Blue Egg - MMM", RITYPE_BLUE_EGG, ACTOR_52_BLUE_EGG, LEVEL_A_MAD_MONSTER_MANSION), - RI(RI_BLUE_EGG_MUMBOS_MOUNTAIN, "a", "Blue Egg - MM", RITYPE_BLUE_EGG, ACTOR_52_BLUE_EGG, LEVEL_1_MUMBOS_MOUNTAIN), - RI(RI_BLUE_EGG_RUSTY_BUCKET_BAY, "a", "Blue Egg - RBB", RITYPE_BLUE_EGG, ACTOR_52_BLUE_EGG, LEVEL_9_RUSTY_BUCKET_BAY), - RI(RI_BLUE_EGG_TREASURE_TROVE_COVE, "a", "Blue Egg - TTC", RITYPE_BLUE_EGG, ACTOR_52_BLUE_EGG, LEVEL_2_TREASURE_TROVE_COVE), + RI(RI_BLUE_EGG, "a", "Blue Egg", RITYPE_BLUE_EGG, ACTOR_52_BLUE_EGG, LEVEL_D_CUTSCENE), RI(RI_EMPTY_HONEYCOMB_BUBBLEGLOOP_SWAMP, "a", "Empty Honeycomb - BGS", RITYPE_EMPTY_HONEYCOMB, ACTOR_47_EMPTY_HONEYCOMB, LEVEL_4_BUBBLEGLOOP_SWAMP), RI(RI_EMPTY_HONEYCOMB_CLANKERS_CAVERN, "a", "Empty Honeycomb - CC", RITYPE_EMPTY_HONEYCOMB, ACTOR_47_EMPTY_HONEYCOMB, LEVEL_3_CLANKERS_CAVERN), RI(RI_EMPTY_HONEYCOMB_CLICK_CLOCK_WOOD, "a", "Empty Honeycomb - CCW", RITYPE_EMPTY_HONEYCOMB, ACTOR_47_EMPTY_HONEYCOMB, LEVEL_8_CLICK_CLOCK_WOOD), RI(RI_EMPTY_HONEYCOMB_FREEZEEZY_PEAK, "a", "Empty Honeycomb - FP", RITYPE_EMPTY_HONEYCOMB, ACTOR_47_EMPTY_HONEYCOMB, LEVEL_5_FREEZEEZY_PEAK), RI(RI_EMPTY_HONEYCOMB_GOBIS_VALLEY, "a", "Empty Honeycomb - GV", RITYPE_EMPTY_HONEYCOMB, ACTOR_47_EMPTY_HONEYCOMB, LEVEL_7_GOBIS_VALLEY), - RI(RI_EMPTY_HONEYCOMB_GRUNTILDAS_LAIR, "a", "Empty Honeycomb - GL", RITYPE_EMPTY_HONEYCOMB, ACTOR_47_EMPTY_HONEYCOMB, LEVEL_6_LAIR), RI(RI_EMPTY_HONEYCOMB_MAD_MONSTER_MANSION, "a", "Empty Honeycomb - MMM", RITYPE_EMPTY_HONEYCOMB, ACTOR_47_EMPTY_HONEYCOMB, LEVEL_A_MAD_MONSTER_MANSION), RI(RI_EMPTY_HONEYCOMB_MUMBOS_MOUNTAIN, "a", "Empty Honeycomb - MM", RITYPE_EMPTY_HONEYCOMB, ACTOR_47_EMPTY_HONEYCOMB, LEVEL_1_MUMBOS_MOUNTAIN), RI(RI_EMPTY_HONEYCOMB_RUSTY_BUCKET_BAY, "a", "Empty Honeycomb - RBB", RITYPE_EMPTY_HONEYCOMB, ACTOR_47_EMPTY_HONEYCOMB, LEVEL_9_RUSTY_BUCKET_BAY), RI(RI_EMPTY_HONEYCOMB_SPIRAL_MOUNTAIN, "a", "Empty Honeycomb - SM", RITYPE_EMPTY_HONEYCOMB, ACTOR_47_EMPTY_HONEYCOMB, LEVEL_B_SPIRAL_MOUNTAIN), RI(RI_EMPTY_HONEYCOMB_TREASURE_TROVE_COVE, "a", "Empty Honeycomb - TTC", RITYPE_EMPTY_HONEYCOMB, ACTOR_47_EMPTY_HONEYCOMB, LEVEL_2_TREASURE_TROVE_COVE), - RI(RI_EXTRA_LIFE_BUBBLEGLOOP_SWAMP, "an", "Extra Life - BGS", RITYPE_EXTRA_LIFE, ACTOR_49_EXTRA_LIFE, LEVEL_4_BUBBLEGLOOP_SWAMP), - RI(RI_EXTRA_LIFE_CLANKERS_CAVERN, "an", "Extra Life - CC", RITYPE_EXTRA_LIFE, ACTOR_49_EXTRA_LIFE, LEVEL_3_CLANKERS_CAVERN), - RI(RI_EXTRA_LIFE_CLICK_CLOCK_WOOD, "an", "Extra Life - CCW", RITYPE_EXTRA_LIFE, ACTOR_49_EXTRA_LIFE, LEVEL_8_CLICK_CLOCK_WOOD), - RI(RI_EXTRA_LIFE_FREEZEEZY_PEAK, "an", "Extra Life - FP", RITYPE_EXTRA_LIFE, ACTOR_49_EXTRA_LIFE, LEVEL_5_FREEZEEZY_PEAK), - RI(RI_EXTRA_LIFE_GOBIS_VALLEY, "an", "Extra Life - GV", RITYPE_EXTRA_LIFE, ACTOR_49_EXTRA_LIFE, LEVEL_7_GOBIS_VALLEY), - RI(RI_EXTRA_LIFE_GRUNTILDAS_LAIR, "an", "Extra Life - GL", RITYPE_EXTRA_LIFE, ACTOR_49_EXTRA_LIFE, LEVEL_6_LAIR), - RI(RI_EXTRA_LIFE_MAD_MONSTER_MANSION, "an", "Extra Life - MMM", RITYPE_EXTRA_LIFE, ACTOR_49_EXTRA_LIFE, LEVEL_A_MAD_MONSTER_MANSION), - RI(RI_EXTRA_LIFE_MUMBOS_MOUNTAIN, "an", "Extra Life - MM", RITYPE_EXTRA_LIFE, ACTOR_49_EXTRA_LIFE, LEVEL_1_MUMBOS_MOUNTAIN), - RI(RI_EXTRA_LIFE_RUSTY_BUCKET_BAY, "an", "Extra Life - RBB", RITYPE_EXTRA_LIFE, ACTOR_49_EXTRA_LIFE, LEVEL_9_RUSTY_BUCKET_BAY), - RI(RI_EXTRA_LIFE_SPIRAL_MOUNTAIN, "an", "Extra Life - SM", RITYPE_EXTRA_LIFE, ACTOR_49_EXTRA_LIFE, LEVEL_B_SPIRAL_MOUNTAIN), - RI(RI_EXTRA_LIFE_TREASURE_TROVE_COVE, "an", "Extra Life - TTC", RITYPE_EXTRA_LIFE, ACTOR_49_EXTRA_LIFE, LEVEL_2_TREASURE_TROVE_COVE), - RI(RI_HONEYCOMB_BUBBLEGLOOP_SWAMP, "a", "Honeycomb - BGS", RITYPE_HONEYCOMB, ACTOR_50_HONEYCOMB, LEVEL_4_BUBBLEGLOOP_SWAMP), - RI(RI_HONEYCOMB_CLANKERS_CAVERN, "a", "Honeycomb - CC", RITYPE_HONEYCOMB, ACTOR_50_HONEYCOMB, LEVEL_3_CLANKERS_CAVERN), - RI(RI_HONEYCOMB_CLICK_CLOCK_WOOD, "a", "Honeycomb - CCW", RITYPE_HONEYCOMB, ACTOR_50_HONEYCOMB, LEVEL_8_CLICK_CLOCK_WOOD), - RI(RI_HONEYCOMB_FREEZEEZY_PEAK, "a", "Honeycomb - FP", RITYPE_HONEYCOMB, ACTOR_50_HONEYCOMB, LEVEL_5_FREEZEEZY_PEAK), - RI(RI_HONEYCOMB_GOBIS_VALLEY, "a", "Honeycomb - GV", RITYPE_HONEYCOMB, ACTOR_50_HONEYCOMB, LEVEL_7_GOBIS_VALLEY), - RI(RI_HONEYCOMB_GRUNTILDAS_LAIR, "a", "Honeycomb - GL", RITYPE_HONEYCOMB, ACTOR_50_HONEYCOMB, LEVEL_6_LAIR), - RI(RI_HONEYCOMB_MAD_MONSTER_MANSION, "a", "Honeycomb - MMM", RITYPE_HONEYCOMB, ACTOR_50_HONEYCOMB, LEVEL_A_MAD_MONSTER_MANSION), - RI(RI_HONEYCOMB_MUMBOS_MOUNTAIN, "a", "Honeycomb - MM", RITYPE_HONEYCOMB, ACTOR_50_HONEYCOMB, LEVEL_1_MUMBOS_MOUNTAIN), - RI(RI_HONEYCOMB_RUSTY_BUCKET_BAY, "a", "Honeycomb - RBB", RITYPE_HONEYCOMB, ACTOR_50_HONEYCOMB, LEVEL_9_RUSTY_BUCKET_BAY), - RI(RI_HONEYCOMB_SPIRAL_MOUNTAIN, "a", "Honeycomb - SM", RITYPE_HONEYCOMB, ACTOR_50_HONEYCOMB, LEVEL_B_SPIRAL_MOUNTAIN), - RI(RI_HONEYCOMB_TREASURE_TROVE_COVE, "a", "Honeycomb - TTC", RITYPE_HONEYCOMB, ACTOR_50_HONEYCOMB, LEVEL_2_TREASURE_TROVE_COVE), + RI(RI_EXTRA_LIFE, "an", "Extra Life", RITYPE_EXTRA_LIFE, ACTOR_49_EXTRA_LIFE, LEVEL_D_CUTSCENE), + RI(RI_HONEYCOMB, "a", "Honeycomb", RITYPE_HONEYCOMB, ACTOR_50_HONEYCOMB, LEVEL_D_CUTSCENE), RI(RI_JIGGY_BUBBLEGLOOP_SWAMP, "a", "Jiggy - BGS", RITYPE_JIGGY, ACTOR_46_JIGGY, LEVEL_4_BUBBLEGLOOP_SWAMP), RI(RI_JIGGY_CLANKERS_CAVERN, "a", "Jiggy - CC", RITYPE_JIGGY, ACTOR_46_JIGGY, LEVEL_3_CLANKERS_CAVERN), RI(RI_JIGGY_CLICK_CLOCK_WOOD, "a", "Jiggy - CCW", RITYPE_JIGGY, ACTOR_46_JIGGY, LEVEL_8_CLICK_CLOCK_WOOD), diff --git a/src/port/Rando/Types.h b/src/port/Rando/Types.h index 8b32a24aa..49786a3a4 100644 --- a/src/port/Rando/Types.h +++ b/src/port/Rando/Types.h @@ -2046,49 +2046,19 @@ typedef enum { typedef enum { RI_UNKNOWN, - RI_BLUE_EGG_BUBBLEGLOOP_SWAMP, - RI_BLUE_EGG_CLANKERS_CAVERN, - RI_BLUE_EGG_CLICK_CLOCK_WOOD, - RI_BLUE_EGG_FREEZEEZY_PEAK, - RI_BLUE_EGG_GOBIS_VALLEY, - RI_BLUE_EGG_GRUNTILDAS_LAIR, - RI_BLUE_EGG_MAD_MONSTER_MANSION, - RI_BLUE_EGG_MUMBOS_MOUNTAIN, - RI_BLUE_EGG_RUSTY_BUCKET_BAY, - RI_BLUE_EGG_TREASURE_TROVE_COVE, + RI_BLUE_EGG, RI_EMPTY_HONEYCOMB_BUBBLEGLOOP_SWAMP, RI_EMPTY_HONEYCOMB_CLANKERS_CAVERN, RI_EMPTY_HONEYCOMB_CLICK_CLOCK_WOOD, RI_EMPTY_HONEYCOMB_FREEZEEZY_PEAK, RI_EMPTY_HONEYCOMB_GOBIS_VALLEY, - RI_EMPTY_HONEYCOMB_GRUNTILDAS_LAIR, RI_EMPTY_HONEYCOMB_MAD_MONSTER_MANSION, RI_EMPTY_HONEYCOMB_MUMBOS_MOUNTAIN, RI_EMPTY_HONEYCOMB_RUSTY_BUCKET_BAY, RI_EMPTY_HONEYCOMB_SPIRAL_MOUNTAIN, RI_EMPTY_HONEYCOMB_TREASURE_TROVE_COVE, - RI_EXTRA_LIFE_BUBBLEGLOOP_SWAMP, - RI_EXTRA_LIFE_CLANKERS_CAVERN, - RI_EXTRA_LIFE_CLICK_CLOCK_WOOD, - RI_EXTRA_LIFE_FREEZEEZY_PEAK, - RI_EXTRA_LIFE_GOBIS_VALLEY, - RI_EXTRA_LIFE_GRUNTILDAS_LAIR, - RI_EXTRA_LIFE_MAD_MONSTER_MANSION, - RI_EXTRA_LIFE_MUMBOS_MOUNTAIN, - RI_EXTRA_LIFE_RUSTY_BUCKET_BAY, - RI_EXTRA_LIFE_SPIRAL_MOUNTAIN, - RI_EXTRA_LIFE_TREASURE_TROVE_COVE, - RI_HONEYCOMB_BUBBLEGLOOP_SWAMP, - RI_HONEYCOMB_CLANKERS_CAVERN, - RI_HONEYCOMB_CLICK_CLOCK_WOOD, - RI_HONEYCOMB_FREEZEEZY_PEAK, - RI_HONEYCOMB_GOBIS_VALLEY, - RI_HONEYCOMB_GRUNTILDAS_LAIR, - RI_HONEYCOMB_MAD_MONSTER_MANSION, - RI_HONEYCOMB_MUMBOS_MOUNTAIN, - RI_HONEYCOMB_RUSTY_BUCKET_BAY, - RI_HONEYCOMB_SPIRAL_MOUNTAIN, - RI_HONEYCOMB_TREASURE_TROVE_COVE, + RI_EXTRA_LIFE, + RI_HONEYCOMB, RI_JIGGY_BUBBLEGLOOP_SWAMP, RI_JIGGY_CLANKERS_CAVERN, RI_JIGGY_CLICK_CLOCK_WOOD, diff --git a/src/port/UI/DeveloperTools/GameplayTools.cpp b/src/port/UI/DeveloperTools/GameplayTools.cpp index 7a8499e8c..399559d2e 100644 --- a/src/port/UI/DeveloperTools/GameplayTools.cpp +++ b/src/port/UI/DeveloperTools/GameplayTools.cpp @@ -70,7 +70,7 @@ int32_t selectedSnsItem = SNS_ITEM_EGG_YELLOW; int32_t selectedJiggy = JIGGY_01_MM_JINJO; int32_t selectedHoneycomb = HONEYCOMB_1_MM_HILL; int32_t selectedToken = MUMBOTOKEN_01_MM_STUMP_NEAR_CONGA; -int32_t selectedCustomCollectible = RI_EMPTY_HONEYCOMB_BUBBLEGLOOP_SWAMP; +int32_t selectedCustomCollectible = RC_BGS_BLUE_EGG_BEHIND_ENTRANCE_1; const char* mapNames[] = { "Mumbo's Mountain", "Treasure Trove Cove", "Clanker's Cavern", "Bubblegloop Swamp", "Freezeezy Peak", @@ -427,17 +427,17 @@ void GameplayTools_ObjectSpawner() { if (ImGui::BeginTable("ObjectSpawner", 2, ImGuiTableFlags_SizingStretchSame)) { ImGui::TableNextColumn(); if (UIWidgets::Button("Spawn Custom Collectible", { .color = THEME_COLOR })) { - Actor* newActor = CustomCollectible::Spawn(spawnPosition, (RandoItemId)selectedCustomCollectible); + Actor* newActor = CustomCollectible::Spawn(spawnPosition, (RandoCheckId)selectedCustomCollectible); } ImGui::TableNextColumn(); - std::string customCollectibleText = Rando::StaticData::Items[(RandoItemId)selectedCustomCollectible].name; + std::string customCollectibleText = Rando::StaticData::Checks[(RandoCheckId)selectedCustomCollectible].name; UIWidgets::SliderInt("##customCollectibleIndex", &selectedCustomCollectible, UIWidgets::IntSliderOptions() .Color(THEME_COLOR) - .Min(RI_UNKNOWN + 1) - .Max(RI_MAX - 1) - .DefaultValue(RI_EMPTY_HONEYCOMB_BUBBLEGLOOP_SWAMP) + .Min(RC_UNKNOWN + 1) + .Max(RC_MAX - 1) + .DefaultValue(RC_BGS_BLUE_EGG_BEHIND_ENTRANCE_1) .Format(customCollectibleText.c_str()) .LabelPosition(UIWidgets::LabelPositions::None)); ImGui::EndTable(); From 6c65366056fb70c9b3578243d9440918a8395f45 Mon Sep 17 00:00:00 2001 From: Malkierian Date: Sun, 2 Aug 2026 14:29:56 -0700 Subject: [PATCH 080/131] Update special thanks section in README --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index af137949f..8b021a139 100644 --- a/README.md +++ b/README.md @@ -108,5 +108,4 @@ If you want to playtest a continuous integration build, you can find them at the # Special Thanks: -* GiantJigglypuff3 for their extensive and continued Banjo Decomp documentation * Fredomato, scorched11 for work on rando From d96fca60c2f176b58d1350d06ecb61e00306b6bb Mon Sep 17 00:00:00 2001 From: aMannus Date: Mon, 3 Aug 2026 00:11:36 +0200 Subject: [PATCH 081/131] More item gives done --- src/port/Rando/ItemQueue.cpp | 76 ++++++ src/port/Rando/StaticData/Checks.cpp | 232 +++++++++---------- src/port/Rando/StaticData/Items.cpp | 11 +- src/port/Rando/Types.h | 11 +- src/port/UI/DeveloperTools/GameplayTools.cpp | 3 +- 5 files changed, 196 insertions(+), 137 deletions(-) diff --git a/src/port/Rando/ItemQueue.cpp b/src/port/Rando/ItemQueue.cpp index 80abe64d2..d1d7b9276 100644 --- a/src/port/Rando/ItemQueue.cpp +++ b/src/port/Rando/ItemQueue.cpp @@ -18,6 +18,10 @@ extern struct { u8 D_803832C0[0xD]; u8 D_803832CD[0xD]; } jiggyscore; +#define MUMBO_TOKEN_COUNT 126 +#define MUMBOSCORE_SIZE (((MUMBO_TOKEN_COUNT - 1 + 7) & ~7) / 8) +u8 sMumboTokenScore[MUMBOSCORE_SIZE]; +extern u8 D_80385FF0[0xE]; } #define CVAR_NAME_SHOW_COLLISION_NOTIFICATIONS "gRandoSettings.RandoNotifications" @@ -114,10 +118,82 @@ void ItemQueue::GiveItem(RandoItemId randoItemId) { case RITYPE_JINJO: break; case RITYPE_MOLEHILL: + coMusicPlayer_playMusic(COMUSIC_D_JINGLE_JIGGY_COLLECTED, -1); + switch (randoItemId) { + case RI_MOLEHILL_BARGE: + ability_unlock(ABILITY_0_BARGE); + break; + case RI_MOLEHILL_BEAK_BOMB: + ability_unlock(ABILITY_1_BEAK_BOMB); + break; + case RI_MOLEHILL_BEAK_BUSTER: + ability_unlock(ABILITY_2_BEAK_BUSTER); + break; + case RI_MOLEHILL_CAMERA_CONTROL: + ability_unlock(ABILITY_3_CAMERA_CONTROL); + break; + case RI_MOLEHILL_CLAW_SWIPE: + ability_unlock(ABILITY_4_CLAW_SWIPE); + ability_unlock(ABILITY_C_ROLL); + ability_unlock(ABILITY_B_RATATAT_RAP); + break; + case RI_MOLEHILL_CLIMB: + ability_unlock(ABILITY_5_CLIMB); + break; + case RI_MOLEHILL_DIVE: + ability_unlock(ABILITY_F_DIVE); + break; + case RI_MOLEHILL_EGGS: + ability_unlock(ABILITY_6_EGGS); + item_adjustByDiffWithHud(ITEM_D_EGGS, 50); + break; + case RI_MOLEHILL_FLAP_FLIP: + ability_unlock(ABILITY_A_HOLD_A_JUMP_HIGHER); + ability_unlock(ABILITY_7_FEATHERY_FLAP); + ability_unlock(ABILITY_8_FLAP_FLIP); + break; + case RI_MOLEHILL_FLIGHT: + ability_unlock(ABILITY_9_FLIGHT); + item_adjustByDiffWithHud(ITEM_F_RED_FEATHER, 25); + break; + case RI_MOLEHILL_SHOCK_JUMP: + ability_unlock(ABILITY_D_SHOCK_JUMP); + break; + case RI_MOLEHILL_TALON_TROT: + ability_unlock(ABILITY_10_TALON_TROT); + break; + case RI_MOLEHILL_TURBO_TALON: + ability_unlock(ABILITY_11_TURBO_TALON); + break; + case RI_MOLEHILL_WADING_BOOTS: + ability_unlock(ABILITY_E_WADING_BOOTS); + break; + case RI_MOLEHILL_WONDERWING: + ability_unlock(ABILITY_12_WONDERWING); + item_adjustByDiffWithHud(ITEM_10_GOLD_FEATHER, 5); + break; + default: + break; + } break; case RITYPE_MUMBO_TOKEN: + func_8030E760((sfx_e)0x401, 1.0f, 0x7fff); + for (uint32_t i = MUMBOTOKEN_01_MM_STUMP_NEAR_CONGA; + i <= MUMBOTOKEN_73_CCW_WINTER_SIR_SLUSH_BETWEEN_BIG_FLOWER_AND_MUMBOS_SKULL; i++) { + if ((sMumboTokenScore[(i - 1) / 8] & (1 << (i & 7))) == 0) { + mumboscore_set((mumbotoken_e)i, true); + break; + } + } + item_inc(ITEM_1C_MUMBO_TOKEN); break; case RITYPE_MUSIC_NOTE: + coMusicPlayer_playMusic(COMUSIC_9_NOTE_COLLECTED, 16000); + D_80385FF0[worldId]++; + if (worldId == map_getLevel(gsworld_getMap())) { + item_set(ITEM_C_NOTE, D_80385FF0[map_getLevel(gsworld_getMap())]); + } + // TODO: Add note data to savefile break; case RITYPE_SNS_EGG: break; diff --git a/src/port/Rando/StaticData/Checks.cpp b/src/port/Rando/StaticData/Checks.cpp index 2470f2866..5856ed647 100644 --- a/src/port/Rando/StaticData/Checks.cpp +++ b/src/port/Rando/StaticData/Checks.cpp @@ -109,16 +109,16 @@ std::map Checks = { RC(RC_BGS_JINJO_PINK, RCTYPE_JINJO, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_JINJO_PINK_BUBBLEGLOOP_SWAMP, NULL, 5670, 0, -4158), RC(RC_BGS_JINJO_YELLOW, RCTYPE_JINJO, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_JINJO_YELLOW_BUBBLEGLOOP_SWAMP, NULL, -1606, 500, 2797), RC(RC_BGS_MOLEHILL_WADING_BOOTS, RCTYPE_MOLEHILL, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_MOLEHILL_WADING_BOOTS, ABILITY_E_WADING_BOOTS, 4297, 100, 6286), - RC(RC_BGS_MUMBO_TOKEN_ALCOVE_ABOVE_YELLOW_FLIBBITS, RCTYPE_MUMBO_TOKEN, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_MUMBO_TOKEN_BUBBLEGLOOP_SWAMP, MUMBOTOKEN_1B_BGS_ALCOVE_ABOVE_YELLOW_FLIBBITS, 4278, 1400, -1302), - RC(RC_BGS_MUMBO_TOKEN_BEHIND_MUMBOS_SKULL, RCTYPE_MUMBO_TOKEN, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_MUMBO_TOKEN_BUBBLEGLOOP_SWAMP, MUMBOTOKEN_1A_BGS_BEHIND_MUMBOS_SKULL, -6940, 1000, -5838), - RC(RC_BGS_MUMBO_TOKEN_BEHIND_TIPTUP, RCTYPE_MUMBO_TOKEN, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_MUMBO_TOKEN_BUBBLEGLOOP_SWAMP, MUMBOTOKEN_1C_BGS_BEHIND_TIPTUP, 0, 0, -1829), - RC(RC_BGS_MUMBO_TOKEN_BEHIND_YELLOW_JINJO, RCTYPE_MUMBO_TOKEN, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_MUMBO_TOKEN_BUBBLEGLOOP_SWAMP, MUMBOTOKEN_18_BGS_BEHIND_YELLOW_JINJO, -1855, 0, 2835), - RC(RC_BGS_MUMBO_TOKEN_FLOATING_BETWEEN_HUT_AND_CROCTUS, RCTYPE_MUMBO_TOKEN, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_MUMBO_TOKEN_BUBBLEGLOOP_SWAMP, MUMBOTOKEN_19_BGS_FLOATING_BETWEEN_HUT_AND_CROCTUS, 6546, 2992, -4697), - RC(RC_BGS_MUMBO_TOKEN_INSIDE_MR_VILES, RCTYPE_MUMBO_TOKEN, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_MUMBO_TOKEN_BUBBLEGLOOP_SWAMP, MUMBOTOKEN_1D_BGS_INSIDE_MR_VILES, 0, 300, -1754), - RC(RC_BGS_MUMBO_TOKEN_INSIDE_MUMBOS_SKULL, RCTYPE_MUMBO_TOKEN, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_MUMBO_TOKEN_BUBBLEGLOOP_SWAMP, MUMBOTOKEN_1E_BGS_INSIDE_MUMBOS_SKULL, 0, 0, -450), - RC(RC_BGS_MUMBO_TOKEN_TOP_OF_POLE_NEXT_TO_BIG_EGG, RCTYPE_MUMBO_TOKEN, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_MUMBO_TOKEN_BUBBLEGLOOP_SWAMP, MUMBOTOKEN_17_BGS_TOP_OF_POLE_NEXT_TO_BIG_EGG, -3993, 1055, 1295), - RC(RC_BGS_MUMBO_TOKEN_UNDER_HUT_1, RCTYPE_MUMBO_TOKEN, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_MUMBO_TOKEN_BUBBLEGLOOP_SWAMP, MUMBOTOKEN_15_BGS_UNDER_HUT_1, 5049, 0, -5142), - RC(RC_BGS_MUMBO_TOKEN_UNDER_HUT_2, RCTYPE_MUMBO_TOKEN, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_MUMBO_TOKEN_BUBBLEGLOOP_SWAMP, MUMBOTOKEN_16_BGS_UNDER_HUT_2, 5347, 0, -5055), + RC(RC_BGS_MUMBO_TOKEN_ALCOVE_ABOVE_YELLOW_FLIBBITS, RCTYPE_MUMBO_TOKEN, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_MUMBO_TOKEN, MUMBOTOKEN_1B_BGS_ALCOVE_ABOVE_YELLOW_FLIBBITS, 4278, 1400, -1302), + RC(RC_BGS_MUMBO_TOKEN_BEHIND_MUMBOS_SKULL, RCTYPE_MUMBO_TOKEN, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_MUMBO_TOKEN, MUMBOTOKEN_1A_BGS_BEHIND_MUMBOS_SKULL, -6940, 1000, -5838), + RC(RC_BGS_MUMBO_TOKEN_BEHIND_TIPTUP, RCTYPE_MUMBO_TOKEN, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_MUMBO_TOKEN, MUMBOTOKEN_1C_BGS_BEHIND_TIPTUP, 0, 0, -1829), + RC(RC_BGS_MUMBO_TOKEN_BEHIND_YELLOW_JINJO, RCTYPE_MUMBO_TOKEN, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_MUMBO_TOKEN, MUMBOTOKEN_18_BGS_BEHIND_YELLOW_JINJO, -1855, 0, 2835), + RC(RC_BGS_MUMBO_TOKEN_FLOATING_BETWEEN_HUT_AND_CROCTUS, RCTYPE_MUMBO_TOKEN, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_MUMBO_TOKEN, MUMBOTOKEN_19_BGS_FLOATING_BETWEEN_HUT_AND_CROCTUS, 6546, 2992, -4697), + RC(RC_BGS_MUMBO_TOKEN_INSIDE_MR_VILES, RCTYPE_MUMBO_TOKEN, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_MUMBO_TOKEN, MUMBOTOKEN_1D_BGS_INSIDE_MR_VILES, 0, 300, -1754), + RC(RC_BGS_MUMBO_TOKEN_INSIDE_MUMBOS_SKULL, RCTYPE_MUMBO_TOKEN, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_MUMBO_TOKEN, MUMBOTOKEN_1E_BGS_INSIDE_MUMBOS_SKULL, 0, 0, -450), + RC(RC_BGS_MUMBO_TOKEN_TOP_OF_POLE_NEXT_TO_BIG_EGG, RCTYPE_MUMBO_TOKEN, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_MUMBO_TOKEN, MUMBOTOKEN_17_BGS_TOP_OF_POLE_NEXT_TO_BIG_EGG, -3993, 1055, 1295), + RC(RC_BGS_MUMBO_TOKEN_UNDER_HUT_1, RCTYPE_MUMBO_TOKEN, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_MUMBO_TOKEN, MUMBOTOKEN_15_BGS_UNDER_HUT_1, 5049, 0, -5142), + RC(RC_BGS_MUMBO_TOKEN_UNDER_HUT_2, RCTYPE_MUMBO_TOKEN, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_MUMBO_TOKEN, MUMBOTOKEN_16_BGS_UNDER_HUT_2, 5347, 0, -5055), RC(RC_BGS_NOTE_ABOVE_MR_VILES_1, RCTYPE_MUSIC_NOTE, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_MUSIC_NOTE_BUBBLEGLOOP_SWAMP, NULL, -912, 347, -3385), RC(RC_BGS_NOTE_ABOVE_MR_VILES_2, RCTYPE_MUSIC_NOTE, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_MUSIC_NOTE_BUBBLEGLOOP_SWAMP, NULL, -1073, 318, -3495), RC(RC_BGS_NOTE_ABOVE_MR_VILES_3, RCTYPE_MUSIC_NOTE, LEVEL_4_BUBBLEGLOOP_SWAMP, RI_MUSIC_NOTE_BUBBLEGLOOP_SWAMP, NULL, -1247, 405, -3608), @@ -293,11 +293,11 @@ std::map Checks = { RC(RC_CC_JINJO_PINK, RCTYPE_JINJO, LEVEL_3_CLANKERS_CAVERN, RI_JINJO_PINK_CLANKERS_CAVERN, NULL, 3644, -474, 48), RC(RC_CC_JINJO_YELLOW, RCTYPE_JINJO, LEVEL_3_CLANKERS_CAVERN, RI_JINJO_YELLOW_CLANKERS_CAVERN, NULL, -4726, 5337, -110), RC(RC_CC_MOLEHILL_WONDERWING, RCTYPE_MOLEHILL, LEVEL_3_CLANKERS_CAVERN, RI_MOLEHILL_WONDERWING, ABILITY_12_WONDERWING, -259, -500, 1413), - RC(RC_CC_MUMBO_TOKEN_CHOMPA_BEHIND_CLANKERS_TAIL, RCTYPE_MUMBO_TOKEN, LEVEL_3_CLANKERS_CAVERN, RI_MUMBO_TOKEN_CLANKERS_CAVERN, MUMBOTOKEN_10_CC_CHOMPA_BEHIND_CLANKERS_TAIL, 9823, 4225, -19), - RC(RC_CC_MUMBO_TOKEN_ABOVE_LEVEL_ENTRANCE, RCTYPE_MUMBO_TOKEN, LEVEL_3_CLANKERS_CAVERN, RI_MUMBO_TOKEN_CLANKERS_CAVERN, MUMBOTOKEN_11_CC_ABOVE_LEVEL_ENTRANCE, -9694, 5272, 1607), - RC(RC_CC_MUMBO_TOKEN_TUNNEL_RIGHT_OF_CLANKER, RCTYPE_MUMBO_TOKEN, LEVEL_3_CLANKERS_CAVERN, RI_MUMBO_TOKEN_CLANKERS_CAVERN, MUMBOTOKEN_12_CC_TUNNEL_RIGHT_OF_CLANKER, 870, 2146, -3148), - RC(RC_CC_MUMBO_TOKEN_ALCOVE_WITH_OPEN_GRATE, RCTYPE_MUMBO_TOKEN, LEVEL_3_CLANKERS_CAVERN, RI_MUMBO_TOKEN_CLANKERS_CAVERN, MUMBOTOKEN_13_CC_ALCOVE_WITH_OPEN_GRATE, 2028, 5456, 2344), - RC(RC_CC_MUMBO_TOKEN_CLANKERS_LEFT_TOOTH, RCTYPE_MUMBO_TOKEN, LEVEL_3_CLANKERS_CAVERN, RI_MUMBO_TOKEN_CLANKERS_CAVERN, MUMBOTOKEN_14_CC_CLANKERS_LEFT_TOOTH, 532, 1424, 6632), + RC(RC_CC_MUMBO_TOKEN_CHOMPA_BEHIND_CLANKERS_TAIL, RCTYPE_MUMBO_TOKEN, LEVEL_3_CLANKERS_CAVERN, RI_MUMBO_TOKEN, MUMBOTOKEN_10_CC_CHOMPA_BEHIND_CLANKERS_TAIL, 9823, 4225, -19), + RC(RC_CC_MUMBO_TOKEN_ABOVE_LEVEL_ENTRANCE, RCTYPE_MUMBO_TOKEN, LEVEL_3_CLANKERS_CAVERN, RI_MUMBO_TOKEN, MUMBOTOKEN_11_CC_ABOVE_LEVEL_ENTRANCE, -9694, 5272, 1607), + RC(RC_CC_MUMBO_TOKEN_TUNNEL_RIGHT_OF_CLANKER, RCTYPE_MUMBO_TOKEN, LEVEL_3_CLANKERS_CAVERN, RI_MUMBO_TOKEN, MUMBOTOKEN_12_CC_TUNNEL_RIGHT_OF_CLANKER, 870, 2146, -3148), + RC(RC_CC_MUMBO_TOKEN_ALCOVE_WITH_OPEN_GRATE, RCTYPE_MUMBO_TOKEN, LEVEL_3_CLANKERS_CAVERN, RI_MUMBO_TOKEN, MUMBOTOKEN_13_CC_ALCOVE_WITH_OPEN_GRATE, 2028, 5456, 2344), + RC(RC_CC_MUMBO_TOKEN_CLANKERS_LEFT_TOOTH, RCTYPE_MUMBO_TOKEN, LEVEL_3_CLANKERS_CAVERN, RI_MUMBO_TOKEN, MUMBOTOKEN_14_CC_CLANKERS_LEFT_TOOTH, 532, 1424, 6632), RC(RC_CC_NOTE_ABOVE_BOLT_1, RCTYPE_MUSIC_NOTE, LEVEL_3_CLANKERS_CAVERN, RI_MUSIC_NOTE_CLANKERS_CAVERN, NULL, 2036, 5693, -15), RC(RC_CC_NOTE_ABOVE_BOLT_2, RCTYPE_MUSIC_NOTE, LEVEL_3_CLANKERS_CAVERN, RI_MUSIC_NOTE_CLANKERS_CAVERN, NULL, 1533, 5693, 381), RC(RC_CC_NOTE_ABOVE_BOLT_3, RCTYPE_MUSIC_NOTE, LEVEL_3_CLANKERS_CAVERN, RI_MUSIC_NOTE_CLANKERS_CAVERN, NULL, 1043, 5693, 377), @@ -571,31 +571,31 @@ std::map Checks = { RC(RC_CCW_JINJO_ORANGE, RCTYPE_JINJO, LEVEL_8_CLICK_CLOCK_WOOD, RI_JINJO_ORANGE_CLICK_CLOCK_WOOD, NULL, -1592, 900, -6073), RC(RC_CCW_JINJO_PINK, RCTYPE_JINJO, LEVEL_8_CLICK_CLOCK_WOOD, RI_JINJO_PINK_CLICK_CLOCK_WOOD, NULL, -225, 1039, -1100), RC(RC_CCW_JINJO_YELLOW, RCTYPE_JINJO, LEVEL_8_CLICK_CLOCK_WOOD, RI_JINJO_YELLOW_CLICK_CLOCK_WOOD, NULL, -3602, 0, 4266), - RC(RC_CCW_MUMBO_TOKEN_AUTUMN_FLOATING_ABOVE_BIG_CLUCKER, RCTYPE_MUMBO_TOKEN, LEVEL_8_CLICK_CLOCK_WOOD, RI_MUMBO_TOKEN_CLICK_CLOCK_WOOD, MUMBOTOKEN_6A_CCW_AUTUMN_FLOATING_ABOVE_BIG_CLUCKER, 153, 1857, 2677), - RC(RC_CCW_MUMBO_TOKEN_AUTUMN_LEAF_NEAR_TREEHOUSE, RCTYPE_MUMBO_TOKEN, LEVEL_8_CLICK_CLOCK_WOOD, RI_MUMBO_TOKEN_CLICK_CLOCK_WOOD, MUMBOTOKEN_6D_CCW_AUTUMN_LEAF_NEAR_TREEHOUSE, 3405, 4107, 1003), - RC(RC_CCW_MUMBO_TOKEN_AUTUMN_SNAREBEAR_NEAR_ENTRANCE, RCTYPE_MUMBO_TOKEN, LEVEL_8_CLICK_CLOCK_WOOD, RI_MUMBO_TOKEN_CLICK_CLOCK_WOOD, MUMBOTOKEN_6B_CCW_AUTUMN_SNAREBEAR_NEAR_ENTRANCE, 500, 166, 5125), - RC(RC_CCW_MUMBO_TOKEN_AUTUMN_SNAREBEAR_TOP_OF_TREE, RCTYPE_MUMBO_TOKEN, LEVEL_8_CLICK_CLOCK_WOOD, RI_MUMBO_TOKEN_CLICK_CLOCK_WOOD, MUMBOTOKEN_6C_CCW_AUTUMN_SNAREBEAR_TOP_OF_TREE, 0, 5830, -3325), - RC(RC_CCW_MUMBO_TOKEN_AUTUMN_TOP_OF_BRANCH, RCTYPE_MUMBO_TOKEN, LEVEL_8_CLICK_CLOCK_WOOD, RI_MUMBO_TOKEN_CLICK_CLOCK_WOOD, MUMBOTOKEN_6E_CCW_AUTUMN_TOP_OF_BRANCH, -5929, 2586, 61), - RC(RC_CCW_MUMBO_TOKEN_SPRING_FRONT_OF_EYRIE, RCTYPE_MUMBO_TOKEN, LEVEL_8_CLICK_CLOCK_WOOD, RI_MUMBO_TOKEN_CLICK_CLOCK_WOOD, MUMBOTOKEN_5D_CCW_SPRING_FRONT_OF_EYRIE, -2750, 4586, -513), - RC(RC_CCW_MUMBO_TOKEN_SPRING_NABNUTS_HOUSE, RCTYPE_MUMBO_TOKEN, LEVEL_8_CLICK_CLOCK_WOOD, RI_MUMBO_TOKEN_CLICK_CLOCK_WOOD, MUMBOTOKEN_62_CCW_SPRING_NABNUTS_HOUSE, -575, 300, -139), - RC(RC_CCW_MUMBO_TOKEN_SPRING_SNAREBEAR_NEAR_BIG_FLOWER, RCTYPE_MUMBO_TOKEN, LEVEL_8_CLICK_CLOCK_WOOD, RI_MUMBO_TOKEN_CLICK_CLOCK_WOOD, MUMBOTOKEN_5F_CCW_SPRING_SNAREBEAR_NEAR_BIG_FLOWER, 1904, 105, -2706), - RC(RC_CCW_MUMBO_TOKEN_SPRING_SNAREBEAR_NEAR_ENTRANCE, RCTYPE_MUMBO_TOKEN, LEVEL_8_CLICK_CLOCK_WOOD, RI_MUMBO_TOKEN_CLICK_CLOCK_WOOD, MUMBOTOKEN_60_CCW_SPRING_SNAREBEAR_NEAR_ENTRANCE, 1000, 105, 5300), - RC(RC_CCW_MUMBO_TOKEN_SPRING_THORN_FIELD_FRONT_OF_MUMBOS_SKULL, RCTYPE_MUMBO_TOKEN, LEVEL_8_CLICK_CLOCK_WOOD, RI_MUMBO_TOKEN_CLICK_CLOCK_WOOD, MUMBOTOKEN_5E_CCW_SPRING_THORN_FIELD_FRONT_OF_MUMBOS_SKULL, -2649, 0, -395), - RC(RC_CCW_MUMBO_TOKEN_SPRING_TOP_OF_BEEHIVE, RCTYPE_MUMBO_TOKEN, LEVEL_8_CLICK_CLOCK_WOOD, RI_MUMBO_TOKEN_CLICK_CLOCK_WOOD, MUMBOTOKEN_61_CCW_SPRING_TOP_OF_BEEHIVE, 0, 3513, -5240), - RC(RC_CCW_MUMBO_TOKEN_SPRING_TOP_OF_BRANCH, RCTYPE_MUMBO_TOKEN, LEVEL_8_CLICK_CLOCK_WOOD, RI_MUMBO_TOKEN_CLICK_CLOCK_WOOD, MUMBOTOKEN_5C_CCW_SPRING_TOP_OF_BRANCH, -4053, 2894, 587), - RC(RC_CCW_MUMBO_TOKEN_SPRING_UNFINISHED_WOOD_TREEHOUSE, RCTYPE_MUMBO_TOKEN, LEVEL_8_CLICK_CLOCK_WOOD, RI_MUMBO_TOKEN_CLICK_CLOCK_WOOD, MUMBOTOKEN_5B_CCW_SPRING_UNFINISHED_WOOD_TREEHOUSE, 6134, 4244, 306), - RC(RC_CCW_MUMBO_TOKEN_SUMMER_BIG_FLOWER_FIELD, RCTYPE_MUMBO_TOKEN, LEVEL_8_CLICK_CLOCK_WOOD, RI_MUMBO_TOKEN_CLICK_CLOCK_WOOD, MUMBOTOKEN_64_CCW_SUMMER_BIG_FLOWER_FIELD, -3578, 40, -4259), - RC(RC_CCW_MUMBO_TOKEN_SUMMER_ENTRANCE_GNAWTYS_HOUSE, RCTYPE_MUMBO_TOKEN, LEVEL_8_CLICK_CLOCK_WOOD, RI_MUMBO_TOKEN_CLICK_CLOCK_WOOD, MUMBOTOKEN_67_CCW_SUMMER_ENTRANCE_GNAWTYS_HOUSE, 2700, -600, 0), - RC(RC_CCW_MUMBO_TOKEN_SUMMER_FLOATING_ABOVE_BIG_CLUCKER, RCTYPE_MUMBO_TOKEN, LEVEL_8_CLICK_CLOCK_WOOD, RI_MUMBO_TOKEN_CLICK_CLOCK_WOOD, MUMBOTOKEN_68_CCW_SUMMER_FLOATING_ABOVE_BIG_CLUCKER, 2043, 3534, 1799), - RC(RC_CCW_MUMBO_TOKEN_SUMMER_INSIDE_MUMBOS_SKULL, RCTYPE_MUMBO_TOKEN, LEVEL_8_CLICK_CLOCK_WOOD, RI_MUMBO_TOKEN_CLICK_CLOCK_WOOD, MUMBOTOKEN_69_CCW_SUMMER_INSIDE_MUMBOS_SKULL, 0, 416, 500), - RC(RC_CCW_MUMBO_TOKEN_SUMMER_PLATFORMS_BEFORE_EYRIES_NEST, RCTYPE_MUMBO_TOKEN, LEVEL_8_CLICK_CLOCK_WOOD, RI_MUMBO_TOKEN_CLICK_CLOCK_WOOD, MUMBOTOKEN_63_CCW_SUMMER_PLATFORMS_BEFORE_EYRIES_NEST, -1861, 4469, 1583), - RC(RC_CCW_MUMBO_TOKEN_SUMMER_SNAREBEAR_NEAR_THORN_FIELD, RCTYPE_MUMBO_TOKEN, LEVEL_8_CLICK_CLOCK_WOOD, RI_MUMBO_TOKEN_CLICK_CLOCK_WOOD, MUMBOTOKEN_65_CCW_SUMMER_SNAREBEAR_NEAR_THORN_FIELD, -3855, 1428, 3840), - RC(RC_CCW_MUMBO_TOKEN_SUMMER_TOP_OF_BRANCH, RCTYPE_MUMBO_TOKEN, LEVEL_8_CLICK_CLOCK_WOOD, RI_MUMBO_TOKEN_CLICK_CLOCK_WOOD, MUMBOTOKEN_66_CCW_SUMMER_TOP_OF_BRANCH, -4661, 2800, -1248), - RC(RC_CCW_MUMBO_TOKEN_WINTER_BIG_FLOWER, RCTYPE_MUMBO_TOKEN, LEVEL_8_CLICK_CLOCK_WOOD, RI_MUMBO_TOKEN_CLICK_CLOCK_WOOD, MUMBOTOKEN_6F_CCW_WINTER_BIG_FLOWER, 0, 105, -5400), - RC(RC_CCW_MUMBO_TOKEN_WINTER_BROKEN_BEEHIVE, RCTYPE_MUMBO_TOKEN, LEVEL_8_CLICK_CLOCK_WOOD, RI_MUMBO_TOKEN_CLICK_CLOCK_WOOD, MUMBOTOKEN_71_CCW_WINTER_BROKEN_BEEHIVE, 0, 3138, -3696), - RC(RC_CCW_MUMBO_TOKEN_WINTER_FROZEN_RIVER_NEAR_FLIGHT_PAD, RCTYPE_MUMBO_TOKEN, LEVEL_8_CLICK_CLOCK_WOOD, RI_MUMBO_TOKEN_CLICK_CLOCK_WOOD, MUMBOTOKEN_70_CCW_WINTER_FROZEN_RIVER_NEAR_FLIGHT_PAD, 5950, -46, 0), - RC(RC_CCW_MUMBO_TOKEN_WINTER_SIR_SLUSH_BETWEEN_BIG_FLOWER_AND_MUMBOS_SKULL, RCTYPE_MUMBO_TOKEN, LEVEL_8_CLICK_CLOCK_WOOD, RI_MUMBO_TOKEN_CLICK_CLOCK_WOOD, MUMBOTOKEN_73_CCW_WINTER_SIR_SLUSH_BETWEEN_BIG_FLOWER_AND_MUMBOS_SKULL, -3157, 300, -3149), - RC(RC_CCW_MUMBO_TOKEN_WINTER_WALKWAY_FRONT_OF_NABNUTS_HOUSE, RCTYPE_MUMBO_TOKEN, LEVEL_8_CLICK_CLOCK_WOOD, RI_MUMBO_TOKEN_CLICK_CLOCK_WOOD, MUMBOTOKEN_72_CCW_WINTER_WALKWAY_FRONT_OF_NABNUTS_HOUSE, 40, 3969, 5000), + RC(RC_CCW_MUMBO_TOKEN_AUTUMN_FLOATING_ABOVE_BIG_CLUCKER, RCTYPE_MUMBO_TOKEN, LEVEL_8_CLICK_CLOCK_WOOD, RI_MUMBO_TOKEN, MUMBOTOKEN_6A_CCW_AUTUMN_FLOATING_ABOVE_BIG_CLUCKER, 153, 1857, 2677), + RC(RC_CCW_MUMBO_TOKEN_AUTUMN_LEAF_NEAR_TREEHOUSE, RCTYPE_MUMBO_TOKEN, LEVEL_8_CLICK_CLOCK_WOOD, RI_MUMBO_TOKEN, MUMBOTOKEN_6D_CCW_AUTUMN_LEAF_NEAR_TREEHOUSE, 3405, 4107, 1003), + RC(RC_CCW_MUMBO_TOKEN_AUTUMN_SNAREBEAR_NEAR_ENTRANCE, RCTYPE_MUMBO_TOKEN, LEVEL_8_CLICK_CLOCK_WOOD, RI_MUMBO_TOKEN, MUMBOTOKEN_6B_CCW_AUTUMN_SNAREBEAR_NEAR_ENTRANCE, 500, 166, 5125), + RC(RC_CCW_MUMBO_TOKEN_AUTUMN_SNAREBEAR_TOP_OF_TREE, RCTYPE_MUMBO_TOKEN, LEVEL_8_CLICK_CLOCK_WOOD, RI_MUMBO_TOKEN, MUMBOTOKEN_6C_CCW_AUTUMN_SNAREBEAR_TOP_OF_TREE, 0, 5830, -3325), + RC(RC_CCW_MUMBO_TOKEN_AUTUMN_TOP_OF_BRANCH, RCTYPE_MUMBO_TOKEN, LEVEL_8_CLICK_CLOCK_WOOD, RI_MUMBO_TOKEN, MUMBOTOKEN_6E_CCW_AUTUMN_TOP_OF_BRANCH, -5929, 2586, 61), + RC(RC_CCW_MUMBO_TOKEN_SPRING_FRONT_OF_EYRIE, RCTYPE_MUMBO_TOKEN, LEVEL_8_CLICK_CLOCK_WOOD, RI_MUMBO_TOKEN, MUMBOTOKEN_5D_CCW_SPRING_FRONT_OF_EYRIE, -2750, 4586, -513), + RC(RC_CCW_MUMBO_TOKEN_SPRING_NABNUTS_HOUSE, RCTYPE_MUMBO_TOKEN, LEVEL_8_CLICK_CLOCK_WOOD, RI_MUMBO_TOKEN, MUMBOTOKEN_62_CCW_SPRING_NABNUTS_HOUSE, -575, 300, -139), + RC(RC_CCW_MUMBO_TOKEN_SPRING_SNAREBEAR_NEAR_BIG_FLOWER, RCTYPE_MUMBO_TOKEN, LEVEL_8_CLICK_CLOCK_WOOD, RI_MUMBO_TOKEN, MUMBOTOKEN_5F_CCW_SPRING_SNAREBEAR_NEAR_BIG_FLOWER, 1904, 105, -2706), + RC(RC_CCW_MUMBO_TOKEN_SPRING_SNAREBEAR_NEAR_ENTRANCE, RCTYPE_MUMBO_TOKEN, LEVEL_8_CLICK_CLOCK_WOOD, RI_MUMBO_TOKEN, MUMBOTOKEN_60_CCW_SPRING_SNAREBEAR_NEAR_ENTRANCE, 1000, 105, 5300), + RC(RC_CCW_MUMBO_TOKEN_SPRING_THORN_FIELD_FRONT_OF_MUMBOS_SKULL, RCTYPE_MUMBO_TOKEN, LEVEL_8_CLICK_CLOCK_WOOD, RI_MUMBO_TOKEN, MUMBOTOKEN_5E_CCW_SPRING_THORN_FIELD_FRONT_OF_MUMBOS_SKULL, -2649, 0, -395), + RC(RC_CCW_MUMBO_TOKEN_SPRING_TOP_OF_BEEHIVE, RCTYPE_MUMBO_TOKEN, LEVEL_8_CLICK_CLOCK_WOOD, RI_MUMBO_TOKEN, MUMBOTOKEN_61_CCW_SPRING_TOP_OF_BEEHIVE, 0, 3513, -5240), + RC(RC_CCW_MUMBO_TOKEN_SPRING_TOP_OF_BRANCH, RCTYPE_MUMBO_TOKEN, LEVEL_8_CLICK_CLOCK_WOOD, RI_MUMBO_TOKEN, MUMBOTOKEN_5C_CCW_SPRING_TOP_OF_BRANCH, -4053, 2894, 587), + RC(RC_CCW_MUMBO_TOKEN_SPRING_UNFINISHED_WOOD_TREEHOUSE, RCTYPE_MUMBO_TOKEN, LEVEL_8_CLICK_CLOCK_WOOD, RI_MUMBO_TOKEN, MUMBOTOKEN_5B_CCW_SPRING_UNFINISHED_WOOD_TREEHOUSE, 6134, 4244, 306), + RC(RC_CCW_MUMBO_TOKEN_SUMMER_BIG_FLOWER_FIELD, RCTYPE_MUMBO_TOKEN, LEVEL_8_CLICK_CLOCK_WOOD, RI_MUMBO_TOKEN, MUMBOTOKEN_64_CCW_SUMMER_BIG_FLOWER_FIELD, -3578, 40, -4259), + RC(RC_CCW_MUMBO_TOKEN_SUMMER_ENTRANCE_GNAWTYS_HOUSE, RCTYPE_MUMBO_TOKEN, LEVEL_8_CLICK_CLOCK_WOOD, RI_MUMBO_TOKEN, MUMBOTOKEN_67_CCW_SUMMER_ENTRANCE_GNAWTYS_HOUSE, 2700, -600, 0), + RC(RC_CCW_MUMBO_TOKEN_SUMMER_FLOATING_ABOVE_BIG_CLUCKER, RCTYPE_MUMBO_TOKEN, LEVEL_8_CLICK_CLOCK_WOOD, RI_MUMBO_TOKEN, MUMBOTOKEN_68_CCW_SUMMER_FLOATING_ABOVE_BIG_CLUCKER, 2043, 3534, 1799), + RC(RC_CCW_MUMBO_TOKEN_SUMMER_INSIDE_MUMBOS_SKULL, RCTYPE_MUMBO_TOKEN, LEVEL_8_CLICK_CLOCK_WOOD, RI_MUMBO_TOKEN, MUMBOTOKEN_69_CCW_SUMMER_INSIDE_MUMBOS_SKULL, 0, 416, 500), + RC(RC_CCW_MUMBO_TOKEN_SUMMER_PLATFORMS_BEFORE_EYRIES_NEST, RCTYPE_MUMBO_TOKEN, LEVEL_8_CLICK_CLOCK_WOOD, RI_MUMBO_TOKEN, MUMBOTOKEN_63_CCW_SUMMER_PLATFORMS_BEFORE_EYRIES_NEST, -1861, 4469, 1583), + RC(RC_CCW_MUMBO_TOKEN_SUMMER_SNAREBEAR_NEAR_THORN_FIELD, RCTYPE_MUMBO_TOKEN, LEVEL_8_CLICK_CLOCK_WOOD, RI_MUMBO_TOKEN, MUMBOTOKEN_65_CCW_SUMMER_SNAREBEAR_NEAR_THORN_FIELD, -3855, 1428, 3840), + RC(RC_CCW_MUMBO_TOKEN_SUMMER_TOP_OF_BRANCH, RCTYPE_MUMBO_TOKEN, LEVEL_8_CLICK_CLOCK_WOOD, RI_MUMBO_TOKEN, MUMBOTOKEN_66_CCW_SUMMER_TOP_OF_BRANCH, -4661, 2800, -1248), + RC(RC_CCW_MUMBO_TOKEN_WINTER_BIG_FLOWER, RCTYPE_MUMBO_TOKEN, LEVEL_8_CLICK_CLOCK_WOOD, RI_MUMBO_TOKEN, MUMBOTOKEN_6F_CCW_WINTER_BIG_FLOWER, 0, 105, -5400), + RC(RC_CCW_MUMBO_TOKEN_WINTER_BROKEN_BEEHIVE, RCTYPE_MUMBO_TOKEN, LEVEL_8_CLICK_CLOCK_WOOD, RI_MUMBO_TOKEN, MUMBOTOKEN_71_CCW_WINTER_BROKEN_BEEHIVE, 0, 3138, -3696), + RC(RC_CCW_MUMBO_TOKEN_WINTER_FROZEN_RIVER_NEAR_FLIGHT_PAD, RCTYPE_MUMBO_TOKEN, LEVEL_8_CLICK_CLOCK_WOOD, RI_MUMBO_TOKEN, MUMBOTOKEN_70_CCW_WINTER_FROZEN_RIVER_NEAR_FLIGHT_PAD, 5950, -46, 0), + RC(RC_CCW_MUMBO_TOKEN_WINTER_SIR_SLUSH_BETWEEN_BIG_FLOWER_AND_MUMBOS_SKULL, RCTYPE_MUMBO_TOKEN, LEVEL_8_CLICK_CLOCK_WOOD, RI_MUMBO_TOKEN, MUMBOTOKEN_73_CCW_WINTER_SIR_SLUSH_BETWEEN_BIG_FLOWER_AND_MUMBOS_SKULL, -3157, 300, -3149), + RC(RC_CCW_MUMBO_TOKEN_WINTER_WALKWAY_FRONT_OF_NABNUTS_HOUSE, RCTYPE_MUMBO_TOKEN, LEVEL_8_CLICK_CLOCK_WOOD, RI_MUMBO_TOKEN, MUMBOTOKEN_72_CCW_WINTER_WALKWAY_FRONT_OF_NABNUTS_HOUSE, 40, 3969, 5000), RC(RC_CCW_NOTE_AUTUMN_BEEHIVE_INTERIOR_1, RCTYPE_MUSIC_NOTE, LEVEL_8_CLICK_CLOCK_WOOD, RI_MUSIC_NOTE_CLICK_CLOCK_WOOD, NULL, -674, -1, 925), RC(RC_CCW_NOTE_AUTUMN_BEEHIVE_INTERIOR_2, RCTYPE_MUSIC_NOTE, LEVEL_8_CLICK_CLOCK_WOOD, RI_MUSIC_NOTE_CLICK_CLOCK_WOOD, NULL, -674, 0, -900), RC(RC_CCW_NOTE_AUTUMN_BEEHIVE_INTERIOR_3, RCTYPE_MUSIC_NOTE, LEVEL_8_CLICK_CLOCK_WOOD, RI_MUSIC_NOTE_CLICK_CLOCK_WOOD, NULL, 675, -2, 925), @@ -780,16 +780,16 @@ std::map Checks = { RC(RC_FP_JINJO_PINK, RCTYPE_JINJO, LEVEL_5_FREEZEEZY_PEAK, RI_JINJO_PINK_FREEZEEZY_PEAK, NULL, -6851, 1193, 930), RC(RC_FP_JINJO_YELLOW, RCTYPE_JINJO, LEVEL_5_FREEZEEZY_PEAK, RI_JINJO_YELLOW_FREEZEEZY_PEAK, NULL, 0, 406, -511), RC(RC_FP_MOLEHILL_BEAK_BOMB, RCTYPE_MOLEHILL, LEVEL_5_FREEZEEZY_PEAK, RI_MOLEHILL_BEAK_BOMB, ABILITY_1_BEAK_BOMB, -7462, 250, 1324), - RC(RC_FP_MUMBO_TOKEN_INSIDE_BOGGYS_IGLOO, RCTYPE_MUMBO_TOKEN, LEVEL_5_FREEZEEZY_PEAK, RI_MUMBO_TOKEN_FREEZEEZY_PEAK, MUMBOTOKEN_28_FP_INSIDE_BOGGYS_IGLOO, 0, 10, -215), - RC(RC_FP_MUMBO_TOKEN_PRESENT_STACK, RCTYPE_MUMBO_TOKEN, LEVEL_5_FREEZEEZY_PEAK, RI_MUMBO_TOKEN_FREEZEEZY_PEAK, MUMBOTOKEN_21_FP_BEHIND_PILE_PRESENT_BOXES, -5904, 260, 794), - RC(RC_FP_MUMBO_TOKEN_POTTED_TREE, RCTYPE_MUMBO_TOKEN, LEVEL_5_FREEZEEZY_PEAK, RI_MUMBO_TOKEN_FREEZEEZY_PEAK, MUMBOTOKEN_25_FP_CHRISTMAS_TREE_POT, -4590, 350, 6344), - RC(RC_FP_MUMBO_TOKEN_SIR_SLUSH_NEAR_RACE_START, RCTYPE_MUMBO_TOKEN, LEVEL_5_FREEZEEZY_PEAK, RI_MUMBO_TOKEN_FREEZEEZY_PEAK, MUMBOTOKEN_23_FP_INSIDE_SIR_SLUSH_NEAR_SNOWMANS_LEFT_FOOT, 1413, 18, 2802), - RC(RC_FP_MUMBO_TOKEN_SIR_SLUSH_NEAR_RACE_FINISH, RCTYPE_MUMBO_TOKEN, LEVEL_5_FREEZEEZY_PEAK, RI_MUMBO_TOKEN_FREEZEEZY_PEAK, MUMBOTOKEN_24_FP_INSIDE_SIR_SLUSH_NEAR_SNOWMANS_RIGHT_FOOT, -4527, 211, -803), - RC(RC_FP_MUMBO_TOKEN_SLED_TO_BOGGY, RCTYPE_MUMBO_TOKEN, LEVEL_5_FREEZEEZY_PEAK, RI_MUMBO_TOKEN_FREEZEEZY_PEAK, MUMBOTOKEN_26_FP_TIP_OF_SCARF, -793, 3020, 4389), - RC(RC_FP_MUMBO_TOKEN_SNOWMAN_LEFT_FOOT, RCTYPE_MUMBO_TOKEN, LEVEL_5_FREEZEEZY_PEAK, RI_MUMBO_TOKEN_FREEZEEZY_PEAK, MUMBOTOKEN_1F_FP_SNOWMAN_LEFT_FOOT, -1815, 4, -1019), - RC(RC_FP_MUMBO_TOKEN_SNOWMAN_RIGHT_FOOT, RCTYPE_MUMBO_TOKEN, LEVEL_5_FREEZEEZY_PEAK, RI_MUMBO_TOKEN_FREEZEEZY_PEAK, MUMBOTOKEN_20_FP_SNOWMAN_RIGHT_FOOT, 634, 5, 769), - RC(RC_FP_MUMBO_TOKEN_VILLAGE_CHIMNEY, RCTYPE_MUMBO_TOKEN, LEVEL_5_FREEZEEZY_PEAK, RI_MUMBO_TOKEN_FREEZEEZY_PEAK, MUMBOTOKEN_22_FP_ABOVE_CHIMNEY_FLIGHT_PAD, 5296, 2013, 2729), - RC(RC_FP_MUMBO_TOKEN_WATER_BEHIND_SNOWMAN, RCTYPE_MUMBO_TOKEN, LEVEL_5_FREEZEEZY_PEAK, RI_MUMBO_TOKEN_FREEZEEZY_PEAK, MUMBOTOKEN_27_FP_WATER_BEHIND_SNOWMAN, -2424, -168, -4235), + RC(RC_FP_MUMBO_TOKEN_INSIDE_BOGGYS_IGLOO, RCTYPE_MUMBO_TOKEN, LEVEL_5_FREEZEEZY_PEAK, RI_MUMBO_TOKEN, MUMBOTOKEN_28_FP_INSIDE_BOGGYS_IGLOO, 0, 10, -215), + RC(RC_FP_MUMBO_TOKEN_PRESENT_STACK, RCTYPE_MUMBO_TOKEN, LEVEL_5_FREEZEEZY_PEAK, RI_MUMBO_TOKEN, MUMBOTOKEN_21_FP_BEHIND_PILE_PRESENT_BOXES, -5904, 260, 794), + RC(RC_FP_MUMBO_TOKEN_POTTED_TREE, RCTYPE_MUMBO_TOKEN, LEVEL_5_FREEZEEZY_PEAK, RI_MUMBO_TOKEN, MUMBOTOKEN_25_FP_CHRISTMAS_TREE_POT, -4590, 350, 6344), + RC(RC_FP_MUMBO_TOKEN_SIR_SLUSH_NEAR_RACE_START, RCTYPE_MUMBO_TOKEN, LEVEL_5_FREEZEEZY_PEAK, RI_MUMBO_TOKEN, MUMBOTOKEN_23_FP_INSIDE_SIR_SLUSH_NEAR_SNOWMANS_LEFT_FOOT, 1413, 18, 2802), + RC(RC_FP_MUMBO_TOKEN_SIR_SLUSH_NEAR_RACE_FINISH, RCTYPE_MUMBO_TOKEN, LEVEL_5_FREEZEEZY_PEAK, RI_MUMBO_TOKEN, MUMBOTOKEN_24_FP_INSIDE_SIR_SLUSH_NEAR_SNOWMANS_RIGHT_FOOT, -4527, 211, -803), + RC(RC_FP_MUMBO_TOKEN_SLED_TO_BOGGY, RCTYPE_MUMBO_TOKEN, LEVEL_5_FREEZEEZY_PEAK, RI_MUMBO_TOKEN, MUMBOTOKEN_26_FP_TIP_OF_SCARF, -793, 3020, 4389), + RC(RC_FP_MUMBO_TOKEN_SNOWMAN_LEFT_FOOT, RCTYPE_MUMBO_TOKEN, LEVEL_5_FREEZEEZY_PEAK, RI_MUMBO_TOKEN, MUMBOTOKEN_1F_FP_SNOWMAN_LEFT_FOOT, -1815, 4, -1019), + RC(RC_FP_MUMBO_TOKEN_SNOWMAN_RIGHT_FOOT, RCTYPE_MUMBO_TOKEN, LEVEL_5_FREEZEEZY_PEAK, RI_MUMBO_TOKEN, MUMBOTOKEN_20_FP_SNOWMAN_RIGHT_FOOT, 634, 5, 769), + RC(RC_FP_MUMBO_TOKEN_VILLAGE_CHIMNEY, RCTYPE_MUMBO_TOKEN, LEVEL_5_FREEZEEZY_PEAK, RI_MUMBO_TOKEN, MUMBOTOKEN_22_FP_ABOVE_CHIMNEY_FLIGHT_PAD, 5296, 2013, 2729), + RC(RC_FP_MUMBO_TOKEN_WATER_BEHIND_SNOWMAN, RCTYPE_MUMBO_TOKEN, LEVEL_5_FREEZEEZY_PEAK, RI_MUMBO_TOKEN, MUMBOTOKEN_27_FP_WATER_BEHIND_SNOWMAN, -2424, -168, -4235), RC(RC_FP_NOTE_FIRST_SLOPE_1, RCTYPE_MUSIC_NOTE, LEVEL_5_FREEZEEZY_PEAK, RI_MUSIC_NOTE_FREEZEEZY_PEAK, NULL, -790, 3505, 8345), RC(RC_FP_NOTE_FIRST_SLOPE_2, RCTYPE_MUSIC_NOTE, LEVEL_5_FREEZEEZY_PEAK, RI_MUSIC_NOTE_FREEZEEZY_PEAK, NULL, -820, 3149, 7926), RC(RC_FP_NOTE_FIRST_SLOPE_3, RCTYPE_MUSIC_NOTE, LEVEL_5_FREEZEEZY_PEAK, RI_MUSIC_NOTE_FREEZEEZY_PEAK, NULL, -843, 2725, 7475), @@ -1004,16 +1004,16 @@ std::map Checks = { RC(RC_GL_JIGGY_WITCH_SWITCH_MUMBOS_MOUNTAIN, RCTYPE_JIGGY, LEVEL_6_LAIR, RI_JIGGY_GRUNTILDAS_LAIR, JIGGY_34_LAIR_MM_WITCH_SWITCH, 4165, 1000, -2363), RC(RC_GL_JIGGY_WITCH_SWITCH_RUSTY_BUCKET_BAY, RCTYPE_JIGGY, LEVEL_6_LAIR, RI_JIGGY_GRUNTILDAS_LAIR, JIGGY_3B_LAIR_RBB_WITCH_SWITCH, 0, 1200, 1650), RC(RC_GL_JIGGY_WITCH_SWITCH_TREASURE_TROVE_COVE, RCTYPE_JIGGY, LEVEL_6_LAIR, RI_JIGGY_GRUNTILDAS_LAIR, JIGGY_36_LAIR_TTC_WITCH_SWITCH, 998, 783, 368), - RC(RC_GL_MUMBO_TOKEN_BEHIND_PURPLE_CAULDRON, RCTYPE_MUMBO_TOKEN, LEVEL_6_LAIR, RI_MUMBO_TOKEN_GRUNTILDAS_LAIR, MUMBOTOKEN_51_LAIR_BEHIND_PURPLE_CAULDRON, 162, -750, 4611), - RC(RC_GL_MUMBO_TOKEN_TOP_OF_PIPE_IN_ORANGE_CAULDRON_ROOM, RCTYPE_MUMBO_TOKEN, LEVEL_6_LAIR, RI_MUMBO_TOKEN_GRUNTILDAS_LAIR, MUMBOTOKEN_53_LAIR_TOP_OF_PIPE_IN_ORANGE_CAULDRON_ROOM, -180, 351, -750), - RC(RC_GL_MUMBO_TOKEN_ABOVE_CC_ENTRANCE, RCTYPE_MUMBO_TOKEN, LEVEL_6_LAIR, RI_MUMBO_TOKEN_GRUNTILDAS_LAIR, MUMBOTOKEN_54_LAIR_ABOVE_CC_ENTRANCE, 0, 850, -2450), - RC(RC_GL_MUMBO_TOKEN_CCW_JIGGY_PODIUM, RCTYPE_MUMBO_TOKEN, LEVEL_6_LAIR, RI_MUMBO_TOKEN_GRUNTILDAS_LAIR, MUMBOTOKEN_52_LAIR_CCW_JIGGY_PODIUM, 4936, -478, 286), - RC(RC_GL_MUMBO_TOKEN_BEHIND_SARCOPHAGUS, RCTYPE_MUMBO_TOKEN, LEVEL_6_LAIR, RI_MUMBO_TOKEN_GRUNTILDAS_LAIR, MUMBOTOKEN_55_LAIR_BEHIND_SARCOPHAGUS, -1486, 0, -922), - RC(RC_GL_MUMBO_TOKEN_ADVENT_TOP_WINDOW, RCTYPE_MUMBO_TOKEN, LEVEL_6_LAIR, RI_MUMBO_TOKEN_GRUNTILDAS_LAIR, MUMBOTOKEN_56_LAIR_ADVENT_TOP_WINDOW, 4155, 1485, 6270), - RC(RC_GL_MUMBO_TOKEN_UNDERWATER_RBB_ENTRANCE_AREA, RCTYPE_MUMBO_TOKEN, LEVEL_6_LAIR, RI_MUMBO_TOKEN_GRUNTILDAS_LAIR, MUMBOTOKEN_59_LAIR_UNDERWATER_RBB_ENTRANCE_AREA, 1764, -1400, -1136), - RC(RC_GL_MUMBO_TOKEN_WHIPCRACK_NEAR_MMM_JIGGY_PODIUM, RCTYPE_MUMBO_TOKEN, LEVEL_6_LAIR, RI_MUMBO_TOKEN_GRUNTILDAS_LAIR, MUMBOTOKEN_5A_LAIR_WHIPCRACK_NEAR_MMM_JIGGY_PODIUM, -1140, 707, 1973), - RC(RC_GL_MUMBO_TOKEN_BEHIND_MUMBO_IN_CRYPT, RCTYPE_MUMBO_TOKEN, LEVEL_6_LAIR, RI_MUMBO_TOKEN_GRUNTILDAS_LAIR, MUMBOTOKEN_57_LAIR_BEHIND_MUMBO_IN_CRYPT, 1488, 249, 0), - RC(RC_GL_MUMBO_TOKEN_ABOVE_NOTE_DOOR_WATER_AREA, RCTYPE_MUMBO_TOKEN, LEVEL_6_LAIR, RI_MUMBO_TOKEN_GRUNTILDAS_LAIR, MUMBOTOKEN_58_LAIR_ABOVE_NOTE_DOOR_WATER_AREA, 1256, 2582, 0), + RC(RC_GL_MUMBO_TOKEN_BEHIND_PURPLE_CAULDRON, RCTYPE_MUMBO_TOKEN, LEVEL_6_LAIR, RI_MUMBO_TOKEN, MUMBOTOKEN_51_LAIR_BEHIND_PURPLE_CAULDRON, 162, -750, 4611), + RC(RC_GL_MUMBO_TOKEN_TOP_OF_PIPE_IN_ORANGE_CAULDRON_ROOM, RCTYPE_MUMBO_TOKEN, LEVEL_6_LAIR, RI_MUMBO_TOKEN, MUMBOTOKEN_53_LAIR_TOP_OF_PIPE_IN_ORANGE_CAULDRON_ROOM, -180, 351, -750), + RC(RC_GL_MUMBO_TOKEN_ABOVE_CC_ENTRANCE, RCTYPE_MUMBO_TOKEN, LEVEL_6_LAIR, RI_MUMBO_TOKEN, MUMBOTOKEN_54_LAIR_ABOVE_CC_ENTRANCE, 0, 850, -2450), + RC(RC_GL_MUMBO_TOKEN_CCW_JIGGY_PODIUM, RCTYPE_MUMBO_TOKEN, LEVEL_6_LAIR, RI_MUMBO_TOKEN, MUMBOTOKEN_52_LAIR_CCW_JIGGY_PODIUM, 4936, -478, 286), + RC(RC_GL_MUMBO_TOKEN_BEHIND_SARCOPHAGUS, RCTYPE_MUMBO_TOKEN, LEVEL_6_LAIR, RI_MUMBO_TOKEN, MUMBOTOKEN_55_LAIR_BEHIND_SARCOPHAGUS, -1486, 0, -922), + RC(RC_GL_MUMBO_TOKEN_ADVENT_TOP_WINDOW, RCTYPE_MUMBO_TOKEN, LEVEL_6_LAIR, RI_MUMBO_TOKEN, MUMBOTOKEN_56_LAIR_ADVENT_TOP_WINDOW, 4155, 1485, 6270), + RC(RC_GL_MUMBO_TOKEN_UNDERWATER_RBB_ENTRANCE_AREA, RCTYPE_MUMBO_TOKEN, LEVEL_6_LAIR, RI_MUMBO_TOKEN, MUMBOTOKEN_59_LAIR_UNDERWATER_RBB_ENTRANCE_AREA, 1764, -1400, -1136), + RC(RC_GL_MUMBO_TOKEN_WHIPCRACK_NEAR_MMM_JIGGY_PODIUM, RCTYPE_MUMBO_TOKEN, LEVEL_6_LAIR, RI_MUMBO_TOKEN, MUMBOTOKEN_5A_LAIR_WHIPCRACK_NEAR_MMM_JIGGY_PODIUM, -1140, 707, 1973), + RC(RC_GL_MUMBO_TOKEN_BEHIND_MUMBO_IN_CRYPT, RCTYPE_MUMBO_TOKEN, LEVEL_6_LAIR, RI_MUMBO_TOKEN, MUMBOTOKEN_57_LAIR_BEHIND_MUMBO_IN_CRYPT, 1488, 249, 0), + RC(RC_GL_MUMBO_TOKEN_ABOVE_NOTE_DOOR_WATER_AREA, RCTYPE_MUMBO_TOKEN, LEVEL_6_LAIR, RI_MUMBO_TOKEN, MUMBOTOKEN_58_LAIR_ABOVE_NOTE_DOOR_WATER_AREA, 1256, 2582, 0), RC(RC_GV_BLUE_EGG_BEHIND_WATER_PYRAMID_1, RCTYPE_BLUE_EGG, LEVEL_7_GOBIS_VALLEY, RI_BLUE_EGG, NULL, 387, 2730, -6645), RC(RC_GV_BLUE_EGG_BEHIND_WATER_PYRAMID_2, RCTYPE_BLUE_EGG, LEVEL_7_GOBIS_VALLEY, RI_BLUE_EGG, NULL, 17, 2730, -6645), RC(RC_GV_BLUE_EGG_BEHIND_WATER_PYRAMID_3, RCTYPE_BLUE_EGG, LEVEL_7_GOBIS_VALLEY, RI_BLUE_EGG, NULL, -342, 2730, -6645), @@ -1099,16 +1099,16 @@ std::map Checks = { RC(RC_GV_JINJO_PINK, RCTYPE_JINJO, LEVEL_7_GOBIS_VALLEY, RI_JINJO_PINK_GOBIS_VALLEY, NULL, -4964, 0, 700), RC(RC_GV_JINJO_YELLOW, RCTYPE_JINJO, LEVEL_7_GOBIS_VALLEY, RI_JINJO_YELLOW_GOBIS_VALLEY, NULL, 3067, 447, 10270), RC(RC_GV_MOLEHILL_TURBO_TALON, RCTYPE_MOLEHILL, LEVEL_7_GOBIS_VALLEY, RI_MOLEHILL_TURBO_TALON, ABILITY_11_TURBO_TALON, -6445, 2831, -822), - RC(RC_GV_MUMBO_TOKEN_BEHIND_SANDYBUTTS_SARCOPHAGUS, RCTYPE_MUMBO_TOKEN, LEVEL_7_GOBIS_VALLEY, RI_MUMBO_TOKEN_GOBIS_VALLEY, MUMBOTOKEN_2F_GV_BEHIND_SANDYBUTTS_SARCOPHAGUS, -5514, 0, 138), - RC(RC_GV_MUMBO_TOKEN_BOTTOM_OF_MOAT, RCTYPE_MUMBO_TOKEN, LEVEL_7_GOBIS_VALLEY, RI_MUMBO_TOKEN_GOBIS_VALLEY, MUMBOTOKEN_2B_GV_BOTTOM_OF_MOAT, 91, 535, -860), - RC(RC_GV_MUMBO_TOKEN_FRONT_OF_STAR_DOOR, RCTYPE_MUMBO_TOKEN, LEVEL_7_GOBIS_VALLEY, RI_MUMBO_TOKEN_GOBIS_VALLEY, MUMBOTOKEN_2D_GV_FRONT_OF_STAR_DOOR, -230, 2843, -3091), - RC(RC_GV_MUMBO_TOKEN_INSIDE_JINXY, RCTYPE_MUMBO_TOKEN, LEVEL_7_GOBIS_VALLEY, RI_MUMBO_TOKEN_GOBIS_VALLEY, MUMBOTOKEN_32_GV_INSIDE_JINXY, -2550, 0, -51), - RC(RC_GV_MUMBO_TOKEN_INSIDE_MEMORY_GAME_ROOM, RCTYPE_MUMBO_TOKEN, LEVEL_7_GOBIS_VALLEY, RI_MUMBO_TOKEN_GOBIS_VALLEY, MUMBOTOKEN_2E_GV_INSIDE_MEMORY_GAME_ROOM, 715, 248, 0), - RC(RC_GV_MUMBO_TOKEN_INSIDE_WATER_PYRAMID, RCTYPE_MUMBO_TOKEN, LEVEL_7_GOBIS_VALLEY, RI_MUMBO_TOKEN_GOBIS_VALLEY, MUMBOTOKEN_30_GV_INSIDE_WATER_PYRAMID, -300, 1439, -1194), - RC(RC_GV_MUMBO_TOKEN_NEXT_TO_RUBEE, RCTYPE_MUMBO_TOKEN, LEVEL_7_GOBIS_VALLEY, RI_MUMBO_TOKEN_GOBIS_VALLEY, MUMBOTOKEN_31_GV_NEXT_TO_RUBEE, 0, 107, -602), - RC(RC_GV_MUMBO_TOKEN_SAND_RIGHT_OF_JINXY, RCTYPE_MUMBO_TOKEN, LEVEL_7_GOBIS_VALLEY, RI_MUMBO_TOKEN_GOBIS_VALLEY, MUMBOTOKEN_2A_GV_SAND_RIGHT_OF_JINXY, -5386, 1420, 10034), - RC(RC_GV_MUMBO_TOKEN_TOP_OF_JINXYS_NOSE, RCTYPE_MUMBO_TOKEN, LEVEL_7_GOBIS_VALLEY, RI_MUMBO_TOKEN_GOBIS_VALLEY, MUMBOTOKEN_29_GV_TOP_OF_JINXYS_NOSE, -2149, 3340, 5867), - RC(RC_GV_MUMBO_TOKEN_TOP_OF_WATER_PYRAMID, RCTYPE_MUMBO_TOKEN, LEVEL_7_GOBIS_VALLEY, RI_MUMBO_TOKEN_GOBIS_VALLEY, MUMBOTOKEN_2C_GV_TOP_OF_WATER_PYRAMID, 64, 3484, 400), + RC(RC_GV_MUMBO_TOKEN_BEHIND_SANDYBUTTS_SARCOPHAGUS, RCTYPE_MUMBO_TOKEN, LEVEL_7_GOBIS_VALLEY, RI_MUMBO_TOKEN, MUMBOTOKEN_2F_GV_BEHIND_SANDYBUTTS_SARCOPHAGUS, -5514, 0, 138), + RC(RC_GV_MUMBO_TOKEN_BOTTOM_OF_MOAT, RCTYPE_MUMBO_TOKEN, LEVEL_7_GOBIS_VALLEY, RI_MUMBO_TOKEN, MUMBOTOKEN_2B_GV_BOTTOM_OF_MOAT, 91, 535, -860), + RC(RC_GV_MUMBO_TOKEN_FRONT_OF_STAR_DOOR, RCTYPE_MUMBO_TOKEN, LEVEL_7_GOBIS_VALLEY, RI_MUMBO_TOKEN, MUMBOTOKEN_2D_GV_FRONT_OF_STAR_DOOR, -230, 2843, -3091), + RC(RC_GV_MUMBO_TOKEN_INSIDE_JINXY, RCTYPE_MUMBO_TOKEN, LEVEL_7_GOBIS_VALLEY, RI_MUMBO_TOKEN, MUMBOTOKEN_32_GV_INSIDE_JINXY, -2550, 0, -51), + RC(RC_GV_MUMBO_TOKEN_INSIDE_MEMORY_GAME_ROOM, RCTYPE_MUMBO_TOKEN, LEVEL_7_GOBIS_VALLEY, RI_MUMBO_TOKEN, MUMBOTOKEN_2E_GV_INSIDE_MEMORY_GAME_ROOM, 715, 248, 0), + RC(RC_GV_MUMBO_TOKEN_INSIDE_WATER_PYRAMID, RCTYPE_MUMBO_TOKEN, LEVEL_7_GOBIS_VALLEY, RI_MUMBO_TOKEN, MUMBOTOKEN_30_GV_INSIDE_WATER_PYRAMID, -300, 1439, -1194), + RC(RC_GV_MUMBO_TOKEN_NEXT_TO_RUBEE, RCTYPE_MUMBO_TOKEN, LEVEL_7_GOBIS_VALLEY, RI_MUMBO_TOKEN, MUMBOTOKEN_31_GV_NEXT_TO_RUBEE, 0, 107, -602), + RC(RC_GV_MUMBO_TOKEN_SAND_RIGHT_OF_JINXY, RCTYPE_MUMBO_TOKEN, LEVEL_7_GOBIS_VALLEY, RI_MUMBO_TOKEN, MUMBOTOKEN_2A_GV_SAND_RIGHT_OF_JINXY, -5386, 1420, 10034), + RC(RC_GV_MUMBO_TOKEN_TOP_OF_JINXYS_NOSE, RCTYPE_MUMBO_TOKEN, LEVEL_7_GOBIS_VALLEY, RI_MUMBO_TOKEN, MUMBOTOKEN_29_GV_TOP_OF_JINXYS_NOSE, -2149, 3340, 5867), + RC(RC_GV_MUMBO_TOKEN_TOP_OF_WATER_PYRAMID, RCTYPE_MUMBO_TOKEN, LEVEL_7_GOBIS_VALLEY, RI_MUMBO_TOKEN, MUMBOTOKEN_2C_GV_TOP_OF_WATER_PYRAMID, 64, 3484, 400), RC(RC_GV_NOTE_DESERT_DOOR_ALCOVE_1, RCTYPE_MUSIC_NOTE, LEVEL_7_GOBIS_VALLEY, RI_MUSIC_NOTE_GOBIS_VALLEY, NULL, -7178, 2372, 1754), RC(RC_GV_NOTE_DESERT_DOOR_ALCOVE_2, RCTYPE_MUSIC_NOTE, LEVEL_7_GOBIS_VALLEY, RI_MUSIC_NOTE_GOBIS_VALLEY, NULL, -7148, 2371, 1568), RC(RC_GV_NOTE_DESERT_DOOR_ALCOVE_3, RCTYPE_MUSIC_NOTE, LEVEL_7_GOBIS_VALLEY, RI_MUSIC_NOTE_GOBIS_VALLEY, NULL, -7123, 2371, 1404), @@ -1278,11 +1278,11 @@ std::map Checks = { RC(RC_MM_MOLEHILL_BEAK_BUSTER, RCTYPE_MOLEHILL, LEVEL_1_MUMBOS_MOUNTAIN, RI_MOLEHILL_BEAK_BUSTER, ABILITY_2_BEAK_BUSTER, 3943, 2155, -3422), RC(RC_MM_MOLEHILL_TALON_TROT, RCTYPE_MOLEHILL, LEVEL_1_MUMBOS_MOUNTAIN, RI_MOLEHILL_TALON_TROT, ABILITY_10_TALON_TROT, -2550, 2255, -1217), RC(RC_MM_MOLEHILL_USE_EGGS, RCTYPE_MOLEHILL, LEVEL_1_MUMBOS_MOUNTAIN, RI_MOLEHILL_EGGS, ABILITY_6_EGGS, -5926, 200, 6213), - RC(RC_MM_MUMBO_TOKEN_BEHIND_PINK_JINJO, RCTYPE_MUMBO_TOKEN, LEVEL_1_MUMBOS_MOUNTAIN, RI_MUMBO_TOKEN_MUMBOS_MOUNTAIN, MUMBOTOKEN_04_MM_BEHIND_PINK_JINJO, 5855, 0, 2169), - RC(RC_MM_MUMBO_TOKEN_BEHIND_RUINS, RCTYPE_MUMBO_TOKEN, LEVEL_1_MUMBOS_MOUNTAIN, RI_MUMBO_TOKEN_MUMBOS_MOUNTAIN, MUMBOTOKEN_02_MM_BEHIND_RUINS, -4869, 2255, -2506), - RC(RC_MM_MUMBO_TOKEN_INSIDE_TICKERS_TOWER, RCTYPE_MUMBO_TOKEN, LEVEL_1_MUMBOS_MOUNTAIN, RI_MUMBO_TOKEN_MUMBOS_MOUNTAIN, MUMBOTOKEN_05_MM_INSIDE_TICKERS_TOWER, -343, 345, -518), - RC(RC_MM_MUMBO_TOKEN_STUMP_NEAR_CONGA, RCTYPE_MUMBO_TOKEN, LEVEL_1_MUMBOS_MOUNTAIN, RI_MUMBO_TOKEN_MUMBOS_MOUNTAIN, MUMBOTOKEN_01_MM_STUMP_NEAR_CONGA, -4431, 475, 6183), - RC(RC_MM_MUMBO_TOKEN_UNDER_RAMP_TO_MUMBOS_SKULL, RCTYPE_MUMBO_TOKEN, LEVEL_1_MUMBOS_MOUNTAIN, RI_MUMBO_TOKEN_MUMBOS_MOUNTAIN, MUMBOTOKEN_03_MM_UNDER_RAMP_TO_MUMBOS_SKULL, 5150, 2168, -2447), + RC(RC_MM_MUMBO_TOKEN_BEHIND_PINK_JINJO, RCTYPE_MUMBO_TOKEN, LEVEL_1_MUMBOS_MOUNTAIN, RI_MUMBO_TOKEN, MUMBOTOKEN_04_MM_BEHIND_PINK_JINJO, 5855, 0, 2169), + RC(RC_MM_MUMBO_TOKEN_BEHIND_RUINS, RCTYPE_MUMBO_TOKEN, LEVEL_1_MUMBOS_MOUNTAIN, RI_MUMBO_TOKEN, MUMBOTOKEN_02_MM_BEHIND_RUINS, -4869, 2255, -2506), + RC(RC_MM_MUMBO_TOKEN_INSIDE_TICKERS_TOWER, RCTYPE_MUMBO_TOKEN, LEVEL_1_MUMBOS_MOUNTAIN, RI_MUMBO_TOKEN, MUMBOTOKEN_05_MM_INSIDE_TICKERS_TOWER, -343, 345, -518), + RC(RC_MM_MUMBO_TOKEN_STUMP_NEAR_CONGA, RCTYPE_MUMBO_TOKEN, LEVEL_1_MUMBOS_MOUNTAIN, RI_MUMBO_TOKEN, MUMBOTOKEN_01_MM_STUMP_NEAR_CONGA, -4431, 475, 6183), + RC(RC_MM_MUMBO_TOKEN_UNDER_RAMP_TO_MUMBOS_SKULL, RCTYPE_MUMBO_TOKEN, LEVEL_1_MUMBOS_MOUNTAIN, RI_MUMBO_TOKEN, MUMBOTOKEN_03_MM_UNDER_RAMP_TO_MUMBOS_SKULL, 5150, 2168, -2447), RC(RC_MM_NOTE_SOUTH_SLOPE_FIRST_PLATFORM_1, RCTYPE_MUSIC_NOTE, LEVEL_1_MUMBOS_MOUNTAIN, RI_MUSIC_NOTE_MUMBOS_MOUNTAIN, NULL, 4867, 297, 1766), RC(RC_MM_NOTE_SOUTH_SLOPE_FIRST_PLATFORM_2, RCTYPE_MUSIC_NOTE, LEVEL_1_MUMBOS_MOUNTAIN, RI_MUSIC_NOTE_MUMBOS_MOUNTAIN, NULL, 4782, 298, 1892), RC(RC_MM_NOTE_SOUTH_SLOPE_FIRST_PLATFORM_3, RCTYPE_MUSIC_NOTE, LEVEL_1_MUMBOS_MOUNTAIN, RI_MUSIC_NOTE_MUMBOS_MOUNTAIN, NULL, 4971, 299, 1887), @@ -1492,22 +1492,22 @@ std::map Checks = { RC(RC_MMM_JINJO_ORANGE, RCTYPE_JINJO, LEVEL_A_MAD_MONSTER_MANSION, RI_JINJO_ORANGE_MAD_MONSTER_MANSION, NULL, -4265, 0, 2668), RC(RC_MMM_JINJO_PINK, RCTYPE_JINJO, LEVEL_A_MAD_MONSTER_MANSION, RI_JINJO_PINK_MAD_MONSTER_MANSION, NULL, 511, 38, 203), RC(RC_MMM_JINJO_YELLOW, RCTYPE_JINJO, LEVEL_A_MAD_MONSTER_MANSION, RI_JINJO_YELLOW_MAD_MONSTER_MANSION, NULL, -250, 540, 300), - RC(RC_MMM_MUMBO_TOKEN_ALCOVE_CLOCK_TOWER, RCTYPE_MUMBO_TOKEN, LEVEL_A_MAD_MONSTER_MANSION, RI_MUMBO_TOKEN_MAD_MONSTER_MANSION, MUMBOTOKEN_35_MMM_ALCOVE_CLOCK_TOWER, -2800, 1475, -1363), - RC(RC_MMM_MUMBO_TOKEN_BEHIND_CHURCH, RCTYPE_MUMBO_TOKEN, LEVEL_A_MAD_MONSTER_MANSION, RI_MUMBO_TOKEN_MAD_MONSTER_MANSION, MUMBOTOKEN_38_MMM_BEHIND_CHURCH, -4700, 175, -5149), - RC(RC_MMM_MUMBO_TOKEN_HIDDEN_NEAR_FOUNTAIN, RCTYPE_MUMBO_TOKEN, LEVEL_A_MAD_MONSTER_MANSION, RI_MUMBO_TOKEN_MAD_MONSTER_MANSION, MUMBOTOKEN_33_MMM_HIDDEN_NEAR_FOUNTAIN, 3950, -175, 325), - RC(RC_MMM_MUMBO_TOKEN_IN_CHIMNEY_INSIDE_DINING_ROOM, RCTYPE_MUMBO_TOKEN, LEVEL_A_MAD_MONSTER_MANSION, RI_MUMBO_TOKEN_MAD_MONSTER_MANSION, MUMBOTOKEN_3E_MMM_IN_CHIMNEY_INSIDE_DINNING_ROOM, -160, 190, -2599), - RC(RC_MMM_MUMBO_TOKEN_IN_THE_MAZE, RCTYPE_MUMBO_TOKEN, LEVEL_A_MAD_MONSTER_MANSION, RI_MUMBO_TOKEN_MAD_MONSTER_MANSION, MUMBOTOKEN_37_MMM_IN_THE_MAZE, -4250, 0, 352), - RC(RC_MMM_MUMBO_TOKEN_INSIDE_BEDROOM, RCTYPE_MUMBO_TOKEN, LEVEL_A_MAD_MONSTER_MANSION, RI_MUMBO_TOKEN_MAD_MONSTER_MANSION, MUMBOTOKEN_40_MMM_INSIDE_BEDROOM, 696, 0, -397), - RC(RC_MMM_MUMBO_TOKEN_INSIDE_LOGGO, RCTYPE_MUMBO_TOKEN, LEVEL_A_MAD_MONSTER_MANSION, RI_MUMBO_TOKEN_MAD_MONSTER_MANSION, RP_MUMBO_TOKEN_INSIDE_LOGGO, 424, 170, 304), - RC(RC_MMM_MUMBO_TOKEN_INSIDE_BARREL_IN_CELLAR, RCTYPE_MUMBO_TOKEN, LEVEL_A_MAD_MONSTER_MANSION, RI_MUMBO_TOKEN_MAD_MONSTER_MANSION, MUMBOTOKEN_3D_MMM_INSIDE_LOGGO_AND_INSIDE_BARREL_IN_CELLAR, -507, 30, 199), - RC(RC_MMM_MUMBO_TOKEN_INSIDE_WELL, RCTYPE_MUMBO_TOKEN, LEVEL_A_MAD_MONSTER_MANSION, RI_MUMBO_TOKEN_MAD_MONSTER_MANSION, MUMBOTOKEN_3F_MMM_INSIDE_WELL, -732, 0, -109), - RC(RC_MMM_MUMBO_TOKEN_INSIDE_WHIPCRACK_IN_FOUNTAIN, RCTYPE_MUMBO_TOKEN, LEVEL_A_MAD_MONSTER_MANSION, RI_MUMBO_TOKEN_MAD_MONSTER_MANSION, MUMBOTOKEN_39_MMM_INSIDE_WHIPCRACK_IN_FOUNTAIN, 5900, -275, 798), - RC(RC_MMM_MUMBO_TOKEN_NEAR_FRONT_TUMBLARS_SHED, RCTYPE_MUMBO_TOKEN, LEVEL_A_MAD_MONSTER_MANSION, RI_MUMBO_TOKEN_MAD_MONSTER_MANSION, MUMBOTOKEN_34_MMM_NEAR_FRONT_TUMBLARS_SHED, 173, 350, -3610), - RC(RC_MMM_MUMBO_TOKEN_NEXT_TO_MAZE_HEDGE_RAMP, RCTYPE_MUMBO_TOKEN, LEVEL_A_MAD_MONSTER_MANSION, RI_MUMBO_TOKEN_MAD_MONSTER_MANSION, MUMBOTOKEN_36_MMM_NEXT_TO_MAZE_HEDGE_RAMP, -1643, 25, -1026), - RC(RC_MMM_MUMBO_TOKEN_IN_LOGGOS_ROOM, RCTYPE_MUMBO_TOKEN, LEVEL_A_MAD_MONSTER_MANSION, RI_MUMBO_TOKEN_MAD_MONSTER_MANSION, MUMBOTOKEN_41_MMM_SINK_IN_LOGGOS_ROOM, 52, 104, 512), - RC(RC_MMM_MUMBO_TOKEN_TOP_OF_RAFTER_INSIDE_CHURCH, RCTYPE_MUMBO_TOKEN, LEVEL_A_MAD_MONSTER_MANSION, RI_MUMBO_TOKEN_MAD_MONSTER_MANSION, MUMBOTOKEN_3A_MMM_TOP_OF_RAFTER_INSIDE_CHURCH, 0, 4806, 341), - RC(RC_MMM_MUMBO_TOKEN_TOP_OF_STOOL_INSIDE_CHURCH, RCTYPE_MUMBO_TOKEN, LEVEL_A_MAD_MONSTER_MANSION, RI_MUMBO_TOKEN_MAD_MONSTER_MANSION, MUMBOTOKEN_3B_MMM_TOP_OF_STOOL_INSIDE_CHURCH, 0, 583, -1300), - RC(RC_MMM_MUMBO_TOKEN_TOP_OF_TUMBLARS_SHED, RCTYPE_MUMBO_TOKEN, LEVEL_A_MAD_MONSTER_MANSION, RI_MUMBO_TOKEN_MAD_MONSTER_MANSION, MUMBOTOKEN_3C_MMM_TOP_OF_TUMBLARS_SHED, 1796, 857, -4243), + RC(RC_MMM_MUMBO_TOKEN_ALCOVE_CLOCK_TOWER, RCTYPE_MUMBO_TOKEN, LEVEL_A_MAD_MONSTER_MANSION, RI_MUMBO_TOKEN, MUMBOTOKEN_35_MMM_ALCOVE_CLOCK_TOWER, -2800, 1475, -1363), + RC(RC_MMM_MUMBO_TOKEN_BEHIND_CHURCH, RCTYPE_MUMBO_TOKEN, LEVEL_A_MAD_MONSTER_MANSION, RI_MUMBO_TOKEN, MUMBOTOKEN_38_MMM_BEHIND_CHURCH, -4700, 175, -5149), + RC(RC_MMM_MUMBO_TOKEN_HIDDEN_NEAR_FOUNTAIN, RCTYPE_MUMBO_TOKEN, LEVEL_A_MAD_MONSTER_MANSION, RI_MUMBO_TOKEN, MUMBOTOKEN_33_MMM_HIDDEN_NEAR_FOUNTAIN, 3950, -175, 325), + RC(RC_MMM_MUMBO_TOKEN_IN_CHIMNEY_INSIDE_DINING_ROOM, RCTYPE_MUMBO_TOKEN, LEVEL_A_MAD_MONSTER_MANSION, RI_MUMBO_TOKEN, MUMBOTOKEN_3E_MMM_IN_CHIMNEY_INSIDE_DINNING_ROOM, -160, 190, -2599), + RC(RC_MMM_MUMBO_TOKEN_IN_THE_MAZE, RCTYPE_MUMBO_TOKEN, LEVEL_A_MAD_MONSTER_MANSION, RI_MUMBO_TOKEN, MUMBOTOKEN_37_MMM_IN_THE_MAZE, -4250, 0, 352), + RC(RC_MMM_MUMBO_TOKEN_INSIDE_BEDROOM, RCTYPE_MUMBO_TOKEN, LEVEL_A_MAD_MONSTER_MANSION, RI_MUMBO_TOKEN, MUMBOTOKEN_40_MMM_INSIDE_BEDROOM, 696, 0, -397), + RC(RC_MMM_MUMBO_TOKEN_INSIDE_LOGGO, RCTYPE_MUMBO_TOKEN, LEVEL_A_MAD_MONSTER_MANSION, RI_MUMBO_TOKEN, RP_MUMBO_TOKEN_INSIDE_LOGGO, 424, 170, 304), + RC(RC_MMM_MUMBO_TOKEN_INSIDE_BARREL_IN_CELLAR, RCTYPE_MUMBO_TOKEN, LEVEL_A_MAD_MONSTER_MANSION, RI_MUMBO_TOKEN, MUMBOTOKEN_3D_MMM_INSIDE_LOGGO_AND_INSIDE_BARREL_IN_CELLAR, -507, 30, 199), + RC(RC_MMM_MUMBO_TOKEN_INSIDE_WELL, RCTYPE_MUMBO_TOKEN, LEVEL_A_MAD_MONSTER_MANSION, RI_MUMBO_TOKEN, MUMBOTOKEN_3F_MMM_INSIDE_WELL, -732, 0, -109), + RC(RC_MMM_MUMBO_TOKEN_INSIDE_WHIPCRACK_IN_FOUNTAIN, RCTYPE_MUMBO_TOKEN, LEVEL_A_MAD_MONSTER_MANSION, RI_MUMBO_TOKEN, MUMBOTOKEN_39_MMM_INSIDE_WHIPCRACK_IN_FOUNTAIN, 5900, -275, 798), + RC(RC_MMM_MUMBO_TOKEN_NEAR_FRONT_TUMBLARS_SHED, RCTYPE_MUMBO_TOKEN, LEVEL_A_MAD_MONSTER_MANSION, RI_MUMBO_TOKEN, MUMBOTOKEN_34_MMM_NEAR_FRONT_TUMBLARS_SHED, 173, 350, -3610), + RC(RC_MMM_MUMBO_TOKEN_NEXT_TO_MAZE_HEDGE_RAMP, RCTYPE_MUMBO_TOKEN, LEVEL_A_MAD_MONSTER_MANSION, RI_MUMBO_TOKEN, MUMBOTOKEN_36_MMM_NEXT_TO_MAZE_HEDGE_RAMP, -1643, 25, -1026), + RC(RC_MMM_MUMBO_TOKEN_IN_LOGGOS_ROOM, RCTYPE_MUMBO_TOKEN, LEVEL_A_MAD_MONSTER_MANSION, RI_MUMBO_TOKEN, MUMBOTOKEN_41_MMM_SINK_IN_LOGGOS_ROOM, 52, 104, 512), + RC(RC_MMM_MUMBO_TOKEN_TOP_OF_RAFTER_INSIDE_CHURCH, RCTYPE_MUMBO_TOKEN, LEVEL_A_MAD_MONSTER_MANSION, RI_MUMBO_TOKEN, MUMBOTOKEN_3A_MMM_TOP_OF_RAFTER_INSIDE_CHURCH, 0, 4806, 341), + RC(RC_MMM_MUMBO_TOKEN_TOP_OF_STOOL_INSIDE_CHURCH, RCTYPE_MUMBO_TOKEN, LEVEL_A_MAD_MONSTER_MANSION, RI_MUMBO_TOKEN, MUMBOTOKEN_3B_MMM_TOP_OF_STOOL_INSIDE_CHURCH, 0, 583, -1300), + RC(RC_MMM_MUMBO_TOKEN_TOP_OF_TUMBLARS_SHED, RCTYPE_MUMBO_TOKEN, LEVEL_A_MAD_MONSTER_MANSION, RI_MUMBO_TOKEN, MUMBOTOKEN_3C_MMM_TOP_OF_TUMBLARS_SHED, 1796, 857, -4243), RC(RC_MMM_NOTE_AROUND_THE_WELL_WEST_2, RCTYPE_MUSIC_NOTE, LEVEL_A_MAD_MONSTER_MANSION, RI_MUSIC_NOTE_MAD_MONSTER_MANSION, NULL, 7150, -275, -3474), RC(RC_MMM_NOTE_AROUND_THE_WELL_WEST_1, RCTYPE_MUSIC_NOTE, LEVEL_A_MAD_MONSTER_MANSION, RI_MUSIC_NOTE_MAD_MONSTER_MANSION, NULL, 7150, -275, -3325), RC(RC_MMM_NOTE_AROUND_THE_WELL_EAST_2, RCTYPE_MUSIC_NOTE, LEVEL_A_MAD_MONSTER_MANSION, RI_MUSIC_NOTE_MAD_MONSTER_MANSION, NULL, 4200, -275, -3325), @@ -1698,21 +1698,21 @@ std::map Checks = { RC(RC_RBB_JINJO_ORANGE, RCTYPE_JINJO, LEVEL_9_RUSTY_BUCKET_BAY, RI_JINJO_ORANGE_RUSTY_BUCKET_BAY, NULL, -193, 0, -979), RC(RC_RBB_JINJO_PINK, RCTYPE_JINJO, LEVEL_9_RUSTY_BUCKET_BAY, RI_JINJO_PINK_RUSTY_BUCKET_BAY, NULL, 7850, -2613, 4026), RC(RC_RBB_JINJO_YELLOW, RCTYPE_JINJO, LEVEL_9_RUSTY_BUCKET_BAY, RI_JINJO_YELLOW_RUSTY_BUCKET_BAY, NULL, -8615, -1000, -3555), - RC(RC_RBB_MUMBO_TOKEN_TOXIC_WASTE_POND, RCTYPE_MUMBO_TOKEN, LEVEL_9_RUSTY_BUCKET_BAY, RI_MUMBO_TOKEN_RUSTY_BUCKET_BAY, MUMBOTOKEN_46_RBB_TOXIC_WASTE_POND, -7401, -1000, -3425), - RC(RC_RBB_MUMBO_TOKEN_ON_LIFE_BOAT, RCTYPE_MUMBO_TOKEN, LEVEL_9_RUSTY_BUCKET_BAY, RI_MUMBO_TOKEN_RUSTY_BUCKET_BAY, MUMBOTOKEN_44_RBB_ON_LIFE_BOAT, 7053, -985, -1672), - RC(RC_RBB_MUMBO_TOKEN_SHIPS_PROW, RCTYPE_MUMBO_TOKEN, LEVEL_9_RUSTY_BUCKET_BAY, RI_MUMBO_TOKEN_RUSTY_BUCKET_BAY, MUMBOTOKEN_43_RBB_SHIPS_PROW, -6200, 150, 0), - RC(RC_RBB_MUMBO_TOKEN_UNDER_CHOMPA_IN_WITCH_SWITCH_TOWER, RCTYPE_MUMBO_TOKEN, LEVEL_9_RUSTY_BUCKET_BAY, RI_MUMBO_TOKEN_RUSTY_BUCKET_BAY, MUMBOTOKEN_47_RBB_UNDER_CHOMPA_IN_WITCH_SWITCH_TOWER, 6200, 400, 0), - RC(RC_RBB_MUMBO_TOKEN_TOP_OF_SHIPS_CHIMNEY, RCTYPE_MUMBO_TOKEN, LEVEL_9_RUSTY_BUCKET_BAY, RI_MUMBO_TOKEN_RUSTY_BUCKET_BAY, MUMBOTOKEN_42_RBB_TOP_OF_SHIPS_CHIMNEY, 1000, 2750, 0), - RC(RC_RBB_MUMBO_TOKEN_FRONT_OF_CHOMPA_LEFT_OF_SHIP, RCTYPE_MUMBO_TOKEN, LEVEL_9_RUSTY_BUCKET_BAY, RI_MUMBO_TOKEN_RUSTY_BUCKET_BAY, MUMBOTOKEN_45_RBB_FRONT_OF_CHOMPA_LEFT_OF_SHIP, -3299, -457, 3800), - RC(RC_RBB_MUMBO_TOKEN_UNDER_CHOMPA_INSIDE_FIRST_BLUE_CONTAINER, RCTYPE_MUMBO_TOKEN, LEVEL_9_RUSTY_BUCKET_BAY, RI_MUMBO_TOKEN_RUSTY_BUCKET_BAY, MUMBOTOKEN_48_RBB_UNDER_CHOMPA_INSIDE_FIRST_BLUE_CONTAINER, -650, 562, -35), - RC(RC_RBB_MUMBO_TOKEN_TOP_OF_BOX_INSIDE_SECOND_BLUE_CONTAINER, RCTYPE_MUMBO_TOKEN, LEVEL_9_RUSTY_BUCKET_BAY, RI_MUMBO_TOKEN_RUSTY_BUCKET_BAY, MUMBOTOKEN_49_RBB_TOP_OF_BOX_INSIDE_SECOND_BLUE_CONTAINER, -278, 710, -557), - RC(RC_RBB_MUMBO_TOKEN_INSIDE_KITCHEN, RCTYPE_MUMBO_TOKEN, LEVEL_9_RUSTY_BUCKET_BAY, RI_MUMBO_TOKEN_RUSTY_BUCKET_BAY, MUMBOTOKEN_4C_RBB_INSIDE_KITCHEN, -771, 238, -293), - RC(RC_RBB_MUMBO_TOKEN_TOP_OF_BUNK_IN_CABIN, RCTYPE_MUMBO_TOKEN, LEVEL_9_RUSTY_BUCKET_BAY, RI_MUMBO_TOKEN_RUSTY_BUCKET_BAY, MUMBOTOKEN_4A_RBB_TOP_OF_BUNK_IN_CABIN, 583, 323, -70), - RC(RC_RBB_MUMBO_TOKEN_TOP_OF_BOX_INSIDE_TNT_ROOM, RCTYPE_MUMBO_TOKEN, LEVEL_9_RUSTY_BUCKET_BAY, RI_MUMBO_TOKEN_RUSTY_BUCKET_BAY, MUMBOTOKEN_50_RBB_TOP_OF_BOX_INSIDE_TNT_ROOM, -435, 300, -435), - RC(RC_RBB_MUMBO_TOKEN_ENGINE_ROOM_LEFT_PIPE, RCTYPE_MUMBO_TOKEN, LEVEL_9_RUSTY_BUCKET_BAY, RI_MUMBO_TOKEN_RUSTY_BUCKET_BAY, MUMBOTOKEN_4D_RBB_ENGINE_ROOM_LEFT_PIPE, -2450, 1100, -400), - RC(RC_RBB_MUMBO_TOKEN_ENGINE_ROOM_RIGHT_PIPE, RCTYPE_MUMBO_TOKEN, LEVEL_9_RUSTY_BUCKET_BAY, RI_MUMBO_TOKEN_RUSTY_BUCKET_BAY, MUMBOTOKEN_4E_RBB_ENGINE_ROOM_RIGHT_PIPE, 2450, 1100, -400), - RC(RC_RBB_MUMBO_TOKEN_ENGINE_ROOM_SPINNING_PLATFORM, RCTYPE_MUMBO_TOKEN, LEVEL_9_RUSTY_BUCKET_BAY, RI_MUMBO_TOKEN_RUSTY_BUCKET_BAY, MUMBOTOKEN_4F_RBB_ENGINE_ROOM_SPINNING_PLATFORM, -319, 12, 1899), - RC(RC_RBB_MUMBO_TOKEN_INSIDE_NAVIGATION_ROOM, RCTYPE_MUMBO_TOKEN, LEVEL_9_RUSTY_BUCKET_BAY, RI_MUMBO_TOKEN_RUSTY_BUCKET_BAY, MUMBOTOKEN_4B_RBB_INSIDE_NAVIGATION_ROOM, -656, 0, -222), + RC(RC_RBB_MUMBO_TOKEN_TOXIC_WASTE_POND, RCTYPE_MUMBO_TOKEN, LEVEL_9_RUSTY_BUCKET_BAY, RI_MUMBO_TOKEN, MUMBOTOKEN_46_RBB_TOXIC_WASTE_POND, -7401, -1000, -3425), + RC(RC_RBB_MUMBO_TOKEN_ON_LIFE_BOAT, RCTYPE_MUMBO_TOKEN, LEVEL_9_RUSTY_BUCKET_BAY, RI_MUMBO_TOKEN, MUMBOTOKEN_44_RBB_ON_LIFE_BOAT, 7053, -985, -1672), + RC(RC_RBB_MUMBO_TOKEN_SHIPS_PROW, RCTYPE_MUMBO_TOKEN, LEVEL_9_RUSTY_BUCKET_BAY, RI_MUMBO_TOKEN, MUMBOTOKEN_43_RBB_SHIPS_PROW, -6200, 150, 0), + RC(RC_RBB_MUMBO_TOKEN_UNDER_CHOMPA_IN_WITCH_SWITCH_TOWER, RCTYPE_MUMBO_TOKEN, LEVEL_9_RUSTY_BUCKET_BAY, RI_MUMBO_TOKEN, MUMBOTOKEN_47_RBB_UNDER_CHOMPA_IN_WITCH_SWITCH_TOWER, 6200, 400, 0), + RC(RC_RBB_MUMBO_TOKEN_TOP_OF_SHIPS_CHIMNEY, RCTYPE_MUMBO_TOKEN, LEVEL_9_RUSTY_BUCKET_BAY, RI_MUMBO_TOKEN, MUMBOTOKEN_42_RBB_TOP_OF_SHIPS_CHIMNEY, 1000, 2750, 0), + RC(RC_RBB_MUMBO_TOKEN_FRONT_OF_CHOMPA_LEFT_OF_SHIP, RCTYPE_MUMBO_TOKEN, LEVEL_9_RUSTY_BUCKET_BAY, RI_MUMBO_TOKEN, MUMBOTOKEN_45_RBB_FRONT_OF_CHOMPA_LEFT_OF_SHIP, -3299, -457, 3800), + RC(RC_RBB_MUMBO_TOKEN_UNDER_CHOMPA_INSIDE_FIRST_BLUE_CONTAINER, RCTYPE_MUMBO_TOKEN, LEVEL_9_RUSTY_BUCKET_BAY, RI_MUMBO_TOKEN, MUMBOTOKEN_48_RBB_UNDER_CHOMPA_INSIDE_FIRST_BLUE_CONTAINER, -650, 562, -35), + RC(RC_RBB_MUMBO_TOKEN_TOP_OF_BOX_INSIDE_SECOND_BLUE_CONTAINER, RCTYPE_MUMBO_TOKEN, LEVEL_9_RUSTY_BUCKET_BAY, RI_MUMBO_TOKEN, MUMBOTOKEN_49_RBB_TOP_OF_BOX_INSIDE_SECOND_BLUE_CONTAINER, -278, 710, -557), + RC(RC_RBB_MUMBO_TOKEN_INSIDE_KITCHEN, RCTYPE_MUMBO_TOKEN, LEVEL_9_RUSTY_BUCKET_BAY, RI_MUMBO_TOKEN, MUMBOTOKEN_4C_RBB_INSIDE_KITCHEN, -771, 238, -293), + RC(RC_RBB_MUMBO_TOKEN_TOP_OF_BUNK_IN_CABIN, RCTYPE_MUMBO_TOKEN, LEVEL_9_RUSTY_BUCKET_BAY, RI_MUMBO_TOKEN, MUMBOTOKEN_4A_RBB_TOP_OF_BUNK_IN_CABIN, 583, 323, -70), + RC(RC_RBB_MUMBO_TOKEN_TOP_OF_BOX_INSIDE_TNT_ROOM, RCTYPE_MUMBO_TOKEN, LEVEL_9_RUSTY_BUCKET_BAY, RI_MUMBO_TOKEN, MUMBOTOKEN_50_RBB_TOP_OF_BOX_INSIDE_TNT_ROOM, -435, 300, -435), + RC(RC_RBB_MUMBO_TOKEN_ENGINE_ROOM_LEFT_PIPE, RCTYPE_MUMBO_TOKEN, LEVEL_9_RUSTY_BUCKET_BAY, RI_MUMBO_TOKEN, MUMBOTOKEN_4D_RBB_ENGINE_ROOM_LEFT_PIPE, -2450, 1100, -400), + RC(RC_RBB_MUMBO_TOKEN_ENGINE_ROOM_RIGHT_PIPE, RCTYPE_MUMBO_TOKEN, LEVEL_9_RUSTY_BUCKET_BAY, RI_MUMBO_TOKEN, MUMBOTOKEN_4E_RBB_ENGINE_ROOM_RIGHT_PIPE, 2450, 1100, -400), + RC(RC_RBB_MUMBO_TOKEN_ENGINE_ROOM_SPINNING_PLATFORM, RCTYPE_MUMBO_TOKEN, LEVEL_9_RUSTY_BUCKET_BAY, RI_MUMBO_TOKEN, MUMBOTOKEN_4F_RBB_ENGINE_ROOM_SPINNING_PLATFORM, -319, 12, 1899), + RC(RC_RBB_MUMBO_TOKEN_INSIDE_NAVIGATION_ROOM, RCTYPE_MUMBO_TOKEN, LEVEL_9_RUSTY_BUCKET_BAY, RI_MUMBO_TOKEN, MUMBOTOKEN_4B_RBB_INSIDE_NAVIGATION_ROOM, -656, 0, -222), RC(RC_RBB_NOTE_ANCHOR_ROOM_1, RCTYPE_MUSIC_NOTE, LEVEL_9_RUSTY_BUCKET_BAY, RI_MUSIC_NOTE_RUSTY_BUCKET_BAY, NULL, 3500, 449, -501), RC(RC_RBB_NOTE_ANCHOR_ROOM_2, RCTYPE_MUSIC_NOTE, LEVEL_9_RUSTY_BUCKET_BAY, RI_MUSIC_NOTE_RUSTY_BUCKET_BAY, NULL, 3499, 449, 499), RC(RC_RBB_NOTE_ANCHOR_ROOM_3, RCTYPE_MUSIC_NOTE, LEVEL_9_RUSTY_BUCKET_BAY, RI_MUSIC_NOTE_RUSTY_BUCKET_BAY, NULL, 4499, 449, -500), @@ -1912,16 +1912,16 @@ std::map Checks = { RC(RC_TTC_JINJO_YELLOW, RCTYPE_JINJO, LEVEL_2_TREASURE_TROVE_COVE, RI_JINJO_YELLOW_TREASURE_TROVE_COVE, NULL, -968, 5358, -776), RC(RC_TTC_MOLEHILL_FLIGHT, RCTYPE_MOLEHILL, LEVEL_2_TREASURE_TROVE_COVE, RI_MOLEHILL_FLIGHT, ABILITY_9_FLIGHT, -288, 2161, 1314), RC(RC_TTC_MOLEHILL_SHOCK_JUMP, RCTYPE_MOLEHILL, LEVEL_2_TREASURE_TROVE_COVE, RI_MOLEHILL_SHOCK_JUMP, ABILITY_D_SHOCK_JUMP, 2698, 1517, 3338), - RC(RC_TTC_MUMBO_TOKEN_BEHIND_PILLAR_UNDERWATER, RCTYPE_MUMBO_TOKEN, LEVEL_2_TREASURE_TROVE_COVE, RI_MUMBO_TOKEN_TREASURE_TROVE_COVE, MUMBOTOKEN_0C_TTC_BEHIND_PILLAR_UNDERWATER, 6480, 597, -258), - RC(RC_TTC_MUMBO_TOKEN_BEHIND_LIGHTHOUSE_DOOR, RCTYPE_MUMBO_TOKEN, LEVEL_2_TREASURE_TROVE_COVE, RI_MUMBO_TOKEN_TREASURE_TROVE_COVE, MUMBOTOKEN_0A_TTC_BEHIND_LIGHTHOUSE_DOOR, 565, 6917, -2776), - RC(RC_TTC_MUMBO_TOKEN_BEHIND_NIPPER, RCTYPE_MUMBO_TOKEN, LEVEL_2_TREASURE_TROVE_COVE, RI_MUMBO_TOKEN_TREASURE_TROVE_COVE, MUMBOTOKEN_0F_TTC_BEHIND_NIPPER, -6620, 510, 4621), - RC(RC_TTC_MUMBO_TOKEN_FLOATING_ABOVE_SHOCKJUMP_PAD, RCTYPE_MUMBO_TOKEN, LEVEL_2_TREASURE_TROVE_COVE, RI_MUMBO_TOKEN_TREASURE_TROVE_COVE, MUMBOTOKEN_0E_TTC_FLOATING_ABOVE_SHOCKJUMP_PAD, 2462, 2217, 2957), - RC(RC_TTC_MUMBO_TOKEN_INSIDE_LOCKUP_1, RCTYPE_MUMBO_TOKEN, LEVEL_2_TREASURE_TROVE_COVE, RI_MUMBO_TOKEN_TREASURE_TROVE_COVE, MUMBOTOKEN_07_TTC_INSIDE_LOCKUP_1, -2660, 2447, -6079), - RC(RC_TTC_MUMBO_TOKEN_INSIDE_LOCKUP_2, RCTYPE_MUMBO_TOKEN, LEVEL_2_TREASURE_TROVE_COVE, RI_MUMBO_TOKEN_TREASURE_TROVE_COVE, MUMBOTOKEN_08_TTC_INSIDE_LOCKUP_2, -2646, 2447, -6223), - RC(RC_TTC_MUMBO_TOKEN_INSIDE_SALTY_HIPPO, RCTYPE_MUMBO_TOKEN, LEVEL_2_TREASURE_TROVE_COVE, RI_MUMBO_TOKEN_TREASURE_TROVE_COVE, MUMBOTOKEN_06_TTC_INSIDE_SALTY_HIPPO, 610, -412, 31), - RC(RC_TTC_MUMBO_TOKEN_ON_FLOATING_BOX, RCTYPE_MUMBO_TOKEN, LEVEL_2_TREASURE_TROVE_COVE, RI_MUMBO_TOKEN_TREASURE_TROVE_COVE, MUMBOTOKEN_0B_TTC_ON_FLOATING_BOX, -783, 745, -3872), - RC(RC_TTC_MUMBO_TOKEN_POND_BOTTOM, RCTYPE_MUMBO_TOKEN, LEVEL_2_TREASURE_TROVE_COVE, RI_MUMBO_TOKEN_TREASURE_TROVE_COVE, MUMBOTOKEN_0D_TTC_POND_BOTTOM, -4932, 1122, -1063), - RC(RC_TTC_MUMBO_TOKEN_SALTY_HIPPO_MAST, RCTYPE_MUMBO_TOKEN, LEVEL_2_TREASURE_TROVE_COVE, RI_MUMBO_TOKEN_TREASURE_TROVE_COVE, MUMBOTOKEN_09_TTC_SALTY_HIPPO_MAST, -221, 2029, 929), + RC(RC_TTC_MUMBO_TOKEN_BEHIND_PILLAR_UNDERWATER, RCTYPE_MUMBO_TOKEN, LEVEL_2_TREASURE_TROVE_COVE, RI_MUMBO_TOKEN, MUMBOTOKEN_0C_TTC_BEHIND_PILLAR_UNDERWATER, 6480, 597, -258), + RC(RC_TTC_MUMBO_TOKEN_BEHIND_LIGHTHOUSE_DOOR, RCTYPE_MUMBO_TOKEN, LEVEL_2_TREASURE_TROVE_COVE, RI_MUMBO_TOKEN, MUMBOTOKEN_0A_TTC_BEHIND_LIGHTHOUSE_DOOR, 565, 6917, -2776), + RC(RC_TTC_MUMBO_TOKEN_BEHIND_NIPPER, RCTYPE_MUMBO_TOKEN, LEVEL_2_TREASURE_TROVE_COVE, RI_MUMBO_TOKEN, MUMBOTOKEN_0F_TTC_BEHIND_NIPPER, -6620, 510, 4621), + RC(RC_TTC_MUMBO_TOKEN_FLOATING_ABOVE_SHOCKJUMP_PAD, RCTYPE_MUMBO_TOKEN, LEVEL_2_TREASURE_TROVE_COVE, RI_MUMBO_TOKEN, MUMBOTOKEN_0E_TTC_FLOATING_ABOVE_SHOCKJUMP_PAD, 2462, 2217, 2957), + RC(RC_TTC_MUMBO_TOKEN_INSIDE_LOCKUP_1, RCTYPE_MUMBO_TOKEN, LEVEL_2_TREASURE_TROVE_COVE, RI_MUMBO_TOKEN, MUMBOTOKEN_07_TTC_INSIDE_LOCKUP_1, -2660, 2447, -6079), + RC(RC_TTC_MUMBO_TOKEN_INSIDE_LOCKUP_2, RCTYPE_MUMBO_TOKEN, LEVEL_2_TREASURE_TROVE_COVE, RI_MUMBO_TOKEN, MUMBOTOKEN_08_TTC_INSIDE_LOCKUP_2, -2646, 2447, -6223), + RC(RC_TTC_MUMBO_TOKEN_INSIDE_SALTY_HIPPO, RCTYPE_MUMBO_TOKEN, LEVEL_2_TREASURE_TROVE_COVE, RI_MUMBO_TOKEN, MUMBOTOKEN_06_TTC_INSIDE_SALTY_HIPPO, 610, -412, 31), + RC(RC_TTC_MUMBO_TOKEN_ON_FLOATING_BOX, RCTYPE_MUMBO_TOKEN, LEVEL_2_TREASURE_TROVE_COVE, RI_MUMBO_TOKEN, MUMBOTOKEN_0B_TTC_ON_FLOATING_BOX, -783, 745, -3872), + RC(RC_TTC_MUMBO_TOKEN_POND_BOTTOM, RCTYPE_MUMBO_TOKEN, LEVEL_2_TREASURE_TROVE_COVE, RI_MUMBO_TOKEN, MUMBOTOKEN_0D_TTC_POND_BOTTOM, -4932, 1122, -1063), + RC(RC_TTC_MUMBO_TOKEN_SALTY_HIPPO_MAST, RCTYPE_MUMBO_TOKEN, LEVEL_2_TREASURE_TROVE_COVE, RI_MUMBO_TOKEN, MUMBOTOKEN_09_TTC_SALTY_HIPPO_MAST, -221, 2029, 929), RC(RC_TTC_NOTE_BEACH_LOCKUP_1, RCTYPE_MUSIC_NOTE, LEVEL_2_TREASURE_TROVE_COVE, RI_MUSIC_NOTE_TREASURE_TROVE_COVE, NULL, 4802, 737, -2351), RC(RC_TTC_NOTE_BEACH_LOCKUP_2, RCTYPE_MUSIC_NOTE, LEVEL_2_TREASURE_TROVE_COVE, RI_MUSIC_NOTE_TREASURE_TROVE_COVE, NULL, 4730, 737, -2420), RC(RC_TTC_NOTE_BEACH_LOCKUP_3, RCTYPE_MUSIC_NOTE, LEVEL_2_TREASURE_TROVE_COVE, RI_MUSIC_NOTE_TREASURE_TROVE_COVE, NULL, 4803, 736, -2444), diff --git a/src/port/Rando/StaticData/Items.cpp b/src/port/Rando/StaticData/Items.cpp index c50326121..9c61ecc40 100644 --- a/src/port/Rando/StaticData/Items.cpp +++ b/src/port/Rando/StaticData/Items.cpp @@ -103,16 +103,7 @@ std::map Items = { RI(RI_MOLEHILL_TURBO_TALON, "", "Turbo Talon", RITYPE_MOLEHILL, ACTOR_12C_MOLEHILL, LEVEL_7_GOBIS_VALLEY), RI(RI_MOLEHILL_WADING_BOOTS, "", "Wading Boots", RITYPE_MOLEHILL, ACTOR_12C_MOLEHILL, LEVEL_4_BUBBLEGLOOP_SWAMP), RI(RI_MOLEHILL_WONDERWING, "", "Wonderwing", RITYPE_MOLEHILL, ACTOR_12C_MOLEHILL, LEVEL_3_CLANKERS_CAVERN), - RI(RI_MUMBO_TOKEN_BUBBLEGLOOP_SWAMP, "a", "Mumbo Token - BGS", RITYPE_MUMBO_TOKEN, ACTOR_2D_MUMBO_TOKEN, LEVEL_4_BUBBLEGLOOP_SWAMP), - RI(RI_MUMBO_TOKEN_CLANKERS_CAVERN, "a", "Mumbo Token - CC", RITYPE_MUMBO_TOKEN, ACTOR_2D_MUMBO_TOKEN, LEVEL_3_CLANKERS_CAVERN), - RI(RI_MUMBO_TOKEN_CLICK_CLOCK_WOOD, "a", "Mumbo Token - CCW", RITYPE_MUMBO_TOKEN, ACTOR_2D_MUMBO_TOKEN, LEVEL_8_CLICK_CLOCK_WOOD), - RI(RI_MUMBO_TOKEN_FREEZEEZY_PEAK, "a", "Mumbo Token - FP", RITYPE_MUMBO_TOKEN, ACTOR_2D_MUMBO_TOKEN, LEVEL_5_FREEZEEZY_PEAK), - RI(RI_MUMBO_TOKEN_GOBIS_VALLEY, "a", "Mumbo Token - GV", RITYPE_MUMBO_TOKEN, ACTOR_2D_MUMBO_TOKEN, LEVEL_7_GOBIS_VALLEY), - RI(RI_MUMBO_TOKEN_GRUNTILDAS_LAIR, "a", "Mumbo Token - GL", RITYPE_MUMBO_TOKEN, ACTOR_2D_MUMBO_TOKEN, LEVEL_6_LAIR), - RI(RI_MUMBO_TOKEN_MAD_MONSTER_MANSION, "a", "Mumbo Token - MMM", RITYPE_MUMBO_TOKEN, ACTOR_2D_MUMBO_TOKEN, LEVEL_A_MAD_MONSTER_MANSION), - RI(RI_MUMBO_TOKEN_MUMBOS_MOUNTAIN, "a", "Mumbo Token - MM", RITYPE_MUMBO_TOKEN, ACTOR_2D_MUMBO_TOKEN, LEVEL_1_MUMBOS_MOUNTAIN), - RI(RI_MUMBO_TOKEN_RUSTY_BUCKET_BAY, "a", "Mumbo Token - RBB", RITYPE_MUMBO_TOKEN, ACTOR_2D_MUMBO_TOKEN, LEVEL_9_RUSTY_BUCKET_BAY), - RI(RI_MUMBO_TOKEN_TREASURE_TROVE_COVE, "a", "Mumbo Token - TTC", RITYPE_MUMBO_TOKEN, ACTOR_2D_MUMBO_TOKEN, LEVEL_2_TREASURE_TROVE_COVE), + RI(RI_MUMBO_TOKEN, "a", "Mumbo Token", RITYPE_MUMBO_TOKEN, ACTOR_2D_MUMBO_TOKEN, LEVEL_D_CUTSCENE), RI(RI_MUSIC_NOTE_BUBBLEGLOOP_SWAMP, "a", "Note - BGS", RITYPE_MUSIC_NOTE, ACTOR_51_MUSIC_NOTE, LEVEL_4_BUBBLEGLOOP_SWAMP), RI(RI_MUSIC_NOTE_CLANKERS_CAVERN, "a", "Note - CC", RITYPE_MUSIC_NOTE, ACTOR_51_MUSIC_NOTE, LEVEL_3_CLANKERS_CAVERN), RI(RI_MUSIC_NOTE_CLICK_CLOCK_WOOD, "a", "Note - CCW", RITYPE_MUSIC_NOTE, ACTOR_51_MUSIC_NOTE, LEVEL_8_CLICK_CLOCK_WOOD), diff --git a/src/port/Rando/Types.h b/src/port/Rando/Types.h index 49786a3a4..6cb807352 100644 --- a/src/port/Rando/Types.h +++ b/src/port/Rando/Types.h @@ -2129,16 +2129,7 @@ typedef enum { RI_MOLEHILL_TURBO_TALON, RI_MOLEHILL_WADING_BOOTS, RI_MOLEHILL_WONDERWING, - RI_MUMBO_TOKEN_BUBBLEGLOOP_SWAMP, - RI_MUMBO_TOKEN_CLANKERS_CAVERN, - RI_MUMBO_TOKEN_CLICK_CLOCK_WOOD, - RI_MUMBO_TOKEN_FREEZEEZY_PEAK, - RI_MUMBO_TOKEN_GOBIS_VALLEY, - RI_MUMBO_TOKEN_GRUNTILDAS_LAIR, - RI_MUMBO_TOKEN_MAD_MONSTER_MANSION, - RI_MUMBO_TOKEN_MUMBOS_MOUNTAIN, - RI_MUMBO_TOKEN_RUSTY_BUCKET_BAY, - RI_MUMBO_TOKEN_TREASURE_TROVE_COVE, + RI_MUMBO_TOKEN, RI_MUSIC_NOTE_BUBBLEGLOOP_SWAMP, RI_MUSIC_NOTE_CLANKERS_CAVERN, RI_MUSIC_NOTE_CLICK_CLOCK_WOOD, diff --git a/src/port/UI/DeveloperTools/GameplayTools.cpp b/src/port/UI/DeveloperTools/GameplayTools.cpp index 399559d2e..a59c0d6f4 100644 --- a/src/port/UI/DeveloperTools/GameplayTools.cpp +++ b/src/port/UI/DeveloperTools/GameplayTools.cpp @@ -430,7 +430,8 @@ void GameplayTools_ObjectSpawner() { Actor* newActor = CustomCollectible::Spawn(spawnPosition, (RandoCheckId)selectedCustomCollectible); } ImGui::TableNextColumn(); - std::string customCollectibleText = Rando::StaticData::Checks[(RandoCheckId)selectedCustomCollectible].name; + std::string customCollectibleText = std::to_string(selectedCustomCollectible) + ": " + + Rando::StaticData::Checks[(RandoCheckId)selectedCustomCollectible].name; UIWidgets::SliderInt("##customCollectibleIndex", &selectedCustomCollectible, UIWidgets::IntSliderOptions() From 493ac361188a8659ffc718d318d2eea4b836ac8b Mon Sep 17 00:00:00 2001 From: Jeod <47716344+JeodC@users.noreply.github.com> Date: Sun, 2 Aug 2026 20:33:19 -0400 Subject: [PATCH 082/131] Modify workflows to upload artifacts from pull requests (#352) Mirror soh a bit --- .github/workflows/linux.yml | 48 ----------------------------------- .github/workflows/mac.yml | 23 ----------------- .github/workflows/main.yml | 37 ++++++++++++++------------- .github/workflows/switch.yml | 38 --------------------------- .github/workflows/windows.yml | 20 --------------- 5 files changed, 20 insertions(+), 146 deletions(-) delete mode 100644 .github/workflows/linux.yml delete mode 100644 .github/workflows/mac.yml delete mode 100644 .github/workflows/switch.yml delete mode 100644 .github/workflows/windows.yml diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml deleted file mode 100644 index dfac3075b..000000000 --- a/.github/workflows/linux.yml +++ /dev/null @@ -1,48 +0,0 @@ -name: Linux Validation -on: [pull_request] - -jobs: - build: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - with: - submodules: recursive - - name: Update machine - run: sudo apt update - - name: Install dependencies - run: sudo apt-get install gcc g++ git cmake ninja-build lsb-release libsdl2-dev libpng-dev libsdl2-net-dev libzip-dev zipcmp zipmerge ziptool nlohmann-json3-dev libtinyxml2-dev libspdlog-dev libboost-dev libopengl-dev libogg-dev libvorbis-dev - - name: Install latest SDL - run: | - export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH" - wget https://www.libsdl.org/release/SDL2-2.24.1.tar.gz - tar -xzf SDL2-2.24.1.tar.gz - cd SDL2-2.24.1 - ./configure - make -j 10 - sudo make install - - name: Install latest tinyxml2 - run: | - export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH" - wget https://github.com/leethomason/tinyxml2/archive/refs/tags/10.0.0.tar.gz - tar -xzf 10.0.0.tar.gz - cd tinyxml2-10.0.0 - mkdir -p build - cd build - cmake .. - make - sudo make install - - name: Build - run: | - cmake -H. -Bbuild-cmake -GNinja -DCMAKE_BUILD_TYPE=Release - cmake --build build-cmake -j - - name: Create Package - run: | - mkdir Lighthouse-release - mv build-cmake/Lighthouse Lighthouse-release/ - - name: Publish packaged artifacts - uses: actions/upload-artifact@v4 - with: - name: Lighthouse-linux-x64 - path: Lighthouse-release - retention-days: 1 diff --git a/.github/workflows/mac.yml b/.github/workflows/mac.yml deleted file mode 100644 index 569dcca20..000000000 --- a/.github/workflows/mac.yml +++ /dev/null @@ -1,23 +0,0 @@ -name: MacOS Validation - -on: - pull_request: - branches: [ "*" ] - -jobs: - build: - runs-on: macos-14 - steps: - - uses: actions/checkout@v6 - with: - submodules: recursive - - uses: melusina-org/setup-macports@v1 - with: - parameters: '.github/macports.yml' - - uses: hendrikmuhs/ccache-action@v1.2 - with: - key: macos # ccache-macos - - name: Build - run: | - cmake -H. -Bbuild-cmake -GNinja -DCMAKE_BUILD_TYPE=Release -D CMAKE_C_COMPILER_LAUNCHER=ccache -D CMAKE_CXX_COMPILER_LAUNCHER=ccache -DCMAKE_OSX_ARCHITECTURES="x86_64;arm64" - cmake --build build-cmake -j \ No newline at end of file diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 8f0e90668..f9d670ee5 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -1,6 +1,7 @@ name: GenerateBuilds on: push: + pull_request: concurrency: group: ${{ github.workflow }}-${{ github.ref }} @@ -8,9 +9,11 @@ concurrency: jobs: generate-port-o2r: + # Same-repo branches fire both push and pull_request; only build once. + if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name != github.repository runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v7 with: submodules: true - name: Extract Project Version @@ -22,7 +25,7 @@ jobs: - name: Install dependencies run: sudo apt-get install gcc g++ git cmake ninja-build lsb-release - name: ccache - uses: hendrikmuhs/ccache-action@v1.2.13 + uses: hendrikmuhs/ccache-action@v1.2.23 with: key: ${{ runner.os }}-o2r-ccache-${{ github.ref }}-${{ github.sha }} restore-keys: | @@ -43,7 +46,7 @@ jobs: make -C Torch type=release -j3 cp -r ./libultraship/src/fast/shaders ./port Torch/cmake-build-release/torch pack port lighthouse.o2r o2r -u ${{ steps.extract_version.outputs.version }} - - uses: actions/upload-artifact@v4 + - uses: actions/upload-artifact@v7 with: name: lighthouse.o2r path: lighthouse.o2r @@ -53,15 +56,15 @@ jobs: needs: generate-port-o2r runs-on: windows-2022 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v7 with: submodules: recursive - name: Build run: | - cmake -S . -B "build/x64" -G "Visual Studio 17 2022" -T v143 -A x64 -DCMAKE_BUILD_TYPE=Release + cmake -S . -B "build/x64" -G "Visual Studio 17 2022" -T v143 -A x64 cmake --build ./build/x64 --config Release --parallel 10 - name: Download lighthouse.o2r - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v8 with: name: lighthouse.o2r path: ./build/x64 @@ -77,7 +80,7 @@ jobs: mv assets lighthouse-release/ Invoke-WebRequest -Uri "https://raw.githubusercontent.com/mdqinc/SDL_GameControllerDB/master/gamecontrollerdb.txt" -OutFile "lighthouse-release/gamecontrollerdb.txt" - name: Upload build - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: Lighthouse-windows path: lighthouse-release @@ -86,13 +89,13 @@ jobs: needs: generate-port-o2r runs-on: macos-14 steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 with: submodules: recursive - uses: melusina-org/setup-macports@v1 with: parameters: '.github/macports.yml' - - uses: hendrikmuhs/ccache-action@v1.2 + - uses: hendrikmuhs/ccache-action@v1.2.23 with: key: macos # ccache-macos - name: Build @@ -100,7 +103,7 @@ jobs: cmake -H. -Bbuild-cmake -GNinja -DCMAKE_BUILD_TYPE=Release -D CMAKE_C_COMPILER_LAUNCHER=ccache -D CMAKE_CXX_COMPILER_LAUNCHER=ccache -DCMAKE_OSX_ARCHITECTURES="x86_64;arm64" cmake --build build-cmake -j - name: Download lighthouse.o2r - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v8 with: name: lighthouse.o2r path: ./build-cmake @@ -110,7 +113,7 @@ jobs: mv _packages/*.dmg Lighthouse.dmg mv README.md readme.txt - name: Publish packaged artifacts - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: Lighthouse-mac path: | @@ -121,7 +124,7 @@ jobs: needs: generate-port-o2r runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v7 with: submodules: recursive - name: Update machine @@ -129,7 +132,7 @@ jobs: - name: Install dependencies run: sudo apt-get install gcc g++ git cmake ninja-build lsb-release libsdl2-dev libpng-dev libsdl2-net-dev libzip-dev zipcmp zipmerge ziptool nlohmann-json3-dev libtinyxml2-dev libspdlog-dev libboost-dev libopengl-dev libogg-dev libvorbis-dev - name: ccache - uses: hendrikmuhs/ccache-action@v1.2.14 + uses: hendrikmuhs/ccache-action@v1.2.23 with: key: linux-ccache-${{ github.ref }}-${{ github.sha }} restore-keys: | @@ -184,7 +187,7 @@ jobs: sudo make install sudo cp -av /usr/local/lib/libzip* /lib/x86_64-linux-gnu/ - name: Download lighthouse.o2r - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v8 with: name: lighthouse.o2r path: ./build-cmake @@ -197,7 +200,7 @@ jobs: mv README.md readme.txt mv build-cmake/*.appimage lighthouse.appimage - name: Upload build - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: Lighthouse-linux path: | @@ -212,7 +215,7 @@ jobs: container: image: devkitpro/devkita64:20241023 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v7 with: submodules: recursive - name: Install dependencies @@ -231,7 +234,7 @@ jobs: mv README.md readme.txt mv build-switch/*.nro Lighthouse.nro - name: Upload build - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: Lighthouse-switch path: | diff --git a/.github/workflows/switch.yml b/.github/workflows/switch.yml deleted file mode 100644 index db9773c5c..000000000 --- a/.github/workflows/switch.yml +++ /dev/null @@ -1,38 +0,0 @@ -name: Switch Validation -on: [pull_request] - -jobs: - build-switch: - if: false - runs-on: ubuntu-latest - container: - image: devkitpro/devkita64:20241023 - steps: - - uses: actions/checkout@v4 - with: - submodules: recursive - - name: Install dependencies - run: | - sudo apt-get update - sudo apt-get install -y ninja-build - sudo apt-get remove -y cmake - git -C libultraship remote add nx https://github.com/YoshiCrystal9/libultraship.git - git -C libultraship fetch nx - git -C libultraship checkout nx/main-nx - wget https://github.com/Kitware/CMake/releases/download/v3.28.3/cmake-3.28.3-linux-x86_64.sh -O /tmp/cmake.sh - sudo sh /tmp/cmake.sh --prefix=/usr/local/ --exclude-subdir - cmake -H. -Bbuild-switch -GNinja -DCMAKE_TOOLCHAIN_FILE=/opt/devkitpro/cmake/Switch.cmake - cmake --build build-switch --config Release -j3 - wget -O gamecontrollerdb.txt https://github.com/mdqinc/SDL_GameControllerDB/blob/master/gamecontrollerdb.txt - mv README.md readme.txt - mv build-switch/*.nro Lighthouse.nro - - name: Upload build - uses: actions/upload-artifact@v4 - with: - name: Lighthouse-switch - retention-days: 1 - path: | - Lighthouse.nro - config.yml - assets - gamecontrollerdb.txt \ No newline at end of file diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml deleted file mode 100644 index a0f8ae5e1..000000000 --- a/.github/workflows/windows.yml +++ /dev/null @@ -1,20 +0,0 @@ -name: Windows Validation -on: [pull_request] - -jobs: - build: - runs-on: windows-2022 - steps: - - uses: actions/checkout@v4 - with: - submodules: recursive - - name: Build - run: | - cmake -S . -B "build/x64" -G "Visual Studio 17 2022" -T v143 -A x64 -DCMAKE_BUILD_TYPE=Release - cmake --build ./build/x64 - - name: Upload build - uses: actions/upload-artifact@v4 - with: - name: lighthouse-windows - path: ./build/x64/Debug - retention-days: 1 \ No newline at end of file From 8736542bd65ccd4142725e8231ecf82309d1a149 Mon Sep 17 00:00:00 2001 From: Jeod <47716344+JeodC@users.noreply.github.com> Date: Sun, 2 Aug 2026 20:33:30 -0400 Subject: [PATCH 083/131] Restore rumble to proper state and restore screenshake (#353) * Restore rumble to proper state and restore screenshake * Make screen shake an accessibility option --- src/core1/bamotor.c | 4 +--- src/core2/nc/camera_nodemanager.c | 3 +++ src/port/Enhancements/Events/Hooks/Events.h | 1 + src/port/Patches/CameraPatches.cpp | 7 +++++++ src/port/UI/LighthouseMenuSettings.cpp | 22 +++++++++------------ 5 files changed, 21 insertions(+), 16 deletions(-) diff --git a/src/core1/bamotor.c b/src/core1/bamotor.c index 7101e75bd..84111a3a3 100644 --- a/src/core1/bamotor.c +++ b/src/core1/bamotor.c @@ -155,9 +155,7 @@ void baMotor_80250D94(f32 arg0, f32 arg1, f32 arg2){ if(arg2 != 0.0f && D_802823AC){ if(func_802E4A08() == 0){ if(!(0.1 < D_80282420 - D_80282424) || !(arg0 + arg1 < D_80282428 + D_8028242C)){ - // [port] Scale intensity by ImGui rumble setting. - // Original N64 values are ~50% of max (duty cycling a binary motor). - f32 scale = port_getRumbleScale() * 2.0f; + f32 scale = port_getRumbleScale(); D_80282420 = arg2; D_80282424 = 0.0f; D_80282428 = MIN(arg0 * scale, 1.0f); diff --git a/src/core2/nc/camera_nodemanager.c b/src/core2/nc/camera_nodemanager.c index 23b7dda8f..de7e2b158 100644 --- a/src/core2/nc/camera_nodemanager.c +++ b/src/core2/nc/camera_nodemanager.c @@ -307,6 +307,9 @@ void ncCamera_update(void){ viewport_getPosition_vec3f(sp2C); viewport_getRotation_vec3f(sp20); func_802BB4D8(sp2C, sp20); + if (EventSystem_Should(VB_CAMERA_APPLY_SHAKE, true)) { + viewport_setPosition_vec3f(sp2C); + } viewport_update(); func_802BEFB0(); func_802BBA84(); diff --git a/src/port/Enhancements/Events/Hooks/Events.h b/src/port/Enhancements/Events/Hooks/Events.h index 99148ae6b..8199841fc 100644 --- a/src/port/Enhancements/Events/Hooks/Events.h +++ b/src/port/Enhancements/Events/Hooks/Events.h @@ -20,6 +20,7 @@ typedef enum VBehaviorID { VB_STATIC_CAMERA_EXIT, VB_CAMERA_LIVE_ASPECT, VB_CAMERA_FOLLOW, + VB_CAMERA_APPLY_SHAKE, // Cutscene and celebration skips VB_PLAY_BOOT_LOGOS, diff --git a/src/port/Patches/CameraPatches.cpp b/src/port/Patches/CameraPatches.cpp index 1121995ca..6770a57f3 100644 --- a/src/port/Patches/CameraPatches.cpp +++ b/src/port/Patches/CameraPatches.cpp @@ -92,6 +92,7 @@ static void updateCutsceneAspect(int32_t mapId) { // Widescreen yaw fix — per-frame yaw adjustment for certain static cameras in widescreen mode #define CVAR_WS_CAMERA_FIX CVAR_ENHANCEMENT("Fix.WidescreenCamera") +#define CVAR_NO_SCREEN_SHAKE CVAR_SETTING("A11yDisableScreenShake") struct WsYawFix { int32_t map; @@ -172,5 +173,11 @@ void RegisterCameraPatches_Init() { }); } +void RegisterScreenShake_Init() { + COND_VB_SHOULD(VB_CAMERA_APPLY_SHAKE, EVENT_PRIORITY_NORMAL, CVarGetInteger(CVAR_NO_SCREEN_SHAKE, 0), + { *should = false; }); +} + static RegisterShipInitFunc cutsceneAspectInitFunc(RegisterCutsceneAspect, { CVAR_CUTSCENE_ASPECT }); static RegisterShipInitFunc staticCamInitFunc(RegisterCameraPatches_Init); +static RegisterShipInitFunc screenShakeInitFunc(RegisterScreenShake_Init, { CVAR_NO_SCREEN_SHAKE }); diff --git a/src/port/UI/LighthouseMenuSettings.cpp b/src/port/UI/LighthouseMenuSettings.cpp index 08336cc00..9f8d09790 100644 --- a/src/port/UI/LighthouseMenuSettings.cpp +++ b/src/port/UI/LighthouseMenuSettings.cpp @@ -261,21 +261,17 @@ void LighthouseMenu::AddMenuSettings() { .Options(ButtonOptions() .Size(Sizes::Inline) .Tooltip("Pick a Banjo-Kazooie ROM and extract only its dialog into a slim language pack.")); + + // Accessibility Options AddWidget(path, "Accessibility", WIDGET_SEPARATOR_TEXT); -#if defined(_WIN32) || defined(__APPLE__) || defined(ESPEAK) - AddWidget(path, "Text to Speech", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_SETTING("A11yTTS")) - .RaceDisable(false) - .Options(CheckboxOptions().Tooltip("Enables text to speech for in game dialog")); -#endif - AddWidget(path, "Disable Idle Camera Re-Centering", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_SETTING("A11yDisableIdleCam")) + AddWidget(path, "Disable Screen Shake", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_SETTING("A11yDisableScreenShake")) .RaceDisable(false) - .Options(CheckboxOptions().Tooltip("Disables the automatic re-centering of the camera when idle.")); - AddWidget(path, "Disable Screen Flash for Finishing Blow", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_SETTING("A11yNoScreenFlashForFinishingBlow")) - .RaceDisable(false) - .Options(CheckboxOptions().Tooltip("Disables the white screen flash on enemy kill.")); + .Options(CheckboxOptions().Tooltip( + "Stops the camera shaking on impacts such as Beak Buster landings, boulders and boss attacks. " + "Controller rumble is unaffected.")); + + // Experimental Options AddWidget(path, "EXPERIMENTAL", WIDGET_SEPARATOR_TEXT).Options(TextOptions().Color(Colors::Orange)); AddWidget(path, "ImGui Menu Scaling", WIDGET_CVAR_COMBOBOX) .CVar(CVAR_SETTING("ImGuiScale")) From bc0bd3f12b104ca2a4c79bb0287fa57da9a3f2c7 Mon Sep 17 00:00:00 2001 From: Jeod <47716344+JeodC@users.noreply.github.com> Date: Sun, 2 Aug 2026 20:35:35 -0400 Subject: [PATCH 084/131] Fix imgui audio backends showing up when they shouldn't (#356) --- src/port/UI/Menu.cpp | 13 ++++++++++--- src/port/UI/Menu.h | 3 +++ src/port/UI/MenuTypes.h | 1 + 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/port/UI/Menu.cpp b/src/port/UI/Menu.cpp index d04ecdd02..778aff569 100644 --- a/src/port/UI/Menu.cpp +++ b/src/port/UI/Menu.cpp @@ -113,6 +113,13 @@ void Menu::UpdateWindowBackendObjects() { } } +void Menu::UpdateAudioBackendObjects() { + availableAudioBackends = Ship::Context::GetRawInstance()->GetAudio()->GetAvailableAudioBackends(); + for (auto& backend : *availableAudioBackends) { + availableAudioBackendsMap[backend] = audioBackendsMap.at(backend); + } +} + bool Menu::IsMenuPopped() { return popped; } @@ -135,6 +142,7 @@ void Menu::InitElement() { menuThemeIndex = static_cast(CVarGetInteger(CVAR_SETTING("Menu.Theme"), defaultThemeIndex)); UpdateWindowBackendObjects(); + UpdateAudioBackendObjects(); } void Menu::UpdateElement() { @@ -342,10 +350,9 @@ void Menu::MenuDrawItem(WidgetInfo& widget, uint32_t width, UIWidgets::Colors me UIWidgets::ComboboxOptions options = {}; options.color = menuThemeIndex; options.tooltip = "Sets the audio API used by the game. Requires a relaunch to take effect."; - options.disabled = - Ship::Context::GetRawInstance()->GetAudio()->GetAvailableAudioBackends()->size() <= 1; + options.disabled = availableAudioBackends->size() <= 1; options.disabledTooltip = "Only one audio API is available on this platform."; - if (UIWidgets::Combobox("Audio API", ¤tAudioBackend, audioBackendsMap, options)) { + if (UIWidgets::Combobox("Audio API", ¤tAudioBackend, availableAudioBackendsMap, options)) { Ship::Context::GetRawInstance()->GetAudio()->SetCurrentAudioBackend(currentAudioBackend); } } break; diff --git a/src/port/UI/Menu.h b/src/port/UI/Menu.h index f32c349d6..b1b8378e3 100644 --- a/src/port/UI/Menu.h +++ b/src/port/UI/Menu.h @@ -20,6 +20,7 @@ class Menu : public GuiWindow { void InsertSidebarSearch(); void RemoveSidebarSearch(); void UpdateWindowBackendObjects(); + void UpdateAudioBackendObjects(); bool IsMenuPopped(); UIWidgets::Colors GetMenuThemeColor(); @@ -41,6 +42,8 @@ class Menu : public GuiWindow { std::shared_ptr> availableWindowBackends; std::unordered_map availableWindowBackendsMap; Fast::WindowBackend configWindowBackend; + std::shared_ptr> availableAudioBackends; + std::unordered_map availableAudioBackendsMap; std::unordered_map disabledMap; std::vector disabledVector; diff --git a/src/port/UI/MenuTypes.h b/src/port/UI/MenuTypes.h index 8131e25af..f86cf363b 100644 --- a/src/port/UI/MenuTypes.h +++ b/src/port/UI/MenuTypes.h @@ -266,6 +266,7 @@ struct MainMenuEntry { static const std::unordered_map audioBackendsMap = { { Ship::AudioBackend::WASAPI, "Windows Audio Session API" }, + { Ship::AudioBackend::COREAUDIO, "Core Audio" }, { Ship::AudioBackend::SDL, "SDL" }, { Ship::AudioBackend::NUL, "Null" }, }; From 1dade8dfd9f5d0ef6d5986bc7c6bd10dc9b861fb Mon Sep 17 00:00:00 2001 From: Jeod <47716344+JeodC@users.noreply.github.com> Date: Sun, 2 Aug 2026 20:36:44 -0400 Subject: [PATCH 085/131] Add missing images and update readme for keyboard keys (#357) --- README.md | 6 +++--- docs/poweredbylus.darkmode.png | Bin 0 -> 213165 bytes docs/poweredbylus.lightmode.png | Bin 0 -> 210989 bytes 3 files changed, 3 insertions(+), 3 deletions(-) create mode 100644 docs/poweredbylus.darkmode.png create mode 100644 docs/poweredbylus.lightmode.png diff --git a/README.md b/README.md index 8b021a139..92f934991 100644 --- a/README.md +++ b/README.md @@ -54,15 +54,15 @@ Your ROM needs to be in .z64 format. If it's in .n64 format, use the following t Lighthouse ships with a file with many standard controller mappings that can be used as-is with most controllers. If your controller isn't recognized by Lighthouse, or isn't working properly, you can create your own custom mapping using the built-in mapper in the Settings menu. ### Default keyboard configuration -| N64 | A | B | Z | Start | Analog stick | C buttons | D-Pad | +| N64 | A | B | L | R | Z | Start | Analog stick | C buttons | D-Pad | | - | - | - | - | - | - | - | - | -| Keyboard | X | C | Z | Space | WASD | Arrow keys | TFGH | +| Keyboard | X | C | E | R | Z | Space | WASD | Arrow keys | TFGH | ### Other shortcuts | Keys | Action | | - | - | | ESC | Toggle menubar | -| Ctrl+R | Reset | +| Ctrl+R / ⌘R | Reset | | F11 | Fullscreen | | Tab | Toggle Alternate assets | diff --git a/docs/poweredbylus.darkmode.png b/docs/poweredbylus.darkmode.png new file mode 100644 index 0000000000000000000000000000000000000000..2e2660814fdc04be71c078bd4e12800849de5394 GIT binary patch literal 213165 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 z

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 XE#MDywVZnl{iC6(rIPiB`OW_WIlKFS literal 0 HcmV?d00001 diff --git a/docs/poweredbylus.lightmode.png b/docs/poweredbylus.lightmode.png new file mode 100644 index 0000000000000000000000000000000000000000..740675417b594e406d85069d54574f1dceadd7b8 GIT binary patch literal 210989 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 PU&=nkg9`C~=wA9Cm#!~S literal 0 HcmV?d00001 From f41c7d5f5ce019c00fc7e5b064501aeb57af67f8 Mon Sep 17 00:00:00 2001 From: Jeod <47716344+JeodC@users.noreply.github.com> Date: Sun, 2 Aug 2026 20:39:21 -0400 Subject: [PATCH 086/131] Add a modern controls exception for jigsaw podiums so player can take their placed pieces back (#360) --- src/lair/jigsawpicture.c | 2 ++ src/port/Controller/ControlSchemes.cpp | 20 +++++++++++++++++-- .../Events/Hooks/List/BehaviorEvent.h | 1 + .../Enhancements/Events/PortEnhancements.cpp | 1 + 4 files changed, 22 insertions(+), 2 deletions(-) diff --git a/src/lair/jigsawpicture.c b/src/lair/jigsawpicture.c index cfb5be6ed..99034541f 100644 --- a/src/lair/jigsawpicture.c +++ b/src/lair/jigsawpicture.c @@ -5,6 +5,7 @@ #include "jigsawpicture.h" #include "port/Romhack/RomhackConfig.h" #include "port/Network/Anchor/JigsawPedestal.h" +#include "port/Enhancements/Events/Hooks/Events.h" extern void player_walkToPosition(f32[3], f32, void(*)(ActorMarker *), ActorMarker *); extern void func_80324CFC(f32, enum comusic_e, s32); extern void rand_seed(s32); @@ -565,6 +566,7 @@ void updateJigsawPictureActor(Actor *this) { break; case 4: //L8038FE28 + { CALL_EVENT(OnJigsawPodiumInput, this->actorTypeSpecificField); } if ((gcdialog_getCurrentTextId() != 0xF7C) && (gcdialog_getCurrentTextId() != 0xF7D)) { if (sp7C[FACE_BUTTON(BUTTON_A)] == 1) { addPieces(this, 5); diff --git a/src/port/Controller/ControlSchemes.cpp b/src/port/Controller/ControlSchemes.cpp index fc468690a..75a725da3 100644 --- a/src/port/Controller/ControlSchemes.cpp +++ b/src/port/Controller/ControlSchemes.cpp @@ -23,6 +23,8 @@ #include "port/UI/cvar_prefixes.h" #include "port/Enhancements/Camera/FreeLookCamera.h" +#include "port/Enhancements/Events/Hooks/Events.h" +#include "port/ShipInit.hpp" #include "port/ShipUtils.h" #include "ControlSchemes.h" @@ -225,6 +227,15 @@ void ControlSchemes_Apply(int scheme) { } } +// Frames of C-Down passthrough left for a jigsaw podium. +static int32_t sJigsawPodiumTTL = 0; + +void RegisterControlSchemes_Init() { + COND_HOOK(OnJigsawPodiumInput, EVENT_PRIORITY_NORMAL, true, [](IEvent*) { sJigsawPodiumTTL = 4; }); +} + +static RegisterShipInitFunc initControlSchemes(RegisterControlSchemes_Init); + extern "C" void port_shapeControllerInput(void* contPad) { auto* pad = static_cast(contPad); if (pad == nullptr) { @@ -262,8 +273,13 @@ extern "C" void port_shapeControllerInput(void* contPad) { int32_t arx = (rx < 0) ? -rx : rx; int32_t ary = (ry < 0) ? -ry : ry; + const bool onJigsawPodium = (sJigsawPodiumTTL > 0); + if (sJigsawPodiumTTL > 0) { + sJigsawPodiumTTL--; + } + if (modern) { - if (!crouched && !eggPooping) { + if (!crouched && !eggPooping && !onJigsawPodium) { pad->button &= ~BTN_CDOWN; } @@ -297,7 +313,7 @@ extern "C" void port_shapeControllerInput(void* contPad) { static uint16_t sLatchDir = 0; static int32_t sLatchTTL = 0; - if (port_freeLook_isEnabled()) { + if (port_freeLook_isEnabled() && !onJigsawPodium) { uint16_t stickBits = 0; if (arx * arx + ary * ary > 24 * 24) { if (arx >= ary) { diff --git a/src/port/Enhancements/Events/Hooks/List/BehaviorEvent.h b/src/port/Enhancements/Events/Hooks/List/BehaviorEvent.h index 2d43b2418..458e9073c 100644 --- a/src/port/Enhancements/Events/Hooks/List/BehaviorEvent.h +++ b/src/port/Enhancements/Events/Hooks/List/BehaviorEvent.h @@ -20,6 +20,7 @@ DEFINE_EVENT(OnGruntyJinjonatorComplete) DEFINE_EVENT(OnIntroCutsceneCheck, bool* skipIntro;) DEFINE_EVENT(OnMiscCutscenesCheck, bool* skipMiscCutscenes;) DEFINE_EVENT(OnTooieJiggyCollect, f32* position;) +DEFINE_EVENT(OnJigsawPodiumInput, s32 podiumId;) DEFINE_EVENT(OnMumboTokenUpdate, Actor* actor;) DEFINE_EVENT(OnMumboTokenIdResolve, s32* tokenId; s32 * position; s32 mapId;) DEFINE_EVENT(OnPlayerAnimChange, AssetID anim_id; f32 duration; AnimControl control; f32 start_position; diff --git a/src/port/Enhancements/Events/PortEnhancements.cpp b/src/port/Enhancements/Events/PortEnhancements.cpp index c8978ce36..749288593 100644 --- a/src/port/Enhancements/Events/PortEnhancements.cpp +++ b/src/port/Enhancements/Events/PortEnhancements.cpp @@ -62,6 +62,7 @@ void PortEnhancements_Register() { REGISTER_EVENT(OnIntroCutsceneCheck); REGISTER_EVENT(OnMiscCutscenesCheck); REGISTER_EVENT(OnTooieJiggyCollect); + REGISTER_EVENT(OnJigsawPodiumInput); REGISTER_EVENT(OnMumboTokenUpdate); REGISTER_EVENT(OnMumboTokenIdResolve); REGISTER_EVENT(OnNametagDraw); From 719f83c7f5e6d95536de42eedacf65071c0a2e40 Mon Sep 17 00:00:00 2001 From: Malkierian Date: Sun, 2 Aug 2026 17:40:11 -0700 Subject: [PATCH 087/131] Anchor fixes (#361) * Gate local Anchor codepaths behind world syncing to prevent operation in global room. * Fix witch switch cutscenes and sub area transitions clearing transient persistence values. --- src/GV/ch/ancientone.c | 6 +- src/core2/quiz/game.c | 4 + src/port/Network/Anchor/Anchor.cpp | 48 ++++++-- src/port/Network/Anchor/Anchor.h | 6 + src/port/Network/Anchor/Authority.cpp | 13 ++- src/port/Network/Anchor/HookHandlers.cpp | 117 +++++++++++++------- src/port/Network/Anchor/JigsawPedestal.cpp | 11 +- src/port/Network/Anchor/JsonConversions.hpp | 1 + src/port/Network/Anchor/Packets/MapLoad.cpp | 3 + src/port/Patches/Patches.h | 2 + src/port/UI/LighthouseMenu.cpp | 2 +- src/port/UI/LighthouseMenuEnhancements.cpp | 2 +- 12 files changed, 151 insertions(+), 64 deletions(-) diff --git a/src/GV/ch/ancientone.c b/src/GV/ch/ancientone.c index b4d535f77..61fee9176 100644 --- a/src/GV/ch/ancientone.c +++ b/src/GV/ch/ancientone.c @@ -4,7 +4,7 @@ #include "variables.h" extern void core1_7090_initSfxSource(s32, s32, s32, f32); -extern s32 port_anchor_isConnected(void); +extern s32 port_anchor_isWorldSyncActive(void); typedef struct { f32 unk0[3]; @@ -135,7 +135,7 @@ void chAncientOne_update(Actor *this){ } // Anchor only. A statue that has not been drawn yet still has to run the // body below so it can catch up to flags another client set. - if(!port_anchor_isConnected()){ + if(!port_anchor_isWorldSyncActive()){ return; } { @@ -152,7 +152,7 @@ void chAncientOne_update(Actor *this){ return; } // Anchor: ring order is randomized per-client; advance by synced-flag count. - if(port_anchor_isConnected()){ + if(port_anchor_isWorldSyncActive()){ s32 fc = 0, fi; for(fi = 7; fi < 0xC && mapSpecificFlags_get(fi); fi++) fc++; if(this->state == 1 && this->actorTypeSpecificField <= fc){ diff --git a/src/core2/quiz/game.c b/src/core2/quiz/game.c index f2654bf14..a058abd6e 100644 --- a/src/core2/quiz/game.c +++ b/src/core2/quiz/game.c @@ -534,6 +534,10 @@ void port_breakable_despawnBrokenRestores(s32 map) { } } +s32 port_cutsceneWarp_getReturnMap(void) { + return D_80367694; +} + void chMMMBreakableWooden_update(Actor *this){ func_802D3CE8(this); } diff --git a/src/port/Network/Anchor/Anchor.cpp b/src/port/Network/Anchor/Anchor.cpp index 0e9fd79cb..b5582a9e9 100644 --- a/src/port/Network/Anchor/Anchor.cpp +++ b/src/port/Network/Anchor/Anchor.cpp @@ -1,5 +1,6 @@ #include "Anchor.h" #include "Authority.h" +#include #include #include #include "port/Engine.h" @@ -32,7 +33,11 @@ void Anchor::Enable() { } bool Anchor::IsGlobalRoom() { - return std::string("lh-global") == CVarGetString(CVAR_REMOTE_ANCHOR("RoomId"), ""); + return strcmp(CVarGetString(CVAR_REMOTE_ANCHOR("RoomId"), ""), "lh-global") == 0; +} + +bool Anchor::IsWorldSyncActive() { + return isConnected && !IsGlobalRoom() && roomState.syncItemsAndFlags != 0; } void Anchor::Disable() { @@ -55,8 +60,8 @@ void Anchor::OnConnected() { SendPacket_Handshake(); RegisterHooks(); - port_noteRetention_setForced(1); - port_jinjoRetention_setForced(1); + port_noteRetention_setForced(IsGlobalRoom() ? 0 : 1); + port_jinjoRetention_setForced(IsGlobalRoom() ? 0 : 1); if (IsSaveLoaded()) { SendPacket_RequestTeamState(); @@ -338,12 +343,18 @@ void Anchor::ClearDummies() { dummies.clear(); } -// Lets decomp gate Anchor-only catch-up paths so single player keeps vanilla behaviour. +// Presence only: true in any room, including the global one. For dummy-player visuals. extern "C" s32 port_anchor_isConnected(void) { Anchor* anchor = Anchor::GetInstance(); return (anchor != nullptr && anchor->isConnected) ? 1 : 0; } +// Lets decomp gate Anchor-only catch-up paths so single player keeps vanilla behaviour. +extern "C" s32 port_anchor_isWorldSyncActive(void) { + Anchor* anchor = Anchor::GetInstance(); + return (anchor != nullptr && anchor->IsWorldSyncActive()) ? 1 : 0; +} + // actorArray_free tears down actors/markers without firing OnActorDestroy; forget them all. extern "C" void port_anchorDummies_onActorsFreed(void) { Anchor* anchor = Anchor::GetInstance(); @@ -398,27 +409,46 @@ void Anchor::RemoveDummy(uint32_t clientId) { } } +extern "C" s32 port_cutsceneWarp_getReturnMap(void); extern void port_breakable_clearForLevel(int32_t levelId); extern void port_hutSmash_clearForLevel(int32_t levelId); extern void port_eggToll_clearForLevel(int32_t levelId); extern void port_puzzleStep_clearForLevel(int32_t levelId); extern void port_carriedSync_clearForLevel(int32_t levelId); +s32 Anchor_LevelOfMap(s32 map) { + if (map <= 0 || map >= MAP_NUM_MAPS) { + return 0; + } + s32 level = (s32)map_getLevel((enum map_e)map); + return (level > 0 && level < 0x20) ? level : 0; +} + void Anchor::SweepUnoccupiedLevelState(GameMap selfMap) { + // Nothing is shared without world sync, so these stores hold only our own progress — + // dropping them on a level change would undo single-player state. + if (!IsWorldSyncActive()) { + return; + } + + s32 selfLevel = Anchor_LevelOfMap((s32)selfMap); + if (selfLevel == 0 || selfLevel == (s32)LEVEL_D_CUTSCENE || selfMap == MAP_91_FILE_SELECT) { + return; + } + bool occupied[0x20] = { false }; // level_e ids are small; matches jinjo retention slot count auto markOccupied = [&occupied](s32 map) { - if (map <= 0 || map >= MAP_NUM_MAPS) { - return; - } - s32 level = (s32)map_getLevel((enum map_e)map); - if (level > 0 && level < 0x20) { + s32 level = Anchor_LevelOfMap(map); + if (level != 0) { occupied[level] = true; } }; markOccupied((s32)selfMap); + markOccupied(port_cutsceneWarp_getReturnMap()); for (auto& [clientId, client] : clients) { if (!client.self && client.online && client.isSaveLoaded) { markOccupied((s32)client.map); + markOccupied(client.cutsceneReturnMap); } } for (s32 level = 1; level < 0x20; level++) { diff --git a/src/port/Network/Anchor/Anchor.h b/src/port/Network/Anchor/Anchor.h index 7f4fa1359..8cccc456d 100644 --- a/src/port/Network/Anchor/Anchor.h +++ b/src/port/Network/Anchor/Anchor.h @@ -31,6 +31,7 @@ typedef struct { bool isGameComplete; GameMap map, prevMap; s32 exit, prevExit; + s32 cutsceneReturnMap; DummyPlayer* dummy; } AnchorClient; @@ -210,6 +211,11 @@ class Anchor : public Network { bool IsGlobalRoom(); + // The single gate for every Anchor behaviour that touches the world. A presence-only + // room (the global room, or a private room with "Sync Items & Flags" off) has to play + // exactly like single player, so only dummy players are allowed past this. + bool IsWorldSyncActive(); + // Presence/position/plumbing packets, the only ones allowed through when the room // is not syncing game state. Anything absent is treated as world state and dropped // at the send and receive choke points, so a new packet type is unsynced by default. diff --git a/src/port/Network/Anchor/Authority.cpp b/src/port/Network/Anchor/Authority.cpp index e5fb55eb8..7a689f011 100644 --- a/src/port/Network/Anchor/Authority.cpp +++ b/src/port/Network/Anchor/Authority.cpp @@ -48,9 +48,14 @@ static void Authority_ClearClaim(NetworkActivityId activity) { } } +static bool Authority_SyncActive() { + Anchor* anchor = Anchor::GetInstance(); + return anchor != nullptr && anchor->IsWorldSyncActive(); +} + bool NetAuthority_IsSelf(NetworkActivityId activity) { Anchor* anchor = Anchor::GetInstance(); - if (anchor == nullptr || !anchor->isConnected || !Authority_IsValidActivity(activity)) { + if (!Authority_SyncActive() || !Authority_IsValidActivity(activity)) { return true; } const ActivityState& state = sActivities[activity]; @@ -58,7 +63,7 @@ bool NetAuthority_IsSelf(NetworkActivityId activity) { } bool NetAuthority_IsClaimed(NetworkActivityId activity) { - return Authority_IsValidActivity(activity) && sActivities[activity].claimed; + return Authority_SyncActive() && Authority_IsValidActivity(activity) && sActivities[activity].claimed; } uint32_t NetAuthority_GetOwner(NetworkActivityId activity) { @@ -70,7 +75,7 @@ uint32_t NetAuthority_GetOwner(NetworkActivityId activity) { void NetAuthority_Claim(NetworkActivityId activity) { Anchor* anchor = Anchor::GetInstance(); - if (anchor == nullptr || !anchor->isConnected || !Authority_IsValidActivity(activity)) { + if (!Authority_SyncActive() || !Authority_IsValidActivity(activity)) { return; } ActivityState& state = sActivities[activity]; @@ -87,7 +92,7 @@ void NetAuthority_Claim(NetworkActivityId activity) { void NetAuthority_Release(NetworkActivityId activity) { Anchor* anchor = Anchor::GetInstance(); - if (anchor == nullptr || !anchor->isConnected || !Authority_IsValidActivity(activity)) { + if (!Authority_SyncActive() || !Authority_IsValidActivity(activity)) { return; } ActivityState& state = sActivities[activity]; diff --git a/src/port/Network/Anchor/HookHandlers.cpp b/src/port/Network/Anchor/HookHandlers.cpp index f7dc3d47f..03cad0bf7 100644 --- a/src/port/Network/Anchor/HookHandlers.cpp +++ b/src/port/Network/Anchor/HookHandlers.cpp @@ -25,6 +25,15 @@ extern "C" void port_fpTwinkly_release(void) { NetAuthority_Release(NET_ACTIVITY_FP_TWINKLY); } +s32 Anchor_LevelOfMap(s32 map); + +// Every listener below that alters vanilla behaviour is wrapped in this. Presence-only rooms +// (the global room, or sync turned off) must play exactly like single player. +static bool Anchor_WorldSyncActive() { + Anchor* anchor = Anchor::GetInstance(); + return anchor != nullptr && anchor->IsWorldSyncActive(); +} + // True when a remote client owns the Mr. Vile minigame (our local logic must follow). static bool Anchor_IsVileFollower() { return !NetAuthority_IsSelf(NET_ACTIVITY_VILE_MINIGAME); @@ -32,8 +41,7 @@ static bool Anchor_IsVileFollower() { // True when we are the live, connected authority for the Mr. Vile minigame. static bool Anchor_IsVileAuthority() { - return Anchor::GetInstance()->isConnected && NetAuthority_IsClaimed(NET_ACTIVITY_VILE_MINIGAME) && - NetAuthority_IsSelf(NET_ACTIVITY_VILE_MINIGAME); + return NetAuthority_IsClaimed(NET_ACTIVITY_VILE_MINIGAME) && NetAuthority_IsSelf(NET_ACTIVITY_VILE_MINIGAME); } // Authority-side per-frame work: stream Mr. Vile's transform and broadcast the periodic @@ -60,7 +68,7 @@ static void Anchor_UpdateVileSync() { static void Anchor_UpdateFightSync() { auto* anchor = Anchor::GetInstance(); - if (!anchor->isConnected || !anchor->IsSaveLoaded() || gsworld_getMap() != MAP_90_GL_BATTLEMENTS) { + if (!Anchor_WorldSyncActive() || !anchor->IsSaveLoaded() || gsworld_getMap() != MAP_90_GL_BATTLEMENTS) { return; } @@ -176,13 +184,16 @@ void Anchor::RegisterHooks() { Anchor::GetInstance()->ClearDummies(); Anchor::GetInstance()->PopulateDummies((GameMap)ev->nextMap); Authority_OnSelfMapChanged(ev->nextMap); - Anchor::GetInstance()->SweepUnoccupiedLevelState((GameMap)ev->nextMap); + s32 prevLevel = Anchor_LevelOfMap((s32)ev->prevMap); + if (prevLevel == 0 || prevLevel != Anchor_LevelOfMap((s32)ev->nextMap)) { + Anchor::GetInstance()->SweepUnoccupiedLevelState((GameMap)ev->nextMap); + } Anchor::GetInstance()->SendPacket_MapLoad((GameMap)ev->nextMap, ev->exit); // Anchor::GetInstance()->SendPacket_PlayerUpdate(true); auto* anchor = Anchor::GetInstance(); - if (anchor->isConnected && anchor->roomState.syncItemsAndFlags && ev->nextMap != MAP_91_FILE_SELECT && - ev->nextMap != MAP_1E_CS_START_NINTENDO && ev->nextMap != MAP_1F_CS_START_RAREWARE) { + if (Anchor_WorldSyncActive() && ev->nextMap != MAP_91_FILE_SELECT && ev->nextMap != MAP_1E_CS_START_NINTENDO && + ev->nextMap != MAP_1F_CS_START_RAREWARE) { anchor->SendPacket_RequestScopedState((GameMap)ev->nextMap); s32 enteredFlag = -1; @@ -248,7 +259,7 @@ void Anchor::RegisterHooks() { Anchor_UpdateVileSync(); Anchor_UpdateFightSync(); - if (anchor->isConnected && anchor->IsSaveLoaded()) { + if (Anchor_WorldSyncActive() && anchor->IsSaveLoaded()) { anchor->FlushPendingJiggySpawns(); if (!anchor->hasCheckedRandoCompat) { anchor->CheckRandoRoomCompatibility(); @@ -268,7 +279,7 @@ void Anchor::RegisterHooks() { // returning to idle (or the player declining) releases it. COND_HOOK(OnVileGameStateChange, EVENT_PRIORITY_NORMAL, true, [](IEvent* event) { auto ev = reinterpret_cast(event); - if (!Anchor::GetInstance()->isConnected || gsworld_getMap() != MAP_10_BGS_MR_VILE) { + if (!Anchor_WorldSyncActive() || gsworld_getMap() != MAP_10_BGS_MR_VILE) { return; } if (ev->state >= 2) { @@ -300,23 +311,35 @@ void Anchor::RegisterHooks() { // Followers: suppress local random logic; network state drives these instead. COND_VB_SHOULD(VB_CCW_FLOWER_REMOTE_GROW, EVENT_PRIORITY_NORMAL, isConnected, { - s32 stageFlag = va_arg(args, s32); - *should = fileProgressFlag_get((enum file_progress_e)stageFlag) != 0; + if (Anchor_WorldSyncActive()) { + s32 stageFlag = va_arg(args, s32); + *should = fileProgressFlag_get((enum file_progress_e)stageFlag) != 0; + } }); - COND_VB_SHOULD(VB_CC_RINGS_SNAP_WATER, EVENT_PRIORITY_NORMAL, isConnected, { *should = false; }); + COND_VB_SHOULD(VB_CC_RINGS_SNAP_WATER, EVENT_PRIORITY_NORMAL, isConnected, { + if (Anchor_WorldSyncActive()) { + *should = false; + } + }); // Vanilla despawns the CCW podium until its switch is pressed, and only rebuilds it when the cube // re-streams. Keep the actor alive (hidden) instead, so a teammate's press reveals it in place. - COND_VB_SHOULD(VB_CCW_PODIUM_DESPAWN, EVENT_PRIORITY_NORMAL, isConnected, { *should = false; }); + COND_VB_SHOULD(VB_CCW_PODIUM_DESPAWN, EVENT_PRIORITY_NORMAL, isConnected, { + if (Anchor_WorldSyncActive()) { + *should = false; + } + }); // Lair door remote-open: Door of Grunty's open flag (0xE2) is already set on arrival; key off // visual state (fully open == 0x1B) instead. Other lair doors stay flag-based. COND_VB_SHOULD(VB_LEVELDOOR_REMOTE_OPEN_DONE, EVENT_PRIORITY_NORMAL, isConnected, { - s32 doorActorId = va_arg(args, s32); - s32 doorState = va_arg(args, s32); - if (doorActorId == ACTOR_2E5_LARGE_DOOR_TO_FINAL_BATTLE) { - *should = (doorState == 0x1B); + if (Anchor_WorldSyncActive()) { + s32 doorActorId = va_arg(args, s32); + s32 doorState = va_arg(args, s32); + if (doorActorId == ACTOR_2E5_LARGE_DOOR_TO_FINAL_BATTLE) { + *should = (doorState == 0x1B); + } } }); @@ -329,25 +352,27 @@ void Anchor::RegisterHooks() { }); COND_VB_SHOULD(VB_DOOR_OPEN_CAMERA, EVENT_PRIORITY_NORMAL, isConnected, { - s32 doorId = va_arg(args, s32); - switch (doorId) { - case GV_DOOR_CAM_SUN: - *should = !port_mapFlag_wasSetRemotely(3); - break; - case GV_DOOR_CAM_STAR: - *should = !port_mapFlag_wasSetRemotely(5); - break; - case GV_DOOR_CAM_KAZOOIE: - *should = !port_mapFlag_wasSetRemotely(6); - break; - case GV_DOOR_CAM_JINXY: - *should = !(port_mapFlag_wasSetRemotely(0) && port_mapFlag_wasSetRemotely(1)); - break; - case MMM_DOOR_CAM_CHURCH: - *should = !port_mapFlag_wasSetRemotely(0); // MMM_SPECIFIC_FLAG_0_UNKNOWN - break; - default: - break; + if (Anchor_WorldSyncActive()) { + s32 doorId = va_arg(args, s32); + switch (doorId) { + case GV_DOOR_CAM_SUN: + *should = !port_mapFlag_wasSetRemotely(3); + break; + case GV_DOOR_CAM_STAR: + *should = !port_mapFlag_wasSetRemotely(5); + break; + case GV_DOOR_CAM_KAZOOIE: + *should = !port_mapFlag_wasSetRemotely(6); + break; + case GV_DOOR_CAM_JINXY: + *should = !(port_mapFlag_wasSetRemotely(0) && port_mapFlag_wasSetRemotely(1)); + break; + case MMM_DOOR_CAM_CHURCH: + *should = !port_mapFlag_wasSetRemotely(0); // MMM_SPECIFIC_FLAG_0_UNKNOWN + break; + default: + break; + } } }); @@ -520,26 +545,32 @@ void Anchor::RegisterHooks() { // SM intro Bottles: the tutorial offer is first-answer-wins for the team. COND_VB_SHOULD(VB_SM_TUTORIAL_CHOICE_OPEN, EVENT_PRIORITY_NORMAL, isConnected, { - if (__chSmBottles_isAnySpiralMountainAbilityLearned() || - (port_puzzleStep_getForMap(MAP_1_SM_SPIRAL_MOUNTAIN, ANCHOR_PUZZLE_SM_TUTORIAL) & 1)) { - *should = false; - } else if (NetAuthority_IsClaimed(NET_ACTIVITY_SM_TUTORIAL) && !NetAuthority_IsSelf(NET_ACTIVITY_SM_TUTORIAL)) { - *should = false; - } else { - NetAuthority_Claim(NET_ACTIVITY_SM_TUTORIAL); + if (Anchor_WorldSyncActive()) { + if (__chSmBottles_isAnySpiralMountainAbilityLearned() || + (port_puzzleStep_getForMap(MAP_1_SM_SPIRAL_MOUNTAIN, ANCHOR_PUZZLE_SM_TUTORIAL) & 1)) { + *should = false; + } else if (NetAuthority_IsClaimed(NET_ACTIVITY_SM_TUTORIAL) && + !NetAuthority_IsSelf(NET_ACTIVITY_SM_TUTORIAL)) { + *should = false; + } else { + NetAuthority_Claim(NET_ACTIVITY_SM_TUTORIAL); + } } }); // Ability molehills wake up only after the tutorial choice exists: the offer was // answered (synced bit) or a move is already known (covers skip-tutorial saves). COND_VB_SHOULD(VB_SM_MOLEHILL_ACTIVE, EVENT_PRIORITY_NORMAL, isConnected, { - if (!__chSmBottles_isAnySpiralMountainAbilityLearned() && + if (Anchor_WorldSyncActive() && !__chSmBottles_isAnySpiralMountainAbilityLearned() && !(port_puzzleStep_getForMap(MAP_1_SM_SPIRAL_MOUNTAIN, ANCHOR_PUZZLE_SM_TUTORIAL) & 1)) { *should = false; } }); COND_HOOK(OnTimedJiggyExpired, EVENT_PRIORITY_NORMAL, isConnected, [](IEvent* event) { + if (!Anchor_WorldSyncActive()) { + return; + } auto ev = reinterpret_cast(event); port_jiggySpawn_remove(ev->jiggyId); }); diff --git a/src/port/Network/Anchor/JigsawPedestal.cpp b/src/port/Network/Anchor/JigsawPedestal.cpp index b2cf51e72..df8464c49 100644 --- a/src/port/Network/Anchor/JigsawPedestal.cpp +++ b/src/port/Network/Anchor/JigsawPedestal.cpp @@ -5,9 +5,14 @@ static std::unordered_map sPedestalOwner; +static bool JigsawPedestal_SyncActive() { + Anchor* anchor = Anchor::GetInstance(); + return anchor != nullptr && anchor->IsWorldSyncActive(); +} + int32_t port_jigsawPedestal_tryClaim(int32_t id) { Anchor* anchor = Anchor::GetInstance(); - if (anchor == nullptr || !anchor->isConnected) { + if (!JigsawPedestal_SyncActive()) { return 1; } auto it = sPedestalOwner.find(id); @@ -21,7 +26,7 @@ int32_t port_jigsawPedestal_tryClaim(int32_t id) { int32_t port_jigsawPedestal_isSelf(int32_t id) { Anchor* anchor = Anchor::GetInstance(); - if (anchor == nullptr || !anchor->isConnected) { + if (!JigsawPedestal_SyncActive()) { return 1; } auto it = sPedestalOwner.find(id); @@ -30,7 +35,7 @@ int32_t port_jigsawPedestal_isSelf(int32_t id) { void port_jigsawPedestal_release(int32_t id) { Anchor* anchor = Anchor::GetInstance(); - if (anchor == nullptr || !anchor->isConnected) { + if (!JigsawPedestal_SyncActive()) { return; } auto it = sPedestalOwner.find(id); diff --git a/src/port/Network/Anchor/JsonConversions.hpp b/src/port/Network/Anchor/JsonConversions.hpp index ada991d3b..b9d250b77 100644 --- a/src/port/Network/Anchor/JsonConversions.hpp +++ b/src/port/Network/Anchor/JsonConversions.hpp @@ -67,6 +67,7 @@ inline void from_json(const json& j, AnchorClient& client) { client.map = j.value("map", MAP_0_UNKNOWN); client.exit = j.value("exit", (s32)0); client.self = j.value("self", false); + client.cutsceneReturnMap = 0; } #endif // __cplusplus diff --git a/src/port/Network/Anchor/Packets/MapLoad.cpp b/src/port/Network/Anchor/Packets/MapLoad.cpp index bf831fe53..f22fc1167 100644 --- a/src/port/Network/Anchor/Packets/MapLoad.cpp +++ b/src/port/Network/Anchor/Packets/MapLoad.cpp @@ -5,6 +5,7 @@ #include "variables.h" #include "functions.h" +#include "port/Patches/Patches.h" /** * MAP_LOAD @@ -18,6 +19,7 @@ void Anchor::SendPacket_MapLoad(GameMap map, s32 exit) { payload["type"] = MAP_LOAD; payload["map"] = map; payload["exit"] = exit; + payload["returnMap"] = port_cutsceneWarp_getReturnMap(); SendJsonToRemote(payload); } @@ -28,6 +30,7 @@ void Anchor::HandlePacket_MapLoad(nlohmann::json& payload) { clients[clientId].map = payload.at("map").get(); clients[clientId].exit = payload.at("exit").get(); + clients[clientId].cutsceneReturnMap = payload.value("returnMap", (s32)0); clients[clientId].isSaveLoaded = clients[clientId].map != MAP_1E_CS_START_NINTENDO && clients[clientId].map != MAP_1F_CS_START_RAREWARE && clients[clientId].map != MAP_91_FILE_SELECT; diff --git a/src/port/Patches/Patches.h b/src/port/Patches/Patches.h index dfb19d101..bf5fd4869 100644 --- a/src/port/Patches/Patches.h +++ b/src/port/Patches/Patches.h @@ -142,6 +142,8 @@ void port_breakable_recordBreak(int32_t markerId, int32_t x, int32_t y, int32_t int32_t port_breakable_isBroken(int32_t map, int32_t markerId, int32_t x, int32_t y, int32_t z); +int32_t port_cutsceneWarp_getReturnMap(void); + void port_eggToll_onAdvance(int32_t map, int32_t secondaryId, int32_t stage); int32_t port_eggToll_getStage(int32_t map, int32_t secondaryId); void port_eggToll_remoteApply(int32_t map, int32_t secondaryId, int32_t stage); diff --git a/src/port/UI/LighthouseMenu.cpp b/src/port/UI/LighthouseMenu.cpp index 766470581..db16a7c99 100644 --- a/src/port/UI/LighthouseMenu.cpp +++ b/src/port/UI/LighthouseMenu.cpp @@ -217,7 +217,7 @@ void LighthouseMenu::InitElement() { { FORCED_ON_FOR_ANCHOR_CONNECTED, { [](disabledInfo& info) -> bool { Anchor* anchor = Anchor::GetInstance(); - return anchor != nullptr && anchor->isConnected; + return anchor != nullptr && anchor->isConnected && !anchor->IsGlobalRoom(); }, "Forced on while connected to Anchor" } }, }; diff --git a/src/port/UI/LighthouseMenuEnhancements.cpp b/src/port/UI/LighthouseMenuEnhancements.cpp index 8e3e17677..2d369820c 100644 --- a/src/port/UI/LighthouseMenuEnhancements.cpp +++ b/src/port/UI/LighthouseMenuEnhancements.cpp @@ -43,7 +43,7 @@ static const char* kBottlesBonusLockedTooltip = static bool IsBottlesBonusUnlocked(int i) { Anchor* anchor = Anchor::GetInstance(); - if (anchor != nullptr && anchor->isConnected) { + if (anchor != nullptr && anchor->isConnected && !anchor->IsGlobalRoom()) { return true; } return gCompletedBottlesBonusGames[i] != 0; From d2119f69724732de7ddc09fc083b3b181de84ad1 Mon Sep 17 00:00:00 2001 From: Jeod <47716344+JeodC@users.noreply.github.com> Date: Sun, 2 Aug 2026 20:40:23 -0400 Subject: [PATCH 088/131] Fix two asan triggers (#362) --- src/port/Rando/Logic/GlitchlessLogic.cpp | 4 +++- src/port/Save/Types.h | 3 +++ src/port/UI/Notification.cpp | 26 +++++++++++++++++++----- 3 files changed, 27 insertions(+), 6 deletions(-) diff --git a/src/port/Rando/Logic/GlitchlessLogic.cpp b/src/port/Rando/Logic/GlitchlessLogic.cpp index e93031ccc..75390a401 100644 --- a/src/port/Rando/Logic/GlitchlessLogic.cpp +++ b/src/port/Rando/Logic/GlitchlessLogic.cpp @@ -241,7 +241,9 @@ void PopulateJinjoCheckIds() { } void ResetSaveData() { - for (int s = 0; s < sizeof(SaveData); s++) { + // [port] `data` is the 112-byte vanilla payload, not the whole SaveData, which is + // ~43 KB once shipSaveData (rando checks, note/jinjo retention) is counted. + for (size_t s = 0; s < sizeof(gameFile_saveData[selectedFileNum].data); s++) { gameFile_saveData[selectedFileNum].data[s] = 0; } diff --git a/src/port/Save/Types.h b/src/port/Save/Types.h index 49a1aa2f9..d5bede421 100644 --- a/src/port/Save/Types.h +++ b/src/port/Save/Types.h @@ -417,6 +417,9 @@ static constexpr int kSnsItemCount = sizeof(kSnsUnlocked) / sizeof(kSnsUnlocked[ // so internal gamenum 0/1/2 corresponds to displayed Game 1/3/2. static int SlotToFileIndex(int gameNum) { static const int fileMap[3] = { 1, 3, 2 }; + if (gameNum < 0 || gameNum >= 3) { + return 0; + } return fileMap[gameNum]; } diff --git a/src/port/UI/Notification.cpp b/src/port/UI/Notification.cpp index e7380efb0..cb89c0311 100644 --- a/src/port/UI/Notification.cpp +++ b/src/port/UI/Notification.cpp @@ -2,11 +2,15 @@ #include "port/UI/cvar_prefixes.h" #include #include +#include +#include namespace Notification { static uint32_t nextId = 0; static std::vector notifications = {}; +// Emit() runs on the game thread; Draw()/UpdateElement() run on the render thread. +static std::mutex notificationsMutex; #define ABS(x) ((x) >= 0 ? (x) : -(x)) @@ -46,9 +50,17 @@ void Window::Draw() { ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(8.0f * CVarGetFloat(CVAR_SETTING("Notifications.Size"), 1.8f), 8.0f)); - for (size_t index = 0; index < notifications.size(); ++index) { - auto& notification = notifications[index]; - int inverseIndex = -ABS((int)index - (int)(notifications.size() - 1)); + // Render from a snapshot rather than the live vector, so a concurrent Emit() can + // reallocate without invalidating anything this loop is reading. + std::vector snapshot; + { + std::lock_guard lock(notificationsMutex); + snapshot = notifications; + } + + for (size_t index = 0; index < snapshot.size(); ++index) { + auto& notification = snapshot[index]; + int inverseIndex = -ABS((int)index - (int)(snapshot.size() - 1)); ImGui::SetNextWindowViewport(vp->ID); if (notification.remainingTime < 4.0f) { @@ -114,6 +126,7 @@ void Window::Draw() { } void Window::UpdateElement() { + std::lock_guard lock(notificationsMutex); for (int index = 0; index < notifications.size(); ++index) { auto& notification = notifications[index]; @@ -129,11 +142,14 @@ void Window::UpdateElement() { } void Emit(Options notification) { - notification.id = nextId++; if (notification.remainingTime == 0.0f) { notification.remainingTime = CVarGetFloat(CVAR_SETTING("Notifications.Duration"), 10.0f); } - notifications.push_back(notification); + { + std::lock_guard lock(notificationsMutex); + notification.id = nextId++; + notifications.push_back(notification); + } if (!notification.mute) { // TODO: play game notification sound } From 4d113a9400d30f9e809cda1af885f70c34ee7547 Mon Sep 17 00:00:00 2001 From: Jeod <47716344+JeodC@users.noreply.github.com> Date: Sun, 2 Aug 2026 20:58:45 -0400 Subject: [PATCH 089/131] Kill note shadows for custom objects (#363) --- src/port/Rando/CustomObject/CustomObject.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/port/Rando/CustomObject/CustomObject.cpp b/src/port/Rando/CustomObject/CustomObject.cpp index aed5bcb2a..c635e879e 100644 --- a/src/port/Rando/CustomObject/CustomObject.cpp +++ b/src/port/Rando/CustomObject/CustomObject.cpp @@ -168,6 +168,10 @@ Actor* CustomObject::SpawnCustomActorEX(RandoCheckId randoCheckId, int32_t posit Actor* customActor = actor_new(position, 0, actorInfo, flags); if (customActor != NULL) { + // Music notes don't cast shadows, custom or otherwise. + if (actorInfo->actorId == ACTOR_51_MUSIC_NOTE) { + customActor->unk124_6 = 0; + } customActor = SetCustomActorParametersEX(randoCheckId, customActor); randoSpawnedCheckIds.push_back(randoCheckId); } From 7a51812b40eda3c1fda6be5ebfc652dd0b801819 Mon Sep 17 00:00:00 2001 From: Malkierian Date: Sun, 2 Aug 2026 18:14:06 -0700 Subject: [PATCH 090/131] Add special thanks to Banjo decomp team --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 92f934991..bfa06e97e 100644 --- a/README.md +++ b/README.md @@ -108,4 +108,5 @@ If you want to playtest a continuous integration build, you can find them at the # Special Thanks: +* The Banjo decomp team * Fredomato, scorched11 for work on rando From efab30bae4f4ae2f048ab6bd99fca1eb2dc277ac Mon Sep 17 00:00:00 2001 From: Caladius Date: Sun, 2 Aug 2026 21:14:25 -0400 Subject: [PATCH 091/131] Fix Gruntys Lair Gate not rising after collection (#364) --- src/port/Rando/MiscBehavior/WorldState.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/port/Rando/MiscBehavior/WorldState.cpp b/src/port/Rando/MiscBehavior/WorldState.cpp index 5a851f09f..03c6c50ab 100644 --- a/src/port/Rando/MiscBehavior/WorldState.cpp +++ b/src/port/Rando/MiscBehavior/WorldState.cpp @@ -173,6 +173,13 @@ void Rando::MiscBehavior::InitWorldStateBehavior() { break; } } + if (ev->jiggyId == JIGGY_37_LAIR_BGS_WITCH_SWITCH) { + if (currenLevel == LEVEL_6_LAIR) { + event->Cancelled = true; + ev->result = RANDO_SAVE_CHECKS[RC_GL_JIGGY_WITCH_SWITCH_BUBBLEGLOOP_SWAMP].obtained; + break; + } + } event->Cancelled = true; ev->result = randoSaveCheck.obtained; From 9f3f30b1ccc03ceeb2f82aebf82e126ac6a81dbd Mon Sep 17 00:00:00 2001 From: Jeod <47716344+JeodC@users.noreply.github.com> Date: Mon, 3 Aug 2026 13:05:59 -0400 Subject: [PATCH 092/131] Init audio before menu (#369) --- src/port/Engine.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/port/Engine.cpp b/src/port/Engine.cpp index 75132ca07..ddd26319a 100644 --- a/src/port/Engine.cpp +++ b/src/port/Engine.cpp @@ -177,6 +177,7 @@ GameEngine::GameEngine() { lhFast3dWindow = std::make_shared(std::vector>({})); this->context->InitWindow(lhFast3dWindow); + this->context->InitAudio({ .SampleRate = 22000, .SampleLength = 736, .DesiredBuffered = 2208 }); LighthouseGui::SetupMenu(); @@ -382,8 +383,6 @@ void GameEngine::FinishInit() { context->InitCrashHandler(); context->InitEventSystem(); - this->context->InitAudio({ .SampleRate = 22000, .SampleLength = 736, .DesiredBuffered = 2208 }); - lhFast3dWindow->SetTargetFps(60); lhFast3dWindow->SetMaximumFrameLatency(1); lhFast3dWindow->SetRendererUCode(ucode_f3d); From 5df2c2b23ce7d24d29bf3dd1ee7320aa170dfba6 Mon Sep 17 00:00:00 2001 From: Jeod <47716344+JeodC@users.noreply.github.com> Date: Mon, 3 Aug 2026 13:06:11 -0400 Subject: [PATCH 093/131] Fix stack overflow in furnace fun (#365) --- src/lair/ff_manager.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lair/ff_manager.c b/src/lair/ff_manager.c index 4b1fee6ff..fb12c5fd2 100644 --- a/src/lair/ff_manager.c +++ b/src/lair/ff_manager.c @@ -1136,7 +1136,7 @@ void func_8038E070(void) void lair_func_8038E0B0(void) { s32 sp48[6]; //buttons s32 temp_v0; - s32 sp3C[2]; //joystick + s32 sp3C[3]; //side buttons (Z, L, R) s32 ff_tile_type; s32 sp28; From cc1c0b5ef31253b100b6ac4f13b045730876a300 Mon Sep 17 00:00:00 2001 From: Jeod <47716344+JeodC@users.noreply.github.com> Date: Mon, 3 Aug 2026 13:06:55 -0400 Subject: [PATCH 094/131] Maintain aspect for auxfbo (bottles bonus) (#372) * Maintain aspect for auxfbo (bottles bonus) * Adjust frame pacing for bottles bonus and sns pictures mode --- src/core2/gameloop.c | 7 ++++++- src/port/Enhancements/Events/Hooks/Events.h | 1 + src/port/Patches/FramePacingPatches.cpp | 13 +++--------- src/port/Patches/FramebufferPatches.cpp | 23 ++++++++++++++++++++- 4 files changed, 32 insertions(+), 12 deletions(-) diff --git a/src/core2/gameloop.c b/src/core2/gameloop.c index 139edd6a9..acb47c9cd 100644 --- a/src/core2/gameloop.c +++ b/src/core2/gameloop.c @@ -122,7 +122,7 @@ void func_802E398C(s32 arg0) { } void func_802E39D0(Gfx **gfx, Mtx **mtx, Vtx **vtx, s32 framebuffer_idx, bool arg4) { - Mtx* mtx_start = *mtx; + Mtx* mtx_start = *mtx; Vtx* vtx_start = *vtx; setupFramebufferForGamemode(gfx, framebuffer_idx); @@ -346,6 +346,11 @@ void game_draw(bool arg0) { func_802E39D0(&gfx, &mtx, &vtx, getActiveFramebuffer(), arg0); + // [port] Frame submission gate + if (!EventSystem_Should(VB_PICTUREBOX_SUBMIT_FRAME, true, (s32)(gfx - gfx_start))) { + return; + } + graphicsCache_checkFrame(gfx_start, gfx, mtx_start, mtx, vtx_start, vtx); // Lighthouse [Port] not sure if this should be here or after the following block diff --git a/src/port/Enhancements/Events/Hooks/Events.h b/src/port/Enhancements/Events/Hooks/Events.h index 8199841fc..6383b6ea6 100644 --- a/src/port/Enhancements/Events/Hooks/Events.h +++ b/src/port/Enhancements/Events/Hooks/Events.h @@ -75,6 +75,7 @@ typedef enum VBehaviorID { VB_SPRITE_RESTORE_ALPHA_COMPARE, VB_DRAWDIST_BOX_CULL, VB_PICTUREBOX_TARGET_FB, + VB_PICTUREBOX_SUBMIT_FRAME, // Anchor VB_VILE_YUMBLIE_EMERGE, diff --git a/src/port/Patches/FramePacingPatches.cpp b/src/port/Patches/FramePacingPatches.cpp index 56a16eeeb..4c7081372 100644 --- a/src/port/Patches/FramePacingPatches.cpp +++ b/src/port/Patches/FramePacingPatches.cpp @@ -31,23 +31,16 @@ void port_setDemoViCount(int viCount) { } int port_getDemoDisplayViCount(int rawViCount) { - int displayViCount = rawViCount; - int game_mode = getGameMode(); - - if (game_mode == GAME_MODE_8_BOTTLES_BONUS) { - displayViCount = 3; - } else if (game_mode == GAME_MODE_A_SNS_PICTURE) { + if (getGameMode() == GAME_MODE_A_SNS_PICTURE) { switch (gsworld_getMap()) { case MAP_7F_FP_WOZZAS_CAVE: case MAP_92_GV_SNS_CHAMBER: - displayViCount = 3; - break; + return 3; default: break; } } - - return displayViCount; + return rawViCount; } // Cutscene Stutter Compensation diff --git a/src/port/Patches/FramebufferPatches.cpp b/src/port/Patches/FramebufferPatches.cpp index 3c6bc8a61..15549e843 100644 --- a/src/port/Patches/FramebufferPatches.cpp +++ b/src/port/Patches/FramebufferPatches.cpp @@ -20,6 +20,7 @@ extern "C" { void gfx_register_fb_texture(const void* cpuAddr, int fbId); BKGfxList* modelbin_getGfxList(BKModelBin* arg0); +s32 getGameMode(void); // During FADE_IN, the game disables scene drawing one frame before // capturing gFramebuffers. Without freezing, the readback would overwrite @@ -227,7 +228,7 @@ static void createAuxFb(void* arg) { if (nativeH < 1) { nativeH = 1; } - sAuxGpuFbId = gfx_create_framebuffer(IMAGE_WIDTH, IMAGE_HEIGHT, nativeW, nativeH, 1, 0); + sAuxGpuFbId = gfx_create_framebuffer(IMAGE_WIDTH, IMAGE_HEIGHT, nativeW, nativeH, 1, true); if (sAuxGpuFbId >= 0) { gfx_register_fb_texture(sAuxFbDummy, sAuxGpuFbId); } @@ -333,6 +334,11 @@ void port_patchTransitionModel(BKModelBin* model_bin) { } // extern "C" +// Submitted picture-mode frames since the last map load. The first few frames a +// reloaded map composes are structurally normal DLs that draw nothing visible. +static s32 sPicFramesSinceMapLoad = 0; +static constexpr s32 kPicWarmupFrames = 3; + void RegisterFramebufferPatches_Init() { REGISTER_VB_SHOULD(VB_PICTUREBOX_TARGET_FB, EVENT_PRIORITY_NORMAL, { Gfx** gdl = va_arg(args, Gfx**); @@ -342,6 +348,21 @@ void RegisterFramebufferPatches_Init() { } (void)should; }); + + REGISTER_LISTENER(OnMapLoad, EVENT_PRIORITY_NORMAL, [](IEvent*) { sPicFramesSinceMapLoad = 0; }); + + REGISTER_VB_SHOULD(VB_PICTUREBOX_SUBMIT_FRAME, EVENT_PRIORITY_NORMAL, { + s32 gfxCount = va_arg(args, s32); + s32 mode = getGameMode(); + if (mode == GAME_MODE_8_BOTTLES_BONUS || mode == GAME_MODE_A_SNS_PICTURE) { + sPicFramesSinceMapLoad++; + if (sPicFramesSinceMapLoad <= kPicWarmupFrames || gfxCount < 100) { + SPDLOG_INFO("[pictureDiag] dropped frame (sinceLoad={}, gfxCount={})", sPicFramesSinceMapLoad, + gfxCount); + *should = false; + } + } + }); } static RegisterShipInitFunc initFramebufferPatches(RegisterFramebufferPatches_Init); From d44c1fc9f5de8e5d7945bd9ca508d5cc4ba2cc77 Mon Sep 17 00:00:00 2001 From: Malkierian Date: Mon, 3 Aug 2026 10:07:22 -0700 Subject: [PATCH 095/131] Prevent EggAim enhancement from allowing transformations to fire in first person. (#368) --- src/port/Enhancements/Backports/EggAim.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/port/Enhancements/Backports/EggAim.cpp b/src/port/Enhancements/Backports/EggAim.cpp index 5fb2d4983..4b4cf0d2a 100644 --- a/src/port/Enhancements/Backports/EggAim.cpp +++ b/src/port/Enhancements/Backports/EggAim.cpp @@ -213,6 +213,10 @@ const uint8_t sCrosshairTextureData[32 * 32 * 4] = { int sFiring = 0; int sOverlayShown = 0; +bool canAimEggs() { + return can_egg() && player_getTransformation() == TRANSFORM_1_BANJO; +} + } // namespace void RegisterEggAimSpawn_Init() { @@ -241,7 +245,7 @@ void RegisterEggAim_Init() { return; } - if (!can_egg()) { + if (!canAimEggs()) { return; } From 9d6f0efae2140e20b79ae30b6138906f7e7bf362 Mon Sep 17 00:00:00 2001 From: Caladius Date: Mon, 3 Aug 2026 13:07:47 -0400 Subject: [PATCH 096/131] Fix Presents not using the correct Level Flag. (#367) --- src/port/Rando/ObjectBehavior/Present.cpp | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/port/Rando/ObjectBehavior/Present.cpp b/src/port/Rando/ObjectBehavior/Present.cpp index d8be0600e..da91e939c 100644 --- a/src/port/Rando/ObjectBehavior/Present.cpp +++ b/src/port/Rando/ObjectBehavior/Present.cpp @@ -10,12 +10,25 @@ s32 levelSpecificFlags_get(s32 i); #define OPTION_ENABLED RANDO_SAVE_OPTIONS[RO_SHUFFLE_JIGGIES].optionValue +std::map presentLevelFlagMap = { + { ACTOR_1ED_BLUE_PRESENT_COLLECTIBLE, LEVEL_FLAG_11_FP_UNKNOWN }, + { ACTOR_1EF_GREEN_PRESENT_COLLECTIBLE, LEVEL_FLAG_12_FP_UNKNOWN }, + { ACTOR_1F1_RED_PRESENT_COLLECTIBLE, LEVEL_FLAG_13_FP_UNKNOWN }, +}; + +void GetPresentLevelFlag(Actor* actor, level_flags_e levelFlag) { + if (levelSpecificFlags_get(levelFlag)) { + marker_despawn(actor->marker); + } +} + void Rando::ObjectBehavior::ModifyPresentBehavior(void* presentActor) { if (!IS_RANDO && !OPTION_ENABLED) { return; } Actor* actor = (Actor*)presentActor; + int32_t actorAdjustment = 0; int32_t levelFlag = 0; switch (actor->actor_info->actorId) { @@ -30,10 +43,7 @@ void Rando::ObjectBehavior::ModifyPresentBehavior(void* presentActor) { case ACTOR_1ED_BLUE_PRESENT_COLLECTIBLE: case ACTOR_1EF_GREEN_PRESENT_COLLECTIBLE: case ACTOR_1F1_RED_PRESENT_COLLECTIBLE: - levelFlag = (LEVEL_FLAG_11_FP_UNKNOWN + (actor->actor_info->actorId - ACTOR_1ED_BLUE_PRESENT_COLLECTIBLE)); - if (levelSpecificFlags_get(levelFlag)) { - marker_despawn(actor->marker); - } + GetPresentLevelFlag(actor, presentLevelFlagMap.at((actor_e)actor->actor_info->actorId)); break; default: break; From adbf32990567191ba2680b182b318440c1df5954 Mon Sep 17 00:00:00 2001 From: Jeod <47716344+JeodC@users.noreply.github.com> Date: Mon, 3 Aug 2026 15:37:45 -0400 Subject: [PATCH 097/131] Update README.md (#383) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index bfa06e97e..2ef18d4ce 100644 --- a/README.md +++ b/README.md @@ -55,7 +55,7 @@ Lighthouse ships with a file with many standard controller mappings that can be ### Default keyboard configuration | N64 | A | B | L | R | Z | Start | Analog stick | C buttons | D-Pad | -| - | - | - | - | - | - | - | - | +| - | - | - | - | - | - | - | - | - | - | | Keyboard | X | C | E | R | Z | Space | WASD | Arrow keys | TFGH | ### Other shortcuts From 71f8127ffc9d59d53bb30506666d18caca13723f Mon Sep 17 00:00:00 2001 From: Jeod <47716344+JeodC@users.noreply.github.com> Date: Mon, 3 Aug 2026 15:38:35 -0400 Subject: [PATCH 098/131] Fix OSTimer teardown race condition (#382) --- src/port/Game.cpp | 1 + src/port/OS/OS.h | 3 +++ src/port/OS/OS_Timer.cpp | 28 +++++++++++++++++++++++++++- 3 files changed, 31 insertions(+), 1 deletion(-) diff --git a/src/port/Game.cpp b/src/port/Game.cpp index bc46b015d..1424dc54d 100644 --- a/src/port/Game.cpp +++ b/src/port/Game.cpp @@ -356,6 +356,7 @@ int SDL_main(int argc, char* argv[]) { OS_JoinDecompThreads(); ThreadWatchdog_Stop(); OS_StopViTicker(); + OS_StopTimerWorker(); #ifdef USE_NETWORKING Anchor::GetInstance()->Disable(); SDLNet_Quit(); diff --git a/src/port/OS/OS.h b/src/port/OS/OS.h index 66f24b5f5..0321ca20c 100644 --- a/src/port/OS/OS.h +++ b/src/port/OS/OS.h @@ -73,6 +73,9 @@ int OS_SiPumpLive(void); // needs this one declared here. int osStopTimer(OSTimer* t); +// The timer worker starts with the first osSetTimer; this stops it at shutdown. +void OS_StopTimerWorker(void); + s32 osPfsInit(OSMesgQueue* mq, OSPfs* pfs, s32 channel); // Whether osViBlack has the display blanked. The renderer blacks the presented diff --git a/src/port/OS/OS_Timer.cpp b/src/port/OS/OS_Timer.cpp index 342e7f8cf..4a1c74361 100644 --- a/src/port/OS/OS_Timer.cpp +++ b/src/port/OS/OS_Timer.cpp @@ -30,13 +30,18 @@ struct Armed { std::mutex sMutex; std::map sTimers; std::condition_variable sCv; +std::thread sWorker; bool sWorkerStarted = false; +bool sStop = false; // One worker serves every timer, waking for whichever is due first and // recomputing whenever the set changes under it. void Worker() { std::unique_lock lock(sMutex); for (;;) { + if (sStop) { + return; + } OSTimer* key = nullptr; std::chrono::steady_clock::time_point deadline{}; for (auto& [t, armed] : sTimers) { @@ -52,6 +57,9 @@ void Worker() { if (sCv.wait_until(lock, deadline) != std::cv_status::timeout) { continue; // re-armed or stopped while waiting } + if (sStop) { + return; + } auto it = sTimers.find(key); if (it == sTimers.end() || it->second.deadline != deadline) { continue; // this one changed under the wait @@ -73,9 +81,12 @@ void Worker() { extern "C" int osSetTimer(OSTimer* t, OSTime countdown, OSTime interval, OSMesgQueue* mq, OSMesg msg) { std::lock_guard lock(sMutex); + if (sStop) { + return 0; + } if (!sWorkerStarted) { sWorkerStarted = true; - std::thread(Worker).detach(); + sWorker = std::thread(Worker); } Armed armed; armed.deadline = std::chrono::steady_clock::now() + std::chrono::nanoseconds(countdown * 64 / 3); @@ -93,3 +104,18 @@ extern "C" int osStopTimer(OSTimer* t) { sCv.notify_all(); return 0; } + +extern "C" void OS_StopTimerWorker(void) { + { + std::lock_guard lock(sMutex); + if (!sWorkerStarted || sStop) { + return; + } + sStop = true; + sTimers.clear(); + } + sCv.notify_all(); + if (sWorker.joinable()) { + sWorker.join(); + } +} From 92fafc39f1c1e9a2c94b308d3094d6d0017048f3 Mon Sep 17 00:00:00 2001 From: Jeod <47716344+JeodC@users.noreply.github.com> Date: Mon, 3 Aug 2026 15:38:48 -0400 Subject: [PATCH 099/131] GV: fix Gobi and Trunker reverting after a death reload (#381) --- src/port/Rando/MiscBehavior/WorldState.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/port/Rando/MiscBehavior/WorldState.cpp b/src/port/Rando/MiscBehavior/WorldState.cpp index 03c6c50ab..902477c3b 100644 --- a/src/port/Rando/MiscBehavior/WorldState.cpp +++ b/src/port/Rando/MiscBehavior/WorldState.cpp @@ -211,7 +211,7 @@ void Rando::MiscBehavior::InitWorldStateBehavior() { ev->result = RANDO_SAVE_FLAGS[RANDO_INF_MINIGAME_RINGS_COMPLETED].flagState || CustomObject::CheckSpawnedIdList(randoCheckId); } else { - ev->result = CustomObject::CheckSpawnedIdList(randoCheckId); + ev->result = CustomObject::CheckSpawnedIdList(randoCheckId) || RANDO_SAVE_CHECKS[randoCheckId].obtained; } } }) From 4faa474a60fd4936c81c6bed157ad75472006bf2 Mon Sep 17 00:00:00 2001 From: Malkierian Date: Mon, 3 Aug 2026 12:39:06 -0700 Subject: [PATCH 100/131] Prevent gag transformation from incurring a token charge while fast transformation is enabled. (#379) Also add a warp entry for Furnace Fun at the pad. --- src/port/Enhancements/Cheats/Cheats.cpp | 14 +++++++------- src/port/UI/DeveloperTools/GameplayTools.cpp | 1 + 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/port/Enhancements/Cheats/Cheats.cpp b/src/port/Enhancements/Cheats/Cheats.cpp index 9544c60f2..f11484436 100644 --- a/src/port/Enhancements/Cheats/Cheats.cpp +++ b/src/port/Enhancements/Cheats/Cheats.cpp @@ -255,11 +255,10 @@ extern u8 D_8037DDF0; // the transformation this hut offers static bool sMumboFastXformStarted = false; -static void FastTransform_startHutTransform(Actor* actor) { +static bool FastTransform_startHutTransform(Actor* actor) { if (actor->has_met_before || (actor->unk10_12 == 0 && (s32)player_getTransformation() != TRANSFORM_1_BANJO && (s32)player_getTransformation() != romhack_mumboWishwashyId())) { - romhack_mumboTransform(TRANSFORM_1_BANJO); - return; + return romhack_mumboTransform(TRANSFORM_1_BANJO); } if (romhack_mumboTransform(D_8037DDF0)) { if (D_8037DDF0 != romhack_mumboWishwashyId()) { @@ -273,7 +272,9 @@ static void FastTransform_startHutTransform(Actor* actor) { if (actor->unk10_12 == 1) { actor->unk10_12 = 0; } + return true; } + return false; } // No has_met_before branch: those sequences are left to vanilla below. @@ -307,12 +308,11 @@ void RegisterFastTransform_Init() { Actor* actor = va_arg(args, Actor*); // T-Rex/mistake gags end in a dialog wired to a callback private to mumbo.c. if (actor != nullptr && !actor->has_met_before) { + // Only latch once the spell has been accepted. Gags don't count as valid. if (!sMumboFastXformStarted) { - sMumboFastXformStarted = true; - FastTransform_startHutTransform(actor); + sMumboFastXformStarted = FastTransform_startHutTransform(actor); } else if (!baflag_isTrue(BA_FLAG_1B_TRANSFORMING)) { - // player_transform sets the flag synchronously, so this can't fire on the - // frame the transform starts. + // Safe to read as "the transformation ended" only because of the latch above. sMumboFastXformStarted = false; FastTransform_endHutTransform(actor); } diff --git a/src/port/UI/DeveloperTools/GameplayTools.cpp b/src/port/UI/DeveloperTools/GameplayTools.cpp index cb5e69abd..1a8c04963 100644 --- a/src/port/UI/DeveloperTools/GameplayTools.cpp +++ b/src/port/UI/DeveloperTools/GameplayTools.cpp @@ -107,6 +107,7 @@ std::map> commonWarpMap = { { MAP_44_CCW_SUMMER, { "Click Clock Wood - Summer", 1 } }, { MAP_45_CCW_AUTUMN, { "Click Clock Wood - Autumn", 1 } }, { MAP_46_CCW_WINTER, { "Click Clock Wood - Winter", 1 } }, + { MAP_8E_GL_FURNACE_FUN, { "Grunty's Furnace Fun", WARP_GL_FURNACE_FUN_2_ENTRANCE_PAD } }, }; // clang-format off From 67463e22ffa010cebba32e7aabac329cbe8e00fe Mon Sep 17 00:00:00 2001 From: aMannus Date: Mon, 3 Aug 2026 23:35:00 +0200 Subject: [PATCH 101/131] Start work on jinjos --- src/port/Rando/ItemQueue.cpp | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/port/Rando/ItemQueue.cpp b/src/port/Rando/ItemQueue.cpp index d1d7b9276..654bfa9c0 100644 --- a/src/port/Rando/ItemQueue.cpp +++ b/src/port/Rando/ItemQueue.cpp @@ -22,6 +22,12 @@ extern struct { #define MUMBOSCORE_SIZE (((MUMBO_TOKEN_COUNT - 1 + 7) & ~7) / 8) u8 sMumboTokenScore[MUMBOSCORE_SIZE]; extern u8 D_80385FF0[0xE]; + +extern ActorInfo chJinjoBlue; +extern ActorInfo chJinjoGreen; +extern ActorInfo chJinjoYellow; +extern ActorInfo chJinjoPink; +extern ActorInfo chJinjoOrange; } #define CVAR_NAME_SHOW_COLLISION_NOTIFICATIONS "gRandoSettings.RandoNotifications" @@ -67,10 +73,14 @@ void ItemQueue::Process() { void ItemQueue::GiveItem(RandoItemId randoItemId) { RandoItemType itemType = Rando::StaticData::Items[randoItemId].randoItemType; + actor_e actorId = (actor_e)Rando::StaticData::Items[randoItemId].actorId; int16_t worldId = Rando::StaticData::Items[randoItemId].worldId; uint16_t combId; uint16_t maxHoneycombs; uint32_t jiggyId; + ActorInfo* actorInfo; + int32_t playerPosition[3]; + Actor* customActor; switch (itemType) { case RITYPE_BLUE_EGG: @@ -116,6 +126,25 @@ void ItemQueue::GiveItem(RandoItemId randoItemId) { spawnOrbit(); break; case RITYPE_JINJO: + switch (actorId) { + case ACTOR_5E_JINJO_YELLOW: + actorInfo = &chJinjoBlue; + break; + case ACTOR_5F_JINJO_ORANGE: + actorInfo = &chJinjoBlue; + break; + case ACTOR_60_JINJO_BLUE: + actorInfo = &chJinjoBlue; + break; + case ACTOR_61_JINJO_PINK: + actorInfo = &chJinjoBlue; + break; + case ACTOR_62_JINJO_GREEN: + actorInfo = &chJinjoBlue; + break; + } + player_getPosition_s32(playerPosition); + customActor = actor_new(playerPosition, 0, actorInfo, ACTOR_FLAG_UNKNOWN_6 | ACTOR_FLAG_UNKNOWN_8); break; case RITYPE_MOLEHILL: coMusicPlayer_playMusic(COMUSIC_D_JINGLE_JIGGY_COLLECTED, -1); From a012f34f5d91787b2a954178bde7a10c0ebea0aa Mon Sep 17 00:00:00 2001 From: aMannus Date: Tue, 4 Aug 2026 13:27:46 +0200 Subject: [PATCH 102/131] More draw work --- .../CustomCollectible/CustomCollectible.cpp | 51 +++++++++++++------ .../CustomCollectible/CustomCollectible.h | 5 +- src/port/Rando/ItemQueue.cpp | 30 +++++------ 3 files changed, 53 insertions(+), 33 deletions(-) diff --git a/src/port/Rando/CustomCollectible/CustomCollectible.cpp b/src/port/Rando/CustomCollectible/CustomCollectible.cpp index 2f96a0bc8..c69aab4aa 100644 --- a/src/port/Rando/CustomCollectible/CustomCollectible.cpp +++ b/src/port/Rando/CustomCollectible/CustomCollectible.cpp @@ -13,21 +13,21 @@ Actor* func_802D41C4(ActorMarker* marker, Gfx** gfx, Mtx** mtx, Vtx** vtx); } std::unordered_map customCollectibleDrawInfo = { - { ACTOR_52_BLUE_EGG, { ASSET_36D_SPRITE_BLUE_EGG, CCT_VANILLA_SPRITE } }, - { ACTOR_47_EMPTY_HONEYCOMB, { ASSET_361_MODEL_EMPTY_HONEYCOMB, CCT_VANILLA_MODEL } }, - { ACTOR_49_EXTRA_LIFE, { ASSET_36E_MODEL_EXTRA_LIFE, CCT_VANILLA_SPRITE } }, - { ACTOR_50_HONEYCOMB, { ASSET_363_MODEL_HONEYCOMB, CCT_VANILLA_MODEL } }, - { ACTOR_46_JIGGY, { ASSET_35F_MODEL_JIGGY, CCT_VANILLA_MODEL } }, + { ACTOR_52_BLUE_EGG, { ASSET_36D_SPRITE_BLUE_EGG, CCT_GENERIC_SPRITE } }, + { ACTOR_47_EMPTY_HONEYCOMB, { ASSET_361_MODEL_EMPTY_HONEYCOMB, CCT_GENERIC_MODEL } }, + { ACTOR_49_EXTRA_LIFE, { ASSET_36E_MODEL_EXTRA_LIFE, CCT_GENERIC_SPRITE } }, + { ACTOR_50_HONEYCOMB, { ASSET_363_MODEL_HONEYCOMB, CCT_GENERIC_MODEL } }, + { ACTOR_46_JIGGY, { ASSET_35F_MODEL_JIGGY, CCT_GENERIC_MODEL } }, { ACTOR_60_JINJO_BLUE, { ASSET_3C0_MODEL_JINJO_BLUE, CCT_JINJO } }, { ACTOR_62_JINJO_GREEN, { ASSET_3C2_MODEL_JINJO_GREEN, CCT_JINJO } }, { ACTOR_5F_JINJO_ORANGE, { ASSET_3BC_MODEL_JINJO_ORANGE, CCT_JINJO } }, { ACTOR_61_JINJO_PINK, { ASSET_3C1_MODEL_JINJO_PINK, CCT_JINJO } }, { ACTOR_5E_JINJO_YELLOW, { ASSET_3BB_MODEL_JINJO_YELLOW, CCT_JINJO } }, { ACTOR_12C_MOLEHILL, { ASSET_387_MODEL_BOTTLES, CCT_MOLEHILL } }, - { ACTOR_2D_MUMBO_TOKEN, { ASSET_41A_SPRITE_MUMBO_TOKEN, CCT_VANILLA_SPRITE } }, - { ACTOR_51_MUSIC_NOTE, { ASSET_6D6_SPRITE_MUSIC_NOTE, CCT_VANILLA_SPRITE } }, + { ACTOR_2D_MUMBO_TOKEN, { ASSET_41A_SPRITE_MUMBO_TOKEN, CCT_GENERIC_SPRITE } }, + { ACTOR_51_MUSIC_NOTE, { ASSET_6D6_SPRITE_MUSIC_NOTE, CCT_GENERIC_SPRITE } }, { ACTOR_25E_SNS_EGG, { ASSET_50D_MODEL_SNS_EGG, CCT_VANILLA_SNS_EGG } }, - { ACTOR_25D_ICE_KEY, { ASSET_50C_MODEL_ICE_KEY, CCT_VANILLA_MODEL } }, + { ACTOR_25D_ICE_KEY, { ASSET_50C_MODEL_ICE_KEY, CCT_GENERIC_MODEL } }, { ACTOR_3CD_CUSTOM_COLLECTIBLE, { ASSET_0_NONE, CCT_CUSTOM_MODEL } }, }; @@ -62,7 +62,7 @@ ActorInfo customActorInfo = { MARKER_300_CUSTOM_COLLECTIBLE, NULL, 0, 0, - 0.9f, + 0.8f, 0 }; void CustomCollectible_Update(Actor* actor) { @@ -72,11 +72,7 @@ void CustomCollectible_Update(Actor* actor) { actor->initialized = true; actor->marker->collidable = true; - if (customLocal->itemType == RITYPE_MUSIC_NOTE) { - actor->scale = 0.4f; - } else if (customLocal->itemType == RITYPE_SNS_EGG) { - actor->scale = 0.4f; - } + actor->scale = CustomCollectible::GetScale(customLocal->itemType); } if (customLocal->itemType == RITYPE_MOLEHILL || customLocal->itemType == RITYPE_JINJO) { @@ -84,6 +80,28 @@ void CustomCollectible_Update(Actor* actor) { } else { actor->yaw += 5.0f; } + + // Sparkles + if (customCollectibleDrawInfo[customLocal->actorId].drawType != CCT_GENERIC_SPRITE) { + for (int i = 0; i < 4; i++) { + if (randf() < 0.03) { + commonParticle_add(actor->marker, i + 5, func_80329904); + commonParticle_new((common_particle_e)8, actor->marker->unk14_21); + } + } + } +} + +f32 CustomCollectible::GetScale(RandoItemType itemType) { + switch (itemType) { + case RITYPE_MUSIC_NOTE: + case RITYPE_SNS_EGG: + return 0.42857143f; + case RITYPE_EMPTY_HONEYCOMB: + return 0.8f; + default: + return 1.0f; + } } void CustomCollectible::FacePlayer(Actor* actor) { @@ -170,11 +188,12 @@ ActorInfo CustomCollectible::GetActorAndDrawInfo(RandoItemId randoItemId) { collectibleInfo.modelId = drawInfo.drawModel; switch (drawInfo.drawType) { - case CCT_VANILLA_MODEL: + case CCT_GENERIC_MODEL: collectibleInfo.draw_func = actor_draw; break; - case CCT_VANILLA_SPRITE: + case CCT_GENERIC_SPRITE: collectibleInfo.draw_func = fxTouchSparkle_draw; + collectibleInfo.shadow_scale = 0.0f; break; case CCT_JINJO: collectibleInfo.draw_func = actor_draw; diff --git a/src/port/Rando/CustomCollectible/CustomCollectible.h b/src/port/Rando/CustomCollectible/CustomCollectible.h index 889114a5a..fac0047cf 100644 --- a/src/port/Rando/CustomCollectible/CustomCollectible.h +++ b/src/port/Rando/CustomCollectible/CustomCollectible.h @@ -10,8 +10,8 @@ typedef struct { } ActorLocal_CustomCollectible; enum CustomCollectibleDrawTypes { - CCT_VANILLA_MODEL, - CCT_VANILLA_SPRITE, + CCT_GENERIC_MODEL, + CCT_GENERIC_SPRITE, CCT_JINJO, CCT_MOLEHILL, CCT_VANILLA_SNS_EGG, @@ -34,5 +34,6 @@ class CustomCollectible { public: static Actor* Spawn(int32_t position[3], RandoCheckId randoCheckId); + static f32 GetScale(RandoItemType itemType); static void FacePlayer(Actor* actor); }; diff --git a/src/port/Rando/ItemQueue.cpp b/src/port/Rando/ItemQueue.cpp index 654bfa9c0..3e3bb48a8 100644 --- a/src/port/Rando/ItemQueue.cpp +++ b/src/port/Rando/ItemQueue.cpp @@ -127,21 +127,21 @@ void ItemQueue::GiveItem(RandoItemId randoItemId) { break; case RITYPE_JINJO: switch (actorId) { - case ACTOR_5E_JINJO_YELLOW: - actorInfo = &chJinjoBlue; - break; - case ACTOR_5F_JINJO_ORANGE: - actorInfo = &chJinjoBlue; - break; - case ACTOR_60_JINJO_BLUE: - actorInfo = &chJinjoBlue; - break; - case ACTOR_61_JINJO_PINK: - actorInfo = &chJinjoBlue; - break; - case ACTOR_62_JINJO_GREEN: - actorInfo = &chJinjoBlue; - break; + case ACTOR_5E_JINJO_YELLOW: + actorInfo = &chJinjoYellow; + break; + case ACTOR_5F_JINJO_ORANGE: + actorInfo = &chJinjoOrange; + break; + case ACTOR_60_JINJO_BLUE: + actorInfo = &chJinjoBlue; + break; + case ACTOR_61_JINJO_PINK: + actorInfo = &chJinjoPink; + break; + case ACTOR_62_JINJO_GREEN: + actorInfo = &chJinjoGreen; + break; } player_getPosition_s32(playerPosition); customActor = actor_new(playerPosition, 0, actorInfo, ACTOR_FLAG_UNKNOWN_6 | ACTOR_FLAG_UNKNOWN_8); From e0e17a3e577d14a712e7d21f870388df4b9bb0dc Mon Sep 17 00:00:00 2001 From: JordanLongstaff Date: Tue, 4 Aug 2026 00:55:58 -0400 Subject: [PATCH 103/131] Disable Note Retention during parades --- src/port/Enhancements/Retention/NoteRetention.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/port/Enhancements/Retention/NoteRetention.cpp b/src/port/Enhancements/Retention/NoteRetention.cpp index 5e716fcfa..894509562 100644 --- a/src/port/Enhancements/Retention/NoteRetention.cpp +++ b/src/port/Enhancements/Retention/NoteRetention.cpp @@ -139,6 +139,11 @@ int32_t countCollectedForLevel(int32_t levelId) { return total; } +bool isInParade() { + return volatileFlag_get(VOLATILE_FLAG_1F_IN_CHARACTER_PARADE) || + volatileFlag_get(VOLATILE_FLAG_C1_IN_FINAL_CHARACTER_PARADE); +} + } // namespace extern "C" void port_noteRetention_getSizeAndPtr(int32_t* size, uint8_t** addr) { @@ -386,7 +391,7 @@ void RegisterNoteRetention_Init() { } const int32_t level = sPendingSeedLevel; sPendingSeedLevel = -1; - if (!systemActive() || !applyEnabled()) { + if (!systemActive() || !applyEnabled() || isInParade()) { return; } item_adjustByDiffWithoutHud(ITEM_C_NOTE, countCollectedForLevel(level) - item_getCount(ITEM_C_NOTE)); From d53552e217434761a068c6c54b53a8c7ee09585a Mon Sep 17 00:00:00 2001 From: Jeod <47716344+JeodC@users.noreply.github.com> Date: Tue, 4 Aug 2026 14:43:11 -0400 Subject: [PATCH 104/131] Stop language packs shadowing HD assets they don't localize (#351) --- src/port/GameVersion/BaseGameVersion.cpp | 12 +++- src/port/GameVersion/BaseGameVersion.h | 3 + src/port/Localization/Language.cpp | 61 +++++++++++++++++++ src/port/Resource/Alt/AltDialogFont.cpp | 74 +++++++++++++++++------- src/port/ResourceHelpers.cpp | 20 ++++--- src/port/ResourceHelpers.h | 2 + 6 files changed, 141 insertions(+), 31 deletions(-) diff --git a/src/port/GameVersion/BaseGameVersion.cpp b/src/port/GameVersion/BaseGameVersion.cpp index 717bbb0fd..a38b55c0c 100644 --- a/src/port/GameVersion/BaseGameVersion.cpp +++ b/src/port/GameVersion/BaseGameVersion.cpp @@ -54,6 +54,14 @@ bool ReadStampedCrc(const std::string& archivePath, uint32_t& outCrc) { } // namespace +std::string BaseArchivePath() { + std::string basePath = Ship::Context::LocateFileAcrossAppDirs("bk.o2r", "bk"); + if (basePath.empty() || !std::filesystem::exists(basePath)) { + return std::string(); // not extracted yet + } + return basePath; +} + BKVersion GetBaseVersion() { static BKVersion sVersion = BK_VER_US_10; static bool sResolved = false; @@ -61,8 +69,8 @@ BKVersion GetBaseVersion() { return sVersion; } - std::string basePath = Ship::Context::LocateFileAcrossAppDirs("bk.o2r", "bk"); - if (basePath.empty() || !std::filesystem::exists(basePath)) { + const std::string basePath = BaseArchivePath(); + if (basePath.empty()) { return sVersion; // not extracted yet — retry on the next call } diff --git a/src/port/GameVersion/BaseGameVersion.h b/src/port/GameVersion/BaseGameVersion.h index 916293690..a6c9ae2f0 100644 --- a/src/port/GameVersion/BaseGameVersion.h +++ b/src/port/GameVersion/BaseGameVersion.h @@ -12,6 +12,9 @@ BKVersion GetBaseVersion(); // Classify a version stamp taken from an archive bool ClassifyArchiveVersion(uint32_t rawVersion, BKVersion& out); +// Filesystem path of the base bk.o2r, or empty if it hasn't been extracted yet +std::string BaseArchivePath(); + // Romhacks are generally only supported by US 1.0 bool BaseGameSupportsRomhacks(); diff --git a/src/port/Localization/Language.cpp b/src/port/Localization/Language.cpp index c066c854f..85c2a3ef6 100644 --- a/src/port/Localization/Language.cpp +++ b/src/port/Localization/Language.cpp @@ -8,6 +8,7 @@ #include #include +#include #include "libultraship/libultraship.h" #include "ship/Context.h" @@ -138,6 +139,61 @@ bool ArchiveHasAssetHex(Ship::Archive* archive, uint32_t hex) { return false; } +bool IsLocalizedText(const std::string& path) { + return path.find("/dialog/") != std::string::npos || path.find("/quizq/") != std::string::npos || + path.find("/gruntyq/") != std::string::npos; +} + +bool EntryStamp(zip_t* z, const std::string& entryPath, uint32_t& outCrc, uint64_t& outSize) { + zip_stat_t st; + zip_stat_init(&st); + if (zip_stat(z, entryPath.c_str(), 0, &st) != 0 || !(st.valid & ZIP_STAT_CRC) || !(st.valid & ZIP_STAT_SIZE)) { + return false; + } + outCrc = static_cast(st.crc); + outSize = static_cast(st.size); + return true; +} + +size_t DropUnchangedOverrides(const std::string& packArchivePath, + std::unordered_map& overrides) { + const std::string basePath = BaseArchivePath(); + if (basePath.empty() || packArchivePath.empty()) { + return 0; + } + zip_t* packZip = zip_open(packArchivePath.c_str(), ZIP_RDONLY, nullptr); + if (packZip == nullptr) { + return 0; // a folder-based archive, not a zip: no cheap stamp to compare + } + zip_t* baseZip = zip_open(basePath.c_str(), ZIP_RDONLY, nullptr); + if (baseZip == nullptr) { + zip_close(packZip); + return 0; + } + + size_t dropped = 0; + for (auto it = overrides.begin(); it != overrides.end();) { + if (IsLocalizedText(it->second)) { + ++it; + continue; + } + uint32_t packCrc = 0, baseCrc = 0; + uint64_t packSize = 0, baseSize = 0; + const std::string baseEntry = ResourceHelpers_GetBaseAssetPath(it->first); + if (baseEntry.empty() || !EntryStamp(packZip, it->second, packCrc, packSize) || + !EntryStamp(baseZip, baseEntry, baseCrc, baseSize) || packCrc != baseCrc || packSize != baseSize) { + ++it; + continue; + } + it = overrides.erase(it); + dropped++; + } + + zip_close(baseZip); + zip_close(packZip); + return dropped; +} + const LanguageEntry* FindLanguage(const std::string& name) { for (const auto& e : sLanguages) { if (e.name == name) { @@ -286,6 +342,11 @@ void SetActiveLanguage(const std::string& name) { } dialogOverride[v10Id] = path; } + + if (const size_t dropped = DropUnchangedOverrides(entry->source->GetPath(), dialogOverride); dropped > 0) { + SPDLOG_INFO("[Lang] '{}': {} pack asset(s) are identical to the base game and were left un-repointed", name, + dropped); + } } // Hand the computed language to the resource layer diff --git a/src/port/Resource/Alt/AltDialogFont.cpp b/src/port/Resource/Alt/AltDialogFont.cpp index f3f477398..76c2782c6 100644 --- a/src/port/Resource/Alt/AltDialogFont.cpp +++ b/src/port/Resource/Alt/AltDialogFont.cpp @@ -15,34 +15,56 @@ #include "port/Enhancements/Events/Hooks/Events.h" #include "port/Patches/Patches.h" +#include "port/ResourceHelpers.h" #include "port/ShipInit.hpp" #include #include #include #include +#include #include namespace { -constexpr const char* kFontBase = "assets/sprite/ASSET_6EB_DIALOG_FONT_ALPHAMASK"; - -bool sBuilt = false; +constexpr uint32_t kDialogFontAssetId = 0x6EB; +constexpr const char* kFontBaseFallback = "assets/sprite/ASSET_6EB_DIALOG_FONT_ALPHAMASK"; +std::unordered_set sBuiltSheets; +std::string fontSheetPath(std::string resolved) { + return resolved.empty() ? kFontBaseFallback : resolved; +} std::shared_ptr loadTex(const std::string& path, bool loadExact) { return std::static_pointer_cast( Ship::Context::GetRawInstance()->GetResourceManager()->LoadResourceProcess(path, loadExact)); } -// Build a corrected alt for one chunk and cache it under "alt/". Returns false when there -// is nothing to do: no alt shipped, the dims already reconcile, or the alt isn't an HD raw texture. -bool correctChunk(const std::string& basePath) { - auto base = loadTex(basePath, true); // live native cell +// HD art for one chunk: the active sheet's own alt when the pack ships one, else the base game's +// alt for the same slot. Null when neither has art for it. +std::shared_ptr loadHdChunk(const std::string& activePath, const std::string& basePath, + const Fast::Texture* nativeCell, bool& fromBaseSheet) { + fromBaseSheet = false; + auto alt = loadTex(activePath, false); + if (alt != nullptr && alt.get() != nativeCell) { + return alt; + } + if (basePath == activePath) { + return nullptr; + } + fromBaseSheet = true; + return loadTex(Ship::IResource::gAltAssetPrefix + basePath, true); +} + +// Build a corrected alt for one chunk and cache it under "alt/". Returns false when +// there is nothing to do: no alt shipped, the dims already reconcile, or it isn't an HD raw texture. +bool correctChunk(const std::string& activePath, const std::string& basePath) { + auto base = loadTex(activePath, true); // live native cell if (base == nullptr || base->Width <= 0 || base->Height <= 0) { return false; } - auto alt = loadTex(basePath, false); // HD art, or the base itself if the pack has no alt - if (alt == nullptr || alt->ImageData == nullptr || alt.get() == base.get()) { + bool fromBaseSheet = false; + auto alt = loadHdChunk(activePath, basePath, base.get(), fromBaseSheet); + if (alt == nullptr || alt->ImageData == nullptr) { return false; } if (alt->Type != Fast::TextureType::RGBA32bpp || (alt->Flags & TEX_FLAG_LOAD_AS_RAW) == 0) { @@ -64,8 +86,10 @@ bool correctChunk(const std::string& basePath) { const int dstW = nativeW * k; const int dstH = nativeH * k; - if (dstH == (int)alt->Height) { - return false; // alt height already matches the live native cell -> no drift, nothing to fix + // Matching heights mean no drift to correct. Art borrowed from the base sheet still has to be + // re-cached, though: nothing is reachable at the active path until we put it there. + if (dstH == (int)alt->Height && !fromBaseSheet) { + return false; } // Top-align the HD rows into the k-scaled native cell; the zero-filled remainder stays transparent. @@ -79,7 +103,7 @@ bool correctChunk(const std::string& basePath) { // Same HD pixels, but VPixelScale re-derived against the live native rows (native_rows * k == dstH). // Cache under the alt path so the resource layer returns this in place of the raw archive alt. - const std::string altPath = std::string("alt/") + basePath; + const std::string altPath = Ship::IResource::gAltAssetPrefix + activePath; auto initData = std::make_shared(); initData->Path = altPath; auto tex = std::make_shared(initData); @@ -99,30 +123,38 @@ bool correctChunk(const std::string& basePath) { } // namespace -// Called when the dialog font is (re)loaded. Scans every font chunk once per boot and corrects each; -// idempotent, and a no-op when no alt pack is mounted (a later call may still succeed). +// Called when the dialog font is (re)loaded, boot and language switch alike. Scans every chunk of +// the sheet now in play and corrects each. extern "C" void port_dialogFontHd_rebuild(void) { - if (sBuilt) { + if (!Ship::Context::GetRawInstance()->GetResourceManager()->IsAltAssetsEnabled()) { return; } - if (!Ship::Context::GetRawInstance()->GetResourceManager()->IsAltAssetsEnabled()) { + + const std::string activeFont = fontSheetPath(ResourceHelpers_GetActiveAssetPath(kDialogFontAssetId)); + if (sBuiltSheets.count(activeFont) != 0) { return; } - sBuilt = true; + const std::string baseFont = fontSheetPath(ResourceHelpers_GetBaseAssetPath(kDialogFontAssetId)); + bool built = false; for (int frame = 0; frame < 64; frame++) { bool anyInFrame = false; for (int chunk = 0; chunk < 256; chunk++) { - const std::string basePath = - std::string(kFontBase) + "_" + std::to_string(frame) + "_" + std::to_string(chunk); - if (loadTex(basePath, true) == nullptr) { + const std::string suffix = "_" + std::to_string(frame) + "_" + std::to_string(chunk); + const std::string activePath = activeFont + suffix; + if (loadTex(activePath, true) == nullptr) { break; } anyInFrame = true; - correctChunk(basePath); + built = true; + correctChunk(activePath, baseFont + suffix); } if (!anyInFrame) { break; } } + + if (built) { + sBuiltSheets.insert(activeFont); + } } diff --git a/src/port/ResourceHelpers.cpp b/src/port/ResourceHelpers.cpp index cdc500ff2..6f20d5836 100644 --- a/src/port/ResourceHelpers.cpp +++ b/src/port/ResourceHelpers.cpp @@ -222,12 +222,8 @@ extern "C" int ResourceMgr_IsAssetRepointed(uint32_t assetId) { return sDialogOverride.find(assetId) != sDialogOverride.end() ? 1 : 0; } -// Resolve an asset id to its o2r path: the active language override wins for -// re-pointed dialog ids, otherwise the base manifest. -static std::string ResolveAssetPath(uint32_t assetId) { - if (auto ov = sDialogOverride.find(assetId); ov != sDialogOverride.end()) { - return ov->second; - } +// The base game's own o2r path for an asset id, ignoring any active language re-point. +std::string ResourceHelpers_GetBaseAssetPath(uint32_t assetId) { const auto& symbolMap = GetAssetSymbolMap(); if (auto entry = symbolMap.find(assetId); entry != symbolMap.end()) { return entry->second; @@ -235,6 +231,14 @@ static std::string ResolveAssetPath(uint32_t assetId) { return std::string(); } +// The o2r path an asset id resolves to right now. +std::string ResourceHelpers_GetActiveAssetPath(uint32_t assetId) { + if (auto ov = sDialogOverride.find(assetId); ov != sDialogOverride.end()) { + return ov->second; + } + return ResourceHelpers_GetBaseAssetPath(assetId); +} + static char* LoadAndRetainResource(const std::string& path, uint32_t assetId) { auto res = GetResourceByName(path.c_str()); if (res && res->GetRawPointer() != nullptr) { @@ -253,7 +257,7 @@ extern "C" char* ResourceMgr_ReloadByAssetId(uint32_t assetId) { sResourceRefCache.erase(it); } - std::string mappedPath = ResolveAssetPath(assetId); + std::string mappedPath = ResourceHelpers_GetActiveAssetPath(assetId); if (!mappedPath.empty()) { std::replace(mappedPath.begin(), mappedPath.end(), '\\', '/'); @@ -278,7 +282,7 @@ extern "C" char* ResourceMgr_LoadByAssetId(uint32_t assetId) { sResourceRefCache.erase(it); } - std::string mappedPath = ResolveAssetPath(assetId); + std::string mappedPath = ResourceHelpers_GetActiveAssetPath(assetId); if (mappedPath.empty()) { // A reserved-but-empty ROM slot resolves to nothing by design (the game // tolerates it, as on N64); only a genuinely-missing asset is worth tracing. diff --git a/src/port/ResourceHelpers.h b/src/port/ResourceHelpers.h index bb0381307..87e5156bc 100644 --- a/src/port/ResourceHelpers.h +++ b/src/port/ResourceHelpers.h @@ -37,6 +37,8 @@ Mtx* ResourceMgr_LoadMtxByName(char* path); void ResourceHelpers_ApplyLanguage(std::unordered_map dialogOverride, bool isJapanese, int dialogCount, int dialogIndex); +std::string ResourceHelpers_GetBaseAssetPath(uint32_t assetId); +std::string ResourceHelpers_GetActiveAssetPath(uint32_t assetId); #endif #endif From 761c7979bdde23c44877faddfcf6635e6d59a9a6 Mon Sep 17 00:00:00 2001 From: Caladius Date: Tue, 4 Aug 2026 14:45:12 -0400 Subject: [PATCH 105/131] Fix GamePlayTimer display and some warnings. (#387) --- src/port/Enhancements/Trackers/DisplayOverlay.cpp | 6 ++---- src/port/ShipUtils.cpp | 2 +- src/port/ShipUtils.h | 2 +- src/port/UI/LighthouseMenuEnhancements.cpp | 2 +- 4 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/port/Enhancements/Trackers/DisplayOverlay.cpp b/src/port/Enhancements/Trackers/DisplayOverlay.cpp index c459bfbc5..97a97f822 100644 --- a/src/port/Enhancements/Trackers/DisplayOverlay.cpp +++ b/src/port/Enhancements/Trackers/DisplayOverlay.cpp @@ -10,11 +10,9 @@ #include "save.h" #include "enums.h" +#include "functions.h" extern "C" { -enum map_e gsworld_getMap(void); -u16 itemscore_timeScores_get(enum level_e level_id); - extern SaveData gameFile_saveData[4]; } @@ -33,7 +31,7 @@ int64_t DisplayOverlay_GetTotalInGameTime() { } void DisplayOverlayWindow::Draw() { - if (!IsVisible() || gsworld_getMap() == MAP_91_FILE_SELECT) { + if (gsworld_getMap() == MAP_91_FILE_SELECT) { return; } diff --git a/src/port/ShipUtils.cpp b/src/port/ShipUtils.cpp index b22bbe3cd..36dbd47a2 100644 --- a/src/port/ShipUtils.cpp +++ b/src/port/ShipUtils.cpp @@ -62,7 +62,7 @@ extern uint32_t Ship_Hash(std::string str) { return hval; } -extern std::string port_FormatTimeDisplay(uint32_t value) { +extern std::string port_FormatTimeDisplay(uint64_t value) { uint32_t sec = value / 10; uint32_t hh = sec / 3600; uint32_t mm = (sec - hh * 3600) / 60; diff --git a/src/port/ShipUtils.h b/src/port/ShipUtils.h index e669191bf..11c5b1764 100644 --- a/src/port/ShipUtils.h +++ b/src/port/ShipUtils.h @@ -20,7 +20,7 @@ extern std::vector abilityNameList; void TableCellCenteredText(const char* text); uint32_t Ship_Hash(std::string str); -std::string port_FormatTimeDisplay(uint32_t value); +std::string port_FormatTimeDisplay(uint64_t value); extern "C" { #endif diff --git a/src/port/UI/LighthouseMenuEnhancements.cpp b/src/port/UI/LighthouseMenuEnhancements.cpp index 2d369820c..2f4cbb1d1 100644 --- a/src/port/UI/LighthouseMenuEnhancements.cpp +++ b/src/port/UI/LighthouseMenuEnhancements.cpp @@ -709,7 +709,7 @@ void LighthouseMenu::AddMenuEnhancements() { AddWidget(path, "Hide Window Background", WIDGET_CVAR_CHECKBOX) .CVar("gDisplayOverlay.Background") .Options(CheckboxOptions().Tooltip("Hides the background of the Display Overlay window.")); - AddWidget(path, "Scale: %.1fx", WIDGET_CVAR_SLIDER_FLOAT) + AddWidget(path, "Timer Scale", WIDGET_CVAR_SLIDER_FLOAT) .CVar("gDisplayOverlay.Scale") .Options(FloatSliderOptions() .Tooltip("Adjust the Scale for the Display Overlay window.") From a221b3e1f864256d15b266f47a39ea6d1e619aa4 Mon Sep 17 00:00:00 2001 From: Caladius Date: Tue, 4 Aug 2026 14:46:56 -0400 Subject: [PATCH 106/131] Moves No Mumbo Detransform to a VB Hook. (#388) --- src/core2/mumbo.c | 38 ++++++++++++--------- src/port/Enhancements/Cheats/Cheats.cpp | 8 ++--- src/port/Enhancements/Events/Hooks/Events.h | 1 + 3 files changed, 24 insertions(+), 23 deletions(-) diff --git a/src/core2/mumbo.c b/src/core2/mumbo.c index aff67980d..4b3031d82 100644 --- a/src/core2/mumbo.c +++ b/src/core2/mumbo.c @@ -514,26 +514,30 @@ Actor *chMumbo_draw(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx) { } void chMumbo_detransformWarn(NodeProp *arg0, ActorMarker *arg1){ - s32 xform; - xform = player_getTransformation(); - if(xform == TRANSFORM_1_BANJO || xform == TRANSFORM_7_WISHWASHY || sHasWarnedBanjoAboutDetransform) - return; - - sHasWarnedBanjoAboutDetransform++; - if(D_8037DDF3) - return; - - gcdialog_showDialog(fileProgressFlag_getAndSet(FILEPROG_83_MAGIC_GET_WEAK_TEXT, TRUE) ? VER_SELECT(ASSET_F5C_DIALOG_MUMBO_MAGIC_GET_WEAK_ABREV, 0xAC2, 0, 0) : VER_SELECT(ASSET_F5B_DIALOG_MUMBO_MAGIC_GET_WEAK_FULL, 0xAC1, 0, 0), 0xe, NULL, NULL, NULL, NULL); + if (EventSystem_Should(VB_MUMBO_DETRANSFORM, true)) { + s32 xform; + xform = player_getTransformation(); + if (xform == TRANSFORM_1_BANJO || xform == TRANSFORM_7_WISHWASHY || sHasWarnedBanjoAboutDetransform) + return; + + sHasWarnedBanjoAboutDetransform++; + if (D_8037DDF3) + return; + + gcdialog_showDialog(fileProgressFlag_getAndSet(FILEPROG_83_MAGIC_GET_WEAK_TEXT, TRUE) ? VER_SELECT(ASSET_F5C_DIALOG_MUMBO_MAGIC_GET_WEAK_ABREV, 0xAC2, 0, 0) : VER_SELECT(ASSET_F5B_DIALOG_MUMBO_MAGIC_GET_WEAK_FULL, 0xAC1, 0, 0), 0xe, NULL, NULL, NULL, NULL); + } } void chMumbo_detransformTrigger(NodeProp *arg0, ActorMarker *arg1){ - s32 xform; - xform = player_getTransformation(); - if(xform == TRANSFORM_1_BANJO || xform == TRANSFORM_7_WISHWASHY || D_8037DDF1) - return; - gcdialog_showDialog(fileProgressFlag_getAndSet(FILEPROG_84_MAGIC_ALL_GONE_TEXT, TRUE) ? VER_SELECT(ASSET_F5E_DIALOG_MUMBO_MAGIC_RUN_OUT_ABREV, 0xAC4, 0, 0): VER_SELECT(ASSET_F5D_DIALOG_MUMBO_MAGIC_RUN_OUT_FULL, 0xAC3, 0, 0), 0xe, NULL, NULL, NULL, NULL); - D_8037DDF1++; - player_transform(TRANSFORM_1_BANJO); + if (EventSystem_Should(VB_MUMBO_DETRANSFORM, true)) { + s32 xform; + xform = player_getTransformation(); + if (xform == TRANSFORM_1_BANJO || xform == TRANSFORM_7_WISHWASHY || D_8037DDF1) + return; + gcdialog_showDialog(fileProgressFlag_getAndSet(FILEPROG_84_MAGIC_ALL_GONE_TEXT, TRUE) ? VER_SELECT(ASSET_F5E_DIALOG_MUMBO_MAGIC_RUN_OUT_ABREV, 0xAC4, 0, 0) : VER_SELECT(ASSET_F5D_DIALOG_MUMBO_MAGIC_RUN_OUT_FULL, 0xAC3, 0, 0), 0xe, NULL, NULL, NULL, NULL); + D_8037DDF1++; + player_transform(TRANSFORM_1_BANJO); + } } void func_802D2CB8(void){ diff --git a/src/port/Enhancements/Cheats/Cheats.cpp b/src/port/Enhancements/Cheats/Cheats.cpp index f11484436..178e3faa8 100644 --- a/src/port/Enhancements/Cheats/Cheats.cpp +++ b/src/port/Enhancements/Cheats/Cheats.cpp @@ -331,12 +331,8 @@ void RegisterFastTransform_Init() { // Disable Mumbo untransform when going too far void RegisterNoMumboUntransform_Init() { - COND_HOOK(GameFrameUpdate, EVENT_PRIORITY_NORMAL, CVarGetInteger(CVAR_NO_MUMBO_UNTRANSFORM, 0), [](IEvent* event) { - // Prevent Mumbo from triggering untransform dialog/warn - // These functions check game state and show dialog - // We disable them by setting a flag they check - volatileFlag_set((enum volatile_flags_e)207, 1); // Prevents detransform warning - }); + COND_VB_SHOULD(VB_MUMBO_DETRANSFORM, EVENT_PRIORITY_NORMAL, CVarGetInteger(CVAR_NO_MUMBO_UNTRANSFORM, 0), + { *should = false; }); } // ============================================================================ diff --git a/src/port/Enhancements/Events/Hooks/Events.h b/src/port/Enhancements/Events/Hooks/Events.h index 6383b6ea6..8c17d2523 100644 --- a/src/port/Enhancements/Events/Hooks/Events.h +++ b/src/port/Enhancements/Events/Hooks/Events.h @@ -48,6 +48,7 @@ typedef enum VBehaviorID { VB_DISABLE_SNACKER, VB_SAVE_AND_EXIT, VB_MUMBO_HUT_TRANSFORM_CUTSCENE, + VB_MUMBO_DETRANSFORM, // Rando object behavior VB_OVERRIDE_BOTTLES_TEXT_CALLBACK, From e258594a10d6ecca5954cb18c8c579fa2e645d49 Mon Sep 17 00:00:00 2001 From: aMannus Date: Tue, 4 Aug 2026 20:52:04 +0200 Subject: [PATCH 107/131] AP item improvements, more item queue work --- .../CustomCollectible/CustomCollectible.cpp | 14 ++++++----- .../CustomCollectibleDrawCustom.cpp | 5 ++-- src/port/Rando/ItemQueue.cpp | 25 ++++++++++++++++++- src/port/Rando/ObjectBehavior/MusicNote.cpp | 18 ++----------- 4 files changed, 37 insertions(+), 25 deletions(-) diff --git a/src/port/Rando/CustomCollectible/CustomCollectible.cpp b/src/port/Rando/CustomCollectible/CustomCollectible.cpp index c69aab4aa..a9c75e2af 100644 --- a/src/port/Rando/CustomCollectible/CustomCollectible.cpp +++ b/src/port/Rando/CustomCollectible/CustomCollectible.cpp @@ -28,7 +28,7 @@ std::unordered_map customCollectibleDrawInfo { ACTOR_51_MUSIC_NOTE, { ASSET_6D6_SPRITE_MUSIC_NOTE, CCT_GENERIC_SPRITE } }, { ACTOR_25E_SNS_EGG, { ASSET_50D_MODEL_SNS_EGG, CCT_VANILLA_SNS_EGG } }, { ACTOR_25D_ICE_KEY, { ASSET_50C_MODEL_ICE_KEY, CCT_GENERIC_MODEL } }, - { ACTOR_3CD_CUSTOM_COLLECTIBLE, { ASSET_0_NONE, CCT_CUSTOM_MODEL } }, + { ACTOR_3CD_CUSTOM_COLLECTIBLE, { ASSET_35F_MODEL_JIGGY, CCT_CUSTOM_MODEL } }, }; ActorAnimationInfo moleAnimations[] = { @@ -90,6 +90,12 @@ void CustomCollectible_Update(Actor* actor) { } } } + + // Allows shadows + if (customLocal->itemType == RITYPE_AP_ITEM) { + actor->unk124_6 = 1; + actor->marker->unk14_21 = 1; + } } f32 CustomCollectible::GetScale(RandoItemType itemType) { @@ -137,13 +143,9 @@ Actor* CustomCollectible::Spawn(int32_t position[3], RandoCheckId randoCheckId) int32_t flags = ACTOR_FLAG_UNKNOWN_6 | ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_21; RandoItemId randoItemId = RANDO_SAVE_CHECKS[randoCheckId].randoItemId; + randoItemId = RI_AP_ITEM_PROGRESSION; RandoItemType itemType = Rando::StaticData::Items[randoItemId].randoItemType; - // Custom models exported for OoT are centered instead of offset to the marker, so they appear underground otherwise - if (itemType == RITYPE_AP_ITEM) { - spawnPosition[1] += 50; - } - // actor_new stores the ActorInfo* permanently, so it must outlive Spawn() static std::unordered_map sActorInfoCache; ActorInfo& collectibleInfo = sActorInfoCache[randoItemId]; diff --git a/src/port/Rando/CustomCollectible/CustomCollectibleDrawCustom.cpp b/src/port/Rando/CustomCollectible/CustomCollectibleDrawCustom.cpp index 0a619dcf5..cf9cd4d9e 100644 --- a/src/port/Rando/CustomCollectible/CustomCollectibleDrawCustom.cpp +++ b/src/port/Rando/CustomCollectible/CustomCollectibleDrawCustom.cpp @@ -39,7 +39,7 @@ static const char* sCustomModelPaths[] = { // The models are authored at OoT world scale, which is roughly 10x too large // for BK. Baked into every draw so callers treat scale 1.0 as "natural size". -static const f32 sCustomModelBaseScale = 0.05f; +static const f32 sCustomModelBaseScale = 0.04f; // BK never uploads RSP lights (its models bake shading into vertex colors), but // these materials enable G_LIGHTING, so without our own light setup the shade @@ -92,9 +92,10 @@ Actor* CustomCollectible_DrawCustomModel(ActorMarker* marker, Gfx** gfx, Mtx** m // scopes instead. FrameInterpolation_RecordOpenChild("custom_item", (uintptr_t)model); f32 rotation[3] = { actor->pitch, actor->yaw, actor->roll }; + f32 position[3] = { actor->position[0], actor->position[1] + 50, actor->position[2] }; // The modelview translation is camera-relative, matching modelRender_draw. mlMtxIdent(); - func_80252AF0(camera_position, actor->position, rotation, actor->scale * sCustomModelBaseScale, NULL); + func_80252AF0(camera_position, position, rotation, actor->scale * sCustomModelBaseScale, NULL); mlMtxApply(*mtx); gSPMatrix((*gfx)++, (*mtx)++, G_MTX_PUSH | G_MTX_LOAD | G_MTX_MODELVIEW); gSPSetLights1((*gfx)++, sCustomModelLights); diff --git a/src/port/Rando/ItemQueue.cpp b/src/port/Rando/ItemQueue.cpp index 3e3bb48a8..102c6cd02 100644 --- a/src/port/Rando/ItemQueue.cpp +++ b/src/port/Rando/ItemQueue.cpp @@ -222,11 +222,34 @@ void ItemQueue::GiveItem(RandoItemId randoItemId) { if (worldId == map_getLevel(gsworld_getMap())) { item_set(ITEM_C_NOTE, D_80385FF0[map_getLevel(gsworld_getMap())]); } - // TODO: Add note data to savefile break; case RITYPE_SNS_EGG: + comusic_playTrack(COMUSIC_88_BIG_SNS_FANFARE); + FUNC_8030E624(SFX_114_BRICKWALL_BREAKING, 0.8f, 15000); + switch (randoItemId) { + case RI_STOP_N_SWOP_EGG_BLUE: + sns_set_item_and_update_payload(SNS_ITEM_EGG_BLUE, 0, 1); + break; + case RI_STOP_N_SWOP_EGG_CYAN: + sns_set_item_and_update_payload(SNS_ITEM_EGG_CYAN, 0, 1); + break; + case RI_STOP_N_SWOP_EGG_GREEN: + sns_set_item_and_update_payload(SNS_ITEM_EGG_GREEN, 0, 1); + break; + case RI_STOP_N_SWOP_EGG_PINK: + sns_set_item_and_update_payload(SNS_ITEM_EGG_PINK, 0, 1); + break; + case RI_STOP_N_SWOP_EGG_RED: + sns_set_item_and_update_payload(SNS_ITEM_EGG_RED, 0, 1); + break; + case RI_STOP_N_SWOP_EGG_YELLOW: + sns_set_item_and_update_payload(SNS_ITEM_EGG_YELLOW, 0, 1); + break; + } break; case RITYPE_SNS_KEY: + sns_set_item_and_update_payload(SNS_ITEM_ICE_KEY, 0, 1); + comusic_playTrack(COMUSIC_88_BIG_SNS_FANFARE); break; case RITYPE_AP_ITEM: break; diff --git a/src/port/Rando/ObjectBehavior/MusicNote.cpp b/src/port/Rando/ObjectBehavior/MusicNote.cpp index 24d32b6ee..485775456 100644 --- a/src/port/Rando/ObjectBehavior/MusicNote.cpp +++ b/src/port/Rando/ObjectBehavior/MusicNote.cpp @@ -10,6 +10,7 @@ extern "C" { void item_inc(enum item_e item); +extern u8 D_80385FF0[0xE]; } #define OPTION_ENABLED RANDO_SAVE_OPTIONS[RO_SHUFFLE_MUSIC_NOTES].optionValue @@ -17,22 +18,7 @@ void item_inc(enum item_e item); void Rando::ObjectBehavior::InitMusicNoteBehavior() { COND_HOOK(OnSetJiggyList, EVENT_PRIORITY_NORMAL, IS_RANDO && OPTION_ENABLED, [](IEvent* event) { OnSetJiggyList* ev = (OnSetJiggyList*)event; - int32_t currentNotes = 0; - for (auto& location : Rando::Logic::shuffledPool) { - Rando::StaticData::RandoStaticItem randoItem = Rando::StaticData::Items[location.randoItemId]; - - if (randoItem.worldId != ev->levelId) { - continue; - } - - if (randoItem.randoItemType == RITYPE_MUSIC_NOTE) { - if (location.obtained) { - currentNotes++; - } - } - } - - item_set(ITEM_C_NOTE, currentNotes); + item_set(ITEM_C_NOTE, D_80385FF0[ev->levelId]); }) } From a7d736f3a4efb23ed34325b23cc5f7a4b8701d19 Mon Sep 17 00:00:00 2001 From: aMannus Date: Tue, 4 Aug 2026 22:30:19 +0200 Subject: [PATCH 108/131] Fix input viewer (#395) * Fix input viewer * Clang and fix menu column * Minor menu tweaks * update cvar to use macro --- port/textures/icons/g2ShipIcon.png | Bin 13286 -> 0 bytes src/port/UI/InputViewer.cpp | 624 ++++++++++----------- src/port/UI/LighthouseGui.cpp | 4 +- src/port/UI/LighthouseMenuEnhancements.cpp | 2 +- src/port/UI/LighthouseMenuSettings.cpp | 3 +- 5 files changed, 315 insertions(+), 318 deletions(-) delete mode 100644 port/textures/icons/g2ShipIcon.png diff --git a/port/textures/icons/g2ShipIcon.png b/port/textures/icons/g2ShipIcon.png deleted file mode 100644 index 49785b681a18951b5611a04a8f594bea3bcab154..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13286 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"Input-Viewer-Background", - "textures/buttons/InputViewerBackground.png"); - GetFast3dGui()->LoadTextureFromRawImage("A-Btn", "textures/buttons/ABtn.png"); - GetFast3dGui()->LoadTextureFromRawImage("B-Btn", "textures/buttons/BBtn.png"); - GetFast3dGui()->LoadTextureFromRawImage("L-Btn", "textures/buttons/LBtn.png"); - GetFast3dGui()->LoadTextureFromRawImage("R-Btn", "textures/buttons/RBtn.png"); - GetFast3dGui()->LoadTextureFromRawImage("Z-Btn", "textures/buttons/ZBtn.png"); - GetFast3dGui()->LoadTextureFromRawImage("Start-Btn", "textures/buttons/StartBtn.png"); - GetFast3dGui()->LoadTextureFromRawImage("C-Left", "textures/buttons/CLeft.png"); - GetFast3dGui()->LoadTextureFromRawImage("C-Right", "textures/buttons/CRight.png"); - GetFast3dGui()->LoadTextureFromRawImage("C-Up", "textures/buttons/CUp.png"); - GetFast3dGui()->LoadTextureFromRawImage("C-Down", "textures/buttons/CDown.png"); - GetFast3dGui()->LoadTextureFromRawImage("Analog-Stick", "textures/buttons/AnalogStick.png"); - GetFast3dGui()->LoadTextureFromRawImage("Dpad-Left", "textures/buttons/DPadLeft.png"); - GetFast3dGui()->LoadTextureFromRawImage("Dpad-Right", "textures/buttons/DPadRight.png"); - GetFast3dGui()->LoadTextureFromRawImage("Dpad-Up", "textures/buttons/DPadUp.png"); - GetFast3dGui()->LoadTextureFromRawImage("Dpad-Down", "textures/buttons/DPadDown.png"); - GetFast3dGui()->LoadTextureFromRawImage("Modifier-1", "textures/buttons/Mod1.png"); - GetFast3dGui()->LoadTextureFromRawImage("Modifier-2", "textures/buttons/Mod2.png"); - GetFast3dGui()->LoadTextureFromRawImage("Right-Stick", "textures/buttons/RightStick.png"); - GetFast3dGui()->LoadTextureFromRawImage("A-Btn Outline", "textures/buttons/ABtnOutline.png"); - GetFast3dGui()->LoadTextureFromRawImage("B-Btn Outline", "textures/buttons/BBtnOutline.png"); - GetFast3dGui()->LoadTextureFromRawImage("L-Btn Outline", "textures/buttons/LBtnOutline.png"); - GetFast3dGui()->LoadTextureFromRawImage("R-Btn Outline", "textures/buttons/RBtnOutline.png"); - GetFast3dGui()->LoadTextureFromRawImage("Z-Btn Outline", "textures/buttons/ZBtnOutline.png"); - GetFast3dGui()->LoadTextureFromRawImage("Start-Btn Outline", "textures/buttons/StartBtnOutline.png"); - GetFast3dGui()->LoadTextureFromRawImage("C-Left Outline", "textures/buttons/CLeftOutline.png"); - GetFast3dGui()->LoadTextureFromRawImage("C-Right Outline", "textures/buttons/CRightOutline.png"); - GetFast3dGui()->LoadTextureFromRawImage("C-Up Outline", "textures/buttons/CUpOutline.png"); - GetFast3dGui()->LoadTextureFromRawImage("C-Down Outline", "textures/buttons/CDownOutline.png"); - GetFast3dGui()->LoadTextureFromRawImage("Analog-Stick Outline", "textures/buttons/AnalogStickOutline.png"); - GetFast3dGui()->LoadTextureFromRawImage("Dpad-Left Outline", "textures/buttons/DPadLeftOutline.png"); - GetFast3dGui()->LoadTextureFromRawImage("Dpad-Right Outline", "textures/buttons/DPadRightOutline.png"); - GetFast3dGui()->LoadTextureFromRawImage("Dpad-Up Outline", "textures/buttons/DPadUpOutline.png"); - GetFast3dGui()->LoadTextureFromRawImage("Dpad-Down Outline", "textures/buttons/DPadDownOutline.png"); - GetFast3dGui()->LoadTextureFromRawImage("Modifier-1 Outline", "textures/buttons/Mod1Outline.png"); - GetFast3dGui()->LoadTextureFromRawImage("Modifier-2 Outline", "textures/buttons/Mod2Outline.png"); - GetFast3dGui()->LoadTextureFromRawImage("Right-Stick Outline", "textures/buttons/RightStickOutline.png"); - sButtonTexturesLoaded = true; - } + static bool sButtonTexturesLoaded = false; + if (!sButtonTexturesLoaded) { + GetFast3dGui()->LoadTextureFromRawImage("Input-Viewer-Background", + "textures/buttons/InputViewerBackground.png"); + GetFast3dGui()->LoadTextureFromRawImage("A-Btn", "textures/buttons/ABtn.png"); + GetFast3dGui()->LoadTextureFromRawImage("B-Btn", "textures/buttons/BBtn.png"); + GetFast3dGui()->LoadTextureFromRawImage("L-Btn", "textures/buttons/LBtn.png"); + GetFast3dGui()->LoadTextureFromRawImage("R-Btn", "textures/buttons/RBtn.png"); + GetFast3dGui()->LoadTextureFromRawImage("Z-Btn", "textures/buttons/ZBtn.png"); + GetFast3dGui()->LoadTextureFromRawImage("Start-Btn", "textures/buttons/StartBtn.png"); + GetFast3dGui()->LoadTextureFromRawImage("C-Left", "textures/buttons/CLeft.png"); + GetFast3dGui()->LoadTextureFromRawImage("C-Right", "textures/buttons/CRight.png"); + GetFast3dGui()->LoadTextureFromRawImage("C-Up", "textures/buttons/CUp.png"); + GetFast3dGui()->LoadTextureFromRawImage("C-Down", "textures/buttons/CDown.png"); + GetFast3dGui()->LoadTextureFromRawImage("Analog-Stick", "textures/buttons/AnalogStick.png"); + GetFast3dGui()->LoadTextureFromRawImage("Dpad-Left", "textures/buttons/DPadLeft.png"); + GetFast3dGui()->LoadTextureFromRawImage("Dpad-Right", "textures/buttons/DPadRight.png"); + GetFast3dGui()->LoadTextureFromRawImage("Dpad-Up", "textures/buttons/DPadUp.png"); + GetFast3dGui()->LoadTextureFromRawImage("Dpad-Down", "textures/buttons/DPadDown.png"); + GetFast3dGui()->LoadTextureFromRawImage("Modifier-1", "textures/buttons/Mod1.png"); + GetFast3dGui()->LoadTextureFromRawImage("Modifier-2", "textures/buttons/Mod2.png"); + GetFast3dGui()->LoadTextureFromRawImage("Right-Stick", "textures/buttons/RightStick.png"); + GetFast3dGui()->LoadTextureFromRawImage("A-Btn Outline", "textures/buttons/ABtnOutline.png"); + GetFast3dGui()->LoadTextureFromRawImage("B-Btn Outline", "textures/buttons/BBtnOutline.png"); + GetFast3dGui()->LoadTextureFromRawImage("L-Btn Outline", "textures/buttons/LBtnOutline.png"); + GetFast3dGui()->LoadTextureFromRawImage("R-Btn Outline", "textures/buttons/RBtnOutline.png"); + GetFast3dGui()->LoadTextureFromRawImage("Z-Btn Outline", "textures/buttons/ZBtnOutline.png"); + GetFast3dGui()->LoadTextureFromRawImage("Start-Btn Outline", "textures/buttons/StartBtnOutline.png"); + GetFast3dGui()->LoadTextureFromRawImage("C-Left Outline", "textures/buttons/CLeftOutline.png"); + GetFast3dGui()->LoadTextureFromRawImage("C-Right Outline", "textures/buttons/CRightOutline.png"); + GetFast3dGui()->LoadTextureFromRawImage("C-Up Outline", "textures/buttons/CUpOutline.png"); + GetFast3dGui()->LoadTextureFromRawImage("C-Down Outline", "textures/buttons/CDownOutline.png"); + GetFast3dGui()->LoadTextureFromRawImage("Analog-Stick Outline", "textures/buttons/AnalogStickOutline.png"); + GetFast3dGui()->LoadTextureFromRawImage("Dpad-Left Outline", "textures/buttons/DPadLeftOutline.png"); + GetFast3dGui()->LoadTextureFromRawImage("Dpad-Right Outline", "textures/buttons/DPadRightOutline.png"); + GetFast3dGui()->LoadTextureFromRawImage("Dpad-Up Outline", "textures/buttons/DPadUpOutline.png"); + GetFast3dGui()->LoadTextureFromRawImage("Dpad-Down Outline", "textures/buttons/DPadDownOutline.png"); + GetFast3dGui()->LoadTextureFromRawImage("Modifier-1 Outline", "textures/buttons/Mod1Outline.png"); + GetFast3dGui()->LoadTextureFromRawImage("Modifier-2 Outline", "textures/buttons/Mod2Outline.png"); + GetFast3dGui()->LoadTextureFromRawImage("Right-Stick Outline", "textures/buttons/RightStickOutline.png"); + sButtonTexturesLoaded = true; + } - ImVec2 mainPos = ImGui::GetWindowPos(); - ImVec2 size = ImGui::GetMainViewport()->WorkSize; + ImVec2 mainPos = ImGui::GetWindowPos(); + ImVec2 size = ImGui::GetMainViewport()->WorkSize; #ifdef __WIIU__ - const float scale = CVarGetFloat(CVAR_INPUT_VIEWER("Scale"), 1.0f) * 2.0f; + const float scale = CVarGetFloat(CVAR_INPUT_VIEWER("Scale"), 1.0f) * 2.0f; #else - const float scale = CVarGetFloat(CVAR_INPUT_VIEWER("Scale"), 1.0f); + const float scale = CVarGetFloat(CVAR_INPUT_VIEWER("Scale"), 1.0f); #endif - const int showAnalogAngles = CVarGetInteger(CVAR_INPUT_VIEWER("AnalogAngles.Enabled"), 0); - const int buttonOutlineMode = - CVarGetInteger(CVAR_INPUT_VIEWER("ButtonOutlineMode"), BUTTON_OUTLINE_NOT_PRESSED); - const bool useGlobalOutlineMode = CVarGetInteger(CVAR_INPUT_VIEWER("UseGlobalButtonOutlineMode"), 1); - - ImVec2 bgSize = GetFast3dGui()->GetTextureSize("Input-Viewer-Background"); - ImVec2 scaledBGSize = ImVec2(bgSize.x * scale, bgSize.y * scale); - - ImGui::SetNextWindowSize( - ImVec2(scaledBGSize.x + 20, scaledBGSize.y + - (showAnalogAngles ? ImGui::CalcTextSize("X").y : 0) * scale * - CVarGetFloat(CVAR_INPUT_VIEWER("AnalogAngles.Scale"), 1.0f) + - 20)); - ImGui::SetNextWindowContentSize( - ImVec2(scaledBGSize.x, scaledBGSize.y + (showAnalogAngles ? 15 : 0) * scale * - CVarGetFloat(CVAR_INPUT_VIEWER("AnalogAngles.Scale"), 1.0f))); - ImGui::SetNextWindowPos( - ImVec2(mainPos.x + size.x - scaledBGSize.x - 30, mainPos.y + size.y - scaledBGSize.y - 30), - ImGuiCond_FirstUseEver); - - ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4(0, 0, 0, 0)); - ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0.0f, 0.0f)); - - OSContPad* pads = - std::dynamic_pointer_cast(Ship::Context::GetRawInstance()->GetControlDeck())->GetPads(); - - ImGuiWindowFlags windowFlags = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoScrollbar | - ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoBackground | - ImGuiWindowFlags_NoFocusOnAppearing; - - if (!CVarGetInteger(CVAR_INPUT_VIEWER("EnableDragging"), 1)) { - windowFlags |= ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_NoMove; - } + const int showAnalogAngles = CVarGetInteger(CVAR_INPUT_VIEWER("AnalogAngles.Enabled"), 0); + const int buttonOutlineMode = CVarGetInteger(CVAR_INPUT_VIEWER("ButtonOutlineMode"), BUTTON_OUTLINE_NOT_PRESSED); + const bool useGlobalOutlineMode = CVarGetInteger(CVAR_INPUT_VIEWER("UseGlobalButtonOutlineMode"), 1); + + ImVec2 bgSize = GetFast3dGui()->GetTextureSize("Input-Viewer-Background"); + ImVec2 scaledBGSize = ImVec2(bgSize.x * scale, bgSize.y * scale); + + ImGui::SetNextWindowSize( + ImVec2(scaledBGSize.x + 20, scaledBGSize.y + + (showAnalogAngles ? ImGui::CalcTextSize("X").y : 0) * scale * + CVarGetFloat(CVAR_INPUT_VIEWER("AnalogAngles.Scale"), 1.0f) + + 20)); + ImGui::SetNextWindowContentSize( + ImVec2(scaledBGSize.x, scaledBGSize.y + (showAnalogAngles ? 15 : 0) * scale * + CVarGetFloat(CVAR_INPUT_VIEWER("AnalogAngles.Scale"), 1.0f))); + ImGui::SetNextWindowPos(ImVec2(mainPos.x + size.x - scaledBGSize.x - 30, mainPos.y + size.y - scaledBGSize.y - 30), + ImGuiCond_FirstUseEver); + + ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4(0, 0, 0, 0)); + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0.0f, 0.0f)); + + OSContPad* pads = + std::dynamic_pointer_cast(Ship::Context::GetRawInstance()->GetControlDeck())->GetPads(); + + ImGuiWindowFlags windowFlags = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoScrollbar | + ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoBackground | + ImGuiWindowFlags_NoFocusOnAppearing; + + if (!CVarGetInteger(CVAR_INPUT_VIEWER("EnableDragging"), 1)) { + windowFlags |= ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_NoMove; + } - if (pads != nullptr && ImGui::Begin("Input Viewer", nullptr, windowFlags)) { - ImGui::SetCursorPos(ImVec2(10, 10)); - const ImVec2 aPos = ImGui::GetCursorPos(); + if (pads != nullptr && ImGui::Begin("Input Viewer", nullptr, windowFlags)) { + ImGui::SetCursorPos(ImVec2(10, 10)); + const ImVec2 aPos = ImGui::GetCursorPos(); - if (CVarGetInteger(CVAR_INPUT_VIEWER("ShowBackground"), 1)) { - ImGui::SetNextItemAllowOverlap(); - // Background - ImGui::Image(GetFast3dGui()->GetTextureByName("Input-Viewer-Background"), scaledBGSize, ImVec2(0, 0), - ImVec2(1.0f, 1.0f)); - } + if (CVarGetInteger(CVAR_INPUT_VIEWER("ShowBackground"), 1)) { + ImGui::SetNextItemAllowOverlap(); + // Background + ImGui::Image(GetFast3dGui()->GetTextureByName("Input-Viewer-Background"), scaledBGSize, ImVec2(0, 0), + ImVec2(1.0f, 1.0f)); + } - // A/B - if (CVarGetInteger(CVAR_INPUT_VIEWER("BBtn"), 1)) { - ImGui::SetNextItemAllowOverlap(); - ImGui::SetCursorPos(aPos); - RenderButton("B-Btn", "B-Btn Outline", pads[0].button & BTN_B, scaledBGSize, - useGlobalOutlineMode - ? buttonOutlineMode - : CVarGetInteger(CVAR_INPUT_VIEWER("BBtnOutlineMode"), BUTTON_OUTLINE_NOT_PRESSED)); - } - if (CVarGetInteger(CVAR_INPUT_VIEWER("ABtn"), 1)) { - ImGui::SetNextItemAllowOverlap(); - ImGui::SetCursorPos(aPos); - RenderButton("A-Btn", "A-Btn Outline", pads[0].button & BTN_A, scaledBGSize, - useGlobalOutlineMode - ? buttonOutlineMode - : CVarGetInteger(CVAR_INPUT_VIEWER("ABtnOutlineMode"), BUTTON_OUTLINE_NOT_PRESSED)); - } + // A/B + if (CVarGetInteger(CVAR_INPUT_VIEWER("BBtn"), 1)) { + ImGui::SetNextItemAllowOverlap(); + ImGui::SetCursorPos(aPos); + RenderButton("B-Btn", "B-Btn Outline", pads[0].button & BTN_B, scaledBGSize, + useGlobalOutlineMode + ? buttonOutlineMode + : CVarGetInteger(CVAR_INPUT_VIEWER("BBtnOutlineMode"), BUTTON_OUTLINE_NOT_PRESSED)); + } + if (CVarGetInteger(CVAR_INPUT_VIEWER("ABtn"), 1)) { + ImGui::SetNextItemAllowOverlap(); + ImGui::SetCursorPos(aPos); + RenderButton("A-Btn", "A-Btn Outline", pads[0].button & BTN_A, scaledBGSize, + useGlobalOutlineMode + ? buttonOutlineMode + : CVarGetInteger(CVAR_INPUT_VIEWER("ABtnOutlineMode"), BUTTON_OUTLINE_NOT_PRESSED)); + } - // C buttons - if (CVarGetInteger(CVAR_INPUT_VIEWER("CUp"), 1)) { - ImGui::SetNextItemAllowOverlap(); - ImGui::SetCursorPos(aPos); - RenderButton("C-Up", "C-Up Outline", pads[0].button & BTN_CUP, scaledBGSize, - useGlobalOutlineMode - ? buttonOutlineMode - : CVarGetInteger(CVAR_INPUT_VIEWER("CUpOutlineMode"), BUTTON_OUTLINE_NOT_PRESSED)); - } - if (CVarGetInteger(CVAR_INPUT_VIEWER("CLeft"), 1)) { - ImGui::SetNextItemAllowOverlap(); - ImGui::SetCursorPos(aPos); - RenderButton("C-Left", "C-Left Outline", pads[0].button & BTN_CLEFT, scaledBGSize, - useGlobalOutlineMode - ? buttonOutlineMode - : CVarGetInteger(CVAR_INPUT_VIEWER("CLeftOutlineMode"), BUTTON_OUTLINE_NOT_PRESSED)); - } - if (CVarGetInteger(CVAR_INPUT_VIEWER("CRight"), 1)) { - ImGui::SetNextItemAllowOverlap(); - ImGui::SetCursorPos(aPos); - RenderButton("C-Right", "C-Right Outline", pads[0].button & BTN_CRIGHT, scaledBGSize, - useGlobalOutlineMode - ? buttonOutlineMode - : CVarGetInteger(CVAR_INPUT_VIEWER("CRightOutlineMode"), BUTTON_OUTLINE_NOT_PRESSED)); - } - if (CVarGetInteger(CVAR_INPUT_VIEWER("CDown"), 1)) { - ImGui::SetNextItemAllowOverlap(); - ImGui::SetCursorPos(aPos); - RenderButton("C-Down", "C-Down Outline", pads[0].button & BTN_CDOWN, scaledBGSize, - useGlobalOutlineMode - ? buttonOutlineMode - : CVarGetInteger(CVAR_INPUT_VIEWER("CDownOutlineMode"), BUTTON_OUTLINE_NOT_PRESSED)); - } + // C buttons + if (CVarGetInteger(CVAR_INPUT_VIEWER("CUp"), 1)) { + ImGui::SetNextItemAllowOverlap(); + ImGui::SetCursorPos(aPos); + RenderButton("C-Up", "C-Up Outline", pads[0].button & BTN_CUP, scaledBGSize, + useGlobalOutlineMode + ? buttonOutlineMode + : CVarGetInteger(CVAR_INPUT_VIEWER("CUpOutlineMode"), BUTTON_OUTLINE_NOT_PRESSED)); + } + if (CVarGetInteger(CVAR_INPUT_VIEWER("CLeft"), 1)) { + ImGui::SetNextItemAllowOverlap(); + ImGui::SetCursorPos(aPos); + RenderButton("C-Left", "C-Left Outline", pads[0].button & BTN_CLEFT, scaledBGSize, + useGlobalOutlineMode + ? buttonOutlineMode + : CVarGetInteger(CVAR_INPUT_VIEWER("CLeftOutlineMode"), BUTTON_OUTLINE_NOT_PRESSED)); + } + if (CVarGetInteger(CVAR_INPUT_VIEWER("CRight"), 1)) { + ImGui::SetNextItemAllowOverlap(); + ImGui::SetCursorPos(aPos); + RenderButton("C-Right", "C-Right Outline", pads[0].button & BTN_CRIGHT, scaledBGSize, + useGlobalOutlineMode + ? buttonOutlineMode + : CVarGetInteger(CVAR_INPUT_VIEWER("CRightOutlineMode"), BUTTON_OUTLINE_NOT_PRESSED)); + } + if (CVarGetInteger(CVAR_INPUT_VIEWER("CDown"), 1)) { + ImGui::SetNextItemAllowOverlap(); + ImGui::SetCursorPos(aPos); + RenderButton("C-Down", "C-Down Outline", pads[0].button & BTN_CDOWN, scaledBGSize, + useGlobalOutlineMode + ? buttonOutlineMode + : CVarGetInteger(CVAR_INPUT_VIEWER("CDownOutlineMode"), BUTTON_OUTLINE_NOT_PRESSED)); + } - // L/R/Z - if (CVarGetInteger(CVAR_INPUT_VIEWER("LBtn"), 1)) { - ImGui::SetNextItemAllowOverlap(); - ImGui::SetCursorPos(aPos); - RenderButton("L-Btn", "L-Btn Outline", pads[0].button & BTN_L, scaledBGSize, - useGlobalOutlineMode - ? buttonOutlineMode - : CVarGetInteger(CVAR_INPUT_VIEWER("LBtnOutlineMode"), BUTTON_OUTLINE_NOT_PRESSED)); - } - if (CVarGetInteger(CVAR_INPUT_VIEWER("RBtn"), 1)) { - ImGui::SetNextItemAllowOverlap(); - ImGui::SetCursorPos(aPos); - RenderButton("R-Btn", "R-Btn Outline", pads[0].button & BTN_R, scaledBGSize, - useGlobalOutlineMode - ? buttonOutlineMode - : CVarGetInteger(CVAR_INPUT_VIEWER("RBtnOutlineMode"), BUTTON_OUTLINE_NOT_PRESSED)); - } - if (CVarGetInteger(CVAR_INPUT_VIEWER("ZBtn"), 1)) { - ImGui::SetNextItemAllowOverlap(); - ImGui::SetCursorPos(aPos); - RenderButton("Z-Btn", "Z-Btn Outline", pads[0].button & BTN_Z, scaledBGSize, - useGlobalOutlineMode - ? buttonOutlineMode - : CVarGetInteger(CVAR_INPUT_VIEWER("ZBtnOutlineMode"), BUTTON_OUTLINE_NOT_PRESSED)); - } + // L/R/Z + if (CVarGetInteger(CVAR_INPUT_VIEWER("LBtn"), 1)) { + ImGui::SetNextItemAllowOverlap(); + ImGui::SetCursorPos(aPos); + RenderButton("L-Btn", "L-Btn Outline", pads[0].button & BTN_L, scaledBGSize, + useGlobalOutlineMode + ? buttonOutlineMode + : CVarGetInteger(CVAR_INPUT_VIEWER("LBtnOutlineMode"), BUTTON_OUTLINE_NOT_PRESSED)); + } + if (CVarGetInteger(CVAR_INPUT_VIEWER("RBtn"), 1)) { + ImGui::SetNextItemAllowOverlap(); + ImGui::SetCursorPos(aPos); + RenderButton("R-Btn", "R-Btn Outline", pads[0].button & BTN_R, scaledBGSize, + useGlobalOutlineMode + ? buttonOutlineMode + : CVarGetInteger(CVAR_INPUT_VIEWER("RBtnOutlineMode"), BUTTON_OUTLINE_NOT_PRESSED)); + } + if (CVarGetInteger(CVAR_INPUT_VIEWER("ZBtn"), 1)) { + ImGui::SetNextItemAllowOverlap(); + ImGui::SetCursorPos(aPos); + RenderButton("Z-Btn", "Z-Btn Outline", pads[0].button & BTN_Z, scaledBGSize, + useGlobalOutlineMode + ? buttonOutlineMode + : CVarGetInteger(CVAR_INPUT_VIEWER("ZBtnOutlineMode"), BUTTON_OUTLINE_NOT_PRESSED)); + } - // Start - if (CVarGetInteger(CVAR_INPUT_VIEWER("StartBtn"), 1)) { - ImGui::SetNextItemAllowOverlap(); - ImGui::SetCursorPos(aPos); - RenderButton("Start-Btn", "Start-Btn Outline", pads[0].button & BTN_START, scaledBGSize, - useGlobalOutlineMode ? buttonOutlineMode - : CVarGetInteger(CVAR_INPUT_VIEWER("StartBtnOutlineMode"), - BUTTON_OUTLINE_NOT_PRESSED)); - } + // Start + if (CVarGetInteger(CVAR_INPUT_VIEWER("StartBtn"), 1)) { + ImGui::SetNextItemAllowOverlap(); + ImGui::SetCursorPos(aPos); + RenderButton("Start-Btn", "Start-Btn Outline", pads[0].button & BTN_START, scaledBGSize, + useGlobalOutlineMode + ? buttonOutlineMode + : CVarGetInteger(CVAR_INPUT_VIEWER("StartBtnOutlineMode"), BUTTON_OUTLINE_NOT_PRESSED)); + } - // Dpad - if (CVarGetInteger(CVAR_INPUT_VIEWER("Dpad"), 0)) { - ImGui::SetNextItemAllowOverlap(); - ImGui::SetCursorPos(aPos); - RenderButton("Dpad-Left", "Dpad-Left Outline", pads[0].button & BTN_DLEFT, scaledBGSize, - useGlobalOutlineMode - ? buttonOutlineMode - : CVarGetInteger(CVAR_INPUT_VIEWER("DpadOutlineMode"), BUTTON_OUTLINE_NOT_PRESSED)); - ImGui::SetNextItemAllowOverlap(); - ImGui::SetCursorPos(aPos); - RenderButton("Dpad-Right", "Dpad-Right Outline", pads[0].button & BTN_DRIGHT, scaledBGSize, - useGlobalOutlineMode - ? buttonOutlineMode - : CVarGetInteger(CVAR_INPUT_VIEWER("DpadOutlineMode"), BUTTON_OUTLINE_NOT_PRESSED)); - ImGui::SetNextItemAllowOverlap(); - ImGui::SetCursorPos(aPos); - RenderButton("Dpad-Up", "Dpad-Up Outline", pads[0].button & BTN_DUP, scaledBGSize, - useGlobalOutlineMode - ? buttonOutlineMode - : CVarGetInteger(CVAR_INPUT_VIEWER("DpadOutlineMode"), BUTTON_OUTLINE_NOT_PRESSED)); - ImGui::SetNextItemAllowOverlap(); - ImGui::SetCursorPos(aPos); - RenderButton("Dpad-Down", "Dpad-Down Outline", pads[0].button & BTN_DDOWN, scaledBGSize, - useGlobalOutlineMode - ? buttonOutlineMode - : CVarGetInteger(CVAR_INPUT_VIEWER("DpadOutlineMode"), BUTTON_OUTLINE_NOT_PRESSED)); - } - // Lighthouse Unused - // Modifier 1 - // if (CVarGetInteger(CVAR_INPUT_VIEWER("Mod1"), 0)) { - // ImGui::SetNextItemAllowOverlap(); - // ImGui::SetCursorPos(aPos); - // RenderButton("Modifier-1", "Modifier-1 Outline", pads[0].button & BTN_CUSTOM_MODIFIER1, scaledBGSize, - // useGlobalOutlineMode - // ? buttonOutlineMode - // : CVarGetInteger(CVAR_INPUT_VIEWER("Mod1OutlineMode"), BUTTON_OUTLINE_NOT_PRESSED)); - //} - // Modifier 2 - // if (CVarGetInteger(CVAR_INPUT_VIEWER("Mod2"), 0)) { - // ImGui::SetNextItemAllowOverlap(); - // ImGui::SetCursorPos(aPos); - // RenderButton("Modifier-2", "Modifier-2 Outline", pads[0].button & BTN_CUSTOM_MODIFIER2, scaledBGSize, - // useGlobalOutlineMode - // ? buttonOutlineMode - // : CVarGetInteger(CVAR_INPUT_VIEWER("Mod2OutlineMode"), BUTTON_OUTLINE_NOT_PRESSED)); - //} - - const bool analogStickIsInDeadzone = !pads[0].stick_x && !pads[0].stick_y; - const bool rightStickIsInDeadzone = !pads[0].right_stick_x && !pads[0].right_stick_y; - - // Analog Stick - const int analogOutlineMode = - CVarGetInteger(CVAR_INPUT_VIEWER("AnalogStick.OutlineMode"), STICK_MODE_ALWAYS_SHOWN); - const int32_t maxStickDistance = CVarGetInteger(CVAR_INPUT_VIEWER("AnalogStick.Movement"), 12); - if (analogOutlineMode == STICK_MODE_ALWAYS_SHOWN || - (analogOutlineMode == STICK_MODE_HIDDEN_IN_DEADZONE && !analogStickIsInDeadzone)) { - ImGui::SetNextItemAllowOverlap(); - ImGui::SetCursorPos(aPos); - ImGui::Image(GetFast3dGui()->GetTextureByName("Analog-Stick Outline"), scaledBGSize, ImVec2(0, 0), - ImVec2(1.0f, 1.0f)); - } - const int analogStickMode = - CVarGetInteger(CVAR_INPUT_VIEWER("AnalogStick.VisibilityMode"), STICK_MODE_ALWAYS_SHOWN); - if (analogStickMode == STICK_MODE_ALWAYS_SHOWN || - (analogStickMode == STICK_MODE_HIDDEN_IN_DEADZONE && !analogStickIsInDeadzone)) { - ImGui::SetNextItemAllowOverlap(); - ImGui::SetCursorPos( - ImVec2(aPos.x + maxStickDistance * ((float)(pads[0].stick_x) / MAX_AXIS_RANGE) * scale, - aPos.y - maxStickDistance * ((float)(pads[0].stick_y) / MAX_AXIS_RANGE) * scale)); - ImGui::Image(GetFast3dGui()->GetTextureByName("Analog-Stick"), scaledBGSize, ImVec2(0, 0), - ImVec2(1.0f, 1.0f)); - } + // Dpad + if (CVarGetInteger(CVAR_INPUT_VIEWER("Dpad"), 0)) { + ImGui::SetNextItemAllowOverlap(); + ImGui::SetCursorPos(aPos); + RenderButton("Dpad-Left", "Dpad-Left Outline", pads[0].button & BTN_DLEFT, scaledBGSize, + useGlobalOutlineMode + ? buttonOutlineMode + : CVarGetInteger(CVAR_INPUT_VIEWER("DpadOutlineMode"), BUTTON_OUTLINE_NOT_PRESSED)); + ImGui::SetNextItemAllowOverlap(); + ImGui::SetCursorPos(aPos); + RenderButton("Dpad-Right", "Dpad-Right Outline", pads[0].button & BTN_DRIGHT, scaledBGSize, + useGlobalOutlineMode + ? buttonOutlineMode + : CVarGetInteger(CVAR_INPUT_VIEWER("DpadOutlineMode"), BUTTON_OUTLINE_NOT_PRESSED)); + ImGui::SetNextItemAllowOverlap(); + ImGui::SetCursorPos(aPos); + RenderButton("Dpad-Up", "Dpad-Up Outline", pads[0].button & BTN_DUP, scaledBGSize, + useGlobalOutlineMode + ? buttonOutlineMode + : CVarGetInteger(CVAR_INPUT_VIEWER("DpadOutlineMode"), BUTTON_OUTLINE_NOT_PRESSED)); + ImGui::SetNextItemAllowOverlap(); + ImGui::SetCursorPos(aPos); + RenderButton("Dpad-Down", "Dpad-Down Outline", pads[0].button & BTN_DDOWN, scaledBGSize, + useGlobalOutlineMode + ? buttonOutlineMode + : CVarGetInteger(CVAR_INPUT_VIEWER("DpadOutlineMode"), BUTTON_OUTLINE_NOT_PRESSED)); + } + // Lighthouse Unused + // Modifier 1 + // if (CVarGetInteger(CVAR_INPUT_VIEWER("Mod1"), 0)) { + // ImGui::SetNextItemAllowOverlap(); + // ImGui::SetCursorPos(aPos); + // RenderButton("Modifier-1", "Modifier-1 Outline", pads[0].button & BTN_CUSTOM_MODIFIER1, scaledBGSize, + // useGlobalOutlineMode + // ? buttonOutlineMode + // : CVarGetInteger(CVAR_INPUT_VIEWER("Mod1OutlineMode"), BUTTON_OUTLINE_NOT_PRESSED)); + //} + // Modifier 2 + // if (CVarGetInteger(CVAR_INPUT_VIEWER("Mod2"), 0)) { + // ImGui::SetNextItemAllowOverlap(); + // ImGui::SetCursorPos(aPos); + // RenderButton("Modifier-2", "Modifier-2 Outline", pads[0].button & BTN_CUSTOM_MODIFIER2, scaledBGSize, + // useGlobalOutlineMode + // ? buttonOutlineMode + // : CVarGetInteger(CVAR_INPUT_VIEWER("Mod2OutlineMode"), BUTTON_OUTLINE_NOT_PRESSED)); + //} + + const bool analogStickIsInDeadzone = !pads[0].stick_x && !pads[0].stick_y; + const bool rightStickIsInDeadzone = !pads[0].right_stick_x && !pads[0].right_stick_y; + + // Analog Stick + const int analogOutlineMode = + CVarGetInteger(CVAR_INPUT_VIEWER("AnalogStick.OutlineMode"), STICK_MODE_ALWAYS_SHOWN); + const int32_t maxStickDistance = CVarGetInteger(CVAR_INPUT_VIEWER("AnalogStick.Movement"), 12); + if (analogOutlineMode == STICK_MODE_ALWAYS_SHOWN || + (analogOutlineMode == STICK_MODE_HIDDEN_IN_DEADZONE && !analogStickIsInDeadzone)) { + ImGui::SetNextItemAllowOverlap(); + ImGui::SetCursorPos(aPos); + ImGui::Image(GetFast3dGui()->GetTextureByName("Analog-Stick Outline"), scaledBGSize, ImVec2(0, 0), + ImVec2(1.0f, 1.0f)); + } + const int analogStickMode = + CVarGetInteger(CVAR_INPUT_VIEWER("AnalogStick.VisibilityMode"), STICK_MODE_ALWAYS_SHOWN); + if (analogStickMode == STICK_MODE_ALWAYS_SHOWN || + (analogStickMode == STICK_MODE_HIDDEN_IN_DEADZONE && !analogStickIsInDeadzone)) { + ImGui::SetNextItemAllowOverlap(); + ImGui::SetCursorPos( + ImVec2(aPos.x + maxStickDistance * ((float)(pads[0].stick_x) / MAX_AXIS_RANGE) * scale, + aPos.y - maxStickDistance * ((float)(pads[0].stick_y) / MAX_AXIS_RANGE) * scale)); + ImGui::Image(GetFast3dGui()->GetTextureByName("Analog-Stick"), scaledBGSize, ImVec2(0, 0), + ImVec2(1.0f, 1.0f)); + } - // Right Stick - const int32_t maxRightStickDistance = CVarGetInteger(CVAR_INPUT_VIEWER("RightStick.Movement"), 7); - const int rightOutlineMode = - CVarGetInteger(CVAR_INPUT_VIEWER("RightStick.OutlineMode"), STICK_MODE_ALWAYS_HIDDEN); - if (rightOutlineMode == STICK_MODE_ALWAYS_SHOWN || - (rightOutlineMode == STICK_MODE_HIDDEN_IN_DEADZONE && !rightStickIsInDeadzone)) { - ImGui::SetNextItemAllowOverlap(); - ImGui::SetCursorPos(aPos); - ImGui::Image(GetFast3dGui()->GetTextureByName("Right-Stick Outline"), scaledBGSize, ImVec2(0, 0), - ImVec2(1.0f, 1.0f)); - } - const int rightStickMode = - CVarGetInteger(CVAR_INPUT_VIEWER("RightStick.VisibilityMode"), STICK_MODE_ALWAYS_HIDDEN); - if (rightStickMode == STICK_MODE_ALWAYS_SHOWN || - (rightStickMode == STICK_MODE_HIDDEN_IN_DEADZONE && !rightStickIsInDeadzone)) { - ImGui::SetNextItemAllowOverlap(); - ImGui::SetCursorPos( - ImVec2(aPos.x + maxRightStickDistance * ((float)(pads[0].right_stick_x) / MAX_AXIS_RANGE) * scale, - aPos.y - maxRightStickDistance * ((float)(pads[0].right_stick_y) / MAX_AXIS_RANGE) * scale)); - ImGui::Image(GetFast3dGui()->GetTextureByName("Right-Stick"), scaledBGSize, ImVec2(0, 0), - ImVec2(1.0f, 1.0f)); - } + // Right Stick + const int32_t maxRightStickDistance = CVarGetInteger(CVAR_INPUT_VIEWER("RightStick.Movement"), 7); + const int rightOutlineMode = + CVarGetInteger(CVAR_INPUT_VIEWER("RightStick.OutlineMode"), STICK_MODE_ALWAYS_HIDDEN); + if (rightOutlineMode == STICK_MODE_ALWAYS_SHOWN || + (rightOutlineMode == STICK_MODE_HIDDEN_IN_DEADZONE && !rightStickIsInDeadzone)) { + ImGui::SetNextItemAllowOverlap(); + ImGui::SetCursorPos(aPos); + ImGui::Image(GetFast3dGui()->GetTextureByName("Right-Stick Outline"), scaledBGSize, ImVec2(0, 0), + ImVec2(1.0f, 1.0f)); + } + const int rightStickMode = + CVarGetInteger(CVAR_INPUT_VIEWER("RightStick.VisibilityMode"), STICK_MODE_ALWAYS_HIDDEN); + if (rightStickMode == STICK_MODE_ALWAYS_SHOWN || + (rightStickMode == STICK_MODE_HIDDEN_IN_DEADZONE && !rightStickIsInDeadzone)) { + ImGui::SetNextItemAllowOverlap(); + ImGui::SetCursorPos( + ImVec2(aPos.x + maxRightStickDistance * ((float)(pads[0].right_stick_x) / MAX_AXIS_RANGE) * scale, + aPos.y - maxRightStickDistance * ((float)(pads[0].right_stick_y) / MAX_AXIS_RANGE) * scale)); + ImGui::Image(GetFast3dGui()->GetTextureByName("Right-Stick"), scaledBGSize, ImVec2(0, 0), + ImVec2(1.0f, 1.0f)); + } - // Analog stick angle text - if (showAnalogAngles) { - ImGui::SetCursorPos( - ImVec2(aPos.x + 10 + CVarGetInteger(CVAR_INPUT_VIEWER("AnalogAngles.Offset"), 0) * scale, - scaledBGSize.y + aPos.y + 10)); - // Scale font with input viewer scale - float oldFontScale = ImGui::GetFont()->Scale; - ImGui::GetFont()->Scale *= scale * CVarGetFloat(CVAR_INPUT_VIEWER("AnalogAngles.Scale"), 1.0f); - ImGui::PushFont(ImGui::GetFont()); - - // Calculate polar R coordinate from X and Y angles, squared to avoid sqrt - const int32_t rSquared = pads[0].stick_x * pads[0].stick_x + pads[0].stick_y * pads[0].stick_y; - - // ESS range - const int range1Min = CVarGetInteger(CVAR_INPUT_VIEWER("AnalogAngles.Range1.Min"), 8); - const int range1Max = CVarGetInteger(CVAR_INPUT_VIEWER("AnalogAngles.Range1.Max"), 27); - // Walking speed range - const int range2Min = CVarGetInteger(CVAR_INPUT_VIEWER("AnalogAngles.Range2.Min"), 27); - const int range2Max = CVarGetInteger(CVAR_INPUT_VIEWER("AnalogAngles.Range2.Max"), 62); - - // Push color based on angle ranges - if (CVarGetInteger(CVAR_INPUT_VIEWER("AnalogAngles.Range1.Enabled"), 0) && - (rSquared >= (range1Min * range1Min)) && (rSquared < (range1Max * range1Max))) { - ImGui::PushStyleColor( - ImGuiCol_Text, VecFromRGBA8(CVarGetColor(CVAR_INPUT_VIEWER("AnalogAngles.Range1.Color.Value"), - range1ColorDefault))); - } else if (CVarGetInteger(CVAR_INPUT_VIEWER("AnalogAngles.Range2.Enabled"), 0) && - (rSquared >= (range2Min * range2Min)) && (rSquared < (range2Max * range2Max))) { - ImGui::PushStyleColor( - ImGuiCol_Text, VecFromRGBA8(CVarGetColor(CVAR_INPUT_VIEWER("AnalogAngles.Range2.Color.Value"), - range2ColorDefault))); - } else { - ImGui::PushStyleColor(ImGuiCol_Text, - VecFromRGBA8(CVarGetColor(CVAR_INPUT_VIEWER("AnalogAngles.TextColor.Value"), - textColorDefault))); - } - - // Render text - ImGui::Text("X: %-3d Y: %-3d", pads[0].stick_x, pads[0].stick_y); - // Restore original color - ImGui::PopStyleColor(); - // Restore original font scale - ImGui::GetFont()->Scale = oldFontScale; - ImGui::PopFont(); + // Analog stick angle text + if (showAnalogAngles) { + ImGui::SetCursorPos( + ImVec2(aPos.x + 10 + CVarGetInteger(CVAR_INPUT_VIEWER("AnalogAngles.Offset"), 0) * scale, + scaledBGSize.y + aPos.y + 10)); + // Scale font with input viewer scale + float oldFontScale = ImGui::GetFont()->Scale; + ImGui::GetFont()->Scale *= scale * CVarGetFloat(CVAR_INPUT_VIEWER("AnalogAngles.Scale"), 1.0f); + ImGui::PushFont(ImGui::GetFont()); + + // Calculate polar R coordinate from X and Y angles, squared to avoid sqrt + const int32_t rSquared = pads[0].stick_x * pads[0].stick_x + pads[0].stick_y * pads[0].stick_y; + + // ESS range + const int range1Min = CVarGetInteger(CVAR_INPUT_VIEWER("AnalogAngles.Range1.Min"), 8); + const int range1Max = CVarGetInteger(CVAR_INPUT_VIEWER("AnalogAngles.Range1.Max"), 27); + // Walking speed range + const int range2Min = CVarGetInteger(CVAR_INPUT_VIEWER("AnalogAngles.Range2.Min"), 27); + const int range2Max = CVarGetInteger(CVAR_INPUT_VIEWER("AnalogAngles.Range2.Max"), 62); + + // Push color based on angle ranges + if (CVarGetInteger(CVAR_INPUT_VIEWER("AnalogAngles.Range1.Enabled"), 0) && + (rSquared >= (range1Min * range1Min)) && (rSquared < (range1Max * range1Max))) { + ImGui::PushStyleColor(ImGuiCol_Text, + VecFromRGBA8(CVarGetColor(CVAR_INPUT_VIEWER("AnalogAngles.Range1.Color.Value"), + range1ColorDefault))); + } else if (CVarGetInteger(CVAR_INPUT_VIEWER("AnalogAngles.Range2.Enabled"), 0) && + (rSquared >= (range2Min * range2Min)) && (rSquared < (range2Max * range2Max))) { + ImGui::PushStyleColor(ImGuiCol_Text, + VecFromRGBA8(CVarGetColor(CVAR_INPUT_VIEWER("AnalogAngles.Range2.Color.Value"), + range2ColorDefault))); + } else { + ImGui::PushStyleColor( + ImGuiCol_Text, + VecFromRGBA8(CVarGetColor(CVAR_INPUT_VIEWER("AnalogAngles.TextColor.Value"), textColorDefault))); } - ImGui::End(); + // Render text + ImGui::Text("X: %-3d Y: %-3d", pads[0].stick_x, pads[0].stick_y); + // Restore original color + ImGui::PopStyleColor(); + // Restore original font scale + ImGui::GetFont()->Scale = oldFontScale; + ImGui::PopFont(); } - ImGui::PopStyleVar(); - ImGui::PopStyleColor(); + ImGui::End(); } + + ImGui::PopStyleVar(); + ImGui::PopStyleColor(); } InputViewerSettingsWindow::~InputViewerSettingsWindow() { diff --git a/src/port/UI/LighthouseGui.cpp b/src/port/UI/LighthouseGui.cpp index 217ba35de..7885ff7af 100644 --- a/src/port/UI/LighthouseGui.cpp +++ b/src/port/UI/LighthouseGui.cpp @@ -198,10 +198,10 @@ void SetupGuiElements() { "gWindows.CheckTrackerSettings", "Check Tracker Settings"); gui->AddGuiWindow(mRandoCheckTrackerSettingsWindow); - mInputViewer = std::make_shared("gWindows.InputViewer", "Input Viewer"); + mInputViewer = std::make_shared(CVAR_WINDOW("InputViewer"), "Input Viewer"); gui->AddGuiWindow(mInputViewer); - mInputViewerSettings = std::make_shared("gWindows.InputViewerSettings", + mInputViewerSettings = std::make_shared(CVAR_WINDOW("InputViewerSettings"), "Input Viewer Settings", ImVec2(500, 525)); gui->AddGuiWindow(mInputViewerSettings); diff --git a/src/port/UI/LighthouseMenuEnhancements.cpp b/src/port/UI/LighthouseMenuEnhancements.cpp index 2f4cbb1d1..ee18db3a6 100644 --- a/src/port/UI/LighthouseMenuEnhancements.cpp +++ b/src/port/UI/LighthouseMenuEnhancements.cpp @@ -680,7 +680,7 @@ void LighthouseMenu::AddMenuEnhancements() { "Disables Mumbo untransforming you when going too far and skips his warning dialog.")); path = { "Enhancements", "Trackers", SECTION_COLUMN_1 }; - AddSidebarEntry("Enhancements", path.sidebarName, 1); + AddSidebarEntry("Enhancements", path.sidebarName, 2); path.column = SECTION_COLUMN_1; AddWidget(path, "Gameplay Timer", WIDGET_SEPARATOR_TEXT); diff --git a/src/port/UI/LighthouseMenuSettings.cpp b/src/port/UI/LighthouseMenuSettings.cpp index 9f8d09790..b463c570a 100644 --- a/src/port/UI/LighthouseMenuSettings.cpp +++ b/src/port/UI/LighthouseMenuSettings.cpp @@ -510,7 +510,8 @@ void LighthouseMenu::AddMenuSettings() { // Input Viewer path.sidebarName = "Input Viewer"; - AddSidebarEntry("Settings", path.sidebarName, 3); + path.column = SECTION_COLUMN_1; + AddSidebarEntry("Settings", path.sidebarName, 2); AddWidget(path, "Input Viewer", WIDGET_SEPARATOR_TEXT); AddWidget(path, "Toggle Input Viewer", WIDGET_WINDOW_BUTTON) .CVar(CVAR_WINDOW("InputViewer")) From 7f1de84003d63123208bb295789a294436f47602 Mon Sep 17 00:00:00 2001 From: Caladius Date: Tue, 4 Aug 2026 16:30:56 -0400 Subject: [PATCH 109/131] [RANDO] Spoiler Generation Option (#370) * Save and Load of Spoiler Logs * Color change for success notification * clangified * Fix if statement to check for string.empty(). * case change * Fix log refresh and seedID * Add Refresh Button * Add Tooltip for refresh button, gross --- src/port/Rando/LighthouseMenuRando.cpp | 33 ++++++ src/port/Rando/Logic/GenerateSaveData.cpp | 29 +++--- src/port/Rando/Logic/Logic.h | 4 + src/port/Rando/MiscBehavior/OnFileLoad.cpp | 25 ++++- src/port/Rando/Rando.cpp | 4 +- src/port/Rando/Spoiler/File.cpp | 72 +++++++++++++ src/port/Rando/Spoiler/Generate.cpp | 111 +++++++++++++++++++++ src/port/Rando/Spoiler/RefreshOptions.cpp | 40 ++++++++ src/port/Rando/Spoiler/Spoiler.h | 26 +++++ 9 files changed, 326 insertions(+), 18 deletions(-) create mode 100644 src/port/Rando/Spoiler/File.cpp create mode 100644 src/port/Rando/Spoiler/Generate.cpp create mode 100644 src/port/Rando/Spoiler/RefreshOptions.cpp create mode 100644 src/port/Rando/Spoiler/Spoiler.h diff --git a/src/port/Rando/LighthouseMenuRando.cpp b/src/port/Rando/LighthouseMenuRando.cpp index 871509332..fefdda2af 100644 --- a/src/port/Rando/LighthouseMenuRando.cpp +++ b/src/port/Rando/LighthouseMenuRando.cpp @@ -7,6 +7,7 @@ #include "port/Rando/CustomObject/CustomObject.h" #include "port/Rando/Logic/Logic.h" +#include "port/Rando/Spoiler/Spoiler.h" #include @@ -59,6 +60,38 @@ void LighthouseMenu::AddMenuRando() { } UIWidgets::PopStyleCombobox(); }); + AddWidget(path, "Load Existing Spoiler Log", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_RANDOMIZER_SETTING("UseExistingLog")) + .RaceDisable(false) + .Options(CheckboxOptions().Tooltip("Uses a Spoiler Log in the randomizer folder.")); + AddWidget(path, "Available Spoiler Logs", WIDGET_CUSTOM).CustomFunction([](WidgetInfo& info) { + std::vector spoilerLogPtrs; + spoilerLogPtrs.reserve(Rando::Spoiler::spoilerLogs.size()); + for (const auto& log : Rando::Spoiler::spoilerLogs) { + spoilerLogPtrs.push_back(log.c_str()); + } + + ImGui::BeginDisabled(!CVarGetInteger(CVAR_RANDOMIZER_SETTING("UseExistingLog"), 0)); + if (UIWidgets::CVarCombobox("Seed", CVAR_RANDOMIZER_SETTING("SpoilerFileIndex"), spoilerLogPtrs, + { .labelPosition = UIWidgets::LabelPositions::None, .color = WIDGET_COLOR })) { + if (CVarGetInteger(CVAR_RANDOMIZER_SETTING("SpoilerFileIndex"), 0) == 0) { + CVarSetString(CVAR_RANDOMIZER_SETTING("SpoilerFile"), ""); + } else { + std::string spoilerName = + Rando::Spoiler::spoilerLogs[CVarGetInteger(CVAR_RANDOMIZER_SETTING("SpoilerFileIndex"), 0)]; + CVarSetString("gRandoSettings.SpoilerFile", spoilerName.c_str()); + } + } + ImGui::SameLine(); + if (UIWidgets::Button(ICON_FA_REFRESH, UIWidgets::ButtonOptions() + .Color(WIDGET_COLOR) + .Size(ImVec2(32.0f, 32.0f)) + .Tooltip("Refreshes the list of Spoiler Logs."))) { + Rando::Spoiler::RefreshSpoilerLogs(); + } + ImGui::EndDisabled(); + }); + AddWidget(path, "Send Collection Notifications", WIDGET_CVAR_CHECKBOX) .CVar(CVAR_RANDOMIZER_SETTING("RandoNotifications")) .Options(CheckboxOptions().Tooltip("Sends notifications when you collect a Rando Item.")); diff --git a/src/port/Rando/Logic/GenerateSaveData.cpp b/src/port/Rando/Logic/GenerateSaveData.cpp index bdbc12e6e..cf978ad22 100644 --- a/src/port/Rando/Logic/GenerateSaveData.cpp +++ b/src/port/Rando/Logic/GenerateSaveData.cpp @@ -170,25 +170,30 @@ void Rando::Logic::GrantStartingLoadout() { item_setMaxCount(item); } } +} - // Set progress flag for tutorial dialogue, skipping them +void Rando::Logic::GrantFileProgressFlags() { for (auto& fileprog : progressLoadout) { fileProgressFlag_set(fileprog, 1); } +} - if (CVarGetInteger(CVAR_ENHANCEMENT("Gameplay.SkipSMTutorial"), 0)) { - for (auto& smCheckId : smRandoCheckIdList) { - RandoSaveCheck randoSaveCheck = RANDO_SAVE_CHECKS[smCheckId]; +void Rando::Logic::GrantSpiralMountainChecks() { + if (!CVarGetInteger(CVAR_ENHANCEMENT("Gameplay.SkipSMTutorial"), 0)) { + return; + } - if (!randoSaveCheck.isShuffled) { - continue; - } + for (auto& smCheckId : smRandoCheckIdList) { + RandoSaveCheck randoSaveCheck = RANDO_SAVE_CHECKS[smCheckId]; + + if (!randoSaveCheck.isShuffled) { + continue; + } - CustomObject::CheckObtainedEX(smCheckId, true); - if (randoSaveCheck.randoItemId == RI_MOLEHILL) { - ability_setLearned((ability_e)randoSaveCheck.randoCollectionId, true); - ability_setHasUsed((ability_e)randoSaveCheck.randoCollectionId); - } + CustomObject::CheckObtainedEX(smCheckId, true); + if (randoSaveCheck.randoItemId == RI_MOLEHILL) { + ability_setLearned((ability_e)randoSaveCheck.randoCollectionId, true); + ability_setHasUsed((ability_e)randoSaveCheck.randoCollectionId); } } } \ No newline at end of file diff --git a/src/port/Rando/Logic/Logic.h b/src/port/Rando/Logic/Logic.h index 609fb5ce6..cbaa9d05b 100644 --- a/src/port/Rando/Logic/Logic.h +++ b/src/port/Rando/Logic/Logic.h @@ -19,6 +19,8 @@ extern int32_t randoFinalSeed; extern std::map> abilityLoadoutMap; extern std::map> itemLoadoutMap; +extern std::vector progressLoadout; +extern std::vector smRandoCheckIdList; extern Rando::StaticData::RandoLogicData reachableRegions[RR_MAX]; extern Rando::StaticData::RandoLogicData reachableEvents[RA_MAX]; @@ -54,6 +56,8 @@ void GeneratePoolFromSaveData(SaveData* saveData); void InitializeSaveData(SaveData* saveData); void GenerateSaveData(SaveData* saveData); void GrantStartingLoadout(); +void GrantFileProgressFlags(); +void GrantSpiralMountainChecks(); void RefreshReachableRegions(); diff --git a/src/port/Rando/MiscBehavior/OnFileLoad.cpp b/src/port/Rando/MiscBehavior/OnFileLoad.cpp index f10df31fd..f948c808f 100644 --- a/src/port/Rando/MiscBehavior/OnFileLoad.cpp +++ b/src/port/Rando/MiscBehavior/OnFileLoad.cpp @@ -1,12 +1,13 @@ #include "MiscBehavior.h" #include +#include "ship/Context.h" #include "port/Enhancements/Events/Hooks/Events.h" #include "port/UI/Notification.h" #include "port/Save/Types.h" #include "port/Rando/Logic/Logic.h" -// #include "port/Rando/Spoiler/Spoiler.h" +#include "port/Rando/Spoiler/Spoiler.h" void Rando::MiscBehavior::OnFileLoad() { REGISTER_LISTENER(OnGameLoad, EVENT_PRIORITY_NORMAL, [](IEvent* event) { @@ -25,10 +26,26 @@ void Rando::MiscBehavior::OnFileLoad() { if (saveData->shipSaveData.fileType == FILE_TYPE_SAVE_RANDO) { Rando::Logic::GeneratePoolFromSaveData(saveData); } - } else if (CVarGetInteger("gRandoSettings.Enable", 0)) { + return; + } + + if (CVarGetInteger(CVAR_RANDOMIZER_SETTING("Enable"), 0)) { Rando::Logic::InitializeSaveData(saveData); - Rando::Logic::GenerateShufflePool(saveData); - Rando::Logic::GrantStartingLoadout(); + std::string spoilerPath = CVarGetString(CVAR_RANDOMIZER_SETTING("SpoilerFile"), ""); + if (CVarGetInteger(CVAR_RANDOMIZER_SETTING("UseExistingLog"), 0) && !spoilerPath.empty()) { + // std::string spoilerPath = CVarGetString(CVAR_RANDOMIZER_SETTING("SpoilerFile"), ""); + Rando::Spoiler::GenerateFromSpoiler(Rando::Spoiler::LoadFromFile(spoilerPath.c_str())); + } else { + Rando::Logic::GenerateShufflePool(saveData); + Rando::Logic::GrantStartingLoadout(); + Rando::Logic::GrantFileProgressFlags(); + Rando::Logic::GrantSpiralMountainChecks(); + std::string spoilerName = std::to_string(saveData->shipSaveData.randoSaveData.seedId).c_str(); + std::erase(spoilerName, '-'); + spoilerName += ".json"; + Rando::Spoiler::SaveToFile(spoilerName, Rando::Spoiler::GenerateFromPoolGeneration()); + } + saveData->shipSaveData.fileType = FILE_TYPE_SAVE_RANDO; saveData->shipSaveData.fileCreatedAt = GetUnixTimestamp(); } diff --git a/src/port/Rando/Rando.cpp b/src/port/Rando/Rando.cpp index cee6eb6b4..6dd76de7a 100644 --- a/src/port/Rando/Rando.cpp +++ b/src/port/Rando/Rando.cpp @@ -5,7 +5,7 @@ #include "MiscBehavior/MiscBehavior.h" #include "port/Rando/CheckTracker/CheckTracker.h" // #include "port/Rando/EntranceTracker/EntranceTracker.h" -// #include "port/Rando/Spoiler/Spoiler.h" +#include "port/Rando/Spoiler/Spoiler.h" #include "port/ShipInit.hpp" #include "spdlog/spdlog.h" @@ -23,7 +23,7 @@ void Rando::Init() { fs::create_directory(randomizerFolderPath); } - // Rando::Spoiler::RefreshSpoilerLogs(); + Rando::Spoiler::RefreshSpoilerLogs(); Rando::MiscBehavior::Init(); // Rando::EntranceTracker::Init(); // Ship::Context::GetInstance()->GetFileDropMgr()->RegisterDropHandler(Rando::Spoiler::HandleFileDropped); diff --git a/src/port/Rando/Spoiler/File.cpp b/src/port/Rando/Spoiler/File.cpp new file mode 100644 index 000000000..67bf5f119 --- /dev/null +++ b/src/port/Rando/Spoiler/File.cpp @@ -0,0 +1,72 @@ +#include "Spoiler.h" +#include "port/UI/Notification.h" +#include "ship/Context.h" +#include + +extern std::string CollapsedJSONArray(const nlohmann::ordered_json& jsonFile); + +namespace fs = std::filesystem; + +namespace Rando { + +namespace Spoiler { + +void SaveToFile(const std::string& fileName, nlohmann::ordered_json spoiler) { + std::string testDirectory = Ship::Context::GetPathRelativeToAppDirectory("randomizer/", "bk64"); + std::string filePath = Ship::Context::GetPathRelativeToAppDirectory("randomizer/" + fileName, "bk64"); + + if (!fs::exists(testDirectory)) { + fs::create_directories(testDirectory); + } + + std::ofstream fileStream(filePath); + if (!fileStream.is_open()) { + Notification::Emit( + { .message = "Error: Failed to open spoiler file.", .messageColor = ImVec4(0.85f, 0.3f, 0, 1) }); + return; + } + + std::string collapsedString = CollapsedJSONArray(spoiler); + if (fileStream.is_open()) { + fileStream << collapsedString; + fileStream.close(); + } else { + Notification::Emit( + { .message = "Error: Failed to open save file.", .messageColor = ImVec4(0.85f, 0.3f, 0, 1) }); + } + + fileStream << spoiler.dump(4); + RefreshSpoilerLogs(); +} + +nlohmann::json LoadFromFile(const std::string& fileName) { + nlohmann::json spoiler; + std::string spoilerFilePath = Ship::Context::GetPathRelativeToAppDirectory("randomizer/" + fileName, "bk64"); + std::ifstream fileStream(spoilerFilePath); + + if (!fs::exists(spoilerFilePath)) { + return spoiler; + } + + if (!fileStream.is_open()) { + Notification::Emit( + { .message = "Error: Failed to open spoiler file.", .messageColor = ImVec4(0.85f, 0.3f, 0, 1) }); + return spoiler; + } + + try { + fileStream >> spoiler; + } catch (nlohmann::json::exception& e) { + throw std::runtime_error("Failed to parse spoiler file: " + std::string(e.what())); + } + + if (!spoiler.contains("type") || spoiler["type"] != "LIGHTHOUSE_RANDO_SPOILER") { + throw std::runtime_error("Spoiler file is not a valid spoiler file"); + } + + return spoiler; +} + +} // namespace Spoiler + +} // namespace Rando diff --git a/src/port/Rando/Spoiler/Generate.cpp b/src/port/Rando/Spoiler/Generate.cpp new file mode 100644 index 000000000..c98ce18a8 --- /dev/null +++ b/src/port/Rando/Spoiler/Generate.cpp @@ -0,0 +1,111 @@ +#include "Spoiler.h" +#include +#include "port/Rando/Logic/Logic.h" +#include "port/UI/Notification.h" + +extern void RandoSaveCheck_to_json(nlohmann::json& j, const RandoSaveCheck& randoSaveCheck); +extern RandoSaveCheck RandoSaveCheck_from_json(const nlohmann::json& j, RandoSaveCheck& randoSaveCheck); + +namespace Rando { + +namespace Spoiler { +nlohmann::ordered_json GenerateFromPoolGeneration() { + nlohmann::ordered_json orderedSpoiler = nlohmann::ordered_json::object(); + + orderedSpoiler["type"] = "LIGHTHOUSE_RANDO_SPOILER"; + orderedSpoiler["seed"] = randoFinalSeed; // TODO: Add once Manual Seed Input is finished. + + orderedSpoiler["options"] = nlohmann::json::object(); + for (auto& optionEntry : RANDO_SAVE_OPTIONS) { + orderedSpoiler["options"][optionEntry.name] = optionEntry.optionValue; + } + + orderedSpoiler["checks"] = nlohmann::json::object(); + + for (auto& checkEntry : RANDO_SAVE_CHECKS) { + nlohmann::json check = nlohmann::json::object(); + RandoSaveCheck_to_json(check, checkEntry); + + if (checkEntry.randoCheckId == RC_UNKNOWN) { + checkEntry.name = "RC_UNKNOWN"; + } + + orderedSpoiler["checks"][checkEntry.name] = check; + } + + orderedSpoiler["loadout"] = nlohmann::json::object(); + + orderedSpoiler["loadout"]["abilities"] = nlohmann::json::array(); + orderedSpoiler["loadout"]["abilities"].push_back(ABILITY_A_HOLD_A_JUMP_HIGHER); + orderedSpoiler["loadout"]["abilities"].push_back(ABILITY_13_1ST_NOTEDOOR); + for (auto& [abilityId, abilityInfo] : abilityLoadoutMap) { + if (CVarGetInteger(abilityInfo.second, 0)) { + orderedSpoiler["loadout"]["abilities"].push_back(abilityId); + } + } + + orderedSpoiler["loadout"]["items"] = nlohmann::json::array(); + for (auto& [item, itemInfo] : itemLoadoutMap) { + if (CVarGetInteger(itemInfo.second, 0)) { + orderedSpoiler["loadout"]["items"].push_back(item); + } + } + + return orderedSpoiler; +} + +void GenerateFromSpoiler(nlohmann::json spoiler) { + Rando::Logic::shuffledPool.clear(); + + if (!spoiler.contains("type") || spoiler["type"] != "LIGHTHOUSE_RANDO_SPOILER") { + Notification::Emit({ .message = "Error: Invalid Spoiler Log.", .messageColor = ImVec4(0.85f, 0.3f, 0, 1) }); + return; + } + + gameFile_saveData[selectedFileNum].shipSaveData.randoSaveData.seedId = spoiler["seed"]; + + if (spoiler.contains("checks") && !spoiler["checks"].empty()) { + for (auto& data : spoiler["checks"].items()) { + RandoSaveCheck checkEntry = RandoSaveCheck_from_json(data.value(), checkEntry); + checkEntry.name = Rando::StaticData::Checks[checkEntry.randoCheckId].name; + RANDO_SAVE_CHECKS[checkEntry.randoCheckId] = checkEntry; + + Rando::Logic::shuffledPool.push_back(checkEntry); + } + } + + if (spoiler.contains("options") && !spoiler["options"].empty()) { + for (auto& data : spoiler["options"].items()) { + for (auto& [optionId, staticOption] : Rando::StaticData::Options) { + if (staticOption.name == data.key()) { + RANDO_SAVE_OPTIONS[optionId].optionValue = data.value().get(); + break; + } + } + } + } + + if (spoiler.contains("loadout") && !spoiler["loadout"].empty()) { + if (spoiler["loadout"].contains("abilities") && !spoiler["loadout"]["abilities"].empty()) { + for (auto& data : spoiler["loadout"]["abilities"].items()) { + ability_setLearned(data.value(), true); + ability_setHasUsed(data.value()); + } + } + + if (spoiler["loadout"].contains("items") && !spoiler["loadout"]["items"].empty()) { + for (auto& data : spoiler["loadout"]["items"].items()) { + item_setMaxCount(data.value()); + } + } + } + + Rando::Logic::GrantFileProgressFlags(); + Rando::Logic::GrantSpiralMountainChecks(); + + Notification::Emit({ .message = "Loaded from Spoiler Log.", .messageColor = ImVec4(0, 0.85f, 0, 1) }); +} + +} // namespace Spoiler + +} // namespace Rando diff --git a/src/port/Rando/Spoiler/RefreshOptions.cpp b/src/port/Rando/Spoiler/RefreshOptions.cpp new file mode 100644 index 000000000..6568f9ed0 --- /dev/null +++ b/src/port/Rando/Spoiler/RefreshOptions.cpp @@ -0,0 +1,40 @@ +#include "Spoiler.h" +#include +#include "ship/Context.h" +#include + +#include + +std::vector Rando::Spoiler::spoilerLogs; +const std::filesystem::path randomizerFolderPath(Ship::Context::GetPathRelativeToAppDirectory("randomizer", "bk64")); + +void Rando::Spoiler::RefreshSpoilerLogs() { + Rando::Spoiler::spoilerLogs.clear(); + + Rando::Spoiler::spoilerLogs.push_back("Generate New Seed"); + s32 spoilerFileIndex = -1; + + if (!std::filesystem::exists(randomizerFolderPath)) { + std::filesystem::create_directory(randomizerFolderPath); + } + + for (const auto& entry : std::filesystem::directory_iterator(randomizerFolderPath)) { + if (entry.is_regular_file()) { + std::string fileName = entry.path().filename().string(); + + Rando::Spoiler::spoilerLogs.push_back(fileName); + + // Check if the current file is the one set in the cvar + if (fileName == CVarGetString("gRandoSettings.SpoilerFile", "")) { + spoilerFileIndex = Rando::Spoiler::spoilerLogs.size() - 1; + } + } + } + + if (spoilerFileIndex == -1) { + CVarSetInteger("gRandoSettings.SpoilerFileIndex", 0); + CVarSetString("gRandoSettings.SpoilerFile", ""); + } else { + CVarSetInteger("gRandoSettings.SpoilerFileIndex", spoilerFileIndex); + } +} \ No newline at end of file diff --git a/src/port/Rando/Spoiler/Spoiler.h b/src/port/Rando/Spoiler/Spoiler.h new file mode 100644 index 000000000..272e70f6a --- /dev/null +++ b/src/port/Rando/Spoiler/Spoiler.h @@ -0,0 +1,26 @@ +#ifndef RANDO_SPOILER_H +#define RANDO_SPOILER_H + +#include +#include +#include "port/Rando/Logic/Logic.h" +#include + +namespace Rando { + +namespace Spoiler { +extern std::vector spoilerLogs; + +nlohmann::ordered_json GenerateFromPoolGeneration(); + +void GenerateFromSpoiler(nlohmann::json spoiler); +void SaveToFile(const std::string& fileName, nlohmann::ordered_json spoiler); +nlohmann::json LoadFromFile(const std::string& filePath); + +void RefreshSpoilerLogs(); + +} // namespace Spoiler + +} // namespace Rando + +#endif \ No newline at end of file From 68a73b170019c90b3331e5c7c3debe70efb8342c Mon Sep 17 00:00:00 2001 From: aMannus Date: Tue, 4 Aug 2026 23:42:24 +0200 Subject: [PATCH 110/131] Randomized props fully replaced --- src/port/Rando/CheckTracker/CheckTracker.cpp | 14 ++-- .../CustomCollectible/CustomCollectible.cpp | 31 ++++++- .../CustomCollectible/CustomCollectible.h | 7 ++ src/port/Rando/CustomObject/CustomObject.cpp | 12 +-- src/port/Rando/ItemQueue.cpp | 2 + src/port/Rando/Logic/GeneratePools.cpp | 6 +- src/port/Rando/Logic/GenerateSaveData.cpp | 2 +- src/port/Rando/Logic/Logic.h | 30 ++----- src/port/Rando/MiscBehavior/WorldState.cpp | 26 +++--- src/port/Rando/ObjectBehavior/Boggy.cpp | 6 +- src/port/Rando/ObjectBehavior/Bundle.cpp | 2 +- src/port/Rando/ObjectBehavior/Gobi.cpp | 6 +- src/port/Rando/ObjectBehavior/Jiggy.cpp | 2 +- src/port/Rando/ObjectBehavior/Jinjo.cpp | 2 +- src/port/Rando/ObjectBehavior/Molehill.cpp | 2 +- .../Rando/ObjectBehavior/ObjectBehavior.cpp | 3 +- .../Rando/ObjectBehavior/ObjectBehavior.h | 1 - src/port/Rando/ObjectBehavior/Prop.cpp | 83 +++++++++---------- src/port/Rando/Types.h | 3 +- src/port/Save/SaveManager.cpp | 4 +- src/port/UI/DeveloperTools/SaveEditor.cpp | 39 +++++---- 21 files changed, 155 insertions(+), 128 deletions(-) diff --git a/src/port/Rando/CheckTracker/CheckTracker.cpp b/src/port/Rando/CheckTracker/CheckTracker.cpp index 1e231cc64..e650188ca 100644 --- a/src/port/Rando/CheckTracker/CheckTracker.cpp +++ b/src/port/Rando/CheckTracker/CheckTracker.cpp @@ -103,7 +103,7 @@ std::string GetTotalCheckCount() { uint32_t collected = 0; uint32_t totalShuffled = 0; for (auto& entry : Rando::Logic::shuffledPool) { - if (entry.obtained || entry.skipped) { + if (entry.eligible || entry.skipped) { collected++; } if (entry.isShuffled) { @@ -131,7 +131,7 @@ void UpdateWorldCheckCount(level_e world) { if (Rando::StaticData::Checks[entry.randoCheckId].worldId != world) { continue; } - if (entry.obtained || entry.skipped) { + if (entry.eligible || entry.skipped) { worldCollected++; } if (entry.isShuffled) { @@ -219,7 +219,7 @@ void DrawCheckTrackerList() { continue; } - if (CVAR_HIDE_COLLECTED && entry.obtained) { + if (CVAR_HIDE_COLLECTED && entry.eligible) { continue; } @@ -227,16 +227,16 @@ void DrawCheckTrackerList() { continue; } - ImVec4 checkTextColor = entry.obtained ? VecFromRGBA8(CVAR_COLLECTED_COLOR) + ImVec4 checkTextColor = entry.eligible ? VecFromRGBA8(CVAR_COLLECTED_COLOR) : UIWidgets::ColorValues.at(UIWidgets::Colors::White); - ImVec4 itemTextColor = entry.obtained ? VecFromRGBA8(CVAR_ITEM_COLOR) + ImVec4 itemTextColor = entry.eligible ? VecFromRGBA8(CVAR_ITEM_COLOR) : UIWidgets::ColorValues.at(UIWidgets::Colors::Indigo); if (entry.skipped) { checkTextColor = itemTextColor = VecFromRGBA8(CVAR_SKIPPED_COLOR); } - if (!entry.obtained && CVAR_SHOW_LOGIC) { + if (!entry.eligible && CVAR_SHOW_LOGIC) { checkTextColor = Rando::Logic::CanAccessCheck(entry.randoCheckId) ? UIWidgets::ColorValues.at(UIWidgets::Colors::White) : VecFromRGBA8(CVAR_LOGIC_COLOR); @@ -244,7 +244,7 @@ void DrawCheckTrackerList() { ImGui::BeginGroup(); ImGui::TextColored(checkTextColor, checkNames.at(entry.randoCheckId).c_str()); - if (entry.obtained) { + if (entry.eligible) { ImGui::SameLine(); RandoItemId randoItemId = Rando::Logic::GetShuffledObject(entry.randoCheckId).randoItemId; const std::string& randoItemName = diff --git a/src/port/Rando/CustomCollectible/CustomCollectible.cpp b/src/port/Rando/CustomCollectible/CustomCollectible.cpp index a9c75e2af..f5e78a2de 100644 --- a/src/port/Rando/CustomCollectible/CustomCollectible.cpp +++ b/src/port/Rando/CustomCollectible/CustomCollectible.cpp @@ -3,6 +3,8 @@ #include #include +#include "port/ShipInit.hpp" +#include extern "C" { #include "functions.h" @@ -12,6 +14,8 @@ Actor* func_802D94B4(ActorMarker* marker, Gfx** gfx, Mtx** mtx, Vtx** vtx); Actor* func_802D41C4(ActorMarker* marker, Gfx** gfx, Mtx** mtx, Vtx** vtx); } +static std::queue propQueue; + std::unordered_map customCollectibleDrawInfo = { { ACTOR_52_BLUE_EGG, { ASSET_36D_SPRITE_BLUE_EGG, CCT_GENERIC_SPRITE } }, { ACTOR_47_EMPTY_HONEYCOMB, { ASSET_361_MODEL_EMPTY_HONEYCOMB, CCT_GENERIC_MODEL } }, @@ -143,7 +147,6 @@ Actor* CustomCollectible::Spawn(int32_t position[3], RandoCheckId randoCheckId) int32_t flags = ACTOR_FLAG_UNKNOWN_6 | ACTOR_FLAG_UNKNOWN_7 | ACTOR_FLAG_UNKNOWN_21; RandoItemId randoItemId = RANDO_SAVE_CHECKS[randoCheckId].randoItemId; - randoItemId = RI_AP_ITEM_PROGRESSION; RandoItemType itemType = Rando::StaticData::Items[randoItemId].randoItemType; // actor_new stores the ActorInfo* permanently, so it must outlive Spawn() @@ -226,3 +229,29 @@ void CustomCollectible::OnCollect(struct actorMarker_s* self, struct actorMarker ItemQueue::AddCheck(customLocal->randoCheckId); marker_despawn(self); } + +// When regular props are spawned in BK, the game isn't fully set up yet to spawn +// actors. So we delay prop spawns until the game's ready to spawn actors. +void CustomCollectible::QueueProp(int32_t position[3], RandoCheckId randoCheckId) { + QueuedProp queuedProp; + queuedProp.position[0] = position[0]; + queuedProp.position[1] = position[1]; + queuedProp.position[2] = position[2]; + queuedProp.randoCheckId = randoCheckId; + propQueue.push(queuedProp); +} + +void CustomCollectible::ProcessPropQueue() { + while (propQueue.size() > 0) { + QueuedProp prop = propQueue.front(); + Actor* actor = CustomCollectible::Spawn(prop.position, prop.randoCheckId); + propQueue.pop(); + } +} + +void RegisterCustomCollectible() { + COND_HOOK(OnActorSpawn, EVENT_PRIORITY_NORMAL, IS_RANDO, + [](IEvent* event) { CustomCollectible::ProcessPropQueue(); }); +} + +static RegisterShipInitFunc initFunc(RegisterCustomCollectible, { "IS_RANDO" }); diff --git a/src/port/Rando/CustomCollectible/CustomCollectible.h b/src/port/Rando/CustomCollectible/CustomCollectible.h index fac0047cf..6e351bf4f 100644 --- a/src/port/Rando/CustomCollectible/CustomCollectible.h +++ b/src/port/Rando/CustomCollectible/CustomCollectible.h @@ -23,6 +23,11 @@ typedef struct { CustomCollectibleDrawTypes drawType; } CustomCollectibleDrawInfo; +typedef struct { + s32 position[3]; + RandoCheckId randoCheckId; +} QueuedProp; + void CustomCollectible_Update(Actor* actor); class CustomCollectible { @@ -36,4 +41,6 @@ class CustomCollectible { static Actor* Spawn(int32_t position[3], RandoCheckId randoCheckId); static f32 GetScale(RandoItemType itemType); static void FacePlayer(Actor* actor); + static void QueueProp(int32_t position[3], RandoCheckId randoCheckId); + static void ProcessPropQueue(); }; diff --git a/src/port/Rando/CustomObject/CustomObject.cpp b/src/port/Rando/CustomObject/CustomObject.cpp index aa30f92d3..047435dfa 100644 --- a/src/port/Rando/CustomObject/CustomObject.cpp +++ b/src/port/Rando/CustomObject/CustomObject.cpp @@ -204,7 +204,7 @@ void CustomObject::FlushRandoSpawnQueue() { } actor_e randoActorId = Rando::StaticData::GetActorIdByRandoItemId(randoSaveCheck.randoItemId); - if (randoSaveCheck.obtained) { + if (randoSaveCheck.eligible) { randoActorId = GetRandomJunkActorId(randoSaveCheck); } @@ -217,7 +217,7 @@ void CustomObject::FlushRandoSpawnQueue() { &actorInfoMap.at(randoActorId).first, actorInfoMap.at(randoActorId).second); - if (randoSaveCheck.obtained && RANDO_SAVE_OPTIONS[RO_SPAWN_JUNK].optionValue == RO_GENERIC_ON) { + if (randoSaveCheck.eligible && RANDO_SAVE_OPTIONS[RO_SPAWN_JUNK].optionValue == RO_GENERIC_ON) { customActor->marker->unk14_21 = true; customActor->scale = 1.0f; } @@ -250,7 +250,7 @@ Actor* CustomObject::ShouldCreateCustomActorEX(RandoCheckId randoCheckId, int32_ return NULL; } - if (randoSaveCheck.obtained) { + if (randoSaveCheck.eligible) { if (refActor != nullptr) { randoActorId = (actor_e)refActor->modelCacheIndex; } else { @@ -335,10 +335,10 @@ void CustomObject::ResolveCustomActorCollisionEX(RandoCheckId randoCheckId) { void CustomObject::CheckObtainedEX(RandoCheckId randoCheckId, bool isInit) { for (auto& pool : Rando::Logic::shuffledPool) { - if (pool.randoCheckId == randoCheckId && !pool.obtained) { - pool.obtained = true; + if (pool.randoCheckId == randoCheckId && !pool.eligible) { + pool.eligible = true; shouldRemoveEX = true; - RANDO_SAVE_CHECKS[pool.randoCheckId].obtained = true; + RANDO_SAVE_CHECKS[pool.randoCheckId].eligible = true; CustomObject::RemoveSpawnedIdFromList(randoCheckId); if (!isInit) { Rando::StaticData::SendCollisionNotification(pool.randoCheckId); diff --git a/src/port/Rando/ItemQueue.cpp b/src/port/Rando/ItemQueue.cpp index 102c6cd02..33a89991f 100644 --- a/src/port/Rando/ItemQueue.cpp +++ b/src/port/Rando/ItemQueue.cpp @@ -67,6 +67,7 @@ void ItemQueue::Process() { RandoSaveCheck randoSaveCheck = RANDO_SAVE_CHECKS[randoCheckId]; ItemQueue::GiveItem(randoSaveCheck.randoItemId); ItemQueue::SendNotification(randoSaveCheck.randoItemId); + RANDO_SAVE_CHECKS[randoCheckId].received = true; itemQueue.pop(); } @@ -301,6 +302,7 @@ void ItemQueue::Clear() { } void ItemQueue::AddCheck(RandoCheckId randoCheckId) { + RANDO_SAVE_CHECKS[randoCheckId].eligible = true; itemQueue.push(randoCheckId); } diff --git a/src/port/Rando/Logic/GeneratePools.cpp b/src/port/Rando/Logic/GeneratePools.cpp index 64aca987e..4adcfbfeb 100644 --- a/src/port/Rando/Logic/GeneratePools.cpp +++ b/src/port/Rando/Logic/GeneratePools.cpp @@ -130,7 +130,7 @@ void GenerateShufflePool(SaveData* saveData) { .randoItemId = Rando::StaticData::Checks[std::get<2>(itemPool[i])].randoItemId, .randoCollectionId = std::get<1>(itemPool[i]), .isShuffled = checkPool[i] == RC_UNKNOWN ? false : true, - .obtained = false, + .eligible = false, .skipped = false, }; @@ -146,7 +146,7 @@ void GenerateShufflePool(SaveData* saveData) { .randoItemId = Rando::StaticData::Checks[std::get<2>(abilityItemPool[a])].randoItemId, .randoCollectionId = std::get<1>(abilityItemPool[a]), .isShuffled = true, - .obtained = false, + .eligible = false, .skipped = false, }; @@ -177,7 +177,7 @@ void GeneratePoolFromSaveData(SaveData* saveData) { .randoItemId = randoSaveCheck.randoItemId, .randoCollectionId = randoSaveCheck.randoCollectionId, .isShuffled = randoSaveCheck.isShuffled, - .obtained = randoSaveCheck.obtained, + .eligible = randoSaveCheck.eligible, .skipped = randoSaveCheck.skipped, }; diff --git a/src/port/Rando/Logic/GenerateSaveData.cpp b/src/port/Rando/Logic/GenerateSaveData.cpp index 3361ce00a..daabf23c3 100644 --- a/src/port/Rando/Logic/GenerateSaveData.cpp +++ b/src/port/Rando/Logic/GenerateSaveData.cpp @@ -128,7 +128,7 @@ void Rando::Logic::InitializeSaveData(SaveData* saveData) { // .randoItemId = Rando::StaticData::GetRandoItemByActorId((actor_e)randoStaticCheck.actorId), .randoCollectionId = randoStaticCheck.collectionId, .isShuffled = false, - .obtained = false, + .eligible = false, .skipped = false, }; diff --git a/src/port/Rando/Logic/Logic.h b/src/port/Rando/Logic/Logic.h index 964235b66..f97c6abdf 100644 --- a/src/port/Rando/Logic/Logic.h +++ b/src/port/Rando/Logic/Logic.h @@ -71,16 +71,11 @@ void GrantStartingLoadout(); void RefreshReachableRegions(); inline bool IsCheckShuffled(RandoCheckId randoCheckId) { - bool isShuffled = false; - - for (auto& object : shuffledPool) { - if (object.randoCheckId == randoCheckId) { - isShuffled = object.isShuffled; - break; - } - } + return RANDO_SAVE_CHECKS[randoCheckId].isShuffled; +} - return isShuffled; +inline bool IsCheckObtained(RandoCheckId randoCheckId) { + return RANDO_SAVE_CHECKS[randoCheckId].eligible; } inline RandoSaveCheck GetShuffledObject(RandoCheckId randoCheckId) { @@ -101,25 +96,12 @@ inline RandoSaveCheck GetShuffledObject(RandoCheckId randoCheckId) { return shuffledObject; } -inline bool IsCheckObtained(RandoCheckId randoCheckId) { - bool isObtained = false; - - for (auto& object : shuffledPool) { - if (object.randoCheckId == randoCheckId) { - isObtained = object.obtained; - break; - } - } - - return isObtained; -} - inline bool ShouldSpawnJinjoJiggy(int16_t levelId) { bool shouldSpawn = false; int16_t jinjoCount = 0; for (auto& location : Rando::Logic::shuffledPool) { - if (!location.obtained) { + if (!location.eligible) { continue; } @@ -145,7 +127,7 @@ inline int32_t GetTotalSnsItemsCollected() { int32_t snsCount = 0; for (auto& location : Rando::Logic::shuffledPool) { - if (!location.obtained) { + if (!location.eligible) { continue; } diff --git a/src/port/Rando/MiscBehavior/WorldState.cpp b/src/port/Rando/MiscBehavior/WorldState.cpp index ab26bea2a..f8dcc3c5a 100644 --- a/src/port/Rando/MiscBehavior/WorldState.cpp +++ b/src/port/Rando/MiscBehavior/WorldState.cpp @@ -41,8 +41,8 @@ void Rando::StaticData::ModifyRandoInfFlagState(RandoCheckId randoCheckId) { break; case RC_GV_JIGGY_WATER_PYRAMID: case RC_GV_MUMBO_TOKEN_INSIDE_WATER_PYRAMID: - if (RANDO_SAVE_CHECKS[RC_GV_JIGGY_WATER_PYRAMID].obtained && - RANDO_SAVE_CHECKS[RC_GV_MUMBO_TOKEN_INSIDE_WATER_PYRAMID].obtained) { + if (RANDO_SAVE_CHECKS[RC_GV_JIGGY_WATER_PYRAMID].eligible && + RANDO_SAVE_CHECKS[RC_GV_MUMBO_TOKEN_INSIDE_WATER_PYRAMID].eligible) { randoInfFlag = RANDO_INF_WATER_PYRAMID_DRAINED; } break; @@ -106,18 +106,18 @@ void Rando::MiscBehavior::InitWorldStateBehavior() { switch (currentLevel) { case LEVEL_1_MUMBOS_MOUNTAIN: - if (RANDO_SAVE_CHECKS[RC_MM_JIGGY_CHIMPY].obtained) { + if (RANDO_SAVE_CHECKS[RC_MM_JIGGY_CHIMPY].eligible) { if (ev->actorId == ACTOR_F_CHIMPY) { event->Cancelled = true; ev->result = NULL; } } mapSpecificFlags_set(MM_SPECIFIC_FLAG_0_CHIMPY_STUMP_RAISED, - RANDO_SAVE_CHECKS[RC_MM_JIGGY_CHIMPY].obtained); + RANDO_SAVE_CHECKS[RC_MM_JIGGY_CHIMPY].eligible); mapSpecificFlags_set(MM_SPECIFIC_FLAG_2_ORANGE_HAS_BEEN_RETURNED, - RANDO_SAVE_CHECKS[RC_MM_JIGGY_CHIMPY].obtained); + RANDO_SAVE_CHECKS[RC_MM_JIGGY_CHIMPY].eligible); mapSpecificFlags_set(MM_SPECIFIC_FLAG_3_CHIMPY_HAS_LEFT, - RANDO_SAVE_CHECKS[RC_MM_JIGGY_CHIMPY].obtained); + RANDO_SAVE_CHECKS[RC_MM_JIGGY_CHIMPY].eligible); break; case LEVEL_3_CLANKERS_CAVERN: if (currentMap == MAP_22_CC_INSIDE_CLANKER && @@ -127,11 +127,11 @@ void Rando::MiscBehavior::InitWorldStateBehavior() { break; case LEVEL_9_RUSTY_BUCKET_BAY: if (ev->actorId == 0x18F) { - mapSpecificFlags_set(0, RANDO_SAVE_CHECKS[RC_RBB_EMPTY_HONEYCOMB_BOAT_HOUSE].obtained); + mapSpecificFlags_set(0, RANDO_SAVE_CHECKS[RC_RBB_EMPTY_HONEYCOMB_BOAT_HOUSE].eligible); } break; case LEVEL_A_MAD_MONSTER_MANSION: - if (ev->actorId == ACTOR_39_NAPPER && RANDO_SAVE_CHECKS[RC_MMM_JIGGY_MANSION_TABLE].obtained) { + if (ev->actorId == ACTOR_39_NAPPER && RANDO_SAVE_CHECKS[RC_MMM_JIGGY_MANSION_TABLE].eligible) { event->Cancelled = true; ev->result = NULL; } @@ -165,7 +165,7 @@ void Rando::MiscBehavior::InitWorldStateBehavior() { if (currentMap == MAP_26_MMM_NAPPERS_ROOM && randoSaveCheck.randoCheckId != RC_MMM_JIGGY_MANSION_TABLE) { event->Cancelled = true; - ev->result = RANDO_SAVE_CHECKS[RC_MMM_JIGGY_MANSION_TABLE].obtained; + ev->result = RANDO_SAVE_CHECKS[RC_MMM_JIGGY_MANSION_TABLE].eligible; break; } } @@ -179,13 +179,13 @@ void Rando::MiscBehavior::InitWorldStateBehavior() { if (ev->jiggyId == JIGGY_2E_FP_PRESENTS) { if (currenLevel == LEVEL_5_FREEZEEZY_PEAK) { event->Cancelled = true; - ev->result = RANDO_SAVE_CHECKS[RC_FP_JIGGY_IGLOO].obtained; + ev->result = RANDO_SAVE_CHECKS[RC_FP_JIGGY_IGLOO].eligible; break; } } event->Cancelled = true; - ev->result = randoSaveCheck.obtained; + ev->result = randoSaveCheck.eligible; break; } } @@ -236,7 +236,7 @@ void Rando::MiscBehavior::InitWorldStateBehavior() { if (ev->honeycombId == HONEYCOMB_17_SM_COLLIWOBBLE) { ev->result = false; } else { - ev->result = saveCheck.obtained; + ev->result = saveCheck.eligible; } break; @@ -264,7 +264,7 @@ void Rando::MiscBehavior::InitWorldStateBehavior() { if (saveCheck.randoCollectionId == ev->tokenId) { event->Cancelled = true; - ev->result = saveCheck.obtained; + ev->result = saveCheck.eligible; break; } } diff --git a/src/port/Rando/ObjectBehavior/Boggy.cpp b/src/port/Rando/ObjectBehavior/Boggy.cpp index 8634b420b..613d96c15 100644 --- a/src/port/Rando/ObjectBehavior/Boggy.cpp +++ b/src/port/Rando/ObjectBehavior/Boggy.cpp @@ -20,7 +20,7 @@ void Rando::ObjectBehavior::ModifyBoggyBehavior(void* boggyActor) { switch (actor->actor_info->actorId) { case ACTOR_160_BOGGY_1: case ACTOR_181_SCARF_SLED: - if (RANDO_SAVE_CHECKS[RC_FP_JIGGY_SLED_TO_BOGGY].obtained) { + if (RANDO_SAVE_CHECKS[RC_FP_JIGGY_SLED_TO_BOGGY].eligible) { marker_despawn(actor->marker); if (actor->actor_info->actorId == ACTOR_160_BOGGY_1) { func_80387760(actor->marker); @@ -28,12 +28,12 @@ void Rando::ObjectBehavior::ModifyBoggyBehavior(void* boggyActor) { } break; case ACTOR_C8_BOGGY_2: - if (!RANDO_SAVE_CHECKS[RC_FP_JIGGY_SLED_TO_BOGGY].obtained) { + if (!RANDO_SAVE_CHECKS[RC_FP_JIGGY_SLED_TO_BOGGY].eligible) { marker_despawn(actor->marker); } break; case 0x33D: - if (!RANDO_SAVE_CHECKS[RC_FP_JIGGY_BOGGY_RACE_2].obtained) { + if (!RANDO_SAVE_CHECKS[RC_FP_JIGGY_BOGGY_RACE_2].eligible) { marker_despawn(actor->marker); } break; diff --git a/src/port/Rando/ObjectBehavior/Bundle.cpp b/src/port/Rando/ObjectBehavior/Bundle.cpp index 6f7806343..6c094b59f 100644 --- a/src/port/Rando/ObjectBehavior/Bundle.cpp +++ b/src/port/Rando/ObjectBehavior/Bundle.cpp @@ -545,7 +545,7 @@ void Rando::ObjectBehavior::InitBundleBehavior() { } RandoSaveCheck randoSaveCheck = RANDO_SAVE_CHECKS[randoCheckId]; - if (randoSaveCheck.obtained) { + if (randoSaveCheck.eligible) { actor_e actorId = (actor_e)Rando::StaticData::Items[randoSaveCheck.randoItemId].actorId; *actor = CustomObject::SpawnCustomActorEX(randoCheckId, spawnPosition, &actorInfoMap.at((actor_e)actorId).first, diff --git a/src/port/Rando/ObjectBehavior/Gobi.cpp b/src/port/Rando/ObjectBehavior/Gobi.cpp index abf0f6ef1..1ac60ec89 100644 --- a/src/port/Rando/ObjectBehavior/Gobi.cpp +++ b/src/port/Rando/ObjectBehavior/Gobi.cpp @@ -22,12 +22,12 @@ void Rando::ObjectBehavior::ModifyGobiBehavior(void* gobiActor) { case ACTOR_12E_GOBI_1: case ACTOR_12F_GOBI_ROPE: case ACTOR_130_GOBI_ROCK: - if (RANDO_SAVE_CHECKS[RC_GV_JIGGY_GOBI_1].obtained) { + if (RANDO_SAVE_CHECKS[RC_GV_JIGGY_GOBI_1].eligible) { marker_despawn(actor->marker); } break; case ACTOR_131_GOBI_2: - if (RANDO_SAVE_CHECKS[RC_GV_JIGGY_GOBI_1].obtained && !RANDO_SAVE_CHECKS[RC_GV_JIGGY_GOBI_2].obtained) { + if (RANDO_SAVE_CHECKS[RC_GV_JIGGY_GOBI_1].eligible && !RANDO_SAVE_CHECKS[RC_GV_JIGGY_GOBI_2].eligible) { if (actor->state == 1) { chGobi2_setState(actor, 2); actor->marker->collidable = true; @@ -41,7 +41,7 @@ void Rando::ObjectBehavior::ModifyGobiBehavior(void* gobiActor) { } break; case ACTOR_135_GOBI_3: - if (RANDO_SAVE_CHECKS[RC_GV_JIGGY_GOBI_2].obtained) { + if (RANDO_SAVE_CHECKS[RC_GV_JIGGY_GOBI_2].eligible) { if (actor->state == 0) { chGobi3_setState(actor, 2); actor->marker->collidable = true; diff --git a/src/port/Rando/ObjectBehavior/Jiggy.cpp b/src/port/Rando/ObjectBehavior/Jiggy.cpp index cc4fc67f8..b703a771c 100644 --- a/src/port/Rando/ObjectBehavior/Jiggy.cpp +++ b/src/port/Rando/ObjectBehavior/Jiggy.cpp @@ -13,7 +13,7 @@ void Rando::ObjectBehavior::InitJiggyBehavior() { return; } - if (RANDO_SAVE_CHECKS[RC_MMM_JIGGY_MANSION_TABLE].obtained) { + if (RANDO_SAVE_CHECKS[RC_MMM_JIGGY_MANSION_TABLE].eligible) { *should = false; } }) diff --git a/src/port/Rando/ObjectBehavior/Jinjo.cpp b/src/port/Rando/ObjectBehavior/Jinjo.cpp index 61764a6bd..026e61f39 100644 --- a/src/port/Rando/ObjectBehavior/Jinjo.cpp +++ b/src/port/Rando/ObjectBehavior/Jinjo.cpp @@ -19,7 +19,7 @@ void Rando::ObjectBehavior::InitJinjoBehavior() { OnSetJiggyList* ev = (OnSetJiggyList*)event; for (auto& location : Rando::Logic::shuffledPool) { - if (!location.obtained) { + if (!location.eligible) { continue; } diff --git a/src/port/Rando/ObjectBehavior/Molehill.cpp b/src/port/Rando/ObjectBehavior/Molehill.cpp index e7e640f73..9008a0118 100644 --- a/src/port/Rando/ObjectBehavior/Molehill.cpp +++ b/src/port/Rando/ObjectBehavior/Molehill.cpp @@ -78,7 +78,7 @@ bool CheckBridgeState() { int32_t smBridgeCheck = 0; if (!mapSpecificFlags_get(SM_SPECIFIC_FLAG_3_ALL_SM_ABILITIES_LEARNED)) { for (auto& check : spiralMountainBridge) { - if (Rando::Logic::GetShuffledObject(check).obtained) { + if (Rando::Logic::GetShuffledObject(check).eligible) { smBridgeCheck++; } } diff --git a/src/port/Rando/ObjectBehavior/ObjectBehavior.cpp b/src/port/Rando/ObjectBehavior/ObjectBehavior.cpp index 68f158eaf..b5c5977df 100644 --- a/src/port/Rando/ObjectBehavior/ObjectBehavior.cpp +++ b/src/port/Rando/ObjectBehavior/ObjectBehavior.cpp @@ -248,7 +248,6 @@ void Rando::ObjectBehavior::Init() { InitJinjoBehavior(); InitMolehillBehavior(); InitMusicNoteBehavior(); - InitPropBehavior(); InitStopNSwopBehavior(); UpdateJunkList(); @@ -266,7 +265,7 @@ void Rando::ObjectBehavior::Init() { if (currentMap == MAP_12_GV_GOBIS_VALLEY) { if (ev->actorId == ACTOR_118_GRABBA) { - event->Cancelled = RANDO_SAVE_CHECKS[RC_GV_JIGGY_GRABBA].obtained; + event->Cancelled = RANDO_SAVE_CHECKS[RC_GV_JIGGY_GRABBA].eligible; ev->result = NULL; } } diff --git a/src/port/Rando/ObjectBehavior/ObjectBehavior.h b/src/port/Rando/ObjectBehavior/ObjectBehavior.h index 25221fd9e..3cb7e5199 100644 --- a/src/port/Rando/ObjectBehavior/ObjectBehavior.h +++ b/src/port/Rando/ObjectBehavior/ObjectBehavior.h @@ -18,7 +18,6 @@ void InitJiggyBehavior(); void InitJinjoBehavior(); void InitMolehillBehavior(); void InitMusicNoteBehavior(); -void InitPropBehavior(); void InitStopNSwopBehavior(); void ModifySwitchBehavior(int32_t switchActorId); diff --git a/src/port/Rando/ObjectBehavior/Prop.cpp b/src/port/Rando/ObjectBehavior/Prop.cpp index db6b416b9..32b0cd6a2 100644 --- a/src/port/Rando/ObjectBehavior/Prop.cpp +++ b/src/port/Rando/ObjectBehavior/Prop.cpp @@ -1,52 +1,49 @@ -#include "ObjectBehavior.h" -#include "port/Rando/Logic/Logic.h" -#include "port/Rando/CustomObject/CustomObject.h" - -#include -#include "port/UI/cvar_prefixes.h" -#include -#include "port/Enhancements/Events/PortEnhancements.h" +#include "port/ShipInit.hpp" #include "port/Enhancements/Events/Hooks/Events.h" - -#include "spdlog/spdlog.h" +#include "port/Rando/Logic/Logic.h" +#include "port/Rando/CustomCollectible/CustomCollectible.h" #define BLUE_EGG_OPTION_ENABLED RANDO_SAVE_OPTIONS[RO_SHUFFLE_BLUE_EGGS].optionValue #define MUSIC_NOTE_OPTION_ENABLED RANDO_SAVE_OPTIONS[RO_SHUFFLE_MUSIC_NOTES].optionValue -void Rando::ObjectBehavior::InitPropBehavior() { +bool OverridePropSpawn(s16 spawnPosition[3], int32_t propAsset) { + s32 position[3] = { spawnPosition[0], spawnPosition[1], spawnPosition[2] }; + + if (!IS_RANDO) { + return false; + } + + if (!BLUE_EGG_OPTION_ENABLED && propAsset == ASSET_6D7_SPRITE_BLUE_EGGS) { + return false; + } + + if (!MUSIC_NOTE_OPTION_ENABLED && propAsset == ASSET_6D6_SPRITE_MUSIC_NOTE) { + return false; + } + + RandoCheckId randoCheckId = Rando::StaticData::GetCheckByPosition(position[0], position[1], position[2]); + if (randoCheckId == RC_UNKNOWN) { + return false; + } + + if (!Rando::Logic::IsCheckShuffled(randoCheckId)) { + return false; + } + + if (Rando::Logic::IsCheckObtained(randoCheckId)) { + return true; + } + + CustomCollectible::QueueProp(position, randoCheckId); + return true; +} + +void RegisterRandoPropBehaviour() { COND_VB_SHOULD(VB_OVERRIDE_PROP_SPAWN, EVENT_PRIORITY_NORMAL, true, { s16* spawnPosition = va_arg(args, s16*); int32_t propAsset = va_arg(args, int32_t); - - if (!IS_RANDO) { - return; - } - - if (!BLUE_EGG_OPTION_ENABLED && propAsset == ASSET_6D7_SPRITE_BLUE_EGGS) { - return; - } - - if (!MUSIC_NOTE_OPTION_ENABLED && propAsset == ASSET_6D6_SPRITE_MUSIC_NOTE) { - return; - } - - int32_t position[3]; - position[0] = spawnPosition[0]; - position[1] = spawnPosition[1]; - position[2] = spawnPosition[2]; - - RandoCheckId randoCheckId = Rando::StaticData::GetCheckByPosition(position[0], position[1], position[2]); - if (randoCheckId == RC_UNKNOWN) { - *should = false; - return; - } - - if (!Rando::Logic::IsCheckShuffled(randoCheckId)) { - *should = false; - return; - } - - Actor* randoCustomActor = CustomObject::ShouldCreateCustomActorEX(randoCheckId, position, true); - *should = true; - }) + *should = OverridePropSpawn(spawnPosition, propAsset); + }); } + +static RegisterShipInitFunc initFunc(RegisterRandoPropBehaviour, { "IS_RANDO" }); diff --git a/src/port/Rando/Types.h b/src/port/Rando/Types.h index 6cb807352..bf46e164d 100644 --- a/src/port/Rando/Types.h +++ b/src/port/Rando/Types.h @@ -2395,7 +2395,8 @@ typedef struct RandoSaveCheck { RandoItemId randoItemId; int32_t randoCollectionId; bool isShuffled; - bool obtained; + bool eligible; + bool received; bool skipped; } RandoSaveCheck; diff --git a/src/port/Save/SaveManager.cpp b/src/port/Save/SaveManager.cpp index 9adfc1394..18a863005 100644 --- a/src/port/Save/SaveManager.cpp +++ b/src/port/Save/SaveManager.cpp @@ -75,7 +75,7 @@ static void BitfieldSetNBits(uint8_t* array, int startIndex, int numBits, int va void RandoSaveCheck_to_json(nlohmann::json& j, const RandoSaveCheck& randoSaveCheck) { j = nlohmann::json::array({ randoSaveCheck.randoCheckId, randoSaveCheck.randoItemId, - randoSaveCheck.randoCollectionId, randoSaveCheck.isShuffled, randoSaveCheck.obtained, + randoSaveCheck.randoCollectionId, randoSaveCheck.isShuffled, randoSaveCheck.eligible, randoSaveCheck.skipped }); } @@ -84,7 +84,7 @@ RandoSaveCheck RandoSaveCheck_from_json(const nlohmann::json& j, RandoSaveCheck& j.at(1).get_to(randoSaveCheck.randoItemId); j.at(2).get_to(randoSaveCheck.randoCollectionId); j.at(3).get_to(randoSaveCheck.isShuffled); - j.at(4).get_to(randoSaveCheck.obtained); + j.at(4).get_to(randoSaveCheck.eligible); j.at(5).get_to(randoSaveCheck.skipped); return randoSaveCheck; diff --git a/src/port/UI/DeveloperTools/SaveEditor.cpp b/src/port/UI/DeveloperTools/SaveEditor.cpp index d93c46eba..dce2307d0 100644 --- a/src/port/UI/DeveloperTools/SaveEditor.cpp +++ b/src/port/UI/DeveloperTools/SaveEditor.cpp @@ -93,39 +93,39 @@ bool SaveEditor_IsHoneycombCollected(honeycomb_e honeycombId) { } void SaveEditor_UpdateCheckTracker(RandoSaveCheck randoSaveCheck) { - if (randoSaveCheck.obtained) { + if (randoSaveCheck.eligible) { CustomObject::CheckObtainedEX(randoSaveCheck.randoCheckId); } for (auto& pool : Rando::Logic::shuffledPool) { if (pool.randoCheckId == randoSaveCheck.randoCheckId) { pool.isShuffled = randoSaveCheck.isShuffled; - pool.obtained = randoSaveCheck.obtained; + pool.eligible = randoSaveCheck.eligible; pool.skipped = randoSaveCheck.skipped; break; } } - int32_t itemIncr = randoSaveCheck.obtained ? 1 : -1; + int32_t itemIncr = randoSaveCheck.eligible ? 1 : -1; Rando::StaticData::RandoStaticItem randoItem = Rando::StaticData::Items[randoSaveCheck.randoItemId]; switch (randoItem.randoItemType) { case RITYPE_JIGGY: - jiggyscore_setCollected(randoSaveCheck.randoCollectionId, randoSaveCheck.obtained); + jiggyscore_setCollected(randoSaveCheck.randoCollectionId, randoSaveCheck.eligible); item_adjustByDiffWithoutHud(ITEM_26_JIGGY_TOTAL, itemIncr); break; case RITYPE_EMPTY_HONEYCOMB: - honeycombscore_set((honeycomb_e)randoSaveCheck.randoCollectionId, randoSaveCheck.obtained); + honeycombscore_set((honeycomb_e)randoSaveCheck.randoCollectionId, randoSaveCheck.eligible); break; case RITYPE_MOLEHILL: - if (randoSaveCheck.obtained) { + if (randoSaveCheck.eligible) { ability_unlock((ability_e)randoSaveCheck.randoCollectionId); } else { ability_setLearned((ability_e)randoSaveCheck.randoCollectionId, 0); } break; case RITYPE_MUMBO_TOKEN: - mumboscore_set((mumbotoken_e)randoSaveCheck.randoCollectionId, randoSaveCheck.obtained); + mumboscore_set((mumbotoken_e)randoSaveCheck.randoCollectionId, randoSaveCheck.eligible); item_adjustByDiffWithoutHud(ITEM_1C_MUMBO_TOKEN, itemIncr); break; default: @@ -394,9 +394,10 @@ void DrawRandoCheckEditor() { } if (ImGui::BeginChild("RandoToolsChild", ImVec2(ImGui::GetContentRegionAvail().x, 0))) { - if (ImGui::BeginTable("RandoSaveEditorTable", 6)) { + if (ImGui::BeginTable("RandoSaveEditorTable", 7)) { ImGui::TableSetupColumn("shuffled", ImGuiTableColumnFlags_WidthFixed, 34.0f); - ImGui::TableSetupColumn("obtained", ImGuiTableColumnFlags_WidthFixed, 34.0f); + ImGui::TableSetupColumn("eligible", ImGuiTableColumnFlags_WidthFixed, 34.0f); + ImGui::TableSetupColumn("received", ImGuiTableColumnFlags_WidthFixed, 34.0f); ImGui::TableSetupColumn("skipped", ImGuiTableColumnFlags_WidthFixed, 34.0f); ImGui::TableSetupColumn("checkName", ImGuiTableColumnFlags_WidthFixed, (ImGui::GetContentRegionAvail().x - 34.0f) * 0.60f); @@ -414,25 +415,35 @@ void DrawRandoCheckEditor() { ImGui::PushID(check.randoCheckId); bool isChanged = false; bool isShuffled = check.isShuffled; - bool obtained = check.obtained; + bool eligible = check.eligible; + bool received = check.received; bool skipped = check.skipped; + std::string checkId = std::to_string((uint32_t)check.randoCheckId); + if (UIWidgets::Checkbox( - "isShuffled", &isShuffled, + ("isShuffled##" + checkId).c_str(), &isShuffled, UIWidgets::CheckboxOptions().LabelPosition(UIWidgets::LabelPositions::None))) { RANDO_SAVE_CHECKS[check.randoCheckId].isShuffled = !check.isShuffled; isChanged = true; } ImGui::TableNextColumn(); if (UIWidgets::Checkbox( - "obtained", &obtained, + ("eligible##" + checkId).c_str(), &eligible, + UIWidgets::CheckboxOptions().LabelPosition(UIWidgets::LabelPositions::None))) { + RANDO_SAVE_CHECKS[check.randoCheckId].eligible = !check.eligible; + isChanged = true; + } + ImGui::TableNextColumn(); + if (UIWidgets::Checkbox( + ("received##" + checkId).c_str(), &received, UIWidgets::CheckboxOptions().LabelPosition(UIWidgets::LabelPositions::None))) { - RANDO_SAVE_CHECKS[check.randoCheckId].obtained = !check.obtained; + RANDO_SAVE_CHECKS[check.randoCheckId].received = !check.received; isChanged = true; } ImGui::TableNextColumn(); if (UIWidgets::Checkbox( - "skipped", &skipped, + ("skipped##" + checkId).c_str(), &skipped, UIWidgets::CheckboxOptions().LabelPosition(UIWidgets::LabelPositions::None))) { RANDO_SAVE_CHECKS[check.randoCheckId].skipped = !check.skipped; isChanged = true; From d2dea7be2fe26db0d07dac878c31096c3ba4df85 Mon Sep 17 00:00:00 2001 From: Malkierian Date: Tue, 4 Aug 2026 19:01:47 -0700 Subject: [PATCH 111/131] Make remote clients live react to puzzle completion and prevent pedestal authority from releasing if a puzzle was completed. (#400) --- src/lair/jigsawpicture.c | 21 +++++++++++++++++++++ src/port/Enhancements/Events/Hooks/Events.h | 5 +++-- src/port/Network/Anchor/HookHandlers.cpp | 6 ++++++ src/port/Network/Anchor/JigsawPedestal.cpp | 6 ++++++ 4 files changed, 36 insertions(+), 2 deletions(-) diff --git a/src/lair/jigsawpicture.c b/src/lair/jigsawpicture.c index 99034541f..12bc1aeae 100644 --- a/src/lair/jigsawpicture.c +++ b/src/lair/jigsawpicture.c @@ -451,6 +451,24 @@ static void revealCcwPuzzlePodium(Actor *this) { } } +static s32 jigsawPicture_placedFromFlags(Actor *this) { + return fileProgressFlag_getN(_puzzleFlag(this->actorTypeSpecificField - 1), _puzzleSize(this->actorTypeSpecificField - 1)); +} + +static void jigsawPicture_resyncFromFlags(Actor *this) { + ActorLocal_lair_86F0 *local = (ActorLocal_lair_86F0*)&this->local; + s32 placed = jigsawPicture_placedFromFlags(this); + s32 i; + + local->unk0 = 0; + local->unk4 = 0; + for(i = 0; i < placed; i++){ + local->unk4++; + local->unk0 |= (1 << getPicturePiecePosition(this)); + } + setInitialJigsawPictureOpacity(this); +} + void updateJigsawPictureActor(Actor *this) { ActorLocal_lair_86F0 *local; s32 sp7C[6]; //buttons @@ -533,6 +551,9 @@ void updateJigsawPictureActor(Actor *this) { controller_copyFaceButtons(0, sp7C); controller_copySideButtons(0, sp6C); func_8038EDBC(this); + if (local->unk4 != jigsawPicture_placedFromFlags(this) && EventSystem_Should(VB_JIGSAW_PICTURE_RESYNC, false, this)) { + jigsawPicture_resyncFromFlags(this); + } if (this->state != JIGSAW_PICTURE_LEAVE_PODIUM && !port_jigsawPedestal_isSelf(this->actorTypeSpecificField)) { jigsawPicture_setState(this, JIGSAW_PICTURE_LEAVE_PODIUM); return; diff --git a/src/port/Enhancements/Events/Hooks/Events.h b/src/port/Enhancements/Events/Hooks/Events.h index 8c17d2523..315c85480 100644 --- a/src/port/Enhancements/Events/Hooks/Events.h +++ b/src/port/Enhancements/Events/Hooks/Events.h @@ -91,8 +91,9 @@ typedef enum VBehaviorID { VB_DOOR_OPEN_CAMERA, // Suppresses door-open camera lock when the flag came from a teammate, not us. VB_CC_RINGS_SNAP_WATER, // CC rings water snap on run teardown: suppressed when a teammate finished the rings. VB_LEVELDOOR_REMOTE_OPEN_DONE, // Lair door remote-open "already handled" test. - VB_CCW_PODIUM_DESPAWN, // Despawn the unrevealed CCW puzzle podium: suppressed so a teammate's switch press can - // reveal it live. + VB_CCW_PODIUM_DESPAWN, // Despawn the unrevealed CCW puzzle podium: suppressed so a teammate's switch press can + // reveal it live. + VB_JIGSAW_PICTURE_RESYNC, // Rebuild a lair podium's cached piece state when the synced flags disagree with it. // Romhack port gates VB_JIGGYSCORE_LEVEL_TOTAL, diff --git a/src/port/Network/Anchor/HookHandlers.cpp b/src/port/Network/Anchor/HookHandlers.cpp index 03cad0bf7..59d8059f1 100644 --- a/src/port/Network/Anchor/HookHandlers.cpp +++ b/src/port/Network/Anchor/HookHandlers.cpp @@ -331,6 +331,12 @@ void Anchor::RegisterHooks() { } }); + COND_VB_SHOULD(VB_JIGSAW_PICTURE_RESYNC, EVENT_PRIORITY_NORMAL, isConnected, { + if (Anchor_WorldSyncActive()) { + *should = true; + } + }); + // Lair door remote-open: Door of Grunty's open flag (0xE2) is already set on arrival; key off // visual state (fully open == 0x1B) instead. Other lair doors stay flag-based. COND_VB_SHOULD(VB_LEVELDOOR_REMOTE_OPEN_DONE, EVENT_PRIORITY_NORMAL, isConnected, { diff --git a/src/port/Network/Anchor/JigsawPedestal.cpp b/src/port/Network/Anchor/JigsawPedestal.cpp index df8464c49..7341efcbb 100644 --- a/src/port/Network/Anchor/JigsawPedestal.cpp +++ b/src/port/Network/Anchor/JigsawPedestal.cpp @@ -1,5 +1,6 @@ #include "port/Network/Anchor/JigsawPedestal.h" #include "port/Network/Anchor/Anchor.h" +#include "functions.h" #include #include @@ -38,6 +39,11 @@ void port_jigsawPedestal_release(int32_t id) { if (!JigsawPedestal_SyncActive()) { return; } + // Keep a finished picture's claim until we leave the map: vanilla already refuses to let anyone + // step back on it, and holding covers a teammate whose completion bits are still in flight. + if (jigsawPicture_isJigsawPictureComplete(id)) { + return; + } auto it = sPedestalOwner.find(id); if (it != sPedestalOwner.end() && it->second == anchor->ownClientId) { sPedestalOwner.erase(it); From 13e690bb4481d9367905e5d15eb95b9c84aaba4a Mon Sep 17 00:00:00 2001 From: Malkierian Date: Tue, 4 Aug 2026 19:14:31 -0700 Subject: [PATCH 112/131] Fix retention behavior while cvar is off (store but don't despawn). (#398) Fix transient persistence clearing bleeding out of Anchor. --- .../Fixes/TransientLevelState.cpp | 62 ++++++ .../Enhancements/Retention/JinjoRetention.cpp | 26 ++- .../Enhancements/Retention/NoteRetention.cpp | 209 +++++++++++------- 3 files changed, 203 insertions(+), 94 deletions(-) create mode 100644 src/port/Enhancements/Fixes/TransientLevelState.cpp diff --git a/src/port/Enhancements/Fixes/TransientLevelState.cpp b/src/port/Enhancements/Fixes/TransientLevelState.cpp new file mode 100644 index 000000000..3c81868e2 --- /dev/null +++ b/src/port/Enhancements/Fixes/TransientLevelState.cpp @@ -0,0 +1,62 @@ +// Transient Level State +// +// The per-level stores Anchor replicates (huts, breakables, egg tolls, puzzle steps, carried +// collectibles) are written unconditionally by decomp, but only Anchor's sweep ever cleared +// them — offline, a smashed hut survived a level exit that should have restored it. +// +// Per level, not per map, so sub-area hops keep their state like the actor savestate did. + +#include "port/ShipInit.hpp" +#include "port/Enhancements/Events/PortEnhancements.h" +#include "port/Enhancements/Events/Hooks/Events.h" + +#include "functions.h" +extern "C" { +#include "enums.h" +s32 port_anchor_isWorldSyncActive(void); +} + +void port_breakable_clearForLevel(int32_t levelId); +void port_hutSmash_clearForLevel(int32_t levelId); +void port_eggToll_clearForLevel(int32_t levelId); +void port_puzzleStep_clearForLevel(int32_t levelId); +void port_carriedSync_clearForLevel(int32_t levelId); + +namespace { + +int32_t sCurrentLevel = -1; + +// 0 for maps outside the section table; map_getLevel would deref null on those. +int32_t levelOfMap(int32_t map) { + if (map <= 0 || map >= MAP_NUM_MAPS) { + return 0; + } + return (int32_t)map_getLevel((enum map_e)map); +} + +} // namespace + +void RegisterTransientLevelState_Init() { + REGISTER_LISTENER(OnSaveLoad, EVENT_PRIORITY_NORMAL, [](IEvent*) { sCurrentLevel = -1; }); + + // HIGH so the stores are empty before this event's NORMAL listeners read them for the new + // map (port_breakable_despawnBrokenRestores). + REGISTER_LISTENER(OnMapLoad, EVENT_PRIORITY_HIGH, [](IEvent* event) { + OnMapLoad* ev = (OnMapLoad*)event; + int32_t nextLevel = levelOfMap((int32_t)ev->nextMap); + if (nextLevel == 0 || nextLevel == sCurrentLevel) { + return; + } + sCurrentLevel = nextLevel; + if (port_anchor_isWorldSyncActive()) { + return; + } + port_breakable_clearForLevel(nextLevel); + port_hutSmash_clearForLevel(nextLevel); + port_eggToll_clearForLevel(nextLevel); + port_puzzleStep_clearForLevel(nextLevel); + port_carriedSync_clearForLevel(nextLevel); + }); +} + +static RegisterShipInitFunc initTransientLevelState(RegisterTransientLevelState_Init, {}); diff --git a/src/port/Enhancements/Retention/JinjoRetention.cpp b/src/port/Enhancements/Retention/JinjoRetention.cpp index ea6d980f3..d820e8510 100644 --- a/src/port/Enhancements/Retention/JinjoRetention.cpp +++ b/src/port/Enhancements/Retention/JinjoRetention.cpp @@ -156,7 +156,7 @@ extern "C" void port_jinjoRetention_applyRemoteCollect(int32_t map, int32_t bit, // Called from the actual pickup (__chJinjo_802CDBA8), not broad-phase collision. extern "C" void port_jinjoRetention_onLocalJinjoCollected(int32_t markerId) { - if (!applyEnabled() || !systemActive()) { + if (!systemActive()) { return; } u8 bit = jinjoBitFromMarker(markerId); @@ -232,16 +232,6 @@ void RegisterJinjoRetention_Init() { event->Cancelled = true; }); - // bcopy's scratch-slot save buffer doesn't carry our bits; sync them in. - COND_HOOK(OnSaveFileSave, EVENT_PRIORITY_HIGH, CVAR_VALUE, [](IEvent* event) { - OnSaveFileSave* ev = (OnSaveFileSave*)event; - SaveData* buf = (SaveData*)ev->saveBuffer; - JinjoRetentionSaveData* live = store(); - if (buf != nullptr && live != nullptr && &buf->shipSaveData.jinjoRetention != live) { - buf->shipSaveData.jinjoRetention = *live; - } - }); - COND_VB_SHOULD(VB_OVERRIDE_BUNDLE_SPAWN, EVENT_PRIORITY_NORMAL, CVAR_VALUE, { (void)va_arg(args, int); BundleInfo* bundleInfo = va_arg(args, BundleInfo*); @@ -265,3 +255,17 @@ void RegisterJinjoRetention_Init() { } static RegisterShipInitFunc initJinjoRetention(RegisterJinjoRetention_Init, { CVAR_JINJO_RETENTION }); + +static void RegisterRetentionSaving_Init() { + // bcopy's scratch-slot save buffer doesn't carry our bits; sync them in. + COND_HOOK(OnSaveFileSave, EVENT_PRIORITY_HIGH, true, [](IEvent* event) { + OnSaveFileSave* ev = (OnSaveFileSave*)event; + SaveData* buf = (SaveData*)ev->saveBuffer; + JinjoRetentionSaveData* live = store(); + if (buf != nullptr && live != nullptr && &buf->shipSaveData.jinjoRetention != live) { + buf->shipSaveData.jinjoRetention = *live; + } + }); +} + +static RegisterShipInitFunc initRetentionSaving(RegisterRetentionSaving_Init); diff --git a/src/port/Enhancements/Retention/NoteRetention.cpp b/src/port/Enhancements/Retention/NoteRetention.cpp index 5e716fcfa..48d5ce9d8 100644 --- a/src/port/Enhancements/Retention/NoteRetention.cpp +++ b/src/port/Enhancements/Retention/NoteRetention.cpp @@ -18,6 +18,7 @@ #include #include +#include #include "functions.h" extern "C" { @@ -74,10 +75,22 @@ int32_t noteCounter = 0; std::vector noteActorQueue; std::unordered_map activeNoteSet; +// Notes taken since entering this level: reproduces the prop "taken" bit they lost to actors. +std::unordered_set collectedThisVisit; +int32_t sVisitLevel = -1; + int64_t noteKey(int32_t mapId, int32_t noteIndex) { return ((int64_t)mapId << 32) | (uint32_t)noteIndex; } +// 0 for maps outside the section table; map_getLevel would deref null on those. +int32_t levelOfMap(int32_t map) { + if (map <= 0 || map >= MAP_NUM_MAPS) { + return 0; + } + return (int32_t)map_getLevel((enum map_e)map); +} + using retention::activeSlot; using retention::systemActive; @@ -88,6 +101,12 @@ bool applyEnabled() { return CVAR_VALUE; } +// Rando drives note props on this same VB when they're shuffled, writing *should for every one +// of them — hand the class over rather than race it on listener order. +bool randoOwnsNoteProps() { + return IS_RANDO && RANDO_SAVE_OPTIONS[RO_SHUFFLE_MUSIC_NOTES].optionValue; +} + NoteRetentionSaveData* store() { int32_t slot = activeSlot(); return slot >= 0 ? &gameFile_saveData[slot].shipSaveData.noteRetention : nullptr; @@ -154,7 +173,7 @@ extern "C" void port_noteRetention_getSizeAndPtr(int32_t* size, uint8_t** addr) // Called from the actual pickup (MARKER_5F_MUSIC_NOTE), not broad-phase collision. extern "C" void port_noteRetention_onLocalNoteCollected(void* markerPtr) { - if (!applyEnabled() || !systemActive()) { + if (!systemActive()) { return; } ActorMarker* marker = (ActorMarker*)markerPtr; @@ -177,6 +196,7 @@ extern "C" void port_noteRetention_onLocalNoteCollected(void* markerPtr) { } bool wasCollected = isCollected(mapId, noteIndex); setCollected(mapId, noteIndex); + collectedThisVisit.insert(noteKey(mapId, noteIndex)); activeNoteSet.erase(noteKey(mapId, noteIndex)); if (!wasCollected) { CALL_EVENT(OnCollectibleCollected, ANCHOR_COLLECTIBLE_NOTE, noteIndex); @@ -212,9 +232,14 @@ extern "C" void port_noteRetention_applyRemoteCollect(int32_t mapId, int32_t not // Called from gsworld_load before cube parsing; fires on every re-parse (map load, intra- // level warps). Resets the index counter. extern "C" void port_noteRetention_beginMapLoad(int32_t mapId) { - (void)mapId; noteCounter = 0; noteActorQueue.clear(); + // Sub-area hops stay within the visit; only a real level change lets notes come back. + int32_t level = levelOfMap(mapId); + if (level != sVisitLevel) { + sVisitLevel = level; + collectedThisVisit.clear(); + } } extern "C" void port_noteRetention_onActorsFreed(void) { @@ -242,68 +267,6 @@ extern "C" int32_t port_noteRetention_debugPickLive(int32_t mapId) { } void RegisterNoteRetention_Init() { - COND_VB_SHOULD(VB_OVERRIDE_PROP_SPAWN, EVENT_PRIORITY_NORMAL, CVAR_VALUE, { - s16* spawnPosition = va_arg(args, s16*); - s32 spriteAsset = va_arg(args, s32); - - if (!systemActive() || spriteAsset != kNoteSpriteAsset) { - return; - } - - int32_t mapId = (int32_t)gsworld_getMap(); - int32_t noteIndex = noteCounter++; - if (!indexInRange(mapId, noteIndex)) { - return; // out of addressable range - } - - // We own this note: suppress the static sprite prop. - *should = true; - - if (activeNoteSet.count(noteKey(mapId, noteIndex))) { - return; // a live actor already exists (re-parse) - } - - if (applyEnabled() && isCollected(mapId, noteIndex)) { - return; // already collected and retention on - } - - QueuedNote queued; - queued.pos[0] = spawnPosition[0]; - queued.pos[1] = spawnPosition[1]; - queued.pos[2] = spawnPosition[2]; - queued.mapId = mapId; - queued.noteIndex = noteIndex; - queued.spawned = false; - noteActorQueue.push_back(queued); - }); - - // Flush queued notes into actors. actor_new does not re-fire OnActorSpawn. - COND_HOOK(OnActorSpawn, EVENT_PRIORITY_NORMAL, CVAR_VALUE, [](IEvent* event) { - if (!systemActive() || noteActorQueue.empty()) { - return; - } - for (auto& q : noteActorQueue) { - if (q.spawned) { - continue; - } - int32_t pos[3]; - pos[0] = q.pos[0]; - pos[1] = q.pos[1]; - pos[2] = q.pos[2]; - Actor* note = actor_new(pos, 0, &sumusicNote, ACTOR_FLAG_UNKNOWN_21); - if (note != nullptr) { - note->unk124_6 = 0; - } - ActorMarker* marker = (note != nullptr) ? note->marker : nullptr; - if (marker != nullptr) { - // Key on the marker (stable across the actor's life). - ObjectExtension::GetInstance().Set(marker, NoteRetentionData(q.mapId, q.noteIndex)); - activeNoteSet[noteKey(q.mapId, q.noteIndex)] = marker; - } - q.spawned = true; - } - }); - // Bundle notes continue the map's index counter; identity stored in actor->local. COND_VB_SHOULD(VB_OVERRIDE_BUNDLE_SPAWN, EVENT_PRIORITY_NORMAL, true, { bundle_e bundleId = (bundle_e)va_arg(args, int); @@ -329,8 +292,8 @@ void RegisterNoteRetention_Init() { if (activeNoteSet.count(key)) { return; // a live actor already exists (re-trigger this load) } - if (applyEnabled() && isCollected(mapId, noteIndex)) { - return; // already collected and retention on + if ((applyEnabled() && isCollected(mapId, noteIndex)) || collectedThisVisit.count(key)) { + return; } int32_t pos[3]; @@ -352,20 +315,6 @@ void RegisterNoteRetention_Init() { *actorOut = note; }); - COND_HOOK(OnLoadActorSaveState, EVENT_PRIORITY_NORMAL, CVAR_VALUE, [](IEvent* event) { - OnLoadActorSaveState* ev = (OnLoadActorSaveState*)event; - if (!systemActive() || ev->actor == nullptr) { - return; - } - if ((int32_t)ev->actor->modelCacheIndex != ACTOR_51_MUSIC_NOTE) { - return; - } - if (ev->actor->is_bundle && bundleNoteLocal(ev->actor) != nullptr) { - return; // keep restored bundle notes alive - } - event->Cancelled = true; - }); - // Seed the level's note counter from collected notes. COND_HOOK(OnSetJiggyList, EVENT_PRIORITY_NORMAL, CVAR_VALUE, [](IEvent* event) { OnSetJiggyList* ev = (OnSetJiggyList*)event; @@ -410,8 +359,102 @@ void RegisterNoteRetention_Init() { break; } }); +} - COND_HOOK(OnActorDestroy, EVENT_PRIORITY_NORMAL, CVAR_VALUE, [](IEvent* event) { +static RegisterShipInitFunc initNoteRetention(RegisterNoteRetention_Init, { CVAR_NOTE_RETENTION }); + +// Always registered: the sprite-prop pickup path has no marker to record through, so notes must +// be actors even when the enhancement isn't applying. Only the suppression below is gated. +static void RegisterRetentionSaving_Init() { + REGISTER_LISTENER(OnSaveLoad, EVENT_PRIORITY_NORMAL, [](IEvent*) { + collectedThisVisit.clear(); + sVisitLevel = -1; + }); + + // The cube parse rebuilds static notes every map load, so a restored copy would double them + // on a sub-area round trip. Bundle notes have no parse to come from and must survive. + REGISTER_LISTENER(OnLoadActorSaveState, EVENT_PRIORITY_NORMAL, [](IEvent* event) { + OnLoadActorSaveState* ev = (OnLoadActorSaveState*)event; + if (!systemActive() || ev->actor == nullptr) { + return; + } + if ((int32_t)ev->actor->modelCacheIndex != ACTOR_51_MUSIC_NOTE) { + return; + } + if (ev->actor->is_bundle && bundleNoteLocal(ev->actor) != nullptr) { + return; // keep restored bundle notes alive + } + event->Cancelled = true; + }); + + COND_VB_SHOULD(VB_OVERRIDE_PROP_SPAWN, EVENT_PRIORITY_NORMAL, true, { + s16* spawnPosition = va_arg(args, s16*); + s32 spriteAsset = va_arg(args, s32); + + if (!systemActive() || spriteAsset != kNoteSpriteAsset) { + return; + } + + int32_t mapId = (int32_t)gsworld_getMap(); + int32_t noteIndex = noteCounter++; + if (!indexInRange(mapId, noteIndex)) { + return; // out of addressable range + } + + // Counter already advanced, so indices stay aligned; rando spawns these itself. + if (randoOwnsNoteProps()) { + return; + } + + // We own this note: suppress the static sprite prop. + *should = true; + + if (activeNoteSet.count(noteKey(mapId, noteIndex))) { + return; // a live actor already exists (re-parse) + } + + if ((applyEnabled() && isCollected(mapId, noteIndex)) || collectedThisVisit.count(noteKey(mapId, noteIndex))) { + return; + } + + QueuedNote queued; + queued.pos[0] = spawnPosition[0]; + queued.pos[1] = spawnPosition[1]; + queued.pos[2] = spawnPosition[2]; + queued.mapId = mapId; + queued.noteIndex = noteIndex; + queued.spawned = false; + noteActorQueue.push_back(queued); + }); + + // Flush queued notes into actors. actor_new does not re-fire OnActorSpawn. + COND_HOOK(OnActorSpawn, EVENT_PRIORITY_NORMAL, true, [](IEvent* event) { + if (!systemActive() || noteActorQueue.empty()) { + return; + } + for (auto& q : noteActorQueue) { + if (q.spawned) { + continue; + } + int32_t pos[3]; + pos[0] = q.pos[0]; + pos[1] = q.pos[1]; + pos[2] = q.pos[2]; + Actor* note = actor_new(pos, 0, &sumusicNote, ACTOR_FLAG_UNKNOWN_21); + if (note != nullptr) { + note->unk124_6 = 0; + } + ActorMarker* marker = (note != nullptr) ? note->marker : nullptr; + if (marker != nullptr) { + // Key on the marker (stable across the actor's life). + ObjectExtension::GetInstance().Set(marker, NoteRetentionData(q.mapId, q.noteIndex)); + activeNoteSet[noteKey(q.mapId, q.noteIndex)] = marker; + } + q.spawned = true; + } + }); + + COND_HOOK(OnActorDestroy, EVENT_PRIORITY_NORMAL, true, [](IEvent* event) { OnActorDestroy* ev = (OnActorDestroy*)event; if (ev->actor == nullptr) { return; @@ -430,7 +473,7 @@ void RegisterNoteRetention_Init() { }); // bcopy's scratch-slot save buffer doesn't carry our bits; sync them in. - COND_HOOK(OnSaveFileSave, EVENT_PRIORITY_HIGH, CVAR_VALUE, [](IEvent* event) { + COND_HOOK(OnSaveFileSave, EVENT_PRIORITY_HIGH, true, [](IEvent* event) { OnSaveFileSave* ev = (OnSaveFileSave*)event; SaveData* buf = (SaveData*)ev->saveBuffer; NoteRetentionSaveData* live = store(); @@ -440,4 +483,4 @@ void RegisterNoteRetention_Init() { }); } -static RegisterShipInitFunc initNoteRetention(RegisterNoteRetention_Init, { CVAR_NOTE_RETENTION }); +static RegisterShipInitFunc initRetentionSaving(RegisterRetentionSaving_Init); From a8809e7c3d980a941ea8f6d836f5ebf24280122f Mon Sep 17 00:00:00 2001 From: Jeod <47716344+JeodC@users.noreply.github.com> Date: Tue, 4 Aug 2026 23:23:57 -0400 Subject: [PATCH 113/131] Language pack modding doc update and Torch bump (#401) * Update lang pack documentation * Bump Torch --- Torch | 2 +- docs/modding/LANGUAGE PACKS.md | 69 ++++++++++++++++++++++++---------- 2 files changed, 50 insertions(+), 21 deletions(-) diff --git a/Torch b/Torch index 270279d41..f89e94467 160000 --- a/Torch +++ b/Torch @@ -1 +1 @@ -Subproject commit 270279d4193d9a09b4525903f5f0471dd3d203fd +Subproject commit f89e944671b406615246685a5a60b65e48ab01f8 diff --git a/docs/modding/LANGUAGE PACKS.md b/docs/modding/LANGUAGE PACKS.md index 3ce7f7d3c..ef42bfc33 100644 --- a/docs/modding/LANGUAGE PACKS.md +++ b/docs/modding/LANGUAGE PACKS.md @@ -8,6 +8,19 @@ This guide walks through building one pack end to end: a **Spanish** translation ## 1. Export the text to editable YAML +Pack mode has to be on **before** you export. In the repo's `config.yml`, find your base ROM's entry (keyed by ROM hash) and add the `dialog_pack` flag to its `config:` block, pointing `output.binary` at your pack's filename: + +```yaml +config: + dialog_pack: true # add + output: + binary: bkes.o2r # was bk.o2r; the pack's filename +``` + +This is the one edit the pack flow makes to the base game's config, and it also redirects the normal game build - so **revert it once your pack is built**. + +Now run the export: + ``` torch modding export -s -d ``` @@ -20,7 +33,13 @@ This decodes every asset into an editable form under `/src/assets/asset | `lang/us/quizq/` | Grunty furnace quiz questions | 170 | | `lang/us/gruntyq/` | Final-boss Grunty questions | 30 | -You only edit the files you want to translate. Anything you leave alone stays in English. Rename the `us` folder to your country code (`es` for this example) and delete whatever asset yamls you won't be modifying. +You only edit the files you want to translate. Anything you leave alone stays in English. Next, edit the country code in **three places**: + +1. the folder name - `lang/us/` -> `lang/es/` (`es` for this example); +2. the top-level key inside each yaml you keep - `lang/us/dialog/ASSET_…` -> `lang/es/dialog/ASSET_…`; +3. both sides of every `modding.yml` entry - `assets/lang/us/…: assets/lang/us/….yaml` -> `assets/lang/es/…`. + +Then delete the asset yamls you won't be modifying and prune their `modding.yml` entries to match. --- @@ -58,7 +77,9 @@ lang/es/quizq/ASSET_1213_FF_QUIZ_QUESTION: - [0x83, 0xfd, 0x6c, "75"] ``` -Translate the question lines and the answer text. On each option, **keep the two bytes before the string** (`0xfd, 0x6c`) as they bind the answer to its slot. (Here `$` and `%` are font slots this pack draws as `¿` and `Ã` once its font is in place; see below.) +Translate the question lines and the answer text. On each option, **keep the two bytes before the string** (`0xfd, 0x6c`) as they bind the answer to its slot; the importer rejects an option row without them. Grunty questions (`gruntyq/`) use the same shape. (Here `$` and `%` are font slots this pack draws as `¿` and `Ã` once its font is in place; see below.) + +One yaml hygiene rule: always put double quotes around your translations - an unquoted `,`, `:` or `#` breaks the yaml when the pack is imported. ### How the text is encoded @@ -70,7 +91,7 @@ The dialog/quiz/grunty font (`0x6EB`) is a flat, contiguous sheet beginning at b ! " # $ % & ' ( ) * + , - . / 0-9 : ; < = > ? @ A-Z [ \ ] ^ ``` -The stock font holds only the ASCII set - `A–Z`, `0–9`, and punctuation. **None of Spanish's accents are in it**: `¡ ¿ à É à Ó Ú Ñ` all live in byte positions the stock font draws as ASCII symbols (`#`, `%`, `&`, …). So each accent has to be **added** to the font, and you type it as whatever slot you put it in. Our Spanish pack repaints eight symbol slots - `#` `$` `%` `&` `(` `)` `*` `+` → `¡` `¿` `Ã` `É` `Ã` `Ó` `Ú` `Ñ` (full table in [#5](#5-fonts-and-glyphs)). That's why `COMPA+ERO` renders *COMPAÑERO* (`+` = Ñ) and `$EST%S` renders *¿ESTÃS*. A `\xNN` escape works for any byte inside a double-quoted string, if you'd rather not type the symbol. +The stock font holds only the ASCII set - `A–Z`, `0–9`, and punctuation. **None of Spanish's accents are in it**: `¡ ¿ à É à Ó Ú Ñ` all live in byte positions the stock font draws as ASCII symbols (`#`, `%`, `&`, …). So each accent has to be **added** to the font, and you type it as whatever slot you put it in. Our Spanish pack repaints eight symbol slots - `#` `$` `%` `&` `(` `)` `*` `+` → `¡` `¿` `Ã` `É` `Ã` `Ó` `Ú` `Ñ` (full table in [#5](#5-fonts-and-glyphs)). That's why `COMPA+ERO` renders *COMPAÑERO* (`+` = Ñ) and `$EST%S` renders *¿ESTÃS*. A `\xNN` escape works for any byte inside a **single-quoted** string (`'\xFD'` style - the importer decodes them, and it's the form the exporter itself emits for text carrying inline control codes). Use it for slots past `0x7E`, an extended sheet's high glyphs included; a literal backslash in such a string is `\\`. Don't put high escapes in *double*-quoted strings - there the yaml parser processes them itself, which is fine up to `\x7F` but re-encodes `\x80`–`\xFF` as two UTF-8 bytes, desyncing the text. The same goes for lowercase `a–z` and any non-Latin script - no stock glyph, so you add one. There are two ways to add glyphs, both covered in [#5 Fonts and glyphs](#5-fonts-and-glyphs): @@ -83,7 +104,7 @@ Either way, you type the **slot**, and the replacement font makes it render. Pic ## 3. Declare the language -Two small things turn an ordinary import into a language pack: a header that names the language, and a config flag that puts the build into pack mode. +Two small things turn an ordinary import into a language pack: the `dialog_pack` config flag you already set in [step 1](#1-export-the-text-to-editable-yaml), and a header that names the language. ### Name the language @@ -98,7 +119,7 @@ strings: # optional - see "Hardcoded UI strings" below "": "" ``` -Torch turns this into the `langinfo` manifest that Lighthouse reads to build its language menu. Because it lives in your pack's source, you never touch the base game's canonical asset config. The fields: +Torch turns this into the `langinfo` manifest that Lighthouse reads to build its language menu. Because it lives in your pack's source, the language list never touches the base game's asset yamls. The fields: - **`name`** - what shows in the options menu. This label is drawn by the PC menu (not the in-game font), so the native spelling with real accents is fine here. - **`index`** - the language's slot; `0` for a single-language pack. @@ -178,18 +199,9 @@ strings: One limit comes with this approach: **word order is fixed by the engine.** The number always precedes its noun and the prefix always precedes the game number, so a language that needs the count *after* the noun can't reorder it here. The numbers and the clock are rendered by the engine and aren't translatable - only the words around them are. And the rebuild only happens for a pack that actually supplies these `strings:`; a base US/PAL game keeps its own built-in line. -### Turn on pack mode - -The second piece is a `dialog_pack` flag in the config entry, plus an output name: +### Pack mode -```yaml -config: - dialog_pack: true - output: - binary: bkes.o2r -``` - -`dialog_pack: true` trims the build down to just the translated assets, prefixes them under `lang//`, and builds the `langinfo` manifest. +The `dialog_pack: true` flag was already set back in [step 1](#1-export-the-text-to-editable-yaml) - the export needs it too. At import time it's what trims the build down to just the translated assets, prefixes them under `lang//`, and builds the `langinfo` manifest. --- @@ -199,7 +211,7 @@ config: torch modding import o2r -s -d ``` -The importer walks the asset list: your edited yamls are re-encoded from ``, everything else parses straight from the ROM, and `dialog_pack` strips the result down to the language assets plus `langinfo`. The finished pack lands in **`mods/~lang/`** automatically, named from your `output.binary` - `bkes.o2r` in our case. Copy that into the game's `mods/~lang/` folder and it shows up in the options menu. +The importer walks the asset list: your edited yamls are re-encoded from ``, everything else parses straight from the ROM, and `dialog_pack` strips the result down to the language assets plus `langinfo`. The finished pack lands in **`/mods/~lang/`** automatically, named from your `output.binary` - `bkes.o2r` in our case. Copy that into Lighthouse's `mods/~lang/` folder and it shows up in the options menu. --- @@ -256,15 +268,32 @@ You can still ship that content by declaring it as an **additive** asset - a slo On import, `dialog_pack` scans your `modding.yml` for any `lang//{dialog,quizq,gruntyq,sprite}/ASSET_` the base table didn't provide and folds it into the pack. Use the **canonical (v1.0) id** for the slot (`0x11CA` for the Motzand credit) no matter which region your base ROM is. -The `sprite` folder also covers **world-name banners** (one per world, at `0x1600`+). Provide them as RGBA32 intensity-mask sprites - the same format the JP cart uses - and the runtime tints each with its world's bold-font sphere colour, rendering titles as graphics instead of bold-font text. - This matters for the parade because Lighthouse keys the alternate (PAL/JP-style) parade on the *presence* of `0x11CA` in the active pack, not on the base version. A player on a plain US v1.0 `bk.o2r` who loads a pack that supplies `0x11CA` gets the Motzand parade order **and** the translated credit, while the rest of the game keeps using US assets. Cover `0x11CA` and the parade switches; omit it and the US parade is left untouched. +### World-name banners + +The `sprite` folder covers the pause-menu **world-name banners** - the pre-rendered titles the JP release draws on its totals pages instead of bold-font text. There are twelve, one per menu page, and a pack ships them as additive sprites at `0x1600 + page`: + +| Id | Page | Id | Page | +|---|---|---|---| +| `0x1600` | Totals overview | `0x1606` | Bubblegloop Swamp | +| `0x1601` | Spiral Mountain | `0x1607` | Freezeezy Peak | +| `0x1602` | Gruntilda's Lair | `0x1608` | Gobi's Valley | +| `0x1603` | Mumbo's Mountain | `0x1609` | Mad Monster Mansion | +| `0x1604` | Treasure Trove Cove | `0x160A` | Rusty Bucket Bay | +| `0x1605` | Clanker's Cavern | `0x160B` | Click Clock Wood | + +Each page is checked on its own: ship any subset, and a page without a banner keeps drawing its name as bold-font text. A `script: 0` pack can banner just the handful of names its repainted font can't spell and leave the rest to text. Declare each one like any other additive asset (the yaml under `sprite/`, plus its `modding.yml` line). + +The sprite itself is a single-frame **RGBA32 intensity mask** - the same format as the JP originals. Draw the title as white-on-transparent artwork, not pre-coloured text: at draw time the runtime refills the mask live with the world's swirling bold-font sphere texture (the highlighted current-world page gets its own sphere; other pages the default fill). The banner renders centered on the page header at its native size and is only scaled down if it's wider than ~92% of the screen, so any sensible resolution works. + +(A `script: 1` pack that reuses the JP cart's own banners keeps their native ids - `0xE2C`–`0xE37` re-point to the `0x1600` slots automatically. `0xE38` is not a banner; it's the default fill texture the masks are filled with.) + --- ## 7. HD fonts & textures (optional) -Everything above produces an **SD** pack - the only kind Torch builds. Players running an HD texture pack need high-resolution versions of whatever you replaced, and those are made with a different tool: [Retro](https://github.com/HarbourMasters/retro), HarbourMasters' OTR/O2R generation tool. The two pipelines are separate - Torch doesn't build HD assets, and Retro doesn't build the SD pack. +Everything above produces an **SD** pack. Players running an HD texture pack need high-resolution versions of whatever you replaced, and those are made with a different tool: [Retro](https://github.com/HarbourMasters/retro), HarbourMasters' OTR/O2R generation tool. The two tiers live at different paths inside the o2r, scoped by language: From 04ac1b4952a34ed074f8c994158a988353e35318 Mon Sep 17 00:00:00 2001 From: Jeod <47716344+JeodC@users.noreply.github.com> Date: Tue, 4 Aug 2026 23:24:07 -0400 Subject: [PATCH 114/131] Batch of romhack bugfixes (#380) * CTC: fix the rock raising itself on map reload * Debugging: add a flag tracer to dev tools * Fix bottles tutorials gated on map instead of level * Anchor: gate sync on singleplayer and romhacks for some cases * Anchor: consolidate remoteOpens into helper remoteCue and add missing * Patch romhack: used ability flags and anchor empty honeycomb sync rework * Fix applying bkcf to wrong warp function and clean up Dreamie no-op * BBB and Gruntch flip UsedAbilities bits * Finish reimplementing Gruntch features * Mark Gruntch as fully supported * Add launch arg handling for romhacks --- CMakeLists.txt | 4 + cmake/GenerateFlagNames.cmake | 123 ++++++ src/CCW/ch/seasonswitchdoors.c | 12 +- src/core2/abilityprogress.c | 18 +- src/core2/ba/ba_lookdir.c | 6 +- src/core2/bs/bEggAss.c | 5 +- src/core2/bs/bEggHead.c | 16 +- src/core2/ch/honeycomb.c | 33 -- src/core2/gameSelect.c | 1 - src/core2/gameloop.c | 1 + src/core2/map/cutscene_skip.c | 15 +- src/lair/lairspawnqueue.c | 108 +++++- src/port/DevTools/FlagTracer.cpp | 243 ++++++++++++ src/port/Engine.cpp | 23 +- src/port/Enhancements/Events/Hooks/Events.h | 3 + .../Events/Hooks/List/EngineEvent.h | 1 + .../Enhancements/Events/PortEnhancements.cpp | 1 + .../Enhancements/Retention/NoteRetention.cpp | 30 +- src/port/Enhancements/Retention/WormSync.cpp | 21 +- src/port/LaunchArgs.cpp | 148 +++++++ src/port/LaunchArgs.h | 13 + src/port/Network/Anchor/Anchor.cpp | 29 ++ src/port/Network/Anchor/Anchor.h | 1 + src/port/Network/Anchor/HookHandlers.cpp | 5 +- .../Network/Anchor/Packets/PuzzleStep.cpp | 96 ++++- .../Network/Anchor/Packets/ScopedFlag.cpp | 5 +- .../Network/Anchor/Packets/ScopedState.cpp | 5 +- src/port/Network/Anchor/Packets/SetFlag.cpp | 4 +- src/port/Patches/Patches.h | 9 +- src/port/Romhack/RomhackTable.h | 2 +- src/port/Romhack/Shared/HackShared.cpp | 21 + src/port/Romhack/Shared/HackShared.h | 15 + src/port/Romhack/Shared/ProximityDialogs.cpp | 5 +- src/port/Romhack/Shared/StealthNoise.cpp | 362 ++++++++++++++++++ src/port/Romhack/Shared/StealthNoise.h | 20 + src/port/Romhack/Specific/BubblingBog.cpp | 2 + src/port/Romhack/Specific/Dreamie.cpp | 3 +- src/port/Romhack/Specific/TheGruntch.cpp | 175 ++++++++- src/port/UI/DeveloperTools/GameplayTools.cpp | 32 ++ 39 files changed, 1490 insertions(+), 126 deletions(-) create mode 100644 cmake/GenerateFlagNames.cmake create mode 100644 src/port/DevTools/FlagTracer.cpp create mode 100644 src/port/LaunchArgs.cpp create mode 100644 src/port/LaunchArgs.h create mode 100644 src/port/Romhack/Shared/StealthNoise.cpp create mode 100644 src/port/Romhack/Shared/StealthNoise.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 86bebe71d..b425c8ead 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -188,12 +188,16 @@ configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/properties.h.in ${CMAKE_CURRENT_SOUR set(Header_Files "resource.h") source_group("include" FILES ${Header_Files}) +# Flag enum name tables for the Flag Tracer, derived from include/enums.h. +include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/GenerateFlagNames.cmake) + # Include directories include_directories( "${PROJECT_SOURCE_DIR}" "${PROJECT_SOURCE_DIR}/include" "${PROJECT_SOURCE_DIR}/lib/ultralib/include" "${PROJECT_SOURCE_DIR}/src" + "${CMAKE_BINARY_DIR}/generated" ) # Collect source files to build the executable diff --git a/cmake/GenerateFlagNames.cmake b/cmake/GenerateFlagNames.cmake new file mode 100644 index 000000000..a2b9388ef --- /dev/null +++ b/cmake/GenerateFlagNames.cmake @@ -0,0 +1,123 @@ +# Lifts the flag enums out of include/enums.h into a lookup table for the Flag +# Tracer. Generated into the build tree so it can't drift from enums.h. + +function(_flagnames_parse_enum ENUM_NAME OUT_VAR) + set(_entries "") + set(_in_enum FALSE) + set(_next 0) + + foreach(_line IN LISTS FLAGNAMES_LINES) + if(NOT _in_enum) + if(_line MATCHES "^[ \t]*enum[ \t]+${ENUM_NAME}[ \t]*(\\{)?[ \t]*$") + set(_in_enum TRUE) + endif() + continue() + endif() + + if(_line MATCHES "^[ \t]*\\}") + break() + endif() + + string(REGEX REPLACE "//.*$" "" _clean "${_line}") + string(REGEX REPLACE "/\\*.*\\*/" "" _clean "${_clean}") + + if(_clean MATCHES "^[ \t]*([A-Za-z_][A-Za-z0-9_]*)[ \t]*(=[ \t]*(0[xX][0-9a-fA-F]+|[0-9]+))?[ \t]*,?[ \t]*$") + set(_ident "${CMAKE_MATCH_1}") + set(_explicit "${CMAKE_MATCH_3}") + if(NOT _explicit STREQUAL "") + math(EXPR _next "${_explicit}") + endif() + list(APPEND _entries " { ${_next}, \"${_ident}\" },") + math(EXPR _next "${_next} + 1") + endif() + endforeach() + + if(_entries STREQUAL "") + message(FATAL_ERROR "GenerateFlagNames: no entries parsed for 'enum ${ENUM_NAME}'! Has enums.h changed shape?") + endif() + + string(REPLACE ";" "\n" _joined "${_entries}") + set(${OUT_VAR} "${_joined}" PARENT_SCOPE) +endfunction() + +function(_flagnames_emit_table ENUM_NAME TABLE_NAME OUT_VAR) + _flagnames_parse_enum("${ENUM_NAME}" _rows) + set(${OUT_VAR} + "// ${ENUM_NAME}\nstatic const FlagName ${TABLE_NAME}[] = {\n${_rows}\n};\n" + PARENT_SCOPE) +endfunction() + +set(FLAGNAMES_HEADER "${CMAKE_BINARY_DIR}/generated/FlagNames.generated.h") +set(FLAGNAMES_SOURCE "${CMAKE_CURRENT_SOURCE_DIR}/include/enums.h") + +file(STRINGS "${FLAGNAMES_SOURCE}" FLAGNAMES_LINES) + +set(FLAGNAMES_BODY +"// GENERATED at configure time by cmake/GenerateFlagNames.cmake from include/enums.h. +#pragma once + +struct FlagName { + int index; + const char* name; +}; +") + +foreach(_pair "file_progress_e:kFileProgressNames" "volatile_flags_e:kVolatileNames" "level_flags_e:kLevelNames") + string(REPLACE ":" ";" _pair "${_pair}") + list(GET _pair 0 _enum) + list(GET _pair 1 _table) + _flagnames_emit_table("${_enum}" "${_table}" _table_text) + string(APPEND FLAGNAMES_BODY "\n${_table_text}") +endforeach() + +set(FLAGNAMES_MAP_GROUPS + "sm_specific_flags:kSmNames:0xB" + "mm_specific_flags:kMmNames:0x1" + "ttc_specific_flags:kTtcNames:0x2" + "bgs_specific_flags:kBgsNames:0x4" + "fp_specific_flags:kFpNames:0x5" + "mmm_specific_flags:kMmmNames:0xA" + "rbb_main_specific_flags:kRbbMainNames:0x9" + "rbb_boat_room_specific_flags:kRbbBoatNames:0x9" + "ccw_zubba_specific_flags:kCcwZubbaNames:0x8" + "ccw_winter_specific_flags:kCcwWinterNames:0x8" + "lair_specific_flags:kLairNames:0x6" +) + +set(FLAGNAMES_GROUP_ROWS "") +foreach(_entry IN LISTS FLAGNAMES_MAP_GROUPS) + string(REPLACE ":" ";" _parts "${_entry}") + list(GET _parts 0 _enum) + list(GET _parts 1 _table) + list(GET _parts 2 _level) + _flagnames_emit_table("${_enum}" "${_table}" _table_text) + string(APPEND FLAGNAMES_BODY "\n${_table_text}") + list(APPEND FLAGNAMES_GROUP_ROWS + " { ${_level}, ${_table}, (int)(sizeof(${_table}) / sizeof(${_table}[0])) },") +endforeach() + +string(REPLACE ";" "\n" FLAGNAMES_GROUP_ROWS "${FLAGNAMES_GROUP_ROWS}") +string(APPEND FLAGNAMES_BODY +" +// Map-specific lookup needs the loaded level to disambiguate. +struct MapFlagGroup { + int level; + const FlagName* names; + int count; +}; + +static const MapFlagGroup kMapFlagGroups[] = { +${FLAGNAMES_GROUP_ROWS} +}; +") + +set(_existing "") +if(EXISTS "${FLAGNAMES_HEADER}") + file(READ "${FLAGNAMES_HEADER}" _existing) +endif() +if(NOT _existing STREQUAL "${FLAGNAMES_BODY}") + file(WRITE "${FLAGNAMES_HEADER}" "${FLAGNAMES_BODY}") + message(STATUS "Generated ${FLAGNAMES_HEADER}") +endif() + +set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS "${FLAGNAMES_SOURCE}") diff --git a/src/CCW/ch/seasonswitchdoors.c b/src/CCW/ch/seasonswitchdoors.c index ac19d4047..9882d0946 100644 --- a/src/CCW/ch/seasonswitchdoors.c +++ b/src/CCW/ch/seasonswitchdoors.c @@ -142,8 +142,10 @@ void chSeasonSwitch_update(Actor *this) { } if (!this->volatile_initialized) { if (fileProgressFlag_get(this->unk10_12 + FILEPROG_8B_CCW_SPRING_OPEN)) { - actor_playAnimationOnce(this); - subaddie_set_state_with_direction(this, CH_CCW_SEASON_SWITCH_DOOR_STATE_4_NO_COLLISION, 0.999f, 1); + if (EventSystem_Should(VB_CCW_SEASON_SWITCH_PRESSED_INIT, true, this)) { + actor_playAnimationOnce(this); + subaddie_set_state_with_direction(this, CH_CCW_SEASON_SWITCH_DOOR_STATE_4_NO_COLLISION, 0.999f, 1); + } actor_collisionOff(this); } else { marker_setCollisionScripts(this->marker, NULL, &chSeasonSwitch_pressed, NULL); @@ -209,7 +211,11 @@ void chSeasonSwitchDoors_update(Actor *this) { this->unk1C[0] = this->position[0]; this->unk1C[1] = this->position[1]; this->unk1C[2] = this->position[2]; - this->unk1C[1] += 250.0f; + // [port] A savestate-restored door comes back at its raised position with + // volatile_initialized cleared. + if (this->state != CH_CCW_SEASON_SWITCH_DOOR_STATE_3_RAISED) { + this->unk1C[1] += 250.0f; + } this->volatile_initialized = true; if (fileProgressFlag_get(this->unk10_12 + FILEPROG_8B_CCW_SPRING_OPEN)) { diff --git a/src/core2/abilityprogress.c b/src/core2/abilityprogress.c index 9a6fab42f..5d08de3a5 100644 --- a/src/core2/abilityprogress.c +++ b/src/core2/abilityprogress.c @@ -14,6 +14,12 @@ static struct { #define abilityprogress_learnedAbilities abilityprogress.learned #define abilityprogress_usedAbilities abilityprogress.used +// [port] The tutorial's flags and dialogs belong to Spiral Mountain, but a romhack may +// place it in any map of that level, so gate on the level rather than one map id. +static s32 inSpiralMountain(void){ + return map_getLevel(gsworld_getMap()) == LEVEL_B_SPIRAL_MOUNTAIN; +} + void ability_use(s32 arg0){ s32 sp2C; s32 sp28; @@ -27,32 +33,32 @@ void ability_use(s32 arg0){ switch(arg0){ case ABILITY_USED_JUMP: // [port] guard with SM check — flags collide with map-specific usage in other worlds (e.g. BGS switches) - if (gsworld_getMap() == MAP_1_SM_SPIRAL_MOUNTAIN) + if (inSpiralMountain()) mapSpecificFlags_set(8, true); sp28 = 1; break; case ABILITY_USED_FLAP: - if (gsworld_getMap() == MAP_1_SM_SPIRAL_MOUNTAIN) + if (inSpiralMountain()) mapSpecificFlags_set(9, true); sp28 = 1; break; case ABILITY_USED_FLIP: - if (gsworld_getMap() == MAP_1_SM_SPIRAL_MOUNTAIN) + if (inSpiralMountain()) mapSpecificFlags_set(0xa, true); sp28 = 1; break; case ABILITY_USED_SWIM: - if(gsworld_getMap() == MAP_1_SM_SPIRAL_MOUNTAIN){ + if(inSpiralMountain()){ sp2C = ASSET_DFC_BOTTLES_UNDERWATER_TUTORIAL; } break; case ABILITY_USED_CLIMB: - if(gsworld_getMap() == MAP_1_SM_SPIRAL_MOUNTAIN){ + if(inSpiralMountain()){ sp2C = ASSET_E02_DIALOG_BOTTLES_CLIMB_OTHER; } break; case ABILITY_USED_BEAK_BARGE: - if(gsworld_getMap() == MAP_1_SM_SPIRAL_MOUNTAIN){ + if(inSpiralMountain()){ sp2C = ASSET_E05_DIALOG_BOTTLES_KAZOOIE_BARGE; } break; diff --git a/src/core2/ba/ba_lookdir.c b/src/core2/ba/ba_lookdir.c index c9c114fe0..0a30418f7 100644 --- a/src/core2/ba/ba_lookdir.c +++ b/src/core2/ba/ba_lookdir.c @@ -690,9 +690,13 @@ void func_8028F408(f32 arg0[3]){ } bool func_8028F428(s32 arg0, ActorMarker *marker) { + s32 handled = 2; func_80296CB4(arg0); func_80296CA8(marker); - return bs_checkInterrupt(BS_INTR_24) == 2; + if (EventSystem_Should(VB_BUMP_REBOUNDS_PLAYER, true, marker)) { + handled = bs_checkInterrupt(BS_INTR_24); + } + return handled == 2; } bool func_8028F45C(s32 arg0, f32 arg1[3]) { diff --git a/src/core2/bs/bEggAss.c b/src/core2/bs/bEggAss.c index e55b3724e..8d92bda7d 100644 --- a/src/core2/bs/bEggAss.c +++ b/src/core2/bs/bEggAss.c @@ -40,7 +40,10 @@ void bseggass_update(void) { } if (has_eggs) { if (anctrl_isAt(plyr_mvmt, 0.3837f)) { - func_8030E760(SFX_3E_POOP_NOISE, 1.4f, 28000); + // [port] Romhack gate + s32 rate = 28000; + EventSystem_Should(VB_EGG_FIRE_SFX, true, 2, &rate); + func_8030E760(SFX_3E_POOP_NOISE, 1.4f, rate); commonParticle_new(COMMON_PARTICLE_4_EGG_ASS, 1); item_dec(ITEM_D_EGGS); ability_use(7); diff --git a/src/core2/bs/bEggHead.c b/src/core2/bs/bEggHead.c index 322d79864..9651e0b00 100644 --- a/src/core2/bs/bEggHead.c +++ b/src/core2/bs/bEggHead.c @@ -42,11 +42,19 @@ void bsegghead_update(void) { func_80346C10((enum bs_e *)&sp28, -1, 0, ITEM_D_EGGS, 0); } if (has_eggs) { - if (anctrl_isAt(aCtrl, 0.1f)) - func_8030E760(SFX_46_KAZOOIE_CHOKING_UP, 1.0f, 0x7fff); + // [port] Romhack gate: listeners may retune the sample rate and hook the + // egg noise into a stealth meter. + if (anctrl_isAt(aCtrl, 0.1f)) { + s32 rate = 0x7fff; + EventSystem_Should(VB_EGG_FIRE_SFX, true, 0, &rate); + func_8030E760(SFX_46_KAZOOIE_CHOKING_UP, 1.0f, rate); + } - if (anctrl_isAt(aCtrl, 0.4f)) - func_8030E760(SFX_57_KAZOOIE_HEGH, 1.0f, 0x7fff); + if (anctrl_isAt(aCtrl, 0.4f)) { + s32 rate = 0x7fff; + EventSystem_Should(VB_EGG_FIRE_SFX, true, 1, &rate); + func_8030E760(SFX_57_KAZOOIE_HEGH, 1.0f, rate); + } if (anctrl_isAt(aCtrl, 0.4704f)){ commonParticle_new(COMMON_PARTICLE_1_EGG_HEAD, 1); diff --git a/src/core2/ch/honeycomb.c b/src/core2/ch/honeycomb.c index fb5cc016b..dcf803337 100644 --- a/src/core2/ch/honeycomb.c +++ b/src/core2/ch/honeycomb.c @@ -136,21 +136,6 @@ void chHoneycomb_update(Actor *this){ } }//L802CA098 - { - s32 gateFlag = -1; - if(local->uid == HONEYCOMB_B_GV_CACTUS) gateFlag = 0xd; - else if(local->uid == HONEYCOMB_F_RBB_BOAT_HOUSE) gateFlag = 0; - if(gateFlag >= 0){ - if(!mapSpecificFlags_get(gateFlag)){ - this->unk58_0 = false; - actor_collisionOff(this); - return; - } - this->unk58_0 = true; - actor_collisionOn(this); - } - } - if(gsworld_getMap() == MAP_27_FP_FREEZEEZY_PEAK){ if(maSlalom_isActive()){ this->unk58_0 = false; @@ -175,24 +160,6 @@ void chHoneycomb_update(Actor *this){ } } -extern void __baMarker_8028BA00(s32); -void chHoneycomb_netRevealFromSwitch(void){ - s32 uid = -1; - - switch(gsworld_getMap()){ - case MAP_12_GV_GOBIS_VALLEY: - if(mapSpecificFlags_get(0xD)) uid = HONEYCOMB_B_GV_CACTUS; - break; - case MAP_31_RBB_RUSTY_BUCKET_BAY: - if(mapSpecificFlags_get(0)) uid = HONEYCOMB_F_RBB_BOAT_HOUSE; - break; - default: - break; - } - if(uid < 0 || honeycombscore_get(uid)) return; - __baMarker_8028BA00(uid); -} - enum honeycomb_e func_802CA1C4(Actor *this){ ActorLocal_EmptyHoneycomb *local = (ActorLocal_EmptyHoneycomb *)&this->local; return local->uid; diff --git a/src/core2/gameSelect.c b/src/core2/gameSelect.c index 7f2dc02cb..8238aae99 100644 --- a/src/core2/gameSelect.c +++ b/src/core2/gameSelect.c @@ -468,7 +468,6 @@ void gameSelect_update(Actor *this){ timedFunc_set_3(0.0f, (GenFunction_3)transitionToMap, newGameMap, 0, 1); if (port_getRomhackKnowAllMoves() >= 0) { ability_setAllLearned(-1); - ability_setAllUsed(-1); } } } diff --git a/src/core2/gameloop.c b/src/core2/gameloop.c index acb47c9cd..c48c00169 100644 --- a/src/core2/gameloop.c +++ b/src/core2/gameloop.c @@ -179,6 +179,7 @@ void func_802E39D0(Gfx **gfx, Mtx **mtx, Vtx **vtx, s32 framebuffer_idx, bool ar } if (!capturing) { + CALL_EVENT(OnHudDraw, gfx, mtx, vtx); printbuffer_draw(gfx, mtx, vtx); } diff --git a/src/core2/map/cutscene_skip.c b/src/core2/map/cutscene_skip.c index 18155463f..32cf24111 100644 --- a/src/core2/map/cutscene_skip.c +++ b/src/core2/map/cutscene_skip.c @@ -135,6 +135,9 @@ void func_8031CB50(enum map_e map_id, s32 exit_id, s32 arg2) { s32 sp1C; if ((D_80383190 == 0) && (getGameMode() != GAME_MODE_8_BOTTLES_BONUS) && (getGameMode() != GAME_MODE_7_ATTRACT_DEMO)) { + // [port] Romhack gate: a listener may call musicKeepsPlaying() here to + // carry a special-music state across this warp. + EventSystem_Should(VB_WARP_KEEPS_MUSIC, true, map_id); sp1C = func_803226E8(gsworld_getMap()); if ((func_803226E8(map_id) != sp1C) && (func_80322914() == 0)) { func_8025A388(0, 0x4E2); @@ -1374,18 +1377,8 @@ void warp_smExitBanjosHouse(NodeProp *arg0, ActorMarker *arg1) { } void warp_lairEnterMMLobbyFromSMLevel(NodeProp *arg0, ActorMarker *arg1) { - // [port] BB romhacks can override this warp destination via BKCF; port - // listeners can refine further by responding to OnWarpResolveDest. s32 dest = 0x6912; - s32 bkcf = port_getRomhackWarpEnterLair(); - if (bkcf >= 0) { - dest = bkcf; - } - s32 mapOverride = port_getRomhackStartLevel2(); - if (mapOverride >= 0) { - dest = (mapOverride << 8) | (dest & 0xFF); - } - CALL_EVENT(OnWarpResolveDest, WARP_ID_LAIR_ENTER_MM_LOBBY_FROM_SM_LEVEL, 0x6912, bkcf, &dest); + CALL_EVENT(OnWarpResolveDest, WARP_ID_LAIR_ENTER_MM_LOBBY_FROM_SM_LEVEL, 0x6912, -1, &dest); func_8031CC8C(arg0, dest); } diff --git a/src/lair/lairspawnqueue.c b/src/lair/lairspawnqueue.c index 5a6b77511..32751345e 100644 --- a/src/lair/lairspawnqueue.c +++ b/src/lair/lairspawnqueue.c @@ -929,20 +929,25 @@ void func_803875F0(Actor * this) if (!this->volatile_initialized) { - if (fileProgressFlag_get(FILEPROG_1E_LAIR_GRATE_TO_BGS_PUZZLE_OPEN)) - { - marker_despawn(this->marker); - return; - } - + // [port] Anchor: a teammate's press delivers map flag 0 and FILEPROG_1E in the same + // packet drain, so check the switch flag first -- while we're here to watch, the rise + // animation should win over the already-open catch-up despawn. if (mapSpecificFlags_get(0)) { this->unk1C_y = this->position_y; - gcStaticCamera_activate(0x2A); + // A remote press shouldn't steal our camera. + if (!port_mapFlag_wasSetRemotely(0)) { + gcStaticCamera_activate(0x2A); + } fileProgressFlag_set(FILEPROG_1E_LAIR_GRATE_TO_BGS_PUZZLE_OPEN, true); this->volatile_initialized = true; this->unk38_31 = 0x0C; } + else if (fileProgressFlag_get(FILEPROG_1E_LAIR_GRATE_TO_BGS_PUZZLE_OPEN)) + { + marker_despawn(this->marker); + return; + } } else { @@ -1086,24 +1091,83 @@ void func_80387730(Actor *this) { } } -void port_notedoor_remoteOpen(s32 progressFlag) { - s32 field; +// A live actor by id (and actorTypeSpecificField when >= 0), or NULL. +static Actor *__lair_findActor(s32 actorId, s32 typeField) { s32 i; - if (progressFlag < FILEPROG_3A_NOTE_DOOR_50_OPEN || progressFlag > FILEPROG_45_NOTE_DOOR_882_OPEN) { - return; - } if (suBaddieActorArray == NULL) { - return; + return NULL; } - field = progressFlag - FILEPROG_39_CCW_OPEN; for (i = 0; i < suBaddieActorArray->cnt; i++) { Actor *actor = &suBaddieActorArray->data[i]; - if (actor->marker != NULL && actor->modelCacheIndex == ACTOR_203_NOTE_DOOR && - actor->actorTypeSpecificField == field) { - actor->unk1C[0] = 1.0f; // picked up by func_80387730 next update - return; + if (actor->marker != NULL && actor->modelCacheIndex == actorId && + (typeField < 0 || actor->actorTypeSpecificField == typeField)) { + return actor; + } + } + return NULL; +} + +// [port] Anchor: one-shot cues for a teammate's file-progress flag. +void port_progressFlag_remoteCue(s32 progressFlag) { + Actor *actor; + + port_notedoor_remoteOpen(progressFlag); + port_leveldoor_remoteOpen(progressFlag); + port_breakable_remoteBreak(progressFlag); + + switch (progressFlag) { + // Circular grate over the BGS puzzle: rise + slam (func_803875F0). + case FILEPROG_1E_LAIR_GRATE_TO_BGS_PUZZLE_OPEN: + actor = __lair_findActor(ACTOR_213_GL_BGS_PUZZLE_GRATE, -1); + if (actor != NULL && !actor->volatile_initialized) { + actor->unk1C_y = actor->position_y; + actor->volatile_initialized = TRUE; + actor->unk38_31 = 0x0C; + } + break; + + // CC lobby pipes: rise + slam (func_80388FC8 / lair_func_80389204). + case FILEPROG_1F_CC_LOBBY_PIPE_1_RAISED: + case FILEPROG_20_CC_LOBBY_PIPE_2_RAISED: + case FILEPROG_21_CC_LOBBY_PIPE_3_RAISED: { + s32 pipeId = (progressFlag == FILEPROG_1F_CC_LOBBY_PIPE_1_RAISED) + ? ACTOR_215_GL_CC_ENTRANCE_LONG_PIPE_GREEN + : (progressFlag == FILEPROG_20_CC_LOBBY_PIPE_2_RAISED) + ? ACTOR_216_GL_CC_ENTRANCE_LONG_PIPE_BLUE + : ACTOR_218_GL_CC_ENTRANCE_SHORT_PIPE; + actor = __lair_findActor(pipeId, -1); + // initialized = rise base captured; lifetime_value != 0 = already raised. + if (actor != NULL && actor->initialized && actor->lifetime_value == 0.0f && + !actor->volatile_initialized) { + actor->volatile_initialized = TRUE; + actor->unk38_31 = 12; + } + break; } + + // Grunty statue hat + case FILEPROG_A1_STATUE_HAT_OPEN: + actor = __lair_findActor(ACTOR_21B_GRUNTY_STATUE_BREAKABLE_HAT_TOP, -1); + if (actor != NULL && actor->volatile_initialized && actor->unk1C[0] == 0.0f) { + actor->unk1C[0] = 1.0f; + } + break; + + default: + break; + } +} + +void port_notedoor_remoteOpen(s32 progressFlag) { + Actor *actor; + + if (progressFlag < FILEPROG_3A_NOTE_DOOR_50_OPEN || progressFlag > FILEPROG_45_NOTE_DOOR_882_OPEN) { + return; + } + actor = __lair_findActor(ACTOR_203_NOTE_DOOR, progressFlag - FILEPROG_39_CCW_OPEN); + if (actor != NULL) { + actor->unk1C[0] = 1.0f; // picked up by func_80387730 next update } } @@ -1732,7 +1796,8 @@ void func_80388FC8(Actor *this) if (mapSpecificFlags_get(1)) { - if (this->modelCacheIndex == 0x215) + // [port] Anchor: a remote press shouldn't steal our camera. + if (this->modelCacheIndex == 0x215 && !port_mapFlag_wasSetRemotely(1)) { gcStaticCamera_activate(0x2B); if (1); // oof @@ -1809,7 +1874,10 @@ void lair_func_80389204(Actor *this) if (mapSpecificFlags_get(2)) { - gcStaticCamera_activate(0x2C); + // [port] Anchor: a remote press shouldn't steal our camera. + if (!port_mapFlag_wasSetRemotely(2)) { + gcStaticCamera_activate(0x2C); + } fileProgressFlag_set(FILEPROG_21_CC_LOBBY_PIPE_3_RAISED, true); this->volatile_initialized = true; diff --git a/src/port/DevTools/FlagTracer.cpp b/src/port/DevTools/FlagTracer.cpp new file mode 100644 index 000000000..81dc27564 --- /dev/null +++ b/src/port/DevTools/FlagTracer.cpp @@ -0,0 +1,243 @@ +// Flag Tracer +// +// Logs every game-flag write with its enum name, optionally with the call stack +// that set it. A flag index alone is a bare number shared by unrelated actors. + +#include +#include +#include + +#include "port/Enhancements/Events/Hooks/Events.h" +#include "port/ShipInit.hpp" +#include "port/UI/cvar_prefixes.h" + +#include "FlagNames.generated.h" + +#include +#include +#include + +#if defined(_WIN32) +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#ifndef NOMINMAX +#define NOMINMAX +#endif +#include +#include +#pragma comment(lib, "dbghelp.lib") +#define LH_FLAGTRACE_STACKS_WIN 1 +#elif defined(__linux__) || defined(__APPLE__) +#include +#include +#include +#include +#define LH_FLAGTRACE_STACKS_POSIX 1 +#endif + +extern "C" { +#include "functions.h" +} + +#define CVAR_FLAG_TRACE CVAR_DEVELOPER_TOOLS("FlagTrace") +#define CVAR_FLAG_TRACE_STACKS CVAR_DEVELOPER_TOOLS("FlagTraceStacks") +#define CVAR_FLAG_TRACE_SPACE CVAR_DEVELOPER_TOOLS("FlagTraceSpace") + +namespace { + +constexpr int32_t kSpaceAll = 0; + +const char* SpaceName(int32_t flagSpace) { + switch (flagSpace) { + case ANCHOR_FLAGSPACE_FILE_PROGRESS: + return "File Progress"; + case ANCHOR_FLAGSPACE_VOLATILE: + return "Volatile"; + case ANCHOR_FLAGSPACE_LEVEL_SPECIFIC: + return "Level"; + case ANCHOR_FLAGSPACE_MAP_SPECIFIC: + return "Map"; + case ANCHOR_FLAGSPACE_RANDO_INF: + return "Rando"; + default: + return "Unknown"; + } +} + +const char* LookupIn(const FlagName* table, int count, int index) { + for (int i = 0; i < count; i++) { + if (table[i].index == index) { + return table[i].name; + } + } + return nullptr; +} + +template const char* LookupIn(const FlagName (&table)[N], int index) { + return LookupIn(table, N, index); +} + +// The enum name behind a flag index, or "" when the decomp hasn't named it. +std::string FlagLabel(int32_t flagSpace, int32_t index) { + const char* name = nullptr; + switch (flagSpace) { + case ANCHOR_FLAGSPACE_FILE_PROGRESS: + name = LookupIn(kFileProgressNames, index); + break; + case ANCHOR_FLAGSPACE_VOLATILE: + name = LookupIn(kVolatileNames, index); + break; + case ANCHOR_FLAGSPACE_LEVEL_SPECIFIC: + name = LookupIn(kLevelNames, index); + break; + case ANCHOR_FLAGSPACE_MAP_SPECIFIC: { + const int level = (int)map_getLevel(gsworld_getMap()); + std::string joined; + for (const auto& group : kMapFlagGroups) { + if (group.level != level) { + continue; + } + if (const char* candidate = LookupIn(group.names, group.count, index)) { + if (!joined.empty()) { + joined += " | "; + } + joined += candidate; + } + } + return joined; + } + default: + break; + } + return name != nullptr ? name : ""; +} + +// Symbolized stack of whatever led here. +std::string CaptureCallerStack(int maxFrames) { + auto isPlumbing = [](const char* name) { + static const char* kPlumbing[] = { "FlagTrace", "EventSystem", "CallEvent", "Flag_set", "Flags_set", + "Flag_setEx", "Flags_setEx", "Flag_setN", "Flags_setN", "Flag_getAndSet", + "Flags_getSet", "invoke", "std::", "lambda" }; + for (const char* p : kPlumbing) { + if (std::strstr(name, p) != nullptr) { + return true; + } + } + return false; + }; + +#if defined(LH_FLAGTRACE_STACKS_WIN) + static std::once_flag symOnce; + static std::mutex symMutex; + HANDLE proc = GetCurrentProcess(); + std::call_once(symOnce, [proc] { + SymSetOptions(SYMOPT_LOAD_LINES | SYMOPT_UNDNAME | SYMOPT_DEFERRED_LOADS); + SymInitialize(proc, nullptr, TRUE); + }); + + void* frames[48] = {}; + const USHORT captured = CaptureStackBackTrace(1, 48, frames, nullptr); + + // dbghelp is not thread safe and its handles are process-wide. + std::lock_guard lock(symMutex); + + alignas(SYMBOL_INFO) char symBuf[sizeof(SYMBOL_INFO) + MAX_SYM_NAME] = {}; + auto* sym = reinterpret_cast(symBuf); + sym->SizeOfStruct = sizeof(SYMBOL_INFO); + sym->MaxNameLen = MAX_SYM_NAME; + + std::string out; + int shown = 0; + for (USHORT i = 0; i < captured && shown < maxFrames; i++) { + DWORD64 disp = 0; + if (!SymFromAddr(proc, (DWORD64)frames[i], &disp, sym)) { + continue; + } + if (out.empty() && isPlumbing(sym->Name)) { + continue; + } + IMAGEHLP_LINE64 line = {}; + line.SizeOfStruct = sizeof(line); + DWORD lineDisp = 0; + if (SymGetLineFromAddr64(proc, (DWORD64)frames[i], &lineDisp, &line)) { + const char* file = std::strrchr(line.FileName, '\\'); + file = file ? file + 1 : line.FileName; + out += fmt::format("\n {} ({}:{})", sym->Name, file, line.LineNumber); + } else { + out += fmt::format("\n {}", sym->Name); + } + shown++; + } + return out; + +#elif defined(LH_FLAGTRACE_STACKS_POSIX) + void* frames[48] = {}; + const int captured = backtrace(frames, 48); + + std::string out; + int shown = 0; + for (int i = 1; i < captured && shown < maxFrames; i++) { + Dl_info info = {}; + if (dladdr(frames[i], &info) == 0 || info.dli_sname == nullptr) { + out += fmt::format("\n {}", frames[i]); + shown++; + continue; + } + + int status = 0; + char* demangled = abi::__cxa_demangle(info.dli_sname, nullptr, nullptr, &status); + const char* name = (status == 0 && demangled != nullptr) ? demangled : info.dli_sname; + const bool skip = out.empty() && isPlumbing(name); + if (!skip) { + out += fmt::format("\n {}", name); + shown++; + } + std::free(demangled); + } + return out; + +#else + (void)maxFrames; + (void)isPlumbing; + return "\n (call stacks are unavailable on this platform)"; +#endif +} + +} // namespace + +void RegisterFlagTracer_Init() { + const bool enabled = CVarGetInteger(CVAR_FLAG_TRACE, 0) != 0; + + COND_HOOK(OnGameFlagSet, EVENT_PRIORITY_NORMAL, enabled, [](IEvent* event) { + auto* ev = reinterpret_cast(event); + + const int32_t spaceFilter = CVarGetInteger(CVAR_FLAG_TRACE_SPACE, kSpaceAll); + if (spaceFilter != kSpaceAll && ev->flagSpace != (spaceFilter - 1)) { + return; + } + + std::string where; + if (ev->length > 1) { + where = fmt::format("0x{:X}-0x{:X}", ev->index, ev->index + ev->length - 1); + } else { + const std::string label = FlagLabel(ev->flagSpace, ev->index); + where = label.empty() ? fmt::format("0x{:X}", ev->index) : fmt::format("0x{:X} {}", ev->index, label); + } + + std::string stack; + if (CVarGetInteger(CVAR_FLAG_TRACE_STACKS, 0)) { + stack = fmt::format("\n set by:{}", CaptureCallerStack(6)); + } + + SPDLOG_INFO("[Flag] {:<13} {} -> {}{}", SpaceName(ev->flagSpace), where, ev->value ? "ON" : "off", stack); + }); + + COND_HOOK(OnMapLoad, EVENT_PRIORITY_NORMAL, enabled, [](IEvent* event) { + auto* ev = reinterpret_cast(event); + SPDLOG_INFO("[Flag] ===== map 0x{:X} -> 0x{:X} (level 0x{:X}, exit {}) =====", (int)ev->prevMap, + (int)ev->nextMap, (int)map_getLevel((enum map_e)ev->nextMap), ev->exit); + }); +} + +static RegisterShipInitFunc initFlagTracer(RegisterFlagTracer_Init, { CVAR_FLAG_TRACE }); diff --git a/src/port/Engine.cpp b/src/port/Engine.cpp index ddd26319a..d8aca8698 100644 --- a/src/port/Engine.cpp +++ b/src/port/Engine.cpp @@ -53,6 +53,7 @@ #include "src/port/Enhancements/Events/Hooks/Events.h" #include "UI/LighthouseGui.hpp" #include "UI/LighthouseModMenuWindow.h" +#include "LaunchArgs.h" #ifdef __SWITCH__ #include @@ -362,6 +363,9 @@ void GameEngine::FinishInit() { std::filesystem::create_directories(patches_path); } + // Apply `-hack ` before the scan. + Lighthouse::ApplyLaunchHack(); + // Load enabled mod o2rs into the ArchiveManager. UpdateModFiles(true); LoadLooseModDirectories(patches_path); @@ -378,6 +382,7 @@ void GameEngine::FinishInit() { Ship::Context::GetRawInstance()->GetLogger()->set_pattern("[%H:%M:%S.%e] [%s:%#] [%l] %v"); SPDLOG_INFO("Starting Lighthouse version {} (Branch: {} | Commit: {})", (char*)gBuildVersion, (char*)gGitBranch, (char*)gGitCommitHash); + Lighthouse::FlushLaunchHackLog(); context->InitFileDropMgr(); context->InitCrashHandler(); @@ -404,6 +409,10 @@ void GameEngine::FinishInit() { Lighthouse::RescanLanguages(); LighthouseGui::SetupGuiElements(); + // Undo the -hack override only now: LighthouseModMenuWindow::InitElement() + // re-runs UpdateModFiles(true) during SetupGuiElements and would otherwise + // re-read the restored CVars and reload the persisted hack over the override. + Lighthouse::RestoreModSelectionAfterLaunchHack(); // If UpdateModFiles(true) above quarantined conflicting romhack overlays, // surface that to the user now that the modal window is alive. MaybeShowModConflictPopup(); @@ -442,10 +451,17 @@ void GameEngine::RunExtract(int argc, char* argv[]) { std::filesystem::path ownPath; std::vector args; - if (argc > 1) { - for (int i = 1; i < argc; i++) { - args.push_back(argv[argc]); + for (int i = 1; i < argc; i++) { + std::string arg = argv[i]; + std::string inlineValue; + bool takesValue = false; + if (Lighthouse::IsLaunchHackFlag(arg, inlineValue, takesValue)) { + if (takesValue) { + i++; + } + continue; } + args.push_back(arg); } GameExtractor extract; PromptSteps promptStep = PS_FILE_CHECK; @@ -1016,6 +1032,7 @@ void GameEngine::ScaleImGui() { } void GameEngine::Create(int argc, char* argv[]) { + Lighthouse::ParseLaunchArgs(argc, argv); const auto instance = Instance = new GameEngine(); // instance->AudioInit(); // DisplayListPatch::Run(); diff --git a/src/port/Enhancements/Events/Hooks/Events.h b/src/port/Enhancements/Events/Hooks/Events.h index 315c85480..fe10572df 100644 --- a/src/port/Enhancements/Events/Hooks/Events.h +++ b/src/port/Enhancements/Events/Hooks/Events.h @@ -106,6 +106,9 @@ typedef enum VBehaviorID { VB_MAP_CHANGE_REQUEST, VB_MAP_TRANSITION_IN_INDEX, VB_VOID_OUT_RESPAWN_TRANSITION, + VB_EGG_FIRE_SFX, + VB_WARP_KEEPS_MUSIC, + VB_BUMP_REBOUNDS_PLAYER, VB_WARP_DISPATCH, VB_GAMESELECT_START_NEW_GAME, VB_NOTEDOOR_DRAW_NUMBER, diff --git a/src/port/Enhancements/Events/Hooks/List/EngineEvent.h b/src/port/Enhancements/Events/Hooks/List/EngineEvent.h index adfb1355b..20cdb1dfc 100644 --- a/src/port/Enhancements/Events/Hooks/List/EngineEvent.h +++ b/src/port/Enhancements/Events/Hooks/List/EngineEvent.h @@ -54,4 +54,5 @@ DEFINE_EVENT(ParadeCreditDialogId, int32_t index; int32_t * dialogId;); DEFINE_EVENT(ResolveBoldFontSlot, int32_t* slot; int32_t * letterId;); DEFINE_EVENT(OnWorldDraw, Gfx** gfx; Mtx * *mtx; Vtx * *vtx;); DEFINE_EVENT(OnPlayerDraw, Gfx** gfx; Mtx * *mtx; Vtx * *vtx;); +DEFINE_EVENT(OnHudDraw, Gfx** gfx; Mtx * *mtx; Vtx * *vtx;); DEFINE_EVENT(OnReset); \ No newline at end of file diff --git a/src/port/Enhancements/Events/PortEnhancements.cpp b/src/port/Enhancements/Events/PortEnhancements.cpp index 749288593..05c4dac0a 100644 --- a/src/port/Enhancements/Events/PortEnhancements.cpp +++ b/src/port/Enhancements/Events/PortEnhancements.cpp @@ -51,6 +51,7 @@ void PortEnhancements_Register() { REGISTER_EVENT(OnBoldFontReset); REGISTER_EVENT(OnWorldDraw); REGISTER_EVENT(OnPlayerDraw); + REGISTER_EVENT(OnHudDraw); // Register behavior events REGISTER_EVENT(OnBeakSwimVelocitySet); diff --git a/src/port/Enhancements/Retention/NoteRetention.cpp b/src/port/Enhancements/Retention/NoteRetention.cpp index 48d5ce9d8..2fe7aa65f 100644 --- a/src/port/Enhancements/Retention/NoteRetention.cpp +++ b/src/port/Enhancements/Retention/NoteRetention.cpp @@ -13,6 +13,7 @@ #include "port/Enhancements/Events/PortEnhancements.h" #include "port/Enhancements/Events/Hooks/Events.h" #include "port/Enhancements/Retention/Retention.h" +#include "port/Romhack/RomhackConfig.h" #include "port/Rando/Rando.h" #include "port/Rando/CustomObject/CustomObject.h" @@ -344,19 +345,22 @@ void RegisterNoteRetention_Init() { // Seeding ITEM_C_NOTE re-triggers vanilla high-score dialogs; suppress them. COND_VB_SHOULD(VB_OVERRIDE_DIALOG_SHOW, EVENT_PRIORITY_NORMAL, true, { s32 textId = va_arg(args, s32); - if (!applyEnabled()) { - return; - } - switch (textId) { - case 0xD9C: // Bottles' first-note text: "you can't take notes with you" - case 0xF76: // "you just beat your high score" - // Milestones...maybe they should not be suppressed? They're aides for new players. - /* case 0xF74: // milestone: 50 notes (Mumbo's Mountain) - case 0xF78: // milestone: collected every note in the level*/ - *should = true; - break; - default: - break; + // Bottles' 50-note-door line assumes vanilla note-door costs, which + // romhacks retune, so it is wrong for them whether or not retention is + // on. In vanilla it stays: it's an aide for new players. + if (textId == 0xF74 && port_isRomhack()) { + *should = true; + } else if (applyEnabled()) { + switch (textId) { + case 0xD9C: // Bottles' first-note text: "you can't take notes with you" + case 0xF76: // "you just beat your high score" + // 0xF78 (every note in the level) is left alone here; hacks that + // want it gone suppress it per-hack, as Gruntch does. + *should = true; + break; + default: + break; + } } }); } diff --git a/src/port/Enhancements/Retention/WormSync.cpp b/src/port/Enhancements/Retention/WormSync.cpp index 0515af21d..b2716fd09 100644 --- a/src/port/Enhancements/Retention/WormSync.cpp +++ b/src/port/Enhancements/Retention/WormSync.cpp @@ -64,6 +64,23 @@ bool isCollected(int32_t slot, int32_t mapId, int32_t hash) { return sCollected.count({ slot, mapId, hash }) != 0; } +// Gold and the presents feed a credit-back reconcile that rebuilds carried counts as +// collected-minus-delivered. Respawn suppression and that credit must fire together +// or a collected item is lost across a reload, so both are scoped to the consumer's +// level; outside it, neither runs and the collectible simply respawns, as on hardware. +bool kindAllowedFor(int32_t kind, int32_t mapId) { + switch (kind) { + case ANCHOR_COLLECTIBLE_GOLD: + return (int32_t)map_getLevel((enum map_e)mapId) == LEVEL_2_TREASURE_TROVE_COVE; + case ANCHOR_COLLECTIBLE_PRESENT_BLUE: + case ANCHOR_COLLECTIBLE_PRESENT_GREEN: + case ANCHOR_COLLECTIBLE_PRESENT_RED: + return (int32_t)map_getLevel((enum map_e)mapId) == LEVEL_5_FREEZEEZY_PEAK; + default: + return true; + } +} + bool inDemoPlayback() { return func_802E4A08() != 0; } @@ -84,7 +101,7 @@ extern "C" void port_carriedSync_register(int32_t kind, void* marker, int32_t x, int32_t mapId = (int32_t)gsworld_getMap(); int32_t hash = spawnHash(x, y, z); ObjectExtension::GetInstance().Set(marker, CarriedSpawnData(mapId, hash)); - if (!inDemoPlayback() && isCollected(slot, mapId, hash)) { + if (!inDemoPlayback() && kindAllowedFor(kind, mapId) && isCollected(slot, mapId, hash)) { *suppress = 1; } } @@ -143,7 +160,7 @@ extern "C" int32_t port_carriedSync_collectedCount(int32_t kind) { } int32_t count = 0; for (const auto& e : sCollected) { - if (e[0] == slot) { + if (e[0] == slot && kindAllowedFor(kind, e[1])) { count++; } } diff --git a/src/port/LaunchArgs.cpp b/src/port/LaunchArgs.cpp new file mode 100644 index 000000000..33c8c817d --- /dev/null +++ b/src/port/LaunchArgs.cpp @@ -0,0 +1,148 @@ +#include "LaunchArgs.h" + +#include +#include + +#include +#include + +#include "UI/LighthouseModMenuWindow.h" +#include "UI/cvar_prefixes.h" + +namespace Lighthouse { + +namespace { + +// Romhack requested via `-hack `; empty when the flag was not passed. +std::string sLaunchHack; + +// Persisted mod selection captured before the override, so it can be restored. +std::string sSavedEnabledMods; +std::string sSavedDisabledMods; +bool sLaunchHackApplied = false; + +// Everything here runs before context->InitLogging(), so diagnostics are buffered +// and emitted by FlushLaunchHackLog() once the logger is live. +std::string sLaunchHackLog; +bool sLaunchHackLogIsError = false; + +void SetLaunchHackLog(bool isError, std::string message) { + sLaunchHackLog = std::move(message); + sLaunchHackLogIsError = isError; +} + +} // namespace + +bool IsLaunchHackFlag(const std::string& arg, std::string& outInlineValue, bool& outTakesValue) { + static const char* kFlags[] = { "-hack", "--hack", "-romhack", "--romhack" }; + for (const char* flag : kFlags) { + if (arg == flag) { + outTakesValue = true; + return true; + } + const std::string prefix = std::string(flag) + "="; + if (arg.rfind(prefix, 0) == 0) { + outInlineValue = arg.substr(prefix.size()); + outTakesValue = false; + return true; + } + } + return false; +} + +void ParseLaunchArgs(int argc, char* argv[]) { + for (int i = 1; i < argc; i++) { + std::string arg = argv[i]; + std::string inlineValue; + bool takesValue = false; + if (!IsLaunchHackFlag(arg, inlineValue, takesValue)) { + continue; + } + if (takesValue) { + if (i + 1 < argc) { + sLaunchHack = argv[++i]; + } else { + SetLaunchHackLog(true, "[Launch] " + arg + " requires a romhack name"); + } + } else { + sLaunchHack = inlineValue; + } + } +} + +void ApplyLaunchHack() { + if (sLaunchHack.empty()) { + return; + } + + // Only strip the extension when it is actually ".o2r", so a hack whose stem + // contains a dot ("my.hack") still resolves when named without the suffix. + const std::filesystem::path requested(sLaunchHack); + const std::string wanted = StringHelper::IEquals(requested.extension().string(), ".o2r") + ? requested.stem().generic_string() + : requested.filename().generic_string(); + + const std::string modsPath = Ship::Context::GetPathRelativeToAppDirectory("mods"); + if (modsPath.empty() || !std::filesystem::is_directory(modsPath)) { + SetLaunchHackLog(true, "[Launch] -hack '" + sLaunchHack + "': no mods directory to search"); + return; + } + + std::string resolved; + std::string available; + std::error_code ec; + for (const auto& entry : std::filesystem::recursive_directory_iterator( + modsPath, std::filesystem::directory_options::follow_directory_symlink, ec)) { + if (entry.is_directory() || !StringHelper::IEquals(entry.path().extension().string(), ".o2r")) { + continue; + } + const std::string stem = entry.path().stem().generic_string(); + if (!available.empty()) { + available += ", "; + } + available += stem; + if (StringHelper::IEquals(stem, wanted)) { + resolved = stem; + } + } + + if (resolved.empty()) { + SetLaunchHackLog(true, "[Launch] -hack '" + sLaunchHack + "': no matching .o2r under mods/. Available: " + + (available.empty() ? std::string("(none)") : available)); + return; + } + + // Snapshot before overriding so RestoreModSelectionAfterLaunchHack() can put + // the user's own selection back once the archives are loaded. + sSavedEnabledMods = CVarGetString(CVAR_SETTING("EnabledMods"), ""); + sSavedDisabledMods = CVarGetString(CVAR_SETTING("DisabledMods"), ""); + sLaunchHackApplied = true; + + // Validates that the match actually carries an aGameConfig, and disables any + // other overlay so the boot-time conflict check does not quarantine them. + SetLaunchHackLog(false, "[Launch] -hack '" + sLaunchHack + "': enabling romhack overlay '" + resolved + "'"); + SetSoleEnabledRomhack(resolved); +} + +void RestoreModSelectionAfterLaunchHack() { + if (!sLaunchHackApplied) { + return; + } + CVarSetString(CVAR_SETTING("EnabledMods"), sSavedEnabledMods.c_str()); + CVarSetString(CVAR_SETTING("DisabledMods"), sSavedDisabledMods.c_str()); + Ship::Context::GetRawInstance()->GetWindow()->GetGui()->SaveConsoleVariablesNextFrame(); +} + +void FlushLaunchHackLog() { + if (sLaunchHackLog.empty()) { + return; + } + if (sLaunchHackLogIsError) { + SPDLOG_ERROR("{}", sLaunchHackLog); + } else { + SPDLOG_INFO("{}", sLaunchHackLog); + } + sLaunchHackLog.clear(); +} + +} // namespace Lighthouse diff --git a/src/port/LaunchArgs.h b/src/port/LaunchArgs.h new file mode 100644 index 000000000..3277382fd --- /dev/null +++ b/src/port/LaunchArgs.h @@ -0,0 +1,13 @@ +#pragma once + +#include + +namespace Lighthouse { + +void ParseLaunchArgs(int argc, char* argv[]); +bool IsLaunchHackFlag(const std::string& arg, std::string& outInlineValue, bool& outTakesValue); +void ApplyLaunchHack(); +void RestoreModSelectionAfterLaunchHack(); +void FlushLaunchHackLog(); + +} // namespace Lighthouse diff --git a/src/port/Network/Anchor/Anchor.cpp b/src/port/Network/Anchor/Anchor.cpp index b5582a9e9..3b515d58d 100644 --- a/src/port/Network/Anchor/Anchor.cpp +++ b/src/port/Network/Anchor/Anchor.cpp @@ -402,6 +402,35 @@ void Anchor::OnActorDestroyed(Actor* actor) { } } +// Queues the honeycomb spawn the switch press performs. +extern "C" void __baMarker_8028BA00(s32 honeycombId); + +// The GV cactus and RBB boathouse honeycombs only exist once their switch is +// beak-busted: marker.c sets a map flag and spawns the actor. A teammate's press +// reaches us as flag state, so spawn the same actor the local press would have. +void Anchor::RevealSwitchHoneycomb() { + s32 uid; + s32 flag; + + switch (gsworld_getMap()) { + case MAP_12_GV_GOBIS_VALLEY: + uid = HONEYCOMB_B_GV_CACTUS; + flag = 0xD; + break; + case MAP_36_RBB_BOATHOUSE: + uid = HONEYCOMB_F_RBB_BOAT_HOUSE; + flag = 0; + break; + default: + return; + } + + if (!mapSpecificFlags_get(flag) || honeycombscore_get((enum honeycomb_e)uid)) { + return; + } + __baMarker_8028BA00(uid); +} + void Anchor::RemoveDummy(uint32_t clientId) { if (dummies.contains(clientId)) { dummies[clientId]->dummy_despawnActor(); diff --git a/src/port/Network/Anchor/Anchor.h b/src/port/Network/Anchor/Anchor.h index 8cccc456d..f70139bd8 100644 --- a/src/port/Network/Anchor/Anchor.h +++ b/src/port/Network/Anchor/Anchor.h @@ -279,6 +279,7 @@ class Anchor : public Network { void SendPacket_VileHoleState(u8 holeId, u8 holeState, u8 pieceType, u32 eaterClientId); void SendPacket_VileUpdate(const f32 position[3], f32 pitch, f32 yaw, f32 roll, u8 animMode); void OnActorDestroyed(Actor* actor); + void RevealSwitchHoneycomb(); void SendToCurrentMapPlayers(nlohmann::json& payload); void SendToCurrentLevelPlayers(nlohmann::json& payload); void SweepUnoccupiedLevelState(GameMap selfMap); diff --git a/src/port/Network/Anchor/HookHandlers.cpp b/src/port/Network/Anchor/HookHandlers.cpp index 59d8059f1..58f1c8921 100644 --- a/src/port/Network/Anchor/HookHandlers.cpp +++ b/src/port/Network/Anchor/HookHandlers.cpp @@ -552,8 +552,9 @@ void Anchor::RegisterHooks() { // SM intro Bottles: the tutorial offer is first-answer-wins for the team. COND_VB_SHOULD(VB_SM_TUTORIAL_CHOICE_OPEN, EVENT_PRIORITY_NORMAL, isConnected, { if (Anchor_WorldSyncActive()) { + // By level, not map: a romhack's Spiral Mountain may be a different map id. if (__chSmBottles_isAnySpiralMountainAbilityLearned() || - (port_puzzleStep_getForMap(MAP_1_SM_SPIRAL_MOUNTAIN, ANCHOR_PUZZLE_SM_TUTORIAL) & 1)) { + (port_puzzleStep_getForLevel(LEVEL_B_SPIRAL_MOUNTAIN, ANCHOR_PUZZLE_SM_TUTORIAL) & 1)) { *should = false; } else if (NetAuthority_IsClaimed(NET_ACTIVITY_SM_TUTORIAL) && !NetAuthority_IsSelf(NET_ACTIVITY_SM_TUTORIAL)) { @@ -568,7 +569,7 @@ void Anchor::RegisterHooks() { // answered (synced bit) or a move is already known (covers skip-tutorial saves). COND_VB_SHOULD(VB_SM_MOLEHILL_ACTIVE, EVENT_PRIORITY_NORMAL, isConnected, { if (Anchor_WorldSyncActive() && !__chSmBottles_isAnySpiralMountainAbilityLearned() && - !(port_puzzleStep_getForMap(MAP_1_SM_SPIRAL_MOUNTAIN, ANCHOR_PUZZLE_SM_TUTORIAL) & 1)) { + !(port_puzzleStep_getForLevel(LEVEL_B_SPIRAL_MOUNTAIN, ANCHOR_PUZZLE_SM_TUTORIAL) & 1)) { *should = false; } }); diff --git a/src/port/Network/Anchor/Packets/PuzzleStep.cpp b/src/port/Network/Anchor/Packets/PuzzleStep.cpp index e926bdb36..638f20dd9 100644 --- a/src/port/Network/Anchor/Packets/PuzzleStep.cpp +++ b/src/port/Network/Anchor/Packets/PuzzleStep.cpp @@ -35,17 +35,92 @@ static int32_t puzzlePosHash(int32_t x, int32_t y, int32_t z) { return (int32_t)((h & 0x7FFFFFFFu) | 1u); // never 0 (the "no positional hash" sentinel) } +/** + * Every bitmask entry is written by one vanilla actor that lives in one known map, and + * some entries are derived from -- or applied back to -- raw map/level flag indices whose + * meaning is map-relative. A romhack that relocates such an actor makes it read one map's + * flag and republish it as another's. To avoid complications, each puzzle id is scoped to + * its actor's home: outside it every leg is inert. + * + * Vanilla is unaffected, and a romhack keeps live sync for every puzzle it didn't relocate. + */ +struct PuzzleHome { + std::set maps; + int32_t level = -1; // home is a whole level (romhacks may remap a level's maps) +}; + +static const std::map& puzzleHomes() { + static const std::map homes = { + { ANCHOR_PUZZLE_BGS_TANKTUP, { { MAP_D_BGS_BUBBLEGLOOP_SWAMP } } }, + { ANCHOR_PUZZLE_BGS_CROCTUS, { { MAP_D_BGS_BUBBLEGLOOP_SWAMP } } }, + // The egg chain's map isn't pinned down in the decomp; its readback only drives + // actor state, so the whole level is safe. + { ANCHOR_PUZZLE_BGS_PINKEGG, { {}, LEVEL_4_BUBBLEGLOOP_SWAMP } }, + { ANCHOR_PUZZLE_CC_CLANKER_TEETH, { { MAP_B_CC_CLANKERS_CAVERN } } }, + { ANCHOR_PUZZLE_GV_JINXY_DOOR, { { MAP_12_GV_GOBIS_VALLEY } } }, + { ANCHOR_PUZZLE_MM_JUJU, { { MAP_2_MM_MUMBOS_MOUNTAIN } } }, + { ANCHOR_PUZZLE_TTC_NIPPER, { { MAP_7_TTC_TREASURE_TROVE_COVE } } }, + { ANCHOR_PUZZLE_TTC_BLUBBER, { { MAP_7_TTC_TREASURE_TROVE_COVE } } }, + { ANCHOR_PUZZLE_TTC_XHUNT, { { MAP_7_TTC_TREASURE_TROVE_COVE } } }, + { ANCHOR_PUZZLE_FP_TREE_ICE, { { MAP_53_FP_CHRISTMAS_TREE } } }, + { ANCHOR_PUZZLE_FP_PRESENTS, { { MAP_27_FP_FREEZEEZY_PEAK } } }, + { ANCHOR_PUZZLE_FP_SNOWBUTTONS, { { MAP_27_FP_FREEZEEZY_PEAK } } }, + { ANCHOR_PUZZLE_FP_SLUSHES, { { MAP_27_FP_FREEZEEZY_PEAK } } }, + { ANCHOR_PUZZLE_RBB_ENGINE_FANS, { { MAP_34_RBB_ENGINE_ROOM } } }, + // Tutorial choreography follows the level, not the map. + { ANCHOR_PUZZLE_SM_TUTORIAL, { {}, LEVEL_B_SPIRAL_MOUNTAIN } }, + }; + return homes; +} + +static bool mirrorAllowedFor(int32_t puzzleId, int32_t map) { + auto it = puzzleHomes().find(puzzleId); + if (it == puzzleHomes().end()) { + return false; // unknown id: fail inert + } + if (it->second.maps.count(map)) { + return true; + } + return it->second.level >= 0 && (int32_t)map_getLevel((enum map_e)map) == it->second.level; +} + +static bool mirrorLive(int32_t puzzleId) { + return mirrorAllowedFor(puzzleId, (int32_t)gsworld_getMap()); +} + extern "C" int32_t port_puzzleStep_get(int32_t puzzleId) { + if (!mirrorLive(puzzleId)) { + return 0; + } auto it = sPuzzleBits.find({ (int32_t)gsworld_getMap(), puzzleId }); return it != sPuzzleBits.end() ? it->second : 0; } extern "C" int32_t port_puzzleStep_getForMap(int32_t map, int32_t puzzleId) { + if (!mirrorAllowedFor(puzzleId, map)) { + return 0; + } auto it = sPuzzleBits.find({ map, puzzleId }); return it != sPuzzleBits.end() ? it->second : 0; } +// For level-homed puzzles: a relocated actor writes under the romhack's map +// key, which a map-keyed read can't know. ORs the puzzle's bits across the level. +extern "C" int32_t port_puzzleStep_getForLevel(int32_t levelId, int32_t puzzleId) { + int32_t bits = 0; + for (const auto& [key, val] : sPuzzleBits) { + if (key[1] == puzzleId && mirrorAllowedFor(puzzleId, key[0]) && + (int32_t)map_getLevel((enum map_e)key[0]) == levelId) { + bits |= val; + } + } + return bits; +} + extern "C" void port_puzzleStep_orBits(int32_t puzzleId, int32_t bits) { + if (!mirrorLive(puzzleId)) { + return; + } int32_t map = (int32_t)gsworld_getMap(); std::array key = { map, puzzleId }; int32_t before = sPuzzleBits.count(key) ? sPuzzleBits[key] : 0; @@ -84,6 +159,9 @@ void Anchor::HandlePacket_PuzzleStep(nlohmann::json& payload) { s32 puzzleId = payload.at("puzzle").get(); s32 map = payload.at("map").get(); + if (!mirrorAllowedFor(puzzleId, map)) { + return; + } s32 phash = payload.value("phash", (s32)0); if (phash != 0) { sPuzzlePos[{ map, puzzleId }].insert(phash); @@ -106,6 +184,9 @@ std::vector port_puzzleStep_snapshot() { void port_puzzleStep_restore(const std::vector& flat) { sPuzzleBits.clear(); for (size_t i = 0; i + 3 <= flat.size(); i += 3) { + if (!mirrorAllowedFor(flat[i + 1], flat[i])) { + continue; + } sPuzzleBits[{ flat[i], flat[i + 1] }] = flat[i + 2]; } } @@ -127,11 +208,17 @@ void port_puzzleStep_clearForLevel(int32_t levelId) { */ extern "C" int32_t port_puzzlePos_isMarked(int32_t puzzleId, int32_t x, int32_t y, int32_t z) { + if (!mirrorLive(puzzleId)) { + return 0; + } auto it = sPuzzlePos.find({ (int32_t)gsworld_getMap(), puzzleId }); return (it != sPuzzlePos.end() && it->second.count(puzzlePosHash(x, y, z))) ? 1 : 0; } extern "C" void port_puzzlePos_mark(int32_t puzzleId, int32_t x, int32_t y, int32_t z) { + if (!mirrorLive(puzzleId)) { + return; + } int32_t map = (int32_t)gsworld_getMap(); int32_t hash = puzzlePosHash(x, y, z); auto& set = sPuzzlePos[{ map, puzzleId }]; @@ -161,9 +248,12 @@ void port_puzzlePos_restore(const std::vector& flat) { while (i + 3 <= flat.size()) { int32_t map = flat[i], puzzleId = flat[i + 1], count = flat[i + 2]; i += 3; - auto& set = sPuzzlePos[{ map, puzzleId }]; + // Still consume the run's hashes when filtered so the stream stays aligned. + const bool allowed = mirrorAllowedFor(puzzleId, map); for (int32_t j = 0; j < count && i < flat.size(); j++, i++) { - set.insert(flat[i]); + if (allowed) { + sPuzzlePos[{ map, puzzleId }].insert(flat[i]); + } } } } @@ -172,6 +262,8 @@ void port_puzzlePos_restore(const std::vector& flat) { * PUZZLE_COUNT * * Companion to PUZZLE_STEP for count-based progress (Eyrie's fed worms, Nabnut's acorns). + * Not home-scoped: counters never touch flag indices (keyed by the real map, applied only + * to actor state), and scoping them would brick a relocated Eyrie/Nabnut. */ extern "C" int32_t port_puzzleCount_get(int32_t counterId) { diff --git a/src/port/Network/Anchor/Packets/ScopedFlag.cpp b/src/port/Network/Anchor/Packets/ScopedFlag.cpp index 19b5c8db6..b6b6e938a 100644 --- a/src/port/Network/Anchor/Packets/ScopedFlag.cpp +++ b/src/port/Network/Anchor/Packets/ScopedFlag.cpp @@ -7,9 +7,6 @@ #include "port/Enhancements/Events/Hooks/Events.h" #include "functions.h" -extern "C" { -void chHoneycomb_netRevealFromSwitch(void); -} static uint32_t sMapFlagSetRemotely = 0; @@ -64,7 +61,7 @@ void Anchor::HandlePacket_ScopedFlag(nlohmann::json& payload) { if (value && index >= 0 && index < 32) { sMapFlagSetRemotely |= (1u << index); } - chHoneycomb_netRevealFromSwitch(); + RevealSwitchHoneycomb(); } } } diff --git a/src/port/Network/Anchor/Packets/ScopedState.cpp b/src/port/Network/Anchor/Packets/ScopedState.cpp index 50fba3eec..ee0f7c1fb 100644 --- a/src/port/Network/Anchor/Packets/ScopedState.cpp +++ b/src/port/Network/Anchor/Packets/ScopedState.cpp @@ -5,9 +5,6 @@ #include #include "functions.h" -extern "C" { -void chHoneycomb_netRevealFromSwitch(void); -} /** * REQUEST_SCOPED_STATE / SCOPED_STATE @@ -86,6 +83,6 @@ void Anchor::HandlePacket_ScopedState(nlohmann::json& payload) { if (payload.contains("mapFlags") && (s32)gsworld_getMap() == payload.at("map").get()) { u32 mapFlags = payload["mapFlags"].get(); mapSpecificFlags_setAll(mapSpecificFlags_getAll() | mapFlags); - chHoneycomb_netRevealFromSwitch(); + RevealSwitchHoneycomb(); } } diff --git a/src/port/Network/Anchor/Packets/SetFlag.cpp b/src/port/Network/Anchor/Packets/SetFlag.cpp index 35c840698..91a57eb06 100644 --- a/src/port/Network/Anchor/Packets/SetFlag.cpp +++ b/src/port/Network/Anchor/Packets/SetFlag.cpp @@ -74,9 +74,7 @@ void Anchor::HandlePacket_SetFlag(nlohmann::json& payload) { } else { bool wasSet = fileProgressFlag_get((enum file_progress_e)flag) != 0; fileProgressFlag_setEx((enum file_progress_e)flag, 1, 0); - port_notedoor_remoteOpen(flag); - port_breakable_remoteBreak(flag); - port_leveldoor_remoteOpen(flag); + port_progressFlag_remoteCue(flag); // Vanilla only; rando reports world access via SET_CHECK_STATUS instead. if (!wasSet && !IS_RANDO && ShouldShowNotifications()) { if (const char* opened = LevelOpenSeenFlagName(flag)) { diff --git a/src/port/Patches/Patches.h b/src/port/Patches/Patches.h index bf5fd4869..52a06b339 100644 --- a/src/port/Patches/Patches.h +++ b/src/port/Patches/Patches.h @@ -129,8 +129,9 @@ void port_beginDemoAudioHold(void); void port_tickDemoAudioHold(void); int port_audioHeld(void); +// One-shot cues when a teammate's file-progress flag arrives +void port_progressFlag_remoteCue(int32_t progressFlag); void port_notedoor_remoteOpen(int32_t progressFlag); - void port_leveldoor_remoteOpen(int32_t progressFlag); void port_breakable_remoteBreak(int32_t progressFlag); @@ -179,9 +180,15 @@ void port_remoteCarry_setCarried(uint32_t clientId, int32_t markerId, float offs void port_remoteCarry_throw(uint32_t clientId, int32_t markerId, float start[3], float target[3]); void port_remoteCarry_reset(void); void port_anchorDummies_onActorsFreed(void); + +// Connected, in a real room, syncing world state. +int32_t port_anchor_isWorldSyncActive(void); + +// The puzzle mirrors below are home-scoped. void port_puzzleStep_orBits(int32_t puzzleId, int32_t bits); int32_t port_puzzleStep_get(int32_t puzzleId); int32_t port_puzzleStep_getForMap(int32_t map, int32_t puzzleId); +int32_t port_puzzleStep_getForLevel(int32_t levelId, int32_t puzzleId); void port_puzzlePos_mark(int32_t puzzleId, int32_t x, int32_t y, int32_t z); int32_t port_puzzlePos_isMarked(int32_t puzzleId, int32_t x, int32_t y, int32_t z); diff --git a/src/port/Romhack/RomhackTable.h b/src/port/Romhack/RomhackTable.h index 3e96f7247..a12e19fc0 100644 --- a/src/port/Romhack/RomhackTable.h +++ b/src/port/Romhack/RomhackTable.h @@ -29,7 +29,7 @@ static constexpr RomhackTableEntry kRomhackTable[] = { { "13f4fa8a180fe5775a606486effbafeb58862d26", "CutThroatCoast", true }, // The Gruntch, Santa's Village - { "bed22dd8ef931228fbc94f006dfc718a4d4f6f8c", "Gruntch", false }, + { "bed22dd8ef931228fbc94f006dfc718a4d4f6f8c", "Gruntch", true }, // Snow Glow Village { "23596c2858283b847e9e0ff44785e35110002fc7", "SnowGlowVillage", false }, diff --git a/src/port/Romhack/Shared/HackShared.cpp b/src/port/Romhack/Shared/HackShared.cpp index 6f18d60ac..f431a00f3 100644 --- a/src/port/Romhack/Shared/HackShared.cpp +++ b/src/port/Romhack/Shared/HackShared.cpp @@ -9,6 +9,7 @@ extern "C" { #include "enums.h" #include "functions.h" #include "actor.h" +#include "core2/abilityprogress.h" extern ActorArray* suBaddieActorArray; @@ -26,10 +27,12 @@ void ApplyNoteSignHooks(); f32 MeasureBoldNameWidth(const char* s); void ApplyPauseNameCentering(); void ApplyDialogSuppression(); +void ApplyForceAbilitiesUsed(); int sNoteSignActorId = -1; const int* sSuppressedDialogs = nullptr; int sSuppressedDialogCount = 0; +s32 sForcedUsedAbilities = 0; // Romhacks that have note signs and Bottles explainers don't need them when // note saving is turned on. Suppress them. @@ -109,6 +112,17 @@ void ApplyDialogSuppression() { }); } +// Mark moves as already used +void ApplyForceAbilitiesUsed() { + COND_HOOK(OnSaveLoad, EVENT_PRIORITY_NORMAL, sForcedUsedAbilities != 0, [](IEvent*) { + for (int move = 0; move < 32; move++) { + if (sForcedUsedAbilities & (1 << move)) { + ability_setHasUsed(static_cast(move)); + } + } + }); +} + RegisterShipInitFunc noteSignInitFunc(ApplyNoteSignHooks, { CVAR_NOTE_RETENTION }); RegisterShipInitFunc pauseNameCenterInit(ApplyPauseNameCentering, { "BOOT" }); @@ -124,3 +138,10 @@ void HackShared_EnableDialogSuppression(const int* dialogIds, int count) { sSuppressedDialogCount = count; ApplyDialogSuppression(); } + +void HackShared_EnableForceAbilitiesUsed(const ability_used* moves, int count) { + for (int i = 0; i < count; i++) { + sForcedUsedAbilities |= (1 << moves[i]); + } + ApplyForceAbilitiesUsed(); +} diff --git a/src/port/Romhack/Shared/HackShared.h b/src/port/Romhack/Shared/HackShared.h index 24b555236..37d8cb578 100644 --- a/src/port/Romhack/Shared/HackShared.h +++ b/src/port/Romhack/Shared/HackShared.h @@ -1,8 +1,23 @@ #pragma once +extern "C" { +#include "core2/abilityprogress.h" +} + +constexpr ability_used kAllUsedAbilities[] = { + ABILITY_USED_JUMP, ABILITY_USED_FLAP, ABILITY_USED_FLIP, ABILITY_USED_SWIM, ABILITY_USED_CLIMB, + ABILITY_USED_BEAK_BARGE, ABILITY_USED_SLIDE, ABILITY_USED_EGG, ABILITY_USED_FLY, ABILITY_USED_SHOCK, + ABILITY_USED_PECK, ABILITY_USED_CLAW, ABILITY_USED_TWIRL, +}; + void HackShared_EnableNoteSignSuppression(int signActorId); void HackShared_EnableDialogSuppression(const int* dialogIds, int count); +void HackShared_EnableForceAbilitiesUsed(const ability_used* moves, int count); template inline void HackShared_EnableDialogSuppression(const int (&dialogIds)[N]) { HackShared_EnableDialogSuppression(dialogIds, N); } + +template inline void HackShared_EnableForceAbilitiesUsed(const ability_used (&moves)[N]) { + HackShared_EnableForceAbilitiesUsed(moves, N); +} diff --git a/src/port/Romhack/Shared/ProximityDialogs.cpp b/src/port/Romhack/Shared/ProximityDialogs.cpp index ba05f6829..1388630dc 100644 --- a/src/port/Romhack/Shared/ProximityDialogs.cpp +++ b/src/port/Romhack/Shared/ProximityDialogs.cpp @@ -11,6 +11,8 @@ extern f32 D_8037C5B0[3]; } namespace { +constexpr s32 kDialogFlagSkippable = 0x1; + u16 sDialogShown[2] = { 0, 0 }; const ProximityDialogMap* sWorldMaps = nullptr; s32 sWorldMapCount = 0; @@ -56,7 +58,8 @@ void ProximityDialogs_Run(const ProximityDialogMap* maps, int count) { if (!(ml_vec3f_distance(anchor, D_8037C5B0) < page.radius)) { return; } - gcdialog_showDialog(page.textId, page.dialogFlags, (f32*)page.dialogPos, NULL, NULL, NULL); + gcdialog_showDialog(page.textId, page.dialogFlags | kDialogFlagSkippable, (f32*)page.dialogPos, NULL, NULL, + NULL); sDialogShown[page.word] |= page.doneBit; if (page.token >= 0) { mumboscore_set((enum mumbotoken_e)page.token, true); diff --git a/src/port/Romhack/Shared/StealthNoise.cpp b/src/port/Romhack/Shared/StealthNoise.cpp new file mode 100644 index 000000000..98147c193 --- /dev/null +++ b/src/port/Romhack/Shared/StealthNoise.cpp @@ -0,0 +1,362 @@ +#include +#include + +#include "port/Enhancements/Events/Hooks/Events.h" +#include "port/Romhack/RomhackConfig.h" +#include "StealthNoise.h" + +extern "C" { +#include "enums.h" +#include "functions.h" +#include "bk_time.h" +#include "core1/core1.h" +#include "core2/timedfunc.h" +#include "core1/pfsmanager.h" + +extern f32 D_8037C5B0[3]; +extern PfsManagerControllerData D_80281138[4]; +extern Gfx D_80369238[]; +f32 randf(void); +s32 getGameMode(void); + +typedef struct { + s16 x, y, topVertexAlpha, bottomVertexAlpha; + u8 fmtString[8]; + f32 scale; + u8* string; + u8 rgba[4]; +} StealthPrintBuffer; +extern StealthPrintBuffer* print_sCurrentPtr; +} + +namespace { + +// Constants +constexpr f32 kHudLerp = 0.25f; +constexpr f32 kAlphaLerp = 0.2f; +constexpr f32 kAlphaEpsilon = 0.01f; +constexpr f32 kHudShownX = 20.0f; +constexpr f32 kHudHiddenX = -70.0f; +constexpr f32 kHudYDialog = 137.0f; +constexpr f32 kHudYPlain = 177.0f; +constexpr f32 kAlphaNear = 1.0f; +constexpr f32 kAlphaFar = 0.6f; +constexpr f32 kStickDeadzone = 0.1f; +constexpr f32 kGainScaleInner = 0.4f; +constexpr f32 kGainScaleOuter = 0.46f; +constexpr f32 kGainJitter = 0.05f; +constexpr f32 kDecay = 0.55f; +constexpr f32 kDecayFloor = 0.1f; +constexpr f32 kEggPeriodHead = 0.4f; +constexpr f32 kEggPeriodAss = 0.6f; +constexpr f32 kEggJitter = 0.07f; +constexpr f32 kLoudAirborne = 0.85f; +constexpr f32 kLoudAirJitter = 0.1f; +constexpr f32 kCatchCamDelay = 0.72f; +constexpr f32 kLabelScale = 0.75f; +constexpr s32 kAirborneForLanding = 3; +constexpr u32 kCatchSfxPacked = 0xB31FF86B; +constexpr s32 kCatchSfxA = 0x142; +constexpr s32 kCatchSfxB = 0x14B; + +// HUD geometry +constexpr s16 kLabelOffX = 8, kLabelOffY = 8; +constexpr s16 kFrameX = 0, kFrameY = 0, kFrameW = 85, kFrameH = 20; +constexpr s16 kBarX = 4, kBarY = 12, kBarW = 77, kBarH = 5; +constexpr f32 kFrameAlphaScale = 160.0f; +constexpr f32 kBarAlphaScale = 136.0f; + +// Quiet-states table +constexpr s32 kQuietStates[] = { + BS_0_NONE, + BS_1_IDLE, + BS_2_WALK_SLOW, + BS_1F_WALK_CREEP, + BS_5A_LOADZONE, + BS_7_CROUCH, + BS_7A_WALK_MUD, + BS_98_WALK_DRONE, + BS_9_EGG_HEAD, + BS_A_EGG_ASS, + BS_14_BTROT_ENTER, + BS_15_BTROT_IDLE, + BS_17_BTROT_EXIT, + BS_1A_WONDERWING_ENTER, + BS_1B_WONDERWING_IDLE, + BS_1E_WONDERWING_EXIT, +}; + +struct NoiseState { + s32 airborneFrames; + bool loudLanding; + f32 noise; + f32 gain; + f32 burstTimer; + f32 burstAmount; + f32 eggTimer; + bool hudRetracted; + f32 hudX, hudY, hudAlpha; + f32 targetX, targetY, targetAlpha; + bool hudOffscreen; +}; + +NoiseState sState{}; +const StealthNoiseConfig* sCfg = nullptr; +bool sCaughtBefore = false; +bool sSuspended = false; +bool sCatchPending = false; + +f32 Clamp01(f32 value) { + return value < 0.0f ? 0.0f : (value > 1.0f ? 1.0f : value); +} + +void Approach(f32& current, f32 target, f32 rate, f32 epsilon) { + const f32 delta = target - current; + if (fabsf(delta) > epsilon) { + current += delta * rate; + } +} + +bool IsQuiet(s32 state) { + for (s32 quietState : kQuietStates) { + if (quietState == state) { + return true; + } + } + return false; +} + +void ResetMeter() { + sState.airborneFrames = 0; + sState.loudLanding = false; + sState.noise = 0.0f; + sState.eggTimer = 0.0f; + sState.burstTimer = 0.0f; + sState.targetX = kHudHiddenX; + sState.targetY = kHudYPlain; + sState.targetAlpha = kAlphaFar; + sState.hudOffscreen = true; +} + +void RetractHud() { + sState.hudRetracted = true; +} + +void TriggerCatch() { + sState.noise = 1.0f; + func_8030E624(kCatchSfxPacked); + gcdialog_showDialog(sCfg->caughtTextId, sCaughtBefore ? 0x02 : 0x82, NULL, NULL, NULL, NULL); + func_80324E38(0.0f, 1); + timed_setStaticCameraToNode(kCatchCamDelay, 1); + timedFunc_set_0(kCatchCamDelay, RetractHud); + sCaughtBefore = true; + sCatchPending = true; +} + +void ResolveCatch() { + gcsfx_play((enum sfx_e)(sfx_randi2(0, 2) != 0 ? kCatchSfxA : kCatchSfxB)); + if (!mumboscore_get((enum mumbotoken_e)sCfg->firstCatchToken)) { + const s32 warpDestination = port_getRomhackWarpDest(sCfg->escapeWarpIndex); + if (warpDestination >= 0) { + func_8031CC8C(NULL, warpDestination); + } else if (sCfg->escapeWarpFallback != nullptr) { + sCfg->escapeWarpFallback(NULL, NULL); + } + mumboscore_set((enum mumbotoken_e)sCfg->firstCatchToken, 1); + } else { + transitionToMap((enum map_e)gsworld_getMap(), gsworld_getExit(), 1); + } + sSuspended = true; + sCatchPending = false; +} + +void Update() { + if (sCfg == nullptr || gsworld_getMap() != sCfg->map) { + return; + } + NoiseState& meter = sState; + + Approach(meter.hudX, meter.targetX, kHudLerp, 1.0f); + Approach(meter.hudY, meter.targetY, kHudLerp, 1.0f); + Approach(meter.hudAlpha, meter.targetAlpha, kAlphaLerp, kAlphaEpsilon); + meter.hudAlpha = Clamp01(meter.hudAlpha); + + if (meter.burstTimer > 0.0f) { + meter.burstTimer -= time_getDelta(); + if (meter.burstTimer < 0.0f) { + meter.burstTimer = 0.0f; + } + } else { + meter.burstAmount = 0.0f; + } + + const bool dialogUp = gcdialog_hasCurrentTextId() != 0; + if (!dialogUp && sCatchPending) { + ResolveCatch(); + } + + const f32 playerX = D_8037C5B0[0]; + const bool inRoom = playerX >= sCfg->zoneMin && playerX <= sCfg->zoneMax; + if (inRoom && !meter.hudRetracted) { + meter.hudOffscreen = false; + } else if (!inRoom) { + meter.hudOffscreen = true; + } + + print_dialog((s32)(kLabelOffX + meter.hudX), (s32)(kLabelOffY + meter.hudY), (u8*)"NOISE"); + if (print_sCurrentPtr != nullptr) { + print_sCurrentPtr->scale = kLabelScale; + if (inRoom && !meter.hudOffscreen) { + meter.targetAlpha = (playerX >= sCfg->innerMin && playerX <= sCfg->innerMax) ? kAlphaNear : kAlphaFar; + } else { + meter.targetAlpha = 0.0f; + } + print_sCurrentPtr->rgba[0] = 0xFF; + print_sCurrentPtr->rgba[1] = 0xFF; + print_sCurrentPtr->rgba[2] = 0xFF; + print_sCurrentPtr->rgba[3] = (u8)(meter.hudAlpha * 255.0f); + } + + meter.targetY = dialogUp ? kHudYDialog : kHudYPlain; + meter.targetX = meter.hudRetracted ? kHudHiddenX : kHudShownX; + meter.hudOffscreen = meter.hudRetracted; + + if (sSuspended || sCatchPending) { + return; + } + + const s32 state = bs_getState(); + const bool quiet = IsQuiet(state); + const bool stable = player_isStable() != 0; + + const bool inner = playerX >= sCfg->innerMin && playerX <= sCfg->innerMax; + if (!inRoom) { + ResetMeter(); + return; + } + + const bool muted = !stable || D_80281138[0].side_button2.button_z != 0 || state == BS_73_UNKNOWN || + state == BS_79_BTROT_LOCKED || state == BS_98_WALK_DRONE || state == BS_1E_WONDERWING_EXIT || + (state & ~0x10) == BS_7_CROUCH; + f32 gain = 0.0f; + if (!muted) { + gain = Clamp01((bastick_distance() - kStickDeadzone) / (inner ? kGainScaleInner : kGainScaleOuter)); + } + meter.gain = Clamp01(gain + randf() * kGainJitter); + + if (state == BS_9_EGG_HEAD || state == BS_A_EGG_ASS) { + meter.eggTimer += time_getDelta(); + const f32 period = (state == BS_9_EGG_HEAD) ? kEggPeriodHead : kEggPeriodAss; + meter.noise = (meter.eggTimer > period ? kStickDeadzone : 0.0f) + meter.burstAmount + randf() * kEggJitter; + } else { + meter.noise = (inner && stable) ? meter.gain : meter.noise + meter.gain; + meter.eggTimer = 0.0f; + if (!stable) { + meter.airborneFrames++; + if (!inner) { + meter.loudLanding = false; + } + } else { + if (meter.airborneFrames >= kAirborneForLanding) { + meter.loudLanding = true; + meter.noise = 1.0f; + } + if (!inner) { + meter.loudLanding = false; + const f32 decayed = meter.noise * kDecay; + if (decayed < kDecayFloor) { + meter.airborneFrames = 0; + meter.noise = 0.0f; + } else { + meter.noise = decayed; + } + meter.noise += randf() * kGainJitter; + } + } + } + + if (state != BS_73_UNKNOWN && state != BS_79_BTROT_LOCKED && !quiet) { + meter.noise = stable ? 1.0f : kLoudAirborne + randf() * kLoudAirJitter; + } + meter.noise = Clamp01(meter.noise); + + if (inner && stable && (!quiet || meter.loudLanding)) { + TriggerCatch(); + } +} + +void FillRect(Gfx** gfx, s32 left, s32 top, s32 width, s32 height, u8 red, u8 green, u8 blue, u8 alpha) { + if (width <= 0 || height <= 0 || alpha == 0) { + return; + } + gDPPipeSync((*gfx)++); + gDPSetPrimColor((*gfx)++, 0, 0, red, green, blue, alpha); + gDPSetCombineMode((*gfx)++, G_CC_PRIMITIVE, G_CC_PRIMITIVE); + gDPScisFillRectangle((*gfx)++, left, top, left + width - 1, top + height - 1); + gDPPipeSync((*gfx)++); +} + +void BarColour(s32 percent, u8* red, u8* green) { + const s32 remaining = 100 - percent; + if (percent >= 100) { + *red = 0xFF; + *green = 0x00; + } else if (remaining >= 100) { + *red = 0x00; + *green = 0xFF; + } else if (remaining < 40) { + *red = 0xFF; + *green = (u8)((255 * remaining) / 40); + } else { + *red = (u8)((255 * percent) / 60); + *green = 0xFF; + } +} + +void Draw(Gfx** gfx) { + if (sCfg == nullptr || gsworld_getMap() != sCfg->map || getGameMode() == GAME_MODE_4_PAUSED) { + return; + } + const NoiseState& meter = sState; + const u8 frameAlpha = (u8)(meter.hudAlpha * kFrameAlphaScale); + if (frameAlpha == 0) { + return; + } + + gSPDisplayList((*gfx)++, D_80369238); + FillRect(gfx, (s32)(kFrameX + meter.hudX), (s32)(kFrameY + meter.hudY), kFrameW, kFrameH, 0x00, 0x00, 0x00, + frameAlpha); + + s32 percent = (s32)(meter.noise * 100.0f); + percent = percent < 0 ? 0 : (percent > 100 ? 100 : percent); + u8 red, green; + BarColour(percent, &red, &green); + FillRect(gfx, (s32)(kBarX + meter.hudX), (s32)(kBarY + meter.hudY), (s32)(kBarW * meter.noise), kBarH, red, green, + 0x00, (u8)(meter.hudAlpha * kBarAlphaScale)); +} + +} // namespace + +void StealthNoise_AddBurst(float amount, float seconds) { + sState.burstAmount = amount; + sState.burstTimer = seconds; +} + +void StealthNoise_Enable(const StealthNoiseConfig& cfg) { + sCfg = &cfg; + ResetMeter(); + + REGISTER_LISTENER(GameFrameUpdate, EVENT_PRIORITY_NORMAL, [](IEvent*) { Update(); }); + + REGISTER_LISTENER(OnHudDraw, EVENT_PRIORITY_NORMAL, [](IEvent* event) { + auto* hudEvent = reinterpret_cast(event); + Draw(hudEvent->gfx); + }); + + REGISTER_LISTENER(OnMapLoad, EVENT_PRIORITY_NORMAL, [](IEvent*) { + sSuspended = false; + sCatchPending = false; + sState.hudRetracted = false; + ResetMeter(); + }); +} diff --git a/src/port/Romhack/Shared/StealthNoise.h b/src/port/Romhack/Shared/StealthNoise.h new file mode 100644 index 000000000..5d25e698c --- /dev/null +++ b/src/port/Romhack/Shared/StealthNoise.h @@ -0,0 +1,20 @@ +#pragma once + +extern "C" { +#include "prop.h" +} + +struct StealthNoiseConfig { + int map; + float zoneMin; + float zoneMax; + float innerMin; + float innerMax; + int caughtTextId; + int escapeWarpIndex; + void (*escapeWarpFallback)(NodeProp*, ActorMarker*); + int firstCatchToken; +}; + +void StealthNoise_Enable(const StealthNoiseConfig& cfg); +void StealthNoise_AddBurst(float amount, float seconds); diff --git a/src/port/Romhack/Specific/BubblingBog.cpp b/src/port/Romhack/Specific/BubblingBog.cpp index fe1e4c682..9762bbe5d 100644 --- a/src/port/Romhack/Specific/BubblingBog.cpp +++ b/src/port/Romhack/Specific/BubblingBog.cpp @@ -1,5 +1,6 @@ #include #include "port/Enhancements/Events/Hooks/Events.h" +#include "port/Romhack/Shared/HackShared.h" extern "C" { #include "enums.h" @@ -11,6 +12,7 @@ void TooieJiggyDance_ForceEnable(); void RegisterBubblingBogPatches() { TooieJiggyDance_ForceEnable(); + HackShared_EnableForceAbilitiesUsed(kAllUsedAbilities); // Bubbling Bog Brewery's swapy water is hazardous REGISTER_VB_SHOULD(VB_GROUND_HAZARD_ACTIVE, EVENT_PRIORITY_NORMAL, { diff --git a/src/port/Romhack/Specific/Dreamie.cpp b/src/port/Romhack/Specific/Dreamie.cpp index e176a277e..2a1dbae0c 100644 --- a/src/port/Romhack/Specific/Dreamie.cpp +++ b/src/port/Romhack/Specific/Dreamie.cpp @@ -30,8 +30,7 @@ void RegisterDreamiePatches() { REGISTER_LISTENER(OnWarpResolveDest, EVENT_PRIORITY_NORMAL, [](IEvent* event) { auto* ev = reinterpret_cast(event); - if (ev->warpId == WARP_ID_SM_EXIT_BANJOS_HOUSE || ev->warpId == WARP_ID_LAIR_ENTER_MM_LOBBY_FROM_SM_LEVEL || - ev->warpId == WARP_ID_LAIR_ENTER_LAIR_FROM_SM_LEVEL) { + if (ev->warpId == WARP_ID_SM_EXIT_BANJOS_HOUSE || ev->warpId == WARP_ID_LAIR_ENTER_LAIR_FROM_SM_LEVEL) { *ev->dest = ev->defaultDest; } }); diff --git a/src/port/Romhack/Specific/TheGruntch.cpp b/src/port/Romhack/Specific/TheGruntch.cpp index 488750ecd..497d139ab 100644 --- a/src/port/Romhack/Specific/TheGruntch.cpp +++ b/src/port/Romhack/Specific/TheGruntch.cpp @@ -8,6 +8,7 @@ #include "port/Romhack/Shared/HackShared.h" #include "port/Romhack/Shared/Storybook.h" #include "port/Romhack/Shared/ProximityDialogs.h" +#include "port/Romhack/Shared/StealthNoise.h" extern "C" { #include "enums.h" @@ -16,9 +17,20 @@ extern "C" { #include "actor.h" #include "core1/ml.h" #include "core2/timedfunc.h" +#include "bk_time.h" extern f32 D_8037C5B0[3]; extern PfsManagerControllerData D_80281138[4]; +extern f32 cameraPosition[3]; +extern f32 cameraRotation[3]; +extern f32 D_8037D948[3]; +extern f32 D_8037D9C8[3]; +extern f32 D_8037D9E0[3]; +extern f32 D_8037D9D4, D_8037D9D8, D_8037D9EC, D_8037D9F0; +extern struct { + u8 unk0; + u8 level; +} D_80383300; typedef struct struct_1A_s { f32 delay; @@ -250,6 +262,7 @@ constexpr s32 kLeaveHutFlags = 0x02; f32 sJiggyPos[3] = { 0.0f, 500.0f, -95.0f }; f32 sMumboState = 0.0f; bool sMumboRewardEnabled = false; +bool sLeaveHutPending = false; void MumboReward_spawnJiggy() { jiggy_spawn((enum jiggy_e)kRewardJiggy, sJiggyPos); @@ -268,7 +281,7 @@ extern "C" s32 romhack_mumboTransform(s32 transformId) { } timedFunc_set_0(kJiggyDelay, MumboReward_spawnJiggy); timedFunc_set_0(kStateDelay, MumboReward_setState); - gcdialog_showDialog(kLeaveHutText, kLeaveHutFlags, NULL, NULL, NULL, NULL); + sLeaveHutPending = true; return 1; } @@ -280,8 +293,145 @@ extern "C" s32 romhack_mumboRandomEventsAllowed(void) { return sMumboRewardEnabled ? 0 : 1; } +// Mumbo's reward shows a static camera +namespace { +constexpr f32 kPanPosition[3] = { -250.0f, 194.0f, 147.0f }; +constexpr f32 kPanRotation[3] = { 35.0f, 315.0f, 0.0f }; + +bool sPanSaved = false; +f32 sPanSavedPosition[3]; +f32 sPanSavedRotation[3]; + +void MumboReward_updatePendingDialog() { + if (!sLeaveHutPending) { + return; + } + const s32 state = bs_getState(); + if (state == BS_74_UNKNOWN || state == BS_20_LANDING || state == BS_44_JIG_JIGGY) { + return; + } + gcdialog_showDialog(kLeaveHutText, kLeaveHutFlags, NULL, NULL, NULL, NULL); + sLeaveHutPending = false; +} + +void MumboReward_updateCamera() { + if (!sMumboRewardEnabled) { + return; + } + MumboReward_updatePendingDialog(); + if (sMumboState > 0.0f) { + if (!sPanSaved) { + sPanSaved = true; + for (int i = 0; i < 3; i++) { + sPanSavedPosition[i] = cameraPosition[i]; + sPanSavedRotation[i] = cameraRotation[i]; + } + } + for (int i = 0; i < 3; i++) { + cameraPosition[i] = kPanPosition[i]; + cameraRotation[i] = kPanRotation[i]; + D_8037D948[i] = kPanPosition[i]; + D_8037D9C8[i] = 0.0f; + D_8037D9E0[i] = 0.0f; + } + D_8037D9D4 = 0.0f; + D_8037D9D8 = 0.0f; + D_8037D9EC = 0.0f; + D_8037D9F0 = 0.0f; + + sMumboState -= time_getDelta(); + if (sMumboState == 0.0f) { + sMumboState = -1.0f; // sentinel: expired, restore next frame + } + } else if (sMumboState < 0.0f && sPanSaved) { + for (int i = 0; i < 3; i++) { + cameraPosition[i] = sPanSavedPosition[i]; + cameraRotation[i] = sPanSavedRotation[i]; + } + sPanSaved = false; + sMumboState = 0.0f; + } +} +} // namespace + static void Gruntch_EnableMumboReward() { sMumboRewardEnabled = true; + REGISTER_LISTENER(GameFrameUpdate, EVENT_PRIORITY_NORMAL, [](IEvent*) { MumboReward_updateCamera(); }); +} + +// Game-Over respawns +static void Gruntch_EnableVoidOutRespawn() { + REGISTER_VB_SHOULD(VB_VOID_OUT_RESPAWN_TRANSITION, EVENT_PRIORITY_NORMAL, { + s32 map = va_arg(args, s32); + s32 exit = va_arg(args, s32); + if (D_80383300.level == 1) { + map = MAP_28_MMM_EGG_ROOM; + exit = 2; + } else if (D_80383300.level == 0xA) { + map = MAP_6C_GL_RED_CAULDRON_ROOM; + exit = 5; + } + transitionToMap((enum map_e)map, exit, 1); + *should = false; + }); +} + +// Firing an egg spikes the stealth meter +static void Gruntch_EnableEggNoise() { + REGISTER_VB_SHOULD(VB_EGG_FIRE_SFX, EVENT_PRIORITY_NORMAL, { + s32 slot = va_arg(args, s32); + s32* rate = va_arg(args, s32*); + switch (slot) { + case 0: + StealthNoise_AddBurst(0.3f, 0.2f); + break; + case 1: + StealthNoise_AddBurst(0.65f, 0.3f); + *rate = 0x6D60; + break; + case 2: + StealthNoise_AddBurst(0.65f, 0.4f); + break; + default: + break; + } + (void)should; + }); +} + +// Lair music persists through various maps +constexpr s32 kMusicGroupLair[] = { 0x6A, 0x6C, 0x6F, 0x71, 0x6B, 0x15 }; +constexpr s32 kMusicGroupVillage[] = { 0x1B, 0x22, 0x0C }; + +static bool SameMusicGroup(const s32* group, int count, s32 a, s32 b) { + bool hasA = false, hasB = false; + for (int i = 0; i < count; i++) { + hasA = hasA || group[i] == a; + hasB = hasB || group[i] == b; + } + return hasA && hasB; +} + +// Banjo & Kazooie don't rebound when hitting windows with Rat-A-Tap Rap +static void Gruntch_EnableWindowRapNoRebound() { + REGISTER_VB_SHOULD(VB_BUMP_REBOUNDS_PLAYER, EVENT_PRIORITY_NORMAL, { + ActorMarker* marker = va_arg(args, ActorMarker*); + if (marker != NULL && marker->id == MARKER_107_ENGINE_ROOM_DOOR) { + *should = false; + } + }); +} + +static void Gruntch_EnableWarpMusic() { + REGISTER_VB_SHOULD(VB_WARP_KEEPS_MUSIC, EVENT_PRIORITY_NORMAL, { + const s32 dest = va_arg(args, s32); + const s32 cur = gsworld_getMap(); + if (SameMusicGroup(kMusicGroupVillage, ARRAY_COUNT(kMusicGroupVillage), cur, dest) || + SameMusicGroup(kMusicGroupLair, ARRAY_COUNT(kMusicGroupLair), cur, dest)) { + musicKeepsPlaying(); + } + (void)should; + }); } // ------------------------------------------------------- Jiggy consolidation @@ -360,22 +510,31 @@ static void Gruntch_EnableActGate() { }); } +// ------------------------------------------------------------ Stealth section +extern "C" void warp_rbbExitBoomBoxContainer(NodeProp*, ActorMarker*); + +constexpr s32 kWarpRbbExitBoomBoxContainer = 182; + +constexpr StealthNoiseConfig kGruntchStealth = { + MAP_3C_RBB_KITCHEN, -500.0f, 3600.0f, 0.0f, 3100.0f, 0xA7B, kWarpRbbExitBoomBoxContainer, + warp_rbbExitBoomBoxContainer, 0x13, +}; + // ------------------------------------------------------- Patch registration void RegisterGruntchPatches() { TooieJiggyDance_ForceEnable(); Storybook_Enable(kGruntchStorybook); ProximityDialogs_Enable(kGruntchGameplayDialogs); + StealthNoise_Enable(kGruntchStealth); Gruntch_EnableActGate(); Gruntch_EnableConditionalActors(); Gruntch_EnableMumboReward(); + Gruntch_EnableVoidOutRespawn(); + Gruntch_EnableEggNoise(); + Gruntch_EnableWarpMusic(); + Gruntch_EnableWindowRapNoRebound(); Gruntch_EnablePauseTotalsLayout(); Gruntch_EnableJiggyTally(); HackShared_EnableDialogSuppression(kGruntchSuppressedDialogs); - - /* MISSING FEATURES - * Static camera pan for mumbo's reward - * Stealth minigame in Gruntch's room (RBB Kitchen) - * Possible retention of turbo trainers through cauldron warp - * Game over respawn to Gruntch Cave - */ + HackShared_EnableForceAbilitiesUsed(kAllUsedAbilities); } diff --git a/src/port/UI/DeveloperTools/GameplayTools.cpp b/src/port/UI/DeveloperTools/GameplayTools.cpp index 1a8c04963..9daf8c844 100644 --- a/src/port/UI/DeveloperTools/GameplayTools.cpp +++ b/src/port/UI/DeveloperTools/GameplayTools.cpp @@ -434,10 +434,42 @@ void DrawGrantUnlocks() { } } +// Index 0 traces every space; the rest are ANCHOR_FLAGSPACE_* ids offset by one. +static const std::unordered_map flagTraceSpaces = { + { 0, "All" }, { 1, "File Progress" }, { 2, "Volatile" }, { 3, "Level Specific" }, + { 4, "Map Specific" }, { 5, "Rando Inf" }, +}; + +void DrawFlagTracer() { + ImGui::SeparatorText("Flag Tracer"); + ImGui::TextWrapped("Logs every flag write to the console and log file, with the flag's enum name and a marker on " + "each map load."); + + UIWidgets::CVarCheckbox("Trace Flag Writes", CVAR_DEVELOPER_TOOLS("FlagTrace"), + UIWidgets::CheckboxOptions().Color(THEME_COLOR).DefaultValue(false)); + + if (!CVarGetInteger(CVAR_DEVELOPER_TOOLS("FlagTrace"), 0)) { + return; + } + + UIWidgets::CVarCombobox("Flag Space", CVAR_DEVELOPER_TOOLS("FlagTraceSpace"), flagTraceSpaces, + UIWidgets::ComboboxOptions() + .Color(THEME_COLOR) + .Tooltip("Limit tracing to a single flag space.") + .DefaultIndex(0)); + UIWidgets::CVarCheckbox("Include Call Stacks", CVAR_DEVELOPER_TOOLS("FlagTraceStacks"), + UIWidgets::CheckboxOptions() + .Color(THEME_COLOR) + .DefaultValue(false) + .Tooltip("Name the function and line that set each flag.")); +} + void DrawMonitoringTools() { level_e currentLevel = map_getLevel(gsworld_getMap()); int32_t mapIndex = 0; + DrawFlagTracer(); + ImGui::SeparatorText("Map Specific Flags"); if (ImGui::BeginChild("MapFlagChild")) { if (ImGui::BeginTable("MapFlagTable", 2, ImGuiTableFlags_SizingFixedFit)) { From ad39f516ed93d6a3c91bcc34993f9ddc246639fc Mon Sep 17 00:00:00 2001 From: aMannus Date: Wed, 5 Aug 2026 07:54:30 +0200 Subject: [PATCH 115/131] Fix saving --- src/port/Rando/ItemQueue.cpp | 2 +- src/port/Rando/Logic/GeneratePools.cpp | 1 + src/port/Rando/Logic/GenerateSaveData.cpp | 2 +- src/port/Rando/ObjectBehavior/BlueEgg.cpp | 40 +++++++++++++++ src/port/Rando/ObjectBehavior/MusicNote.cpp | 45 +++++++++++++---- .../Rando/ObjectBehavior/ObjectBehavior.cpp | 1 - .../Rando/ObjectBehavior/ObjectBehavior.h | 1 - src/port/Rando/ObjectBehavior/Prop.cpp | 49 ------------------- src/port/Save/SaveManager.cpp | 5 +- 9 files changed, 81 insertions(+), 65 deletions(-) create mode 100644 src/port/Rando/ObjectBehavior/BlueEgg.cpp delete mode 100644 src/port/Rando/ObjectBehavior/Prop.cpp diff --git a/src/port/Rando/ItemQueue.cpp b/src/port/Rando/ItemQueue.cpp index 33a89991f..3e25558bf 100644 --- a/src/port/Rando/ItemQueue.cpp +++ b/src/port/Rando/ItemQueue.cpp @@ -67,7 +67,7 @@ void ItemQueue::Process() { RandoSaveCheck randoSaveCheck = RANDO_SAVE_CHECKS[randoCheckId]; ItemQueue::GiveItem(randoSaveCheck.randoItemId); ItemQueue::SendNotification(randoSaveCheck.randoItemId); - RANDO_SAVE_CHECKS[randoCheckId].received = true; + randoSaveCheck.received = true; itemQueue.pop(); } diff --git a/src/port/Rando/Logic/GeneratePools.cpp b/src/port/Rando/Logic/GeneratePools.cpp index 4adcfbfeb..f6eace65e 100644 --- a/src/port/Rando/Logic/GeneratePools.cpp +++ b/src/port/Rando/Logic/GeneratePools.cpp @@ -178,6 +178,7 @@ void GeneratePoolFromSaveData(SaveData* saveData) { .randoCollectionId = randoSaveCheck.randoCollectionId, .isShuffled = randoSaveCheck.isShuffled, .eligible = randoSaveCheck.eligible, + .received = randoSaveCheck.received, .skipped = randoSaveCheck.skipped, }; diff --git a/src/port/Rando/Logic/GenerateSaveData.cpp b/src/port/Rando/Logic/GenerateSaveData.cpp index daabf23c3..a71e69b61 100644 --- a/src/port/Rando/Logic/GenerateSaveData.cpp +++ b/src/port/Rando/Logic/GenerateSaveData.cpp @@ -150,7 +150,7 @@ void Rando::Logic::InitializeSaveData(SaveData* saveData) { } void Rando::Logic::GenerateSaveData(SaveData* saveData) { - for (auto& object : Rando::Logic::shuffledPool) { + for (auto& object : RANDO_SAVE_CHECKS) { saveData->shipSaveData.randoSaveData.randoSaveCheck[object.randoCheckId] = object; } diff --git a/src/port/Rando/ObjectBehavior/BlueEgg.cpp b/src/port/Rando/ObjectBehavior/BlueEgg.cpp new file mode 100644 index 000000000..7d55692d7 --- /dev/null +++ b/src/port/Rando/ObjectBehavior/BlueEgg.cpp @@ -0,0 +1,40 @@ +#include "port/ShipInit.hpp" +#include "port/Enhancements/Events/Hooks/Events.h" +#include "port/Rando/Logic/Logic.h" +#include "port/Rando/CustomCollectible/CustomCollectible.h" + +#define OPTION_ENABLED RANDO_SAVE_OPTIONS[RO_SHUFFLE_BLUE_EGGS].optionValue + +bool OverrideBlueEggSpawn(s16 spawnPosition[3], int32_t propAsset) { + if (propAsset != ASSET_6D7_SPRITE_BLUE_EGGS) { + return false; + } + + s32 position[3] = { spawnPosition[0], spawnPosition[1], spawnPosition[2] }; + RandoCheckId randoCheckId = Rando::StaticData::GetCheckByPosition(position[0], position[1], position[2]); + + if (randoCheckId == RC_UNKNOWN || !Rando::Logic::IsCheckShuffled(randoCheckId)) { + return false; + } + + // Let vanilla blue eggs spawn after check has been obtained. + if (Rando::Logic::IsCheckObtained(randoCheckId)) { + return false; + } + + CustomCollectible::QueueProp(position, randoCheckId); + return true; +} + +void RegisterRandoBlueEggs() { + COND_VB_SHOULD(VB_OVERRIDE_PROP_SPAWN, EVENT_PRIORITY_NORMAL, IS_RANDO && OPTION_ENABLED, { + s16* spawnPosition = va_arg(args, s16*); + int32_t propAsset = va_arg(args, int32_t); + bool replaceEgg = OverrideBlueEggSpawn(spawnPosition, propAsset); + if (replaceEgg) { + *should = true; + } + }); +} + +static RegisterShipInitFunc initFunc(RegisterRandoBlueEggs, { "IS_RANDO" }); diff --git a/src/port/Rando/ObjectBehavior/MusicNote.cpp b/src/port/Rando/ObjectBehavior/MusicNote.cpp index 485775456..ec2ec0595 100644 --- a/src/port/Rando/ObjectBehavior/MusicNote.cpp +++ b/src/port/Rando/ObjectBehavior/MusicNote.cpp @@ -1,12 +1,7 @@ -#include "ObjectBehavior.h" -#include "port/Rando/Logic/Logic.h" -#include "port/Rando/CustomObject/CustomObject.h" - -#include -#include "port/UI/cvar_prefixes.h" -#include -#include "port/Enhancements/Events/PortEnhancements.h" +#include "port/ShipInit.hpp" #include "port/Enhancements/Events/Hooks/Events.h" +#include "port/Rando/Logic/Logic.h" +#include "port/Rando/CustomCollectible/CustomCollectible.h" extern "C" { void item_inc(enum item_e item); @@ -15,10 +10,40 @@ extern u8 D_80385FF0[0xE]; #define OPTION_ENABLED RANDO_SAVE_OPTIONS[RO_SHUFFLE_MUSIC_NOTES].optionValue -void Rando::ObjectBehavior::InitMusicNoteBehavior() { +bool OverrideMusicNoteSpawn(s16 spawnPosition[3], int32_t propAsset) { + if (propAsset != ASSET_6D6_SPRITE_MUSIC_NOTE) { + return false; + } + + s32 position[3] = { spawnPosition[0], spawnPosition[1], spawnPosition[2] }; + RandoCheckId randoCheckId = Rando::StaticData::GetCheckByPosition(position[0], position[1], position[2]); + + if (randoCheckId == RC_UNKNOWN || !Rando::Logic::IsCheckShuffled(randoCheckId)) { + return false; + } + + if (!Rando::Logic::IsCheckObtained(randoCheckId)) { + CustomCollectible::QueueProp(position, randoCheckId); + } + + return true; +} + +void RegisterRandoMusicNotes() { COND_HOOK(OnSetJiggyList, EVENT_PRIORITY_NORMAL, IS_RANDO && OPTION_ENABLED, [](IEvent* event) { OnSetJiggyList* ev = (OnSetJiggyList*)event; item_set(ITEM_C_NOTE, D_80385FF0[ev->levelId]); - }) + }); + + COND_VB_SHOULD(VB_OVERRIDE_PROP_SPAWN, EVENT_PRIORITY_NORMAL, IS_RANDO && OPTION_ENABLED, { + s16* spawnPosition = va_arg(args, s16*); + int32_t propAsset = va_arg(args, int32_t); + bool replaceNote = OverrideMusicNoteSpawn(spawnPosition, propAsset); + if (replaceNote) { + *should = true; + } + }); } + +static RegisterShipInitFunc initFunc(RegisterRandoMusicNotes, { "IS_RANDO" }); diff --git a/src/port/Rando/ObjectBehavior/ObjectBehavior.cpp b/src/port/Rando/ObjectBehavior/ObjectBehavior.cpp index b5c5977df..6215487a7 100644 --- a/src/port/Rando/ObjectBehavior/ObjectBehavior.cpp +++ b/src/port/Rando/ObjectBehavior/ObjectBehavior.cpp @@ -247,7 +247,6 @@ void Rando::ObjectBehavior::Init() { InitJiggyBehavior(); InitJinjoBehavior(); InitMolehillBehavior(); - InitMusicNoteBehavior(); InitStopNSwopBehavior(); UpdateJunkList(); diff --git a/src/port/Rando/ObjectBehavior/ObjectBehavior.h b/src/port/Rando/ObjectBehavior/ObjectBehavior.h index 3cb7e5199..bb1cd4437 100644 --- a/src/port/Rando/ObjectBehavior/ObjectBehavior.h +++ b/src/port/Rando/ObjectBehavior/ObjectBehavior.h @@ -17,7 +17,6 @@ void InitBundleBehavior(); void InitJiggyBehavior(); void InitJinjoBehavior(); void InitMolehillBehavior(); -void InitMusicNoteBehavior(); void InitStopNSwopBehavior(); void ModifySwitchBehavior(int32_t switchActorId); diff --git a/src/port/Rando/ObjectBehavior/Prop.cpp b/src/port/Rando/ObjectBehavior/Prop.cpp deleted file mode 100644 index 32b0cd6a2..000000000 --- a/src/port/Rando/ObjectBehavior/Prop.cpp +++ /dev/null @@ -1,49 +0,0 @@ -#include "port/ShipInit.hpp" -#include "port/Enhancements/Events/Hooks/Events.h" -#include "port/Rando/Logic/Logic.h" -#include "port/Rando/CustomCollectible/CustomCollectible.h" - -#define BLUE_EGG_OPTION_ENABLED RANDO_SAVE_OPTIONS[RO_SHUFFLE_BLUE_EGGS].optionValue -#define MUSIC_NOTE_OPTION_ENABLED RANDO_SAVE_OPTIONS[RO_SHUFFLE_MUSIC_NOTES].optionValue - -bool OverridePropSpawn(s16 spawnPosition[3], int32_t propAsset) { - s32 position[3] = { spawnPosition[0], spawnPosition[1], spawnPosition[2] }; - - if (!IS_RANDO) { - return false; - } - - if (!BLUE_EGG_OPTION_ENABLED && propAsset == ASSET_6D7_SPRITE_BLUE_EGGS) { - return false; - } - - if (!MUSIC_NOTE_OPTION_ENABLED && propAsset == ASSET_6D6_SPRITE_MUSIC_NOTE) { - return false; - } - - RandoCheckId randoCheckId = Rando::StaticData::GetCheckByPosition(position[0], position[1], position[2]); - if (randoCheckId == RC_UNKNOWN) { - return false; - } - - if (!Rando::Logic::IsCheckShuffled(randoCheckId)) { - return false; - } - - if (Rando::Logic::IsCheckObtained(randoCheckId)) { - return true; - } - - CustomCollectible::QueueProp(position, randoCheckId); - return true; -} - -void RegisterRandoPropBehaviour() { - COND_VB_SHOULD(VB_OVERRIDE_PROP_SPAWN, EVENT_PRIORITY_NORMAL, true, { - s16* spawnPosition = va_arg(args, s16*); - int32_t propAsset = va_arg(args, int32_t); - *should = OverridePropSpawn(spawnPosition, propAsset); - }); -} - -static RegisterShipInitFunc initFunc(RegisterRandoPropBehaviour, { "IS_RANDO" }); diff --git a/src/port/Save/SaveManager.cpp b/src/port/Save/SaveManager.cpp index 18a863005..55c807f9a 100644 --- a/src/port/Save/SaveManager.cpp +++ b/src/port/Save/SaveManager.cpp @@ -76,7 +76,7 @@ static void BitfieldSetNBits(uint8_t* array, int startIndex, int numBits, int va void RandoSaveCheck_to_json(nlohmann::json& j, const RandoSaveCheck& randoSaveCheck) { j = nlohmann::json::array({ randoSaveCheck.randoCheckId, randoSaveCheck.randoItemId, randoSaveCheck.randoCollectionId, randoSaveCheck.isShuffled, randoSaveCheck.eligible, - randoSaveCheck.skipped }); + randoSaveCheck.received, randoSaveCheck.skipped }); } RandoSaveCheck RandoSaveCheck_from_json(const nlohmann::json& j, RandoSaveCheck& randoSaveCheck) { @@ -85,7 +85,8 @@ RandoSaveCheck RandoSaveCheck_from_json(const nlohmann::json& j, RandoSaveCheck& j.at(2).get_to(randoSaveCheck.randoCollectionId); j.at(3).get_to(randoSaveCheck.isShuffled); j.at(4).get_to(randoSaveCheck.eligible); - j.at(5).get_to(randoSaveCheck.skipped); + j.at(5).get_to(randoSaveCheck.received); + j.at(6).get_to(randoSaveCheck.skipped); return randoSaveCheck; } From 210101d47d185a4a16e4dea744d3cfab596f3a19 Mon Sep 17 00:00:00 2001 From: aMannus Date: Wed, 5 Aug 2026 13:28:12 +0200 Subject: [PATCH 116/131] Shuffle molehills with custom collectible --- .../CustomCollectible/CustomCollectible.cpp | 1 + src/port/Rando/ObjectBehavior/Molehill.cpp | 36 +++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/src/port/Rando/CustomCollectible/CustomCollectible.cpp b/src/port/Rando/CustomCollectible/CustomCollectible.cpp index f5e78a2de..63eee11ce 100644 --- a/src/port/Rando/CustomCollectible/CustomCollectible.cpp +++ b/src/port/Rando/CustomCollectible/CustomCollectible.cpp @@ -108,6 +108,7 @@ f32 CustomCollectible::GetScale(RandoItemType itemType) { case RITYPE_SNS_EGG: return 0.42857143f; case RITYPE_EMPTY_HONEYCOMB: + case RITYPE_MOLEHILL: return 0.8f; default: return 1.0f; diff --git a/src/port/Rando/ObjectBehavior/Molehill.cpp b/src/port/Rando/ObjectBehavior/Molehill.cpp index 9008a0118..9984e0ec4 100644 --- a/src/port/Rando/ObjectBehavior/Molehill.cpp +++ b/src/port/Rando/ObjectBehavior/Molehill.cpp @@ -7,6 +7,9 @@ #include #include "port/Enhancements/Events/PortEnhancements.h" #include "port/Enhancements/Events/Hooks/Events.h" +#include "port/ShipInit.hpp" + +#include "port/Rando/CustomCollectible/CustomCollectible.h" #define MOLETABLE_SIZE 16 #define BRIDGE_REQUIREMENT 6 @@ -201,3 +204,36 @@ void Rando::ObjectBehavior::InitMolehillBehavior() { } }) } + +bool OverrideMoleSpawn(OnActorSpawn* ev) { + if (ev->actorId != ACTOR_12B_TUTORIAL_BOTTLES) { + return false; + } + + int32_t spawnPosition[3] = { ev->posX, ev->posY, ev->posZ }; + RandoCheckId randoCheckId = Rando::StaticData::GetCheckByPosition(ev->posX, ev->posY, ev->posZ); + + if (randoCheckId == RC_UNKNOWN || !Rando::Logic::IsCheckShuffled(randoCheckId)) { + return false; + } + + if (Rando::Logic::IsCheckObtained(randoCheckId)) { + return true; + } + + CustomCollectible::Spawn(spawnPosition, randoCheckId); + return true; +} + +void RegisterRandoMolehills() { + COND_HOOK(OnActorSpawn, EVENT_PRIORITY_NORMAL, IS_RANDO && OPTION_ENABLED, [](IEvent* event) { + OnActorSpawn* ev = (OnActorSpawn*)event; + + bool replaceMole = OverrideMoleSpawn(ev); + if (replaceMole) { + event->Cancelled = true; + } + }); +} + +static RegisterShipInitFunc initFunc(RegisterRandoMolehills, { "IS_RANDO" }); From 89571c0299195fe9a6886932d10b4660ecb130b0 Mon Sep 17 00:00:00 2001 From: Jeod <47716344+JeodC@users.noreply.github.com> Date: Wed, 5 Aug 2026 13:32:42 -0400 Subject: [PATCH 117/131] General bug fixes (#402) * Fix SNS demos not working on v1.1, PAL, JP * Fix audio bgm running when game window is frozen (drag/resize) * Fix audio static on certain platforms * Fix decomp animation function names being backwards --- include/functions.h | 8 +- src/core1/audio_manager.c | 13 + src/core1/graphics_thread.c | 7 +- src/core2/ba/anim.c | 15 +- src/core2/bs/bEggAss.c | 2 +- src/core2/bs/bEggHead.c | 2 +- src/core2/bs/bFlap.c | 2 +- src/core2/bs/bFly.c | 14 +- src/core2/bs/bPeck.c | 2 +- src/core2/bs/bSwim.c | 4 +- src/core2/bs/bTrot.c | 6 +- src/core2/bs/bWhirl.c | 2 +- src/core2/bs/beeFly.c | 2 +- src/core2/bs/claw.c | 2 +- src/core2/bs/climb.c | 2 +- src/core2/bs/croc.c | 6 +- src/core2/bs/crouch.c | 4 +- src/core2/bs/rest.c | 2 +- src/core2/bs/splat.c | 4 +- src/core2/bs/stand.c | 6 +- src/core2/bs/timeout.c | 2 +- src/core2/bs/walrus.c | 4 +- src/core2/bs/washy.c | 2 +- src/core2/map/exit.c | 4 +- src/port/Audio/AudioSync.cpp | 23 + src/port/DevTools/DevSequences.cpp | 4 + src/port/DevTools/DevSequences.h | 1 + src/port/Game.cpp | 1 + src/port/GameVersion/AssetVersionRemap.h | 1115 +++++++++++----------- src/port/OS/OS_AI.cpp | 13 + src/port/Patches/Patches.h | 3 + src/port/ResourceHelpers.cpp | 20 + src/port/UI/LighthouseMenuDevTools.cpp | 5 + 33 files changed, 695 insertions(+), 607 deletions(-) diff --git a/include/functions.h b/include/functions.h index 531d6728e..8222da5b3 100644 --- a/include/functions.h +++ b/include/functions.h @@ -483,10 +483,10 @@ bool baanim_isAnimID(enum asset_e anim_id); AnimCtrl *baanim_getAnimCtrlPtr(void); bool baanim_isAt(f32); void baanim_playForDuration_loopSmooth(enum asset_e anim_id, f32 duration); -void baanim_playForDuration_loopStartingAt(enum asset_e anim_id, f32, f32); -void baanim_playForDuration_once(enum asset_e anim_id, f32 duration); -void baanim_playForDuration_onceSmooth(enum asset_e, f32); -void baanim_playForDuration_onceStartingAt(enum asset_e anim_id, f32 duration, f32 arg2); +void baanim_playForDuration_loopSmoothStartingAt(enum asset_e anim_id, f32, f32); +void baanim_playForDuration_onceSmooth(enum asset_e anim_id, f32 duration); +void baanim_playForDuration_once(enum asset_e, f32); +void baanim_playForDuration_onceSmoothStartingAt(enum asset_e anim_id, f32 duration, f32 arg2); void baanim_scaleDuration(f32); void baanim_setDurationRange(f32, f32); void baanim_setEnd(f32); diff --git a/src/core1/audio_manager.c b/src/core1/audio_manager.c index d6d669dac..091412825 100644 --- a/src/core1/audio_manager.c +++ b/src/core1/audio_manager.c @@ -362,6 +362,11 @@ void audioManagerThread_entry(void *arg) { return; } ThreadWatchdog_Beat(WATCHDOG_AUDIO_MANAGER); // [port] one beat per audio frame + // [port] Pump messages backlog while a stall blocks this thread + // and then burst. + if (osAiGetLength() / 4 >= sMaxFrameSize) { + continue; + } if (audioManager_handleFrameMsg(audioManager.audio_info[sAudioInfoID % 3], sPrevFinishedAudioInfo)) { if (skip_handle_done_mesg == 0) { osRecvMesg(&audioManager.audioReplyMsgQ, (OSMesg *) &D_80275844, OS_MESG_BLOCK); @@ -371,6 +376,14 @@ void audioManagerThread_entry(void *arg) { skip_handle_done_mesg--; } } + // [port] The N64 pacing is open-loop (pump cadence x frame size vs the + // DAC, same crystal), so a pump missed on PC drains the playback + // cushion for tens of seconds. Self-post one extra frame at a time, + // re-deciding on the fresh buffer level after each push, until the + // cushion is rebuilt. + if (port_audioCatchupFrames() > 0) { + osSendMesgPtr(&audioManager.audioFrameMsgQ, NULL, OS_MESG_NOBLOCK); + } } } diff --git a/src/core1/graphics_thread.c b/src/core1/graphics_thread.c index 4df502bf2..63e6ba620 100644 --- a/src/core1/graphics_thread.c +++ b/src/core1/graphics_thread.c @@ -210,6 +210,11 @@ void thread5_startGfxTask(struct ucode_task_data_s *task_data) { void thread5_handleAudioTaskMesg(OSMesg msg) { thread5_insertAudioTaskData(msg); + if ((sUnkFlag1 == UNKFLAG1_NO_TASK) && (sActiveAudioTaskDataID != sSelectedAudioTaskDataID)) { + struct ucode_task_data_s *ptr = sAudioTaskDataList[sActiveAudioTaskDataID]; + sActiveAudioTaskDataID = (sActiveAudioTaskDataID + 1) % 20; + thread5_startAudioTask(ptr); + } } void thread5_handleF3DEXTaskMesg(OSMesg msg) { @@ -368,7 +373,7 @@ void thread5_handleTask7Mesg(OSMesg arg0) { void thread5_handleAudioTimerEvent(void) { // [port] While the demo audio hold is up, skip the frame message so the // engine does not consume sfx cues queued for the demo's first frame. - if (port_audioHeld()) { + if (port_audioHeld() || port_audioStallHold()) { return; } osSendMesgPtr(audioManager_getFrameMesgQueue(), NULL, OS_MESG_NOBLOCK); diff --git a/src/core2/ba/anim.c b/src/core2/ba/anim.c index 6c639148d..c0fe50101 100644 --- a/src/core2/ba/anim.c +++ b/src/core2/ba/anim.c @@ -278,7 +278,7 @@ void baanim_playForDuration_loop(enum asset_e anim_id, f32 duration){ anctrl_start(playerAnimCtrl, "baanim.c", 0x193); } -void baanim_playForDuration_loopStartingAt(enum asset_e anim_id, f32 duration, f32 start_position){ +void baanim_playForDuration_loopSmoothStartingAt(enum asset_e anim_id, f32 duration, f32 start_position){ anctrl_reset(playerAnimCtrl); anctrl_setIndex(playerAnimCtrl, anim_id); anctrl_setDuration(playerAnimCtrl, duration); @@ -287,17 +287,15 @@ void baanim_playForDuration_loopStartingAt(enum asset_e anim_id, f32 duration, f anctrl_start(playerAnimCtrl, "baanim.c", 0x19e); } -void baanim_playForDuration_once(enum asset_e anim_id, f32 duration){ +void baanim_playForDuration_onceSmooth(enum asset_e anim_id, f32 duration){ anctrl_reset(playerAnimCtrl); - // [port] smooth should be off, isn't in decomp - anctrl_setSmoothTransition(playerAnimCtrl, false); anctrl_setIndex(playerAnimCtrl, anim_id); anctrl_setDuration(playerAnimCtrl, duration); anctrl_setPlaybackType(playerAnimCtrl, ANIMCTRL_ONCE); anctrl_start(playerAnimCtrl, "baanim.c", 0x1a8); } -void baanim_playForDuration_onceStartingAt(enum asset_e anim_id, f32 duration, f32 start_position){ +void baanim_playForDuration_onceSmoothStartingAt(enum asset_e anim_id, f32 duration, f32 start_position){ anctrl_reset(playerAnimCtrl); anctrl_setIndex(playerAnimCtrl, anim_id); anctrl_setDuration(playerAnimCtrl, duration); @@ -306,17 +304,16 @@ void baanim_playForDuration_onceStartingAt(enum asset_e anim_id, f32 duration, f anctrl_start(playerAnimCtrl, "baanim.c", 0x1b3); } -void baanim_playForDuration_onceSmooth(enum asset_e anim_id, f32 duration){ +void baanim_playForDuration_once(enum asset_e anim_id, f32 duration){ anctrl_reset(playerAnimCtrl); - // [port] possible decomp/src bug? smooth should be on here, and off above - // anctrl_setSmoothTransition(playerAnimCtrl, false); + anctrl_setSmoothTransition(playerAnimCtrl, false); anctrl_setIndex(playerAnimCtrl, anim_id); anctrl_setDuration(playerAnimCtrl, duration); anctrl_setPlaybackType(playerAnimCtrl, ANIMCTRL_ONCE); anctrl_start(playerAnimCtrl, "baanim.c", 0x1bd); } -void baanim_playForDuration_onceSmoothStartingAt(enum asset_e anim_id, f32 duration, f32 start_position){ +void baanim_playForDuration_onceStartingAt(enum asset_e anim_id, f32 duration, f32 start_position){ anctrl_reset(playerAnimCtrl); anctrl_setSmoothTransition(playerAnimCtrl, false); anctrl_setIndex(playerAnimCtrl, anim_id); diff --git a/src/core2/bs/bEggAss.c b/src/core2/bs/bEggAss.c index 8d92bda7d..b4941a6b0 100644 --- a/src/core2/bs/bEggAss.c +++ b/src/core2/bs/bEggAss.c @@ -12,7 +12,7 @@ u8 D_8037D2E1; /* .code */ void bseggass_init(void){ - baanim_playForDuration_onceSmooth(ASSET_2B_ANIM_BSEGGASS, 1.0f); + baanim_playForDuration_once(ASSET_2B_ANIM_BSEGGASS, 1.0f); code_14420_setUpdateTypes(1, YAW_STATE_3_BOUNDED, 1, BA_PHYSICS_LOCKED_ROTATION); yaw_setVelocityBounded(350.0f, 14.0f); baphysics_set_target_horizontal_velocity(0.0f); diff --git a/src/core2/bs/bEggHead.c b/src/core2/bs/bEggHead.c index 9651e0b00..65dedeff8 100644 --- a/src/core2/bs/bEggHead.c +++ b/src/core2/bs/bEggHead.c @@ -15,7 +15,7 @@ u8 D_8037D2F1; /* .code */ void bsegghead_init(void){ - baanim_playForDuration_onceSmooth(ASSET_2A_ANIM_BSEGGHEAD, 1.0f); + baanim_playForDuration_once(ASSET_2A_ANIM_BSEGGHEAD, 1.0f); code_14420_setUpdateTypes(1, YAW_STATE_3_BOUNDED, 1, BA_PHYSICS_LOCKED_ROTATION); yaw_setVelocityBounded(350.0f, 14.0f); baphysics_set_target_horizontal_velocity(0.0f); diff --git a/src/core2/bs/bFlap.c b/src/core2/bs/bFlap.c index 326279bb4..bf2615a71 100644 --- a/src/core2/bs/bFlap.c +++ b/src/core2/bs/bFlap.c @@ -22,7 +22,7 @@ f32 D_8037D308; u8 D_8037D30C; void bsbflap_init(void) { - baanim_playForDuration_onceSmooth(ASSET_18_ANIM_BSBFLAP_ENTER, 0.3f); + baanim_playForDuration_once(ASSET_18_ANIM_BSBFLAP_ENTER, 0.3f); code_14420_setUpdateTypes(1, YAW_STATE_1_DEFAULT, 1, BA_PHYSICS_NORMAL); if (bastick_distance() != 0.0f) { yaw_setIdeal(bastick_getAngleRelativeToBanjo()); diff --git a/src/core2/bs/bFly.c b/src/core2/bs/bFly.c index 5cc44ef2e..539528063 100644 --- a/src/core2/bs/bFly.c +++ b/src/core2/bs/bFly.c @@ -138,7 +138,7 @@ int func_802A37F8(void){ } void bsbfly_enter_init(void){ - baanim_playForDuration_onceSmooth(ASSET_45_ANIM_BSBFLY_ENTER, 1.4f); + baanim_playForDuration_once(ASSET_45_ANIM_BSBFLY_ENTER, 1.4f); code_14420_setUpdateTypes(1, YAW_STATE_1_DEFAULT, 3, BA_PHYSICS_AIRBORN); if(bastick_distance() != 0.0f) yaw_setIdeal(bastick_getAngleRelativeToBanjo()); @@ -325,7 +325,7 @@ int bsbfly_bombHitboxActive(void){ //bsbfly_bomb_init void bsbfly_bomb_init(void){ f32 sp1C[3]; - baanim_playForDuration_once(ASSET_43_ANIM_BSBFLY_BEAKBOMB_START, 1.0f); + baanim_playForDuration_onceSmooth(ASSET_43_ANIM_BSBFLY_BEAKBOMB_START, 1.0f); code_14420_setUpdateTypes(1, YAW_STATE_1_DEFAULT, 3, BA_PHYSICS_FREEZE); func_802A339C(D_8037D338, sp1C, 4200.0f); yaw_setIdeal(sp1C[1] + 180.0f); @@ -481,7 +481,7 @@ void bsbfly_beakbombend_update(void){ switch(D_8037D344){ case 0://L802A457C if(func_8028B254(0x5A)){ - baanim_playForDuration_onceStartingAt(ASSET_8_ANIM_BSJUMP, 2.0f, 0.6667f); + baanim_playForDuration_onceSmoothStartingAt(ASSET_8_ANIM_BSJUMP, 2.0f, 0.6667f); D_8037D344 = 1; } break; @@ -532,7 +532,7 @@ void func_802A46C8(void) { void bsbfly_beakbomb_crash_init(void) { - baanim_playForDuration_once(ASSET_3E_ANIM_BSBFLY_BEAKBOMB_CRASH, 1.4f); + baanim_playForDuration_onceSmooth(ASSET_3E_ANIM_BSBFLY_BEAKBOMB_CRASH, 1.4f); code_14420_setUpdateTypes(1, YAW_STATE_1_DEFAULT, 3, BA_PHYSICS_LOCKED_ROTATION); modelAppendages_setKazooiesUpperHalfVisibility(true); FUNC_8030E624(SFX_1F_HITTING_AN_ENEMY_3, 0.8f, 32750); @@ -584,7 +584,7 @@ void func_802A48B4(void) { D_8037D344 = 2; } } else if (anctrl_isAt(sp18, 0.92f)) { - baanim_playForDuration_once(ASSET_D2_ANIM_BSSPLAT, 2.25f); + baanim_playForDuration_onceSmooth(ASSET_D2_ANIM_BSSPLAT, 2.25f); D_8037D344 = 1; } break; @@ -636,7 +636,7 @@ void func_802A4A78(s32 arg0) { sp20 = 400.0f; } func_802BB3DC(2, 100.0f, 0.85f); - baanim_playForDuration_onceSmooth(ASSET_D3_ANIM_BSBFLY_BEAKBOMB_REBOUND, 1.2f); + baanim_playForDuration_once(ASSET_D3_ANIM_BSBFLY_BEAKBOMB_REBOUND, 1.2f); basfx_playOwSfx(1.0f); baMotor_80250D94(1.0f, 0.5f, 0.5f); playerPosition_get(sp3C); @@ -714,7 +714,7 @@ void bsbfly_knockback_init(void) { f32 sp1C[3]; func_802BB3DC(2, 100.0f, 0.85f); - baanim_playForDuration_onceSmooth(0x10D, 1.0f); + baanim_playForDuration_once(0x10D, 1.0f); func_8030E58C(SFX_56_BANJO_HUI, 1.0f); playerPosition_get(player_position); func_80294980(sp1C); diff --git a/src/core2/bs/bPeck.c b/src/core2/bs/bPeck.c index a4f234268..8f1bcc506 100644 --- a/src/core2/bs/bPeck.c +++ b/src/core2/bs/bPeck.c @@ -40,7 +40,7 @@ void bsbpeck_init(void){ if(bafalldamage_get_state() == 1) bafalldamage_set_state(2); - baanim_playForDuration_onceSmooth(ASSET_1A_ANIM_BSBPECK, 0.2f); + baanim_playForDuration_once(ASSET_1A_ANIM_BSBPECK, 0.2f); code_14420_setUpdateTypes(1, YAW_STATE_3_BOUNDED, 1, BA_PHYSICS_AIRBORN); yaw_setVelocityBounded(1200.0f, 10.0f); modelAppendages_setKazooiesUpperHalfVisibility(true); diff --git a/src/core2/bs/bSwim.c b/src/core2/bs/bSwim.c index 93be28c9c..15abe2080 100644 --- a/src/core2/bs/bSwim.c +++ b/src/core2/bs/bSwim.c @@ -288,7 +288,7 @@ void bsbswim_ow_init(void) { f32 sp24[3]; barebound_set_active(func_80296560()); - baanim_playForDuration_onceSmooth(0x1A0, 1.4f); + baanim_playForDuration_once(0x1A0, 1.4f); basfx_playOwSfx(1.0f); playerPosition_get(sp30); func_80294980(sp24); @@ -334,7 +334,7 @@ void bsbswim_ow_end(void) { void bsSwim_dive_init(void) { ability_use(ABILITY_3_CAMERA_CONTROL); - baanim_playForDuration_once(ASSET_3C_ANIM_BSSWIM_DIVE_ENTER, 1.0f); + baanim_playForDuration_onceSmooth(ASSET_3C_ANIM_BSSWIM_DIVE_ENTER, 1.0f); func_802A7140(); yaw_setVelocityBounded(500.0f, 5.0f); baphysics_set_target_velocity(0); diff --git a/src/core2/bs/bTrot.c b/src/core2/bs/bTrot.c index de118fec9..59af518e6 100644 --- a/src/core2/bs/bTrot.c +++ b/src/core2/bs/bTrot.c @@ -215,7 +215,7 @@ enum bs_e func_802A8D84(enum bs_e arg0){ void bsbtrot_enter_init(void){ func_802A8AD8(); - baanim_playForDuration_onceSmooth(ASSET_16_ANIM_BSBTROT_ENTER, 1.0f); + baanim_playForDuration_once(ASSET_16_ANIM_BSBTROT_ENTER, 1.0f); code_14420_setUpdateTypes(1, YAW_STATE_1_DEFAULT, 2, BA_PHYSICS_NORMAL); baphysics_set_target_horizontal_velocity(0.0f); func_802A8A40(); @@ -482,7 +482,7 @@ void bsbtrot_jump_end(void){ } void bsbtrot_exit_init(void){ - baanim_playForDuration_onceSmooth(ASSET_7_ANIM_BSBTROT_EXIT, 0.6f); + baanim_playForDuration_once(ASSET_7_ANIM_BSBTROT_EXIT, 0.6f); baanim_setUpdateType(BAANIM_UPDATE_1_NORMAL); baphysics_set_target_horizontal_velocity(0.0f); } @@ -711,7 +711,7 @@ void bsbtrot_ow_init(void){ func_802A8A40(); barebound_set_active(func_80296560()); - baanim_playForDuration_onceSmooth(ASSET_66_ANIM_BSBTROT_OW, 1.1f); + baanim_playForDuration_once(ASSET_66_ANIM_BSBTROT_OW, 1.1f); basfx_playOwSfx(1.0f); playerPosition_get(sp30); func_80294980(sp24); diff --git a/src/core2/bs/bWhirl.c b/src/core2/bs/bWhirl.c index 95b7a6d3b..4db5bd97a 100644 --- a/src/core2/bs/bWhirl.c +++ b/src/core2/bs/bWhirl.c @@ -81,7 +81,7 @@ void func_802AA58C(enum bs_e *arg0){ } void bsbwhirl_enter_init(void){ - baanim_playForDuration_onceSmooth(ASSET_22_ANIM_BSWHIRL_EXIT, 0.5f); + baanim_playForDuration_once(ASSET_22_ANIM_BSWHIRL_EXIT, 0.5f); code_14420_setUpdateTypes(1, YAW_STATE_1_DEFAULT, 1, BA_PHYSICS_NORMAL); baphysics_set_target_horizontal_velocity(0.0f); bastick_setZoneMax(0, 0.03f); diff --git a/src/core2/bs/beeFly.c b/src/core2/bs/beeFly.c index 1310f07d3..b837172ea 100644 --- a/src/core2/bs/beeFly.c +++ b/src/core2/bs/beeFly.c @@ -44,7 +44,7 @@ void func_802A04F0(void){ void bsbeefly_bs8Bunknown_init(void){ func_802A0340(); - baanim_playForDuration_onceSmooth(0x1df, 1.5f); + baanim_playForDuration_once(0x1df, 1.5f); code_14420_setUpdateTypes(1, YAW_STATE_1_DEFAULT, 3, BA_PHYSICS_AIRBORN); if(bastick_distance() != 0.0f){ yaw_setIdeal(bastick_getAngleRelativeToBanjo()); diff --git a/src/core2/bs/claw.c b/src/core2/bs/claw.c index 121490781..cd43bd2eb 100644 --- a/src/core2/bs/claw.c +++ b/src/core2/bs/claw.c @@ -18,7 +18,7 @@ int bsclaw_hitboxActive(void){ } void bsclaw_init(void){ - baanim_playForDuration_once(ASSET_5_ANIM_BSPUNCH, 1.3f); + baanim_playForDuration_onceSmooth(ASSET_5_ANIM_BSPUNCH, 1.3f); code_14420_setUpdateTypes(1, YAW_STATE_1_DEFAULT, 3, BA_PHYSICS_LOCKED_ROTATION); baphysics_set_target_yaw(yaw_getIdeal()); baphysics_set_target_horizontal_velocity(160.0f); diff --git a/src/core2/bs/climb.c b/src/core2/bs/climb.c index 618913ffb..38b9724af 100644 --- a/src/core2/bs/climb.c +++ b/src/core2/bs/climb.c @@ -96,7 +96,7 @@ void bsclimb_idle_update(void){ case 0: D_8037D3D4 -= time_getDelta(); if(D_8037D3D4 <= 0.0f){ - baanim_playForDuration_once(ASSET_B1_ANIM_BSCLIMB_IDLE_1, 2.96f); + baanim_playForDuration_onceSmooth(ASSET_B1_ANIM_BSCLIMB_IDLE_1, 2.96f); D_8037D3D0 = 1; } break; diff --git a/src/core2/bs/croc.c b/src/core2/bs/croc.c index bf4606934..c9671d38f 100644 --- a/src/core2/bs/croc.c +++ b/src/core2/bs/croc.c @@ -146,7 +146,7 @@ void bscroc_idle_end(void){ } void bscroc_walk_init(void){ - baanim_playForDuration_loopStartingAt(ASSET_E0_ANIM_BSCROC_WALK, 0.8f, 0.4f); + baanim_playForDuration_loopSmoothStartingAt(ASSET_E0_ANIM_BSCROC_WALK, 0.8f, 0.4f); code_14420_setUpdateTypes(BAANIM_UPDATE_2_SCALE_HORZ, YAW_STATE_1_DEFAULT, 1, BA_PHYSICS_NORMAL); baanim_setVelocityMapRanges(bsCrocMinWalkVelocity, bsCrocMaxWalkVelocity, bsCrocSlowestWalkDuration, bsCrocFastestWalkDuration); func_802900B4(); @@ -514,7 +514,7 @@ static void func_802ACF58(void){ } void bscroc_bite_init(void){ - baanim_playForDuration_loopStartingAt(ASSET_122_ANIM_BSCROC_BITE, 0.25f, 0.2f); + baanim_playForDuration_loopSmoothStartingAt(ASSET_122_ANIM_BSCROC_BITE, 0.25f, 0.2f); code_14420_setUpdateTypes(1, YAW_STATE_1_DEFAULT, 1, BA_PHYSICS_LOCKED_ROTATION); func_802ACF58(); D_8037D3F4 = 0; @@ -563,7 +563,7 @@ void bscroc_bite_end(void){ } void bscroc_eat_bad_init(void){ - baanim_playForDuration_once(ASSET_123_ANIM_BSCROC_EAT_BAD, 2.41f); + baanim_playForDuration_onceSmooth(ASSET_123_ANIM_BSCROC_EAT_BAD, 2.41f); code_14420_setUpdateTypes(1, YAW_STATE_1_DEFAULT, 2, BA_PHYSICS_LOCKED_ROTATION); baphysics_set_target_horizontal_velocity(0.0f); } diff --git a/src/core2/bs/crouch.c b/src/core2/bs/crouch.c index e9cd93c54..440744f60 100644 --- a/src/core2/bs/crouch.c +++ b/src/core2/bs/crouch.c @@ -18,12 +18,12 @@ void func_802AD6D0(void){ } void func_802AD6FC(void){ - baanim_playForDuration_once(ASSET_116_ANIM_BSCROUCH_NOINPUT, 2.0f); + baanim_playForDuration_onceSmooth(ASSET_116_ANIM_BSCROUCH_NOINPUT, 2.0f); D_8037D404 = 2; } void func_802AD728(void){ - baanim_playForDuration_onceStartingAt(ASSET_10C_ANIM_BSCROUCH_IDLE, 0.5f, 0.9999f); + baanim_playForDuration_onceSmoothStartingAt(ASSET_10C_ANIM_BSCROUCH_IDLE, 0.5f, 0.9999f); batimer_set(2, 2.0f); D_8037D404 = 1; } diff --git a/src/core2/bs/rest.c b/src/core2/bs/rest.c index e652db7b4..b811abb7d 100644 --- a/src/core2/bs/rest.c +++ b/src/core2/bs/rest.c @@ -35,7 +35,7 @@ void func_802B3AAC(enum asset_e anim_id, f32 anim_duration) { anctrl_setPlaybackType(anim_ctrl, ANIMCTRL_ONCE); break; default: - baanim_playForDuration_once(ASSET_167_ANIM_BSREST_MOVE, 0.5f); + baanim_playForDuration_onceSmooth(ASSET_167_ANIM_BSREST_MOVE, 0.5f); anctrl_setPlaybackType(anim_ctrl, ANIMCTRL_ONCE); break; } diff --git a/src/core2/bs/splat.c b/src/core2/bs/splat.c index 7d5c1fc52..0ec89715c 100644 --- a/src/core2/bs/splat.c +++ b/src/core2/bs/splat.c @@ -23,7 +23,7 @@ void func_802B4570(void) { void bssplat_init(void){ s32 sp1C; - baanim_playForDuration_onceSmooth(ASSET_149_ANIM_BSSPLAT, 1.1f); + baanim_playForDuration_once(ASSET_149_ANIM_BSSPLAT, 1.1f); code_14420_setUpdateTypes(1, YAW_STATE_1_DEFAULT, 3, BA_PHYSICS_LOCKED_ROTATION); bafalldamage_get_damage(&sp1C); item_adjustByDiffWithHud(ITEM_14_HEALTH, -sp1C); @@ -60,7 +60,7 @@ void bssplat_update(void){ sp1C = BS_2F_FALL; if(anctrl_isStopped(aCtrl)){ - baanim_playForDuration_once(ASSET_D2_ANIM_BSSPLAT, 2.25f); + baanim_playForDuration_onceSmooth(ASSET_D2_ANIM_BSSPLAT, 2.25f); D_8037D530 = 1; } break; diff --git a/src/core2/bs/stand.c b/src/core2/bs/stand.c index da427da74..d049e10fa 100644 --- a/src/core2/bs/stand.c +++ b/src/core2/bs/stand.c @@ -92,7 +92,7 @@ void bsstand_init(void){ if(bsclimb_inSet(bs_getPrevState())) climb_release(); - baanim_playForDuration_once(ASSET_6F_ANIM_BSSTAND_IDLE, 5.5f); + baanim_playForDuration_onceSmooth(ASSET_6F_ANIM_BSSTAND_IDLE, 5.5f); code_14420_setUpdateTypes(1, YAW_STATE_1_DEFAULT, 1, BA_PHYSICS_NORMAL); baphysics_set_target_horizontal_velocity(0.0f); func_802900B4(); @@ -243,12 +243,12 @@ void bsstand_update(void) { D_8037D540 = func_802B4870(D_8037D540); sp18 = D_80364D20[D_8037D540]; if (sp18 & 0x10) { - baanim_playForDuration_once(ASSET_95_ANIM_BSSTAND_KAZOOIE_PECK, 5.5f); + baanim_playForDuration_onceSmooth(ASSET_95_ANIM_BSSTAND_KAZOOIE_PECK, 5.5f); anctrl_start(anim_ctrl, "bsstand.c", 0x1AB); modelAppendages_setKazooiesUpperHalfVisibility(true); func_802900FC(); } else if (sp18 & 0x20) { - baanim_playForDuration_once(ASSET_95_ANIM_BSSTAND_KAZOOIE_PECK, 5.5f); + baanim_playForDuration_onceSmooth(ASSET_95_ANIM_BSSTAND_KAZOOIE_PECK, 5.5f); modelAppendages_setKazooiesUpperHalfVisibility(true); func_802900FC(); } else if (sp18 & 8) { diff --git a/src/core2/bs/timeout.c b/src/core2/bs/timeout.c index f4c636b9a..03b3fef09 100644 --- a/src/core2/bs/timeout.c +++ b/src/core2/bs/timeout.c @@ -11,7 +11,7 @@ f32 func_8029B41C(void); void ncbadie_func_802BF2C0(f32); void timeout_banjo_init(void){ - baanim_playForDuration_once(ASSET_77_ANIM_BSTIMEOUT, 3.2f); + baanim_playForDuration_onceSmooth(ASSET_77_ANIM_BSTIMEOUT, 3.2f); code_14420_setUpdateTypes(1, YAW_STATE_1_DEFAULT, 3, BA_PHYSICS_NORMAL); baphysics_set_target_horizontal_velocity(0.0f); func_802914CC(0xD); diff --git a/src/core2/bs/walrus.c b/src/core2/bs/walrus.c index cd53cfb7b..9b45a6a76 100644 --- a/src/core2/bs/walrus.c +++ b/src/core2/bs/walrus.c @@ -373,7 +373,7 @@ static void __bswalrus_recoil_init(s32 damage){ f32 sp24[3]; barebound_set_active(func_80296560()); - baanim_playForDuration_onceSmooth(ASSET_19C_ANIM_BSWALRUS_BOUNCE, 1.0f); + baanim_playForDuration_once(ASSET_19C_ANIM_BSWALRUS_BOUNCE, 1.0f); if(damage == 1) func_8030E58C(SFX_38_BANJO_AYE_1, 1.8f); else @@ -726,7 +726,7 @@ void bswalrus_sledloseinair_end(void){ } void bswalrus_timeout_init(void) { - baanim_playForDuration_once(ASSET_1A9_ANIM_BSWALRUS_LOSS, 3.2f); + baanim_playForDuration_onceSmooth(ASSET_1A9_ANIM_BSWALRUS_LOSS, 3.2f); code_14420_setUpdateTypes(1, YAW_STATE_1_DEFAULT, 3, BA_PHYSICS_FREEZE); baphysics_set_target_horizontal_velocity(0.0f); func_802914CC(0xD); diff --git a/src/core2/bs/washy.c b/src/core2/bs/washy.c index 9efa5bf21..6494ece1b 100644 --- a/src/core2/bs/washy.c +++ b/src/core2/bs/washy.c @@ -49,7 +49,7 @@ void bswashy_end(void){ } void bswashy_init(void){ - baanim_playForDuration_once(ASSET_281_ANIM_WISHYWASHY_DOOOH, 40.0f); + baanim_playForDuration_onceSmooth(ASSET_281_ANIM_WISHYWASHY_DOOOH, 40.0f); code_14420_setUpdateTypes(1, YAW_STATE_1_DEFAULT, 3, BA_PHYSICS_NORMAL); func_802900B4(); func_802B9980(0); diff --git a/src/core2/map/exit.c b/src/core2/map/exit.c index 565369751..ef01e5a22 100644 --- a/src/core2/map/exit.c +++ b/src/core2/map/exit.c @@ -222,7 +222,9 @@ void func_8034B8C0(enum map_e map_id, s32 demo_id) { volatileFlag_set(VOLATILE_FLAG_1F_IN_CHARACTER_PARADE, 1); func_802E4A70(); } - if ((demo_id == 0x5B) || (demo_id == 0x5F)) { + // [port] 0x5E: SNS picture demo slot on non-v1.0 bases (table retargeted in + // ResourceHelpers); unused leftover slot on v1.0, so always safe to accept. + if ((demo_id == 0x5B) || (demo_id == 0x5E) || (demo_id == 0x5F)) { sns_backup_items_and_unlock_all(); } } diff --git a/src/port/Audio/AudioSync.cpp b/src/port/Audio/AudioSync.cpp index c349e5986..435de1960 100644 --- a/src/port/Audio/AudioSync.cpp +++ b/src/port/Audio/AudioSync.cpp @@ -7,6 +7,9 @@ // thread-shared section with osSetIntMask(OS_IM_NONE)/restore. Routing those brackets to this // lock protects all of them with no edits to the audio code. +#include +#include +#include #include extern "C" { @@ -18,6 +21,26 @@ std::recursive_mutex gAudioLock; thread_local int gAudioMaskDepth = 0; } // namespace +// Window-freeze audio hold +namespace { +constexpr int64_t kCushionMs = 100; +std::atomic sAllowedUntilMs{ 0 }; + +int64_t NowMs() { + return std::chrono::duration_cast(std::chrono::steady_clock::now().time_since_epoch()) + .count(); +} +} // namespace + +extern "C" void port_noteMainLoopAlive(void) { + sAllowedUntilMs.store(NowMs() + kCushionMs, std::memory_order_relaxed); +} + +extern "C" int port_audioStallHold(void) { + const int64_t allowedUntil = sAllowedUntilMs.load(std::memory_order_relaxed); + return allowedUntil != 0 && NowMs() > allowedUntil; +} + extern "C" void port_lockAudio(void) { gAudioLock.lock(); } diff --git a/src/port/DevTools/DevSequences.cpp b/src/port/DevTools/DevSequences.cpp index 26758347c..fc9d07cd0 100644 --- a/src/port/DevTools/DevSequences.cpp +++ b/src/port/DevTools/DevSequences.cpp @@ -14,6 +14,7 @@ extern "C" { void gcparade_beginFFParade(void); void gcparade_beginFinalParade(void); void func_8034BA7C(enum map_e map_id, int exit_id); // warp (B&K demo uses MAP_1, exit 93) +void transitionToMap(enum map_e map, int exit, int transition); void func_8034B968(void); // start the attract demo selected by D_80386110 (sets transition + D_80386114) extern int D_80386110; // attract-demo cycle index void func_8025A55C(int, int, int); // fade the active music track @@ -72,6 +73,9 @@ void RegisterDevSequences_Init() { func_8034BA7C(MAP_1_SM_SPIRAL_MOUNTAIN, 93); sPending = SEQ_MODE9_DIALOG; break; + case SEQ_ENDING_ALL_100: + transitionToMap(MAP_95_CS_END_ALL_100, 0, 1); + break; default: D_80386110 = seq - SEQ_ATTRACT_BASE; func_8034B968(); diff --git a/src/port/DevTools/DevSequences.h b/src/port/DevTools/DevSequences.h index fb850057d..1ee871283 100644 --- a/src/port/DevTools/DevSequences.h +++ b/src/port/DevTools/DevSequences.h @@ -9,6 +9,7 @@ enum DevSequenceId { SEQ_PARADE_FINAL, SEQ_MODE9_BK, SEQ_MODE9_DIALOG, + SEQ_ENDING_ALL_100, SEQ_ATTRACT_BASE, }; diff --git a/src/port/Game.cpp b/src/port/Game.cpp index 1424dc54d..05a50561e 100644 --- a/src/port/Game.cpp +++ b/src/port/Game.cpp @@ -316,6 +316,7 @@ int SDL_main(int argc, char* argv[]) { }); while (WindowIsRunning() || !sGameThreadDone.load()) { ThreadWatchdog_Beat(WATCHDOG_MAIN_LOOP); + port_noteMainLoopAlive(); // Pump events every iteration: a task-starved pass must not starve // input and window messages. Ship::Context::GetRawInstance()->GetWindow()->HandleEvents(); diff --git a/src/port/GameVersion/AssetVersionRemap.h b/src/port/GameVersion/AssetVersionRemap.h index b905a2b55..5d17eb6f1 100644 --- a/src/port/GameVersion/AssetVersionRemap.h +++ b/src/port/GameVersion/AssetVersionRemap.h @@ -4,579 +4,580 @@ #include #include -// v1.0 -> v1.1 asset ID remap table. 1310 entries. +// v1.0 -> v1.1 asset ID remap table. 1313 entries. static const std::unordered_map sV10toV11Remap = { { 2468, 2212 }, { 2469, 2213 }, { 2470, 2214 }, { 2471, 2215 }, { 2472, 2268 }, { 2473, 2269 }, { 2474, 2218 }, { 2475, 2219 }, { 2476, 2220 }, { 2477, 2221 }, { 2478, 2274 }, { 2481, 2277 }, { 2483, 2279 }, { 2484, 2228 }, { 2485, 2229 }, { 2487, 2283 }, { 2488, 2232 }, { 2489, 2233 }, { 2490, 2234 }, { 2491, 2235 }, { 2498, 2294 }, - { 2504, 2248 }, { 2521, 2252 }, { 2524, 2255 }, { 2526, 2257 }, { 2528, 2311 }, { 2529, 2312 }, { 2571, 2315 }, - { 2572, 2316 }, { 2573, 2317 }, { 2574, 2318 }, { 2575, 2319 }, { 2576, 2320 }, { 2577, 2321 }, { 2578, 2322 }, - { 2579, 2323 }, { 2580, 2324 }, { 2581, 2325 }, { 2582, 2326 }, { 2583, 2327 }, { 2584, 2328 }, { 2585, 2329 }, - { 2586, 2330 }, { 2587, 2331 }, { 2588, 2332 }, { 2589, 2333 }, { 2590, 2334 }, { 2591, 2335 }, { 2592, 2336 }, - { 2593, 2337 }, { 2594, 2338 }, { 2595, 2339 }, { 2596, 2340 }, { 2597, 2341 }, { 2598, 2342 }, { 2599, 2343 }, - { 2600, 2344 }, { 2601, 2345 }, { 2602, 2346 }, { 2671, 2347 }, { 2672, 2348 }, { 2673, 2349 }, { 2674, 2350 }, - { 2675, 2351 }, { 2676, 2352 }, { 2677, 2353 }, { 2678, 2354 }, { 2679, 2355 }, { 2680, 2356 }, { 2681, 2357 }, - { 2682, 2358 }, { 2683, 2359 }, { 2684, 2360 }, { 2685, 2361 }, { 2686, 2362 }, { 2687, 2363 }, { 2688, 2364 }, - { 2689, 2365 }, { 2690, 2366 }, { 2691, 2367 }, { 2692, 2368 }, { 2693, 2369 }, { 2694, 2370 }, { 2695, 2371 }, - { 2696, 2372 }, { 2771, 2373 }, { 2772, 2374 }, { 2773, 2375 }, { 2774, 2376 }, { 2775, 2377 }, { 2776, 2378 }, - { 2777, 2379 }, { 2778, 2380 }, { 2779, 2381 }, { 2780, 2382 }, { 2781, 2383 }, { 2782, 2384 }, { 2783, 2385 }, - { 2784, 2386 }, { 2785, 2387 }, { 2786, 2388 }, { 2871, 2389 }, { 2872, 2390 }, { 2873, 2391 }, { 2874, 2392 }, - { 2875, 2393 }, { 2876, 2394 }, { 2877, 2395 }, { 2878, 2396 }, { 2879, 2397 }, { 2880, 2398 }, { 2881, 2399 }, - { 2882, 2400 }, { 2883, 2401 }, { 2884, 2402 }, { 2885, 2403 }, { 2886, 2404 }, { 2887, 2405 }, { 2888, 2406 }, - { 2889, 2407 }, { 2890, 2408 }, { 2891, 2409 }, { 2892, 2410 }, { 2893, 2411 }, { 2894, 2412 }, { 2895, 2413 }, - { 2896, 2414 }, { 2897, 2415 }, { 2971, 2416 }, { 2972, 2417 }, { 2973, 2418 }, { 2974, 2419 }, { 2975, 2420 }, - { 2976, 2421 }, { 2977, 2422 }, { 2978, 2423 }, { 2979, 2424 }, { 3071, 2425 }, { 3072, 2426 }, { 3073, 2427 }, - { 3074, 2428 }, { 3075, 2429 }, { 3076, 2430 }, { 3077, 2431 }, { 3078, 2432 }, { 3079, 2433 }, { 3080, 2434 }, - { 3081, 2435 }, { 3082, 2436 }, { 3083, 2437 }, { 3084, 2438 }, { 3085, 2439 }, { 3086, 2440 }, { 3087, 2441 }, - { 3088, 2442 }, { 3089, 2443 }, { 3090, 2444 }, { 3091, 2445 }, { 3092, 2446 }, { 3093, 2447 }, { 3094, 2448 }, - { 3095, 2449 }, { 3096, 2450 }, { 3097, 2451 }, { 3098, 2452 }, { 3099, 2453 }, { 3100, 2454 }, { 3101, 2455 }, - { 3102, 2456 }, { 3103, 2457 }, { 3104, 2458 }, { 3105, 2459 }, { 3106, 2460 }, { 3107, 2461 }, { 3108, 2462 }, - { 3109, 2463 }, { 3110, 2464 }, { 3111, 2465 }, { 3112, 2466 }, { 3113, 2467 }, { 3114, 2468 }, { 3115, 2469 }, - { 3171, 2470 }, { 3172, 2471 }, { 3173, 2472 }, { 3174, 2473 }, { 3175, 2474 }, { 3176, 2475 }, { 3177, 2476 }, - { 3178, 2477 }, { 3179, 2478 }, { 3180, 2479 }, { 3181, 2480 }, { 3182, 2481 }, { 3183, 2482 }, { 3184, 2483 }, - { 3185, 2484 }, { 3186, 2485 }, { 3187, 2486 }, { 3188, 2487 }, { 3189, 2488 }, { 3190, 2489 }, { 3191, 2490 }, - { 3192, 2491 }, { 3193, 2492 }, { 3194, 2493 }, { 3195, 2494 }, { 3196, 2495 }, { 3197, 2496 }, { 3198, 2497 }, - { 3199, 2498 }, { 3200, 2499 }, { 3201, 2500 }, { 3202, 2501 }, { 3203, 2502 }, { 3204, 2503 }, { 3205, 2504 }, - { 3206, 2505 }, { 3207, 2506 }, { 3208, 2507 }, { 3209, 2508 }, { 3210, 2509 }, { 3211, 2510 }, { 3212, 2511 }, - { 3213, 2512 }, { 3214, 2513 }, { 3215, 2514 }, { 3216, 2515 }, { 3217, 2516 }, { 3218, 2517 }, { 3219, 2518 }, - { 3220, 2519 }, { 3221, 2520 }, { 3222, 2521 }, { 3223, 2522 }, { 3224, 2523 }, { 3271, 2524 }, { 3272, 2525 }, - { 3273, 2526 }, { 3274, 2527 }, { 3275, 2528 }, { 3276, 2529 }, { 3277, 2530 }, { 3278, 2531 }, { 3279, 2532 }, - { 3280, 2533 }, { 3281, 2534 }, { 3282, 2535 }, { 3283, 2536 }, { 3284, 2537 }, { 3285, 2538 }, { 3286, 2539 }, - { 3287, 2540 }, { 3288, 2541 }, { 3289, 2542 }, { 3290, 2543 }, { 3291, 2544 }, { 3292, 2545 }, { 3293, 2546 }, - { 3294, 2547 }, { 3295, 2548 }, { 3296, 2549 }, { 3297, 2550 }, { 3298, 2551 }, { 3299, 2552 }, { 3300, 2553 }, - { 3301, 2554 }, { 3302, 2555 }, { 3303, 2556 }, { 3304, 2557 }, { 3371, 2558 }, { 3372, 2559 }, { 3373, 2560 }, - { 3374, 2561 }, { 3375, 2562 }, { 3376, 2563 }, { 3377, 2564 }, { 3378, 2565 }, { 3379, 2566 }, { 3380, 2567 }, - { 3381, 2568 }, { 3382, 2569 }, { 3383, 2570 }, { 3384, 2571 }, { 3385, 2572 }, { 3471, 2573 }, { 3472, 2574 }, - { 3473, 2575 }, { 3474, 2576 }, { 3475, 2577 }, { 3476, 2578 }, { 3477, 2579 }, { 3478, 2580 }, { 3479, 2581 }, - { 3480, 2582 }, { 3481, 2583 }, { 3482, 2584 }, { 3483, 2585 }, { 3484, 2586 }, { 3485, 2587 }, { 3486, 2588 }, - { 3487, 2589 }, { 3488, 2590 }, { 3489, 2591 }, { 3490, 2592 }, { 3491, 2593 }, { 3492, 2594 }, { 3493, 2595 }, - { 3494, 2596 }, { 3495, 2597 }, { 3496, 2598 }, { 3497, 2599 }, { 3498, 2600 }, { 3499, 2601 }, { 3500, 2602 }, - { 3501, 2603 }, { 3502, 2604 }, { 3503, 2605 }, { 3504, 2606 }, { 3505, 2607 }, { 3506, 2608 }, { 3507, 2609 }, - { 3508, 2610 }, { 3509, 2611 }, { 3510, 2612 }, { 3571, 2613 }, { 3572, 2614 }, { 3573, 2615 }, { 3574, 2616 }, - { 3575, 2617 }, { 3576, 2618 }, { 3577, 2619 }, { 3578, 2620 }, { 3579, 2621 }, { 3580, 2622 }, { 3581, 2623 }, - { 3582, 2624 }, { 3583, 2625 }, { 3584, 2626 }, { 3585, 2627 }, { 3586, 2628 }, { 3587, 2629 }, { 3588, 2630 }, - { 3589, 2631 }, { 3590, 2632 }, { 3591, 2633 }, { 3592, 2634 }, { 3593, 2635 }, { 3594, 2636 }, { 3595, 2637 }, - { 3596, 2638 }, { 3597, 2639 }, { 3598, 2640 }, { 3599, 2641 }, { 3600, 2642 }, { 3601, 2643 }, { 3602, 2644 }, - { 3603, 2645 }, { 3604, 2646 }, { 3605, 2647 }, { 3606, 2648 }, { 3607, 2649 }, { 3608, 2650 }, { 3609, 2651 }, - { 3610, 2652 }, { 3611, 2653 }, { 3612, 2654 }, { 3613, 2655 }, { 3614, 2656 }, { 3615, 2657 }, { 3616, 2658 }, - { 3617, 2659 }, { 3618, 2660 }, { 3619, 2661 }, { 3620, 2662 }, { 3621, 2663 }, { 3622, 2664 }, { 3623, 2665 }, - { 3624, 2666 }, { 3625, 2667 }, { 3626, 2668 }, { 3627, 2669 }, { 3628, 2670 }, { 3629, 2671 }, { 3630, 2672 }, - { 3631, 2673 }, { 3632, 2674 }, { 3633, 2675 }, { 3634, 2676 }, { 3635, 2677 }, { 3636, 2678 }, { 3637, 2679 }, - { 3638, 2680 }, { 3639, 2681 }, { 3640, 2682 }, { 3641, 2683 }, { 3642, 2684 }, { 3643, 2685 }, { 3644, 2686 }, - { 3645, 2687 }, { 3646, 2688 }, { 3671, 2689 }, { 3672, 2690 }, { 3673, 2691 }, { 3674, 2692 }, { 3675, 2693 }, - { 3676, 2694 }, { 3677, 2695 }, { 3678, 2696 }, { 3679, 2697 }, { 3680, 2698 }, { 3681, 2699 }, { 3682, 2700 }, - { 3683, 2701 }, { 3684, 2702 }, { 3685, 2703 }, { 3686, 2704 }, { 3687, 2705 }, { 3688, 2706 }, { 3689, 2707 }, - { 3690, 2708 }, { 3691, 2709 }, { 3692, 2710 }, { 3693, 2711 }, { 3694, 2712 }, { 3695, 2713 }, { 3696, 2714 }, - { 3697, 2715 }, { 3698, 2716 }, { 3699, 2717 }, { 3700, 2718 }, { 3701, 2719 }, { 3702, 2720 }, { 3703, 2721 }, - { 3704, 2722 }, { 3705, 2723 }, { 3706, 2724 }, { 3707, 2725 }, { 3708, 2726 }, { 3709, 2727 }, { 3710, 2728 }, - { 3711, 2729 }, { 3712, 2730 }, { 3713, 2731 }, { 3714, 2732 }, { 3715, 2733 }, { 3716, 2734 }, { 3717, 2735 }, - { 3718, 2736 }, { 3719, 2737 }, { 3720, 2738 }, { 3721, 2739 }, { 3722, 2740 }, { 3723, 2741 }, { 3724, 2742 }, - { 3725, 2743 }, { 3726, 2744 }, { 3727, 2745 }, { 3728, 2746 }, { 3729, 2747 }, { 3730, 2748 }, { 3927, 2749 }, - { 3928, 2750 }, { 3929, 2751 }, { 3930, 2752 }, { 3931, 2753 }, { 3932, 2754 }, { 3933, 2755 }, { 3934, 2756 }, - { 3940, 2762 }, { 3941, 2763 }, { 3942, 2764 }, { 3943, 2765 }, { 3944, 2766 }, { 3945, 2767 }, { 3946, 2768 }, - { 3947, 2769 }, { 3948, 2770 }, { 3949, 2771 }, { 3950, 2772 }, { 3951, 2773 }, { 3952, 2774 }, { 3953, 2775 }, - { 3954, 2776 }, { 3955, 2777 }, { 3956, 2778 }, { 3957, 2779 }, { 3958, 2780 }, { 3959, 2781 }, { 3960, 2782 }, - { 3961, 2783 }, { 3962, 2784 }, { 3963, 2785 }, { 3964, 2786 }, { 3965, 2787 }, { 3966, 2788 }, { 3967, 2789 }, - { 3968, 2790 }, { 3969, 2791 }, { 3970, 2792 }, { 3971, 2793 }, { 3972, 2794 }, { 3973, 2795 }, { 3974, 2796 }, - { 3975, 2797 }, { 3976, 2798 }, { 3977, 2799 }, { 3978, 2800 }, { 3979, 2801 }, { 3980, 2802 }, { 3981, 2803 }, - { 3982, 2804 }, { 3983, 2805 }, { 3984, 2806 }, { 3985, 2807 }, { 3986, 2808 }, { 3987, 2809 }, { 3988, 2810 }, - { 3989, 2811 }, { 3990, 2812 }, { 3991, 2813 }, { 3992, 2814 }, { 3993, 2815 }, { 3994, 2816 }, { 3995, 2817 }, - { 3996, 2818 }, { 3997, 2819 }, { 3998, 2820 }, { 3999, 2821 }, { 4000, 2822 }, { 4001, 2823 }, { 4002, 2824 }, - { 4003, 2825 }, { 4004, 2826 }, { 4005, 2827 }, { 4006, 2828 }, { 4007, 2829 }, { 4008, 2830 }, { 4009, 2831 }, - { 4010, 2832 }, { 4011, 2833 }, { 4012, 2834 }, { 4013, 2835 }, { 4014, 2836 }, { 4015, 2837 }, { 4016, 2838 }, - { 4017, 2839 }, { 4018, 2840 }, { 4019, 2841 }, { 4020, 2842 }, { 4021, 2843 }, { 4022, 2844 }, { 4023, 2845 }, - { 4024, 2846 }, { 4025, 2847 }, { 4026, 2848 }, { 4027, 2849 }, { 4028, 2850 }, { 4029, 2851 }, { 4030, 2852 }, - { 4031, 2853 }, { 4032, 2854 }, { 4127, 2855 }, { 4128, 2856 }, { 4129, 2857 }, { 4130, 2858 }, { 4131, 2859 }, - { 4132, 2860 }, { 4133, 2861 }, { 4134, 2862 }, { 4135, 2863 }, { 4136, 2864 }, { 4137, 2865 }, { 4138, 2866 }, - { 4139, 2867 }, { 4140, 2868 }, { 4145, 2873 }, { 4146, 2874 }, { 4147, 2875 }, { 4148, 2876 }, { 4149, 2877 }, - { 4150, 2878 }, { 4151, 2879 }, { 4152, 2880 }, { 4153, 2881 }, { 4154, 2882 }, { 4155, 2883 }, { 4156, 2884 }, - { 4157, 2885 }, { 4158, 2886 }, { 4159, 2887 }, { 4160, 2888 }, { 4227, 2889 }, { 4228, 2890 }, { 4229, 2891 }, - { 4230, 2892 }, { 4231, 2893 }, { 4232, 2894 }, { 4233, 2895 }, { 4234, 2896 }, { 4235, 2897 }, { 4236, 2898 }, - { 4237, 2899 }, { 4238, 2900 }, { 4239, 2901 }, { 4240, 2902 }, { 4241, 2903 }, { 4242, 2904 }, { 4243, 2905 }, - { 4244, 2906 }, { 4245, 2907 }, { 4246, 2908 }, { 4247, 2909 }, { 4248, 2910 }, { 4249, 2911 }, { 4250, 2912 }, - { 4251, 2913 }, { 4252, 2914 }, { 4253, 2915 }, { 4254, 2916 }, { 4255, 2917 }, { 4256, 2918 }, { 4257, 2919 }, - { 4258, 2920 }, { 4327, 2921 }, { 4328, 2922 }, { 4329, 2923 }, { 4330, 2924 }, { 4331, 2925 }, { 4332, 2926 }, - { 4333, 2927 }, { 4334, 2928 }, { 4335, 2929 }, { 4336, 2930 }, { 4337, 2931 }, { 4338, 2932 }, { 4339, 2933 }, - { 4340, 2934 }, { 4341, 2935 }, { 4342, 2936 }, { 4343, 2937 }, { 4344, 2938 }, { 4345, 2939 }, { 4346, 2940 }, - { 4347, 2941 }, { 4348, 2942 }, { 4349, 2943 }, { 4350, 2944 }, { 4351, 2945 }, { 4352, 2946 }, { 4353, 2947 }, - { 4354, 2948 }, { 4355, 2949 }, { 4356, 2950 }, { 4357, 2951 }, { 4358, 2952 }, { 4359, 2953 }, { 4360, 2954 }, - { 4361, 2955 }, { 4362, 2956 }, { 4363, 2957 }, { 4364, 2958 }, { 4365, 2959 }, { 4366, 2960 }, { 4367, 2961 }, - { 4368, 2962 }, { 4369, 2963 }, { 4370, 2964 }, { 4371, 2965 }, { 4372, 2966 }, { 4373, 2967 }, { 4374, 2968 }, - { 4375, 2969 }, { 4376, 2970 }, { 4377, 2971 }, { 4378, 2972 }, { 4379, 2973 }, { 4380, 2974 }, { 4381, 2975 }, - { 4382, 2976 }, { 4383, 2977 }, { 4384, 2978 }, { 4385, 2979 }, { 4386, 2980 }, { 4387, 2981 }, { 4388, 2982 }, - { 4389, 2983 }, { 4390, 2984 }, { 4391, 2985 }, { 4392, 2986 }, { 4393, 2987 }, { 4394, 2988 }, { 4395, 2989 }, - { 4396, 2990 }, { 4397, 2991 }, { 4398, 2992 }, { 4399, 2993 }, { 4400, 2994 }, { 4401, 2995 }, { 4402, 2996 }, - { 4403, 2997 }, { 4404, 2998 }, { 4405, 2999 }, { 4406, 3000 }, { 4407, 3001 }, { 4408, 3002 }, { 4409, 3003 }, - { 4410, 3004 }, { 4411, 3005 }, { 4412, 3006 }, { 4413, 3007 }, { 4414, 3008 }, { 4415, 3009 }, { 4416, 3010 }, - { 4417, 3011 }, { 4418, 3012 }, { 4419, 3013 }, { 4420, 3014 }, { 4421, 3015 }, { 4422, 3016 }, { 4423, 3017 }, - { 4424, 3018 }, { 4425, 3019 }, { 4426, 3020 }, { 4427, 3021 }, { 4428, 3022 }, { 4429, 3023 }, { 4430, 3024 }, - { 4431, 3025 }, { 4432, 3026 }, { 4433, 3027 }, { 4434, 3028 }, { 4435, 3029 }, { 4436, 3030 }, { 4437, 3031 }, - { 4438, 3032 }, { 4439, 3033 }, { 4440, 3034 }, { 4441, 3035 }, { 4442, 3036 }, { 4443, 3037 }, { 4444, 3038 }, - { 4445, 3039 }, { 4446, 3040 }, { 4447, 3041 }, { 4448, 3042 }, { 4449, 3043 }, { 4450, 3044 }, { 4527, 3045 }, - { 4528, 3046 }, { 4529, 3047 }, { 4530, 3048 }, { 4531, 3049 }, { 4532, 3050 }, { 4533, 3051 }, { 4534, 3052 }, - { 4535, 3053 }, { 4536, 3054 }, { 4537, 3055 }, { 4538, 3056 }, { 4539, 3057 }, { 4540, 3058 }, { 4541, 3059 }, - { 4542, 3060 }, { 4543, 3061 }, { 4544, 3062 }, { 4545, 3063 }, { 4546, 3064 }, { 4547, 3065 }, { 4548, 3066 }, - { 4549, 3067 }, { 4550, 3068 }, { 4551, 3069 }, { 4552, 3070 }, { 4553, 3071 }, { 4627, 3072 }, { 4628, 3073 }, - { 4629, 3074 }, { 4630, 3075 }, { 4631, 3076 }, { 4632, 3077 }, { 4633, 3078 }, { 4634, 3079 }, { 4635, 3080 }, - { 4636, 3081 }, { 4637, 3082 }, { 4638, 3083 }, { 4639, 3084 }, { 4640, 3085 }, { 4641, 3086 }, { 4642, 3087 }, - { 4643, 3088 }, { 4644, 3089 }, { 4645, 3090 }, { 4646, 3091 }, { 4647, 3092 }, { 4648, 3093 }, { 4649, 3094 }, - { 4650, 3095 }, { 4651, 3096 }, { 4652, 3097 }, { 4653, 3098 }, { 4654, 3099 }, { 4655, 3100 }, { 4656, 3101 }, - { 4657, 3102 }, { 4658, 3103 }, { 4659, 3104 }, { 4660, 3105 }, { 4661, 3106 }, { 4662, 3107 }, { 4663, 3108 }, - { 4664, 3109 }, { 4665, 3110 }, { 4666, 3111 }, { 4667, 3112 }, { 4668, 3113 }, { 4669, 3114 }, { 4670, 3115 }, - { 4671, 3116 }, { 4672, 3117 }, { 4673, 3118 }, { 4674, 3119 }, { 4675, 3120 }, { 4676, 3121 }, { 4677, 3122 }, - { 4678, 3123 }, { 4679, 3124 }, { 4680, 3125 }, { 4681, 3126 }, { 4682, 3127 }, { 4683, 3128 }, { 4684, 3129 }, - { 4685, 3130 }, { 4686, 3131 }, { 4687, 3132 }, { 4688, 3133 }, { 4689, 3134 }, { 4690, 3135 }, { 4691, 3136 }, - { 4692, 3137 }, { 4693, 3138 }, { 4694, 3139 }, { 4695, 3140 }, { 4696, 3141 }, { 4697, 3142 }, { 4698, 3143 }, - { 4699, 3144 }, { 4700, 3145 }, { 4701, 3146 }, { 4702, 3147 }, { 4703, 3148 }, { 4704, 3149 }, { 4705, 3150 }, - { 4706, 3151 }, { 4707, 3152 }, { 4708, 3153 }, { 4709, 3154 }, { 4710, 3155 }, { 4711, 3156 }, { 4712, 3157 }, - { 4713, 3158 }, { 4714, 3159 }, { 4715, 3160 }, { 4716, 3161 }, { 4717, 3162 }, { 4718, 3163 }, { 4719, 3164 }, - { 4720, 3165 }, { 4721, 3166 }, { 4722, 3167 }, { 4723, 3168 }, { 4724, 3169 }, { 4725, 3170 }, { 4726, 3171 }, - { 4827, 3172 }, { 4828, 3173 }, { 4829, 3174 }, { 4830, 3175 }, { 4831, 3176 }, { 4832, 3177 }, { 4833, 3178 }, - { 4834, 3179 }, { 4835, 3180 }, { 4836, 3181 }, { 4837, 3182 }, { 4838, 3183 }, { 4839, 3184 }, { 4840, 3185 }, - { 4841, 3186 }, { 4842, 3187 }, { 4843, 3188 }, { 4844, 3189 }, { 4845, 3190 }, { 5027, 3191 }, { 5028, 3192 }, - { 5029, 3193 }, { 5030, 3194 }, { 5031, 3195 }, { 5032, 3196 }, { 5033, 3197 }, { 5034, 3198 }, { 5035, 3199 }, - { 5036, 3200 }, { 5037, 3201 }, { 5038, 3202 }, { 5039, 3203 }, { 5040, 3204 }, { 5041, 3205 }, { 5042, 3206 }, - { 5043, 3207 }, { 5044, 3208 }, { 5045, 3209 }, { 5046, 3210 }, { 5047, 3211 }, { 5048, 3212 }, { 5049, 3213 }, - { 5050, 3214 }, { 5051, 3215 }, { 5052, 3216 }, { 5053, 3217 }, { 5054, 3218 }, { 5055, 3219 }, { 5056, 3220 }, - { 5057, 3221 }, { 5058, 3222 }, { 5059, 3223 }, { 5060, 3224 }, { 5061, 3225 }, { 5062, 3226 }, { 5063, 3227 }, - { 5064, 3228 }, { 5065, 3229 }, { 5066, 3230 }, { 5067, 3231 }, { 5068, 3232 }, { 5069, 3233 }, { 5070, 3234 }, - { 5071, 3235 }, { 5072, 3236 }, { 5073, 3237 }, { 5074, 3238 }, { 5075, 3239 }, { 5076, 3240 }, { 5077, 3241 }, - { 5127, 3242 }, { 5128, 3243 }, { 5129, 3244 }, { 5130, 3245 }, { 5131, 3246 }, { 5132, 3247 }, { 5133, 3248 }, - { 5134, 3249 }, { 5135, 3250 }, { 5136, 3251 }, { 5137, 3252 }, { 5138, 3253 }, { 5139, 3254 }, { 5140, 3255 }, - { 5141, 3256 }, { 5142, 3257 }, { 5143, 3258 }, { 5144, 3259 }, { 5145, 3260 }, { 5146, 3261 }, { 5147, 3262 }, - { 5148, 3263 }, { 5149, 3264 }, { 5150, 3265 }, { 5151, 3266 }, { 5152, 3267 }, { 5153, 3268 }, { 5154, 3269 }, - { 5155, 3270 }, { 5156, 3271 }, { 5227, 3272 }, { 5228, 3273 }, { 5229, 3274 }, { 5230, 3275 }, { 5231, 3276 }, - { 5232, 3277 }, { 5233, 3278 }, { 5234, 3279 }, { 5235, 3280 }, { 5236, 3281 }, { 5237, 3282 }, { 5238, 3283 }, - { 5240, 3285 }, { 5241, 3286 }, { 5242, 3287 }, { 5243, 3288 }, { 5244, 3289 }, { 5245, 3290 }, { 5246, 3291 }, - { 5247, 3292 }, { 5248, 3293 }, { 5249, 3294 }, { 5250, 3295 }, { 5251, 3296 }, { 5252, 3297 }, { 5253, 3298 }, - { 5254, 3299 }, { 5255, 3300 }, { 5256, 3301 }, { 5257, 3302 }, { 5258, 3303 }, { 5259, 3304 }, { 5260, 3305 }, - { 5261, 3306 }, { 5262, 3307 }, { 5263, 3308 }, { 5264, 3309 }, { 5265, 3310 }, { 5266, 3311 }, { 5267, 3312 }, - { 5268, 3313 }, { 5269, 3314 }, { 5270, 3315 }, { 5271, 3316 }, { 5272, 3317 }, { 5273, 3318 }, { 5274, 3319 }, - { 5275, 3320 }, { 5276, 3321 }, { 5277, 3322 }, { 5278, 3323 }, { 5279, 3324 }, { 5280, 3325 }, { 5281, 3326 }, - { 5282, 3327 }, { 5283, 3328 }, { 5284, 3329 }, { 5285, 3330 }, { 5286, 3331 }, { 5288, 3333 }, { 5289, 3334 }, - { 5290, 3335 }, { 5291, 3336 }, { 5292, 3337 }, { 5293, 3338 }, { 5294, 3339 }, { 5296, 3341 }, { 5297, 3342 }, - { 5298, 3343 }, { 5299, 3344 }, { 5300, 3345 }, { 5301, 3346 }, { 5302, 3347 }, { 5303, 3348 }, { 5304, 3349 }, - { 5305, 3350 }, { 5306, 3351 }, { 5307, 3352 }, { 5308, 3353 }, { 5309, 3354 }, { 5310, 3355 }, { 5311, 3356 }, - { 5312, 3357 }, { 5313, 3358 }, { 5314, 3359 }, { 5315, 3360 }, { 5316, 3361 }, { 5317, 3362 }, { 5318, 3363 }, - { 5319, 3364 }, { 5320, 3365 }, { 5321, 3366 }, { 5322, 3367 }, { 5323, 3368 }, { 5324, 3369 }, { 5325, 3370 }, - { 5326, 3371 }, { 5327, 3372 }, { 5328, 3373 }, { 5329, 3374 }, { 5330, 3375 }, { 5331, 3376 }, { 5332, 3377 }, - { 5333, 3378 }, { 5336, 3381 }, { 5337, 3382 }, { 5338, 3383 }, { 5339, 3384 }, { 5340, 3385 }, { 5341, 3386 }, - { 5342, 3387 }, { 5343, 3388 }, { 5344, 3389 }, { 5345, 3390 }, { 5346, 3391 }, { 5347, 3392 }, { 5348, 3393 }, - { 5349, 3394 }, { 5350, 3395 }, { 5351, 3396 }, { 5352, 3397 }, { 5357, 3402 }, { 5358, 3403 }, { 5359, 3404 }, - { 5360, 3405 }, { 5361, 3406 }, { 5362, 3407 }, { 5363, 3408 }, { 5364, 3409 }, { 5365, 3410 }, { 5366, 3411 }, - { 5367, 3412 }, { 5368, 3413 }, { 5369, 3414 }, { 5370, 3415 }, { 5371, 3416 }, { 5372, 3417 }, { 5373, 3418 }, - { 5374, 3419 }, { 5375, 3420 }, { 5376, 3421 }, { 5377, 3422 }, { 5378, 3423 }, { 5379, 3424 }, { 5380, 3425 }, - { 5381, 3426 }, { 5382, 3427 }, { 5383, 3428 }, { 5384, 3429 }, { 5385, 3430 }, { 5386, 3431 }, { 5387, 3432 }, - { 5388, 3433 }, { 5389, 3434 }, { 5390, 3435 }, { 5391, 3436 }, { 5392, 3437 }, { 5393, 3438 }, { 5394, 3439 }, - { 5395, 3440 }, { 5396, 3441 }, { 5397, 3442 }, { 5398, 3443 }, { 5399, 3444 }, { 5400, 3445 }, { 5401, 3446 }, - { 5402, 3447 }, { 5403, 3448 }, { 5404, 3449 }, { 5405, 3450 }, { 5406, 3451 }, { 5407, 3452 }, { 5408, 3453 }, - { 5409, 3454 }, { 5410, 3455 }, { 5411, 3456 }, { 5412, 3457 }, { 5413, 3458 }, { 5414, 3459 }, { 5415, 3460 }, - { 5416, 3461 }, { 5417, 3462 }, { 5418, 3463 }, { 5419, 3464 }, { 5420, 3465 }, { 5421, 3466 }, { 5422, 3467 }, - { 5423, 3468 }, { 5424, 3469 }, { 5425, 3470 }, { 5426, 3471 }, { 5427, 3472 }, { 5428, 3473 }, { 5429, 3474 }, - { 5430, 3475 }, { 5431, 3476 }, { 5432, 3477 }, { 5433, 3478 }, { 5434, 3479 }, { 5435, 3480 }, { 5436, 3481 }, - { 5437, 3482 }, { 5438, 3483 }, { 5439, 3484 }, { 5440, 3485 }, { 5441, 3486 }, { 5442, 3487 }, { 5443, 3488 }, - { 5444, 3489 }, { 5445, 3490 }, { 5446, 3491 }, { 5447, 3492 }, { 5448, 3493 }, { 5449, 3494 }, { 5450, 3495 }, - { 5451, 3496 }, { 5452, 3497 }, { 5453, 3498 }, { 5454, 3499 }, { 5455, 3500 }, { 5456, 3501 }, { 5457, 3502 }, - { 5458, 3503 }, { 5459, 3504 }, { 5460, 3505 }, { 5461, 3506 }, { 5462, 3507 }, { 5463, 3508 }, { 5464, 3509 }, - { 5465, 3510 }, { 5466, 3511 }, { 5467, 3512 }, { 5468, 3513 }, { 5469, 3514 }, { 5470, 3515 }, { 5471, 3516 }, - { 5472, 3517 }, { 5473, 3518 }, { 5474, 3519 }, { 5475, 3520 }, { 5476, 3521 }, { 5477, 3522 }, { 5478, 3523 }, - { 5479, 3524 }, { 5480, 3525 }, { 5481, 3526 }, { 5482, 3527 }, { 5483, 3528 }, { 5484, 3529 }, { 5485, 3530 }, - { 5486, 3531 }, { 5487, 3532 }, { 5488, 3533 }, { 5489, 3534 }, { 5490, 3535 }, { 5491, 3536 }, { 5492, 3537 }, - { 5493, 3538 }, { 5494, 3539 }, { 5495, 3540 }, { 5496, 3541 }, { 5497, 3542 }, { 5498, 3543 }, { 5499, 3544 }, - { 5500, 3545 }, { 5501, 3546 }, { 5502, 3547 }, { 5503, 3548 }, { 5504, 3549 }, { 5505, 3550 }, { 5506, 3551 }, - { 5507, 3552 }, { 5508, 3553 }, { 5509, 3554 }, { 5510, 3555 }, { 5511, 3556 }, { 5512, 3557 }, { 5513, 3558 }, - { 5514, 3559 }, { 5515, 3560 }, { 5516, 3561 }, { 5517, 3562 }, { 5518, 3563 }, { 5519, 3564 }, { 5520, 3565 }, - { 5521, 3566 }, { 5522, 3567 }, { 5523, 3568 }, { 5524, 3569 }, { 5525, 3570 }, { 5526, 3571 }, { 5527, 3572 }, - { 5528, 3573 }, { 5529, 3574 }, { 5530, 3575 }, { 5531, 3576 }, { 5532, 3577 }, { 5533, 3578 }, { 5534, 3579 }, - { 5535, 3580 }, { 5536, 3581 }, { 5537, 3582 }, { 5538, 3583 }, { 5539, 3584 }, { 5540, 3585 }, { 5541, 3586 }, - { 5542, 3587 }, { 5543, 3588 }, { 5544, 3589 }, { 5545, 3590 }, { 5546, 3591 }, { 5547, 3592 }, { 5548, 3593 }, - { 5549, 3594 }, { 5550, 3595 }, { 5551, 3596 }, { 5552, 3597 }, { 5553, 3598 }, { 5554, 3599 }, { 5555, 3600 }, - { 5556, 3601 }, { 5557, 3602 }, { 5558, 3603 }, { 5559, 3604 }, { 5560, 3605 }, { 5561, 3606 }, { 5562, 3607 }, - { 5563, 3608 }, { 5564, 3609 }, { 5565, 3610 }, { 5566, 3611 }, { 5567, 3612 }, { 5568, 3613 }, { 5569, 3614 }, - { 5570, 3615 } + { 2504, 2248 }, { 2508, 2252 }, { 2511, 2255 }, { 2513, 2257 }, { 2521, 2252 }, { 2524, 2255 }, { 2526, 2257 }, + { 2528, 2311 }, { 2529, 2312 }, { 2571, 2315 }, { 2572, 2316 }, { 2573, 2317 }, { 2574, 2318 }, { 2575, 2319 }, + { 2576, 2320 }, { 2577, 2321 }, { 2578, 2322 }, { 2579, 2323 }, { 2580, 2324 }, { 2581, 2325 }, { 2582, 2326 }, + { 2583, 2327 }, { 2584, 2328 }, { 2585, 2329 }, { 2586, 2330 }, { 2587, 2331 }, { 2588, 2332 }, { 2589, 2333 }, + { 2590, 2334 }, { 2591, 2335 }, { 2592, 2336 }, { 2593, 2337 }, { 2594, 2338 }, { 2595, 2339 }, { 2596, 2340 }, + { 2597, 2341 }, { 2598, 2342 }, { 2599, 2343 }, { 2600, 2344 }, { 2601, 2345 }, { 2602, 2346 }, { 2671, 2347 }, + { 2672, 2348 }, { 2673, 2349 }, { 2674, 2350 }, { 2675, 2351 }, { 2676, 2352 }, { 2677, 2353 }, { 2678, 2354 }, + { 2679, 2355 }, { 2680, 2356 }, { 2681, 2357 }, { 2682, 2358 }, { 2683, 2359 }, { 2684, 2360 }, { 2685, 2361 }, + { 2686, 2362 }, { 2687, 2363 }, { 2688, 2364 }, { 2689, 2365 }, { 2690, 2366 }, { 2691, 2367 }, { 2692, 2368 }, + { 2693, 2369 }, { 2694, 2370 }, { 2695, 2371 }, { 2696, 2372 }, { 2771, 2373 }, { 2772, 2374 }, { 2773, 2375 }, + { 2774, 2376 }, { 2775, 2377 }, { 2776, 2378 }, { 2777, 2379 }, { 2778, 2380 }, { 2779, 2381 }, { 2780, 2382 }, + { 2781, 2383 }, { 2782, 2384 }, { 2783, 2385 }, { 2784, 2386 }, { 2785, 2387 }, { 2786, 2388 }, { 2871, 2389 }, + { 2872, 2390 }, { 2873, 2391 }, { 2874, 2392 }, { 2875, 2393 }, { 2876, 2394 }, { 2877, 2395 }, { 2878, 2396 }, + { 2879, 2397 }, { 2880, 2398 }, { 2881, 2399 }, { 2882, 2400 }, { 2883, 2401 }, { 2884, 2402 }, { 2885, 2403 }, + { 2886, 2404 }, { 2887, 2405 }, { 2888, 2406 }, { 2889, 2407 }, { 2890, 2408 }, { 2891, 2409 }, { 2892, 2410 }, + { 2893, 2411 }, { 2894, 2412 }, { 2895, 2413 }, { 2896, 2414 }, { 2897, 2415 }, { 2971, 2416 }, { 2972, 2417 }, + { 2973, 2418 }, { 2974, 2419 }, { 2975, 2420 }, { 2976, 2421 }, { 2977, 2422 }, { 2978, 2423 }, { 2979, 2424 }, + { 3071, 2425 }, { 3072, 2426 }, { 3073, 2427 }, { 3074, 2428 }, { 3075, 2429 }, { 3076, 2430 }, { 3077, 2431 }, + { 3078, 2432 }, { 3079, 2433 }, { 3080, 2434 }, { 3081, 2435 }, { 3082, 2436 }, { 3083, 2437 }, { 3084, 2438 }, + { 3085, 2439 }, { 3086, 2440 }, { 3087, 2441 }, { 3088, 2442 }, { 3089, 2443 }, { 3090, 2444 }, { 3091, 2445 }, + { 3092, 2446 }, { 3093, 2447 }, { 3094, 2448 }, { 3095, 2449 }, { 3096, 2450 }, { 3097, 2451 }, { 3098, 2452 }, + { 3099, 2453 }, { 3100, 2454 }, { 3101, 2455 }, { 3102, 2456 }, { 3103, 2457 }, { 3104, 2458 }, { 3105, 2459 }, + { 3106, 2460 }, { 3107, 2461 }, { 3108, 2462 }, { 3109, 2463 }, { 3110, 2464 }, { 3111, 2465 }, { 3112, 2466 }, + { 3113, 2467 }, { 3114, 2468 }, { 3115, 2469 }, { 3171, 2470 }, { 3172, 2471 }, { 3173, 2472 }, { 3174, 2473 }, + { 3175, 2474 }, { 3176, 2475 }, { 3177, 2476 }, { 3178, 2477 }, { 3179, 2478 }, { 3180, 2479 }, { 3181, 2480 }, + { 3182, 2481 }, { 3183, 2482 }, { 3184, 2483 }, { 3185, 2484 }, { 3186, 2485 }, { 3187, 2486 }, { 3188, 2487 }, + { 3189, 2488 }, { 3190, 2489 }, { 3191, 2490 }, { 3192, 2491 }, { 3193, 2492 }, { 3194, 2493 }, { 3195, 2494 }, + { 3196, 2495 }, { 3197, 2496 }, { 3198, 2497 }, { 3199, 2498 }, { 3200, 2499 }, { 3201, 2500 }, { 3202, 2501 }, + { 3203, 2502 }, { 3204, 2503 }, { 3205, 2504 }, { 3206, 2505 }, { 3207, 2506 }, { 3208, 2507 }, { 3209, 2508 }, + { 3210, 2509 }, { 3211, 2510 }, { 3212, 2511 }, { 3213, 2512 }, { 3214, 2513 }, { 3215, 2514 }, { 3216, 2515 }, + { 3217, 2516 }, { 3218, 2517 }, { 3219, 2518 }, { 3220, 2519 }, { 3221, 2520 }, { 3222, 2521 }, { 3223, 2522 }, + { 3224, 2523 }, { 3271, 2524 }, { 3272, 2525 }, { 3273, 2526 }, { 3274, 2527 }, { 3275, 2528 }, { 3276, 2529 }, + { 3277, 2530 }, { 3278, 2531 }, { 3279, 2532 }, { 3280, 2533 }, { 3281, 2534 }, { 3282, 2535 }, { 3283, 2536 }, + { 3284, 2537 }, { 3285, 2538 }, { 3286, 2539 }, { 3287, 2540 }, { 3288, 2541 }, { 3289, 2542 }, { 3290, 2543 }, + { 3291, 2544 }, { 3292, 2545 }, { 3293, 2546 }, { 3294, 2547 }, { 3295, 2548 }, { 3296, 2549 }, { 3297, 2550 }, + { 3298, 2551 }, { 3299, 2552 }, { 3300, 2553 }, { 3301, 2554 }, { 3302, 2555 }, { 3303, 2556 }, { 3304, 2557 }, + { 3371, 2558 }, { 3372, 2559 }, { 3373, 2560 }, { 3374, 2561 }, { 3375, 2562 }, { 3376, 2563 }, { 3377, 2564 }, + { 3378, 2565 }, { 3379, 2566 }, { 3380, 2567 }, { 3381, 2568 }, { 3382, 2569 }, { 3383, 2570 }, { 3384, 2571 }, + { 3385, 2572 }, { 3471, 2573 }, { 3472, 2574 }, { 3473, 2575 }, { 3474, 2576 }, { 3475, 2577 }, { 3476, 2578 }, + { 3477, 2579 }, { 3478, 2580 }, { 3479, 2581 }, { 3480, 2582 }, { 3481, 2583 }, { 3482, 2584 }, { 3483, 2585 }, + { 3484, 2586 }, { 3485, 2587 }, { 3486, 2588 }, { 3487, 2589 }, { 3488, 2590 }, { 3489, 2591 }, { 3490, 2592 }, + { 3491, 2593 }, { 3492, 2594 }, { 3493, 2595 }, { 3494, 2596 }, { 3495, 2597 }, { 3496, 2598 }, { 3497, 2599 }, + { 3498, 2600 }, { 3499, 2601 }, { 3500, 2602 }, { 3501, 2603 }, { 3502, 2604 }, { 3503, 2605 }, { 3504, 2606 }, + { 3505, 2607 }, { 3506, 2608 }, { 3507, 2609 }, { 3508, 2610 }, { 3509, 2611 }, { 3510, 2612 }, { 3571, 2613 }, + { 3572, 2614 }, { 3573, 2615 }, { 3574, 2616 }, { 3575, 2617 }, { 3576, 2618 }, { 3577, 2619 }, { 3578, 2620 }, + { 3579, 2621 }, { 3580, 2622 }, { 3581, 2623 }, { 3582, 2624 }, { 3583, 2625 }, { 3584, 2626 }, { 3585, 2627 }, + { 3586, 2628 }, { 3587, 2629 }, { 3588, 2630 }, { 3589, 2631 }, { 3590, 2632 }, { 3591, 2633 }, { 3592, 2634 }, + { 3593, 2635 }, { 3594, 2636 }, { 3595, 2637 }, { 3596, 2638 }, { 3597, 2639 }, { 3598, 2640 }, { 3599, 2641 }, + { 3600, 2642 }, { 3601, 2643 }, { 3602, 2644 }, { 3603, 2645 }, { 3604, 2646 }, { 3605, 2647 }, { 3606, 2648 }, + { 3607, 2649 }, { 3608, 2650 }, { 3609, 2651 }, { 3610, 2652 }, { 3611, 2653 }, { 3612, 2654 }, { 3613, 2655 }, + { 3614, 2656 }, { 3615, 2657 }, { 3616, 2658 }, { 3617, 2659 }, { 3618, 2660 }, { 3619, 2661 }, { 3620, 2662 }, + { 3621, 2663 }, { 3622, 2664 }, { 3623, 2665 }, { 3624, 2666 }, { 3625, 2667 }, { 3626, 2668 }, { 3627, 2669 }, + { 3628, 2670 }, { 3629, 2671 }, { 3630, 2672 }, { 3631, 2673 }, { 3632, 2674 }, { 3633, 2675 }, { 3634, 2676 }, + { 3635, 2677 }, { 3636, 2678 }, { 3637, 2679 }, { 3638, 2680 }, { 3639, 2681 }, { 3640, 2682 }, { 3641, 2683 }, + { 3642, 2684 }, { 3643, 2685 }, { 3644, 2686 }, { 3645, 2687 }, { 3646, 2688 }, { 3671, 2689 }, { 3672, 2690 }, + { 3673, 2691 }, { 3674, 2692 }, { 3675, 2693 }, { 3676, 2694 }, { 3677, 2695 }, { 3678, 2696 }, { 3679, 2697 }, + { 3680, 2698 }, { 3681, 2699 }, { 3682, 2700 }, { 3683, 2701 }, { 3684, 2702 }, { 3685, 2703 }, { 3686, 2704 }, + { 3687, 2705 }, { 3688, 2706 }, { 3689, 2707 }, { 3690, 2708 }, { 3691, 2709 }, { 3692, 2710 }, { 3693, 2711 }, + { 3694, 2712 }, { 3695, 2713 }, { 3696, 2714 }, { 3697, 2715 }, { 3698, 2716 }, { 3699, 2717 }, { 3700, 2718 }, + { 3701, 2719 }, { 3702, 2720 }, { 3703, 2721 }, { 3704, 2722 }, { 3705, 2723 }, { 3706, 2724 }, { 3707, 2725 }, + { 3708, 2726 }, { 3709, 2727 }, { 3710, 2728 }, { 3711, 2729 }, { 3712, 2730 }, { 3713, 2731 }, { 3714, 2732 }, + { 3715, 2733 }, { 3716, 2734 }, { 3717, 2735 }, { 3718, 2736 }, { 3719, 2737 }, { 3720, 2738 }, { 3721, 2739 }, + { 3722, 2740 }, { 3723, 2741 }, { 3724, 2742 }, { 3725, 2743 }, { 3726, 2744 }, { 3727, 2745 }, { 3728, 2746 }, + { 3729, 2747 }, { 3730, 2748 }, { 3927, 2749 }, { 3928, 2750 }, { 3929, 2751 }, { 3930, 2752 }, { 3931, 2753 }, + { 3932, 2754 }, { 3933, 2755 }, { 3934, 2756 }, { 3940, 2762 }, { 3941, 2763 }, { 3942, 2764 }, { 3943, 2765 }, + { 3944, 2766 }, { 3945, 2767 }, { 3946, 2768 }, { 3947, 2769 }, { 3948, 2770 }, { 3949, 2771 }, { 3950, 2772 }, + { 3951, 2773 }, { 3952, 2774 }, { 3953, 2775 }, { 3954, 2776 }, { 3955, 2777 }, { 3956, 2778 }, { 3957, 2779 }, + { 3958, 2780 }, { 3959, 2781 }, { 3960, 2782 }, { 3961, 2783 }, { 3962, 2784 }, { 3963, 2785 }, { 3964, 2786 }, + { 3965, 2787 }, { 3966, 2788 }, { 3967, 2789 }, { 3968, 2790 }, { 3969, 2791 }, { 3970, 2792 }, { 3971, 2793 }, + { 3972, 2794 }, { 3973, 2795 }, { 3974, 2796 }, { 3975, 2797 }, { 3976, 2798 }, { 3977, 2799 }, { 3978, 2800 }, + { 3979, 2801 }, { 3980, 2802 }, { 3981, 2803 }, { 3982, 2804 }, { 3983, 2805 }, { 3984, 2806 }, { 3985, 2807 }, + { 3986, 2808 }, { 3987, 2809 }, { 3988, 2810 }, { 3989, 2811 }, { 3990, 2812 }, { 3991, 2813 }, { 3992, 2814 }, + { 3993, 2815 }, { 3994, 2816 }, { 3995, 2817 }, { 3996, 2818 }, { 3997, 2819 }, { 3998, 2820 }, { 3999, 2821 }, + { 4000, 2822 }, { 4001, 2823 }, { 4002, 2824 }, { 4003, 2825 }, { 4004, 2826 }, { 4005, 2827 }, { 4006, 2828 }, + { 4007, 2829 }, { 4008, 2830 }, { 4009, 2831 }, { 4010, 2832 }, { 4011, 2833 }, { 4012, 2834 }, { 4013, 2835 }, + { 4014, 2836 }, { 4015, 2837 }, { 4016, 2838 }, { 4017, 2839 }, { 4018, 2840 }, { 4019, 2841 }, { 4020, 2842 }, + { 4021, 2843 }, { 4022, 2844 }, { 4023, 2845 }, { 4024, 2846 }, { 4025, 2847 }, { 4026, 2848 }, { 4027, 2849 }, + { 4028, 2850 }, { 4029, 2851 }, { 4030, 2852 }, { 4031, 2853 }, { 4032, 2854 }, { 4127, 2855 }, { 4128, 2856 }, + { 4129, 2857 }, { 4130, 2858 }, { 4131, 2859 }, { 4132, 2860 }, { 4133, 2861 }, { 4134, 2862 }, { 4135, 2863 }, + { 4136, 2864 }, { 4137, 2865 }, { 4138, 2866 }, { 4139, 2867 }, { 4140, 2868 }, { 4145, 2873 }, { 4146, 2874 }, + { 4147, 2875 }, { 4148, 2876 }, { 4149, 2877 }, { 4150, 2878 }, { 4151, 2879 }, { 4152, 2880 }, { 4153, 2881 }, + { 4154, 2882 }, { 4155, 2883 }, { 4156, 2884 }, { 4157, 2885 }, { 4158, 2886 }, { 4159, 2887 }, { 4160, 2888 }, + { 4227, 2889 }, { 4228, 2890 }, { 4229, 2891 }, { 4230, 2892 }, { 4231, 2893 }, { 4232, 2894 }, { 4233, 2895 }, + { 4234, 2896 }, { 4235, 2897 }, { 4236, 2898 }, { 4237, 2899 }, { 4238, 2900 }, { 4239, 2901 }, { 4240, 2902 }, + { 4241, 2903 }, { 4242, 2904 }, { 4243, 2905 }, { 4244, 2906 }, { 4245, 2907 }, { 4246, 2908 }, { 4247, 2909 }, + { 4248, 2910 }, { 4249, 2911 }, { 4250, 2912 }, { 4251, 2913 }, { 4252, 2914 }, { 4253, 2915 }, { 4254, 2916 }, + { 4255, 2917 }, { 4256, 2918 }, { 4257, 2919 }, { 4258, 2920 }, { 4327, 2921 }, { 4328, 2922 }, { 4329, 2923 }, + { 4330, 2924 }, { 4331, 2925 }, { 4332, 2926 }, { 4333, 2927 }, { 4334, 2928 }, { 4335, 2929 }, { 4336, 2930 }, + { 4337, 2931 }, { 4338, 2932 }, { 4339, 2933 }, { 4340, 2934 }, { 4341, 2935 }, { 4342, 2936 }, { 4343, 2937 }, + { 4344, 2938 }, { 4345, 2939 }, { 4346, 2940 }, { 4347, 2941 }, { 4348, 2942 }, { 4349, 2943 }, { 4350, 2944 }, + { 4351, 2945 }, { 4352, 2946 }, { 4353, 2947 }, { 4354, 2948 }, { 4355, 2949 }, { 4356, 2950 }, { 4357, 2951 }, + { 4358, 2952 }, { 4359, 2953 }, { 4360, 2954 }, { 4361, 2955 }, { 4362, 2956 }, { 4363, 2957 }, { 4364, 2958 }, + { 4365, 2959 }, { 4366, 2960 }, { 4367, 2961 }, { 4368, 2962 }, { 4369, 2963 }, { 4370, 2964 }, { 4371, 2965 }, + { 4372, 2966 }, { 4373, 2967 }, { 4374, 2968 }, { 4375, 2969 }, { 4376, 2970 }, { 4377, 2971 }, { 4378, 2972 }, + { 4379, 2973 }, { 4380, 2974 }, { 4381, 2975 }, { 4382, 2976 }, { 4383, 2977 }, { 4384, 2978 }, { 4385, 2979 }, + { 4386, 2980 }, { 4387, 2981 }, { 4388, 2982 }, { 4389, 2983 }, { 4390, 2984 }, { 4391, 2985 }, { 4392, 2986 }, + { 4393, 2987 }, { 4394, 2988 }, { 4395, 2989 }, { 4396, 2990 }, { 4397, 2991 }, { 4398, 2992 }, { 4399, 2993 }, + { 4400, 2994 }, { 4401, 2995 }, { 4402, 2996 }, { 4403, 2997 }, { 4404, 2998 }, { 4405, 2999 }, { 4406, 3000 }, + { 4407, 3001 }, { 4408, 3002 }, { 4409, 3003 }, { 4410, 3004 }, { 4411, 3005 }, { 4412, 3006 }, { 4413, 3007 }, + { 4414, 3008 }, { 4415, 3009 }, { 4416, 3010 }, { 4417, 3011 }, { 4418, 3012 }, { 4419, 3013 }, { 4420, 3014 }, + { 4421, 3015 }, { 4422, 3016 }, { 4423, 3017 }, { 4424, 3018 }, { 4425, 3019 }, { 4426, 3020 }, { 4427, 3021 }, + { 4428, 3022 }, { 4429, 3023 }, { 4430, 3024 }, { 4431, 3025 }, { 4432, 3026 }, { 4433, 3027 }, { 4434, 3028 }, + { 4435, 3029 }, { 4436, 3030 }, { 4437, 3031 }, { 4438, 3032 }, { 4439, 3033 }, { 4440, 3034 }, { 4441, 3035 }, + { 4442, 3036 }, { 4443, 3037 }, { 4444, 3038 }, { 4445, 3039 }, { 4446, 3040 }, { 4447, 3041 }, { 4448, 3042 }, + { 4449, 3043 }, { 4450, 3044 }, { 4527, 3045 }, { 4528, 3046 }, { 4529, 3047 }, { 4530, 3048 }, { 4531, 3049 }, + { 4532, 3050 }, { 4533, 3051 }, { 4534, 3052 }, { 4535, 3053 }, { 4536, 3054 }, { 4537, 3055 }, { 4538, 3056 }, + { 4539, 3057 }, { 4540, 3058 }, { 4541, 3059 }, { 4542, 3060 }, { 4543, 3061 }, { 4544, 3062 }, { 4545, 3063 }, + { 4546, 3064 }, { 4547, 3065 }, { 4548, 3066 }, { 4549, 3067 }, { 4550, 3068 }, { 4551, 3069 }, { 4552, 3070 }, + { 4553, 3071 }, { 4627, 3072 }, { 4628, 3073 }, { 4629, 3074 }, { 4630, 3075 }, { 4631, 3076 }, { 4632, 3077 }, + { 4633, 3078 }, { 4634, 3079 }, { 4635, 3080 }, { 4636, 3081 }, { 4637, 3082 }, { 4638, 3083 }, { 4639, 3084 }, + { 4640, 3085 }, { 4641, 3086 }, { 4642, 3087 }, { 4643, 3088 }, { 4644, 3089 }, { 4645, 3090 }, { 4646, 3091 }, + { 4647, 3092 }, { 4648, 3093 }, { 4649, 3094 }, { 4650, 3095 }, { 4651, 3096 }, { 4652, 3097 }, { 4653, 3098 }, + { 4654, 3099 }, { 4655, 3100 }, { 4656, 3101 }, { 4657, 3102 }, { 4658, 3103 }, { 4659, 3104 }, { 4660, 3105 }, + { 4661, 3106 }, { 4662, 3107 }, { 4663, 3108 }, { 4664, 3109 }, { 4665, 3110 }, { 4666, 3111 }, { 4667, 3112 }, + { 4668, 3113 }, { 4669, 3114 }, { 4670, 3115 }, { 4671, 3116 }, { 4672, 3117 }, { 4673, 3118 }, { 4674, 3119 }, + { 4675, 3120 }, { 4676, 3121 }, { 4677, 3122 }, { 4678, 3123 }, { 4679, 3124 }, { 4680, 3125 }, { 4681, 3126 }, + { 4682, 3127 }, { 4683, 3128 }, { 4684, 3129 }, { 4685, 3130 }, { 4686, 3131 }, { 4687, 3132 }, { 4688, 3133 }, + { 4689, 3134 }, { 4690, 3135 }, { 4691, 3136 }, { 4692, 3137 }, { 4693, 3138 }, { 4694, 3139 }, { 4695, 3140 }, + { 4696, 3141 }, { 4697, 3142 }, { 4698, 3143 }, { 4699, 3144 }, { 4700, 3145 }, { 4701, 3146 }, { 4702, 3147 }, + { 4703, 3148 }, { 4704, 3149 }, { 4705, 3150 }, { 4706, 3151 }, { 4707, 3152 }, { 4708, 3153 }, { 4709, 3154 }, + { 4710, 3155 }, { 4711, 3156 }, { 4712, 3157 }, { 4713, 3158 }, { 4714, 3159 }, { 4715, 3160 }, { 4716, 3161 }, + { 4717, 3162 }, { 4718, 3163 }, { 4719, 3164 }, { 4720, 3165 }, { 4721, 3166 }, { 4722, 3167 }, { 4723, 3168 }, + { 4724, 3169 }, { 4725, 3170 }, { 4726, 3171 }, { 4827, 3172 }, { 4828, 3173 }, { 4829, 3174 }, { 4830, 3175 }, + { 4831, 3176 }, { 4832, 3177 }, { 4833, 3178 }, { 4834, 3179 }, { 4835, 3180 }, { 4836, 3181 }, { 4837, 3182 }, + { 4838, 3183 }, { 4839, 3184 }, { 4840, 3185 }, { 4841, 3186 }, { 4842, 3187 }, { 4843, 3188 }, { 4844, 3189 }, + { 4845, 3190 }, { 5027, 3191 }, { 5028, 3192 }, { 5029, 3193 }, { 5030, 3194 }, { 5031, 3195 }, { 5032, 3196 }, + { 5033, 3197 }, { 5034, 3198 }, { 5035, 3199 }, { 5036, 3200 }, { 5037, 3201 }, { 5038, 3202 }, { 5039, 3203 }, + { 5040, 3204 }, { 5041, 3205 }, { 5042, 3206 }, { 5043, 3207 }, { 5044, 3208 }, { 5045, 3209 }, { 5046, 3210 }, + { 5047, 3211 }, { 5048, 3212 }, { 5049, 3213 }, { 5050, 3214 }, { 5051, 3215 }, { 5052, 3216 }, { 5053, 3217 }, + { 5054, 3218 }, { 5055, 3219 }, { 5056, 3220 }, { 5057, 3221 }, { 5058, 3222 }, { 5059, 3223 }, { 5060, 3224 }, + { 5061, 3225 }, { 5062, 3226 }, { 5063, 3227 }, { 5064, 3228 }, { 5065, 3229 }, { 5066, 3230 }, { 5067, 3231 }, + { 5068, 3232 }, { 5069, 3233 }, { 5070, 3234 }, { 5071, 3235 }, { 5072, 3236 }, { 5073, 3237 }, { 5074, 3238 }, + { 5075, 3239 }, { 5076, 3240 }, { 5077, 3241 }, { 5127, 3242 }, { 5128, 3243 }, { 5129, 3244 }, { 5130, 3245 }, + { 5131, 3246 }, { 5132, 3247 }, { 5133, 3248 }, { 5134, 3249 }, { 5135, 3250 }, { 5136, 3251 }, { 5137, 3252 }, + { 5138, 3253 }, { 5139, 3254 }, { 5140, 3255 }, { 5141, 3256 }, { 5142, 3257 }, { 5143, 3258 }, { 5144, 3259 }, + { 5145, 3260 }, { 5146, 3261 }, { 5147, 3262 }, { 5148, 3263 }, { 5149, 3264 }, { 5150, 3265 }, { 5151, 3266 }, + { 5152, 3267 }, { 5153, 3268 }, { 5154, 3269 }, { 5155, 3270 }, { 5156, 3271 }, { 5227, 3272 }, { 5228, 3273 }, + { 5229, 3274 }, { 5230, 3275 }, { 5231, 3276 }, { 5232, 3277 }, { 5233, 3278 }, { 5234, 3279 }, { 5235, 3280 }, + { 5236, 3281 }, { 5237, 3282 }, { 5238, 3283 }, { 5240, 3285 }, { 5241, 3286 }, { 5242, 3287 }, { 5243, 3288 }, + { 5244, 3289 }, { 5245, 3290 }, { 5246, 3291 }, { 5247, 3292 }, { 5248, 3293 }, { 5249, 3294 }, { 5250, 3295 }, + { 5251, 3296 }, { 5252, 3297 }, { 5253, 3298 }, { 5254, 3299 }, { 5255, 3300 }, { 5256, 3301 }, { 5257, 3302 }, + { 5258, 3303 }, { 5259, 3304 }, { 5260, 3305 }, { 5261, 3306 }, { 5262, 3307 }, { 5263, 3308 }, { 5264, 3309 }, + { 5265, 3310 }, { 5266, 3311 }, { 5267, 3312 }, { 5268, 3313 }, { 5269, 3314 }, { 5270, 3315 }, { 5271, 3316 }, + { 5272, 3317 }, { 5273, 3318 }, { 5274, 3319 }, { 5275, 3320 }, { 5276, 3321 }, { 5277, 3322 }, { 5278, 3323 }, + { 5279, 3324 }, { 5280, 3325 }, { 5281, 3326 }, { 5282, 3327 }, { 5283, 3328 }, { 5284, 3329 }, { 5285, 3330 }, + { 5286, 3331 }, { 5288, 3333 }, { 5289, 3334 }, { 5290, 3335 }, { 5291, 3336 }, { 5292, 3337 }, { 5293, 3338 }, + { 5294, 3339 }, { 5296, 3341 }, { 5297, 3342 }, { 5298, 3343 }, { 5299, 3344 }, { 5300, 3345 }, { 5301, 3346 }, + { 5302, 3347 }, { 5303, 3348 }, { 5304, 3349 }, { 5305, 3350 }, { 5306, 3351 }, { 5307, 3352 }, { 5308, 3353 }, + { 5309, 3354 }, { 5310, 3355 }, { 5311, 3356 }, { 5312, 3357 }, { 5313, 3358 }, { 5314, 3359 }, { 5315, 3360 }, + { 5316, 3361 }, { 5317, 3362 }, { 5318, 3363 }, { 5319, 3364 }, { 5320, 3365 }, { 5321, 3366 }, { 5322, 3367 }, + { 5323, 3368 }, { 5324, 3369 }, { 5325, 3370 }, { 5326, 3371 }, { 5327, 3372 }, { 5328, 3373 }, { 5329, 3374 }, + { 5330, 3375 }, { 5331, 3376 }, { 5332, 3377 }, { 5333, 3378 }, { 5336, 3381 }, { 5337, 3382 }, { 5338, 3383 }, + { 5339, 3384 }, { 5340, 3385 }, { 5341, 3386 }, { 5342, 3387 }, { 5343, 3388 }, { 5344, 3389 }, { 5345, 3390 }, + { 5346, 3391 }, { 5347, 3392 }, { 5348, 3393 }, { 5349, 3394 }, { 5350, 3395 }, { 5351, 3396 }, { 5352, 3397 }, + { 5357, 3402 }, { 5358, 3403 }, { 5359, 3404 }, { 5360, 3405 }, { 5361, 3406 }, { 5362, 3407 }, { 5363, 3408 }, + { 5364, 3409 }, { 5365, 3410 }, { 5366, 3411 }, { 5367, 3412 }, { 5368, 3413 }, { 5369, 3414 }, { 5370, 3415 }, + { 5371, 3416 }, { 5372, 3417 }, { 5373, 3418 }, { 5374, 3419 }, { 5375, 3420 }, { 5376, 3421 }, { 5377, 3422 }, + { 5378, 3423 }, { 5379, 3424 }, { 5380, 3425 }, { 5381, 3426 }, { 5382, 3427 }, { 5383, 3428 }, { 5384, 3429 }, + { 5385, 3430 }, { 5386, 3431 }, { 5387, 3432 }, { 5388, 3433 }, { 5389, 3434 }, { 5390, 3435 }, { 5391, 3436 }, + { 5392, 3437 }, { 5393, 3438 }, { 5394, 3439 }, { 5395, 3440 }, { 5396, 3441 }, { 5397, 3442 }, { 5398, 3443 }, + { 5399, 3444 }, { 5400, 3445 }, { 5401, 3446 }, { 5402, 3447 }, { 5403, 3448 }, { 5404, 3449 }, { 5405, 3450 }, + { 5406, 3451 }, { 5407, 3452 }, { 5408, 3453 }, { 5409, 3454 }, { 5410, 3455 }, { 5411, 3456 }, { 5412, 3457 }, + { 5413, 3458 }, { 5414, 3459 }, { 5415, 3460 }, { 5416, 3461 }, { 5417, 3462 }, { 5418, 3463 }, { 5419, 3464 }, + { 5420, 3465 }, { 5421, 3466 }, { 5422, 3467 }, { 5423, 3468 }, { 5424, 3469 }, { 5425, 3470 }, { 5426, 3471 }, + { 5427, 3472 }, { 5428, 3473 }, { 5429, 3474 }, { 5430, 3475 }, { 5431, 3476 }, { 5432, 3477 }, { 5433, 3478 }, + { 5434, 3479 }, { 5435, 3480 }, { 5436, 3481 }, { 5437, 3482 }, { 5438, 3483 }, { 5439, 3484 }, { 5440, 3485 }, + { 5441, 3486 }, { 5442, 3487 }, { 5443, 3488 }, { 5444, 3489 }, { 5445, 3490 }, { 5446, 3491 }, { 5447, 3492 }, + { 5448, 3493 }, { 5449, 3494 }, { 5450, 3495 }, { 5451, 3496 }, { 5452, 3497 }, { 5453, 3498 }, { 5454, 3499 }, + { 5455, 3500 }, { 5456, 3501 }, { 5457, 3502 }, { 5458, 3503 }, { 5459, 3504 }, { 5460, 3505 }, { 5461, 3506 }, + { 5462, 3507 }, { 5463, 3508 }, { 5464, 3509 }, { 5465, 3510 }, { 5466, 3511 }, { 5467, 3512 }, { 5468, 3513 }, + { 5469, 3514 }, { 5470, 3515 }, { 5471, 3516 }, { 5472, 3517 }, { 5473, 3518 }, { 5474, 3519 }, { 5475, 3520 }, + { 5476, 3521 }, { 5477, 3522 }, { 5478, 3523 }, { 5479, 3524 }, { 5480, 3525 }, { 5481, 3526 }, { 5482, 3527 }, + { 5483, 3528 }, { 5484, 3529 }, { 5485, 3530 }, { 5486, 3531 }, { 5487, 3532 }, { 5488, 3533 }, { 5489, 3534 }, + { 5490, 3535 }, { 5491, 3536 }, { 5492, 3537 }, { 5493, 3538 }, { 5494, 3539 }, { 5495, 3540 }, { 5496, 3541 }, + { 5497, 3542 }, { 5498, 3543 }, { 5499, 3544 }, { 5500, 3545 }, { 5501, 3546 }, { 5502, 3547 }, { 5503, 3548 }, + { 5504, 3549 }, { 5505, 3550 }, { 5506, 3551 }, { 5507, 3552 }, { 5508, 3553 }, { 5509, 3554 }, { 5510, 3555 }, + { 5511, 3556 }, { 5512, 3557 }, { 5513, 3558 }, { 5514, 3559 }, { 5515, 3560 }, { 5516, 3561 }, { 5517, 3562 }, + { 5518, 3563 }, { 5519, 3564 }, { 5520, 3565 }, { 5521, 3566 }, { 5522, 3567 }, { 5523, 3568 }, { 5524, 3569 }, + { 5525, 3570 }, { 5526, 3571 }, { 5527, 3572 }, { 5528, 3573 }, { 5529, 3574 }, { 5530, 3575 }, { 5531, 3576 }, + { 5532, 3577 }, { 5533, 3578 }, { 5534, 3579 }, { 5535, 3580 }, { 5536, 3581 }, { 5537, 3582 }, { 5538, 3583 }, + { 5539, 3584 }, { 5540, 3585 }, { 5541, 3586 }, { 5542, 3587 }, { 5543, 3588 }, { 5544, 3589 }, { 5545, 3590 }, + { 5546, 3591 }, { 5547, 3592 }, { 5548, 3593 }, { 5549, 3594 }, { 5550, 3595 }, { 5551, 3596 }, { 5552, 3597 }, + { 5553, 3598 }, { 5554, 3599 }, { 5555, 3600 }, { 5556, 3601 }, { 5557, 3602 }, { 5558, 3603 }, { 5559, 3604 }, + { 5560, 3605 }, { 5561, 3606 }, { 5562, 3607 }, { 5563, 3608 }, { 5564, 3609 }, { 5565, 3610 }, { 5566, 3611 }, + { 5567, 3612 }, { 5568, 3613 }, { 5569, 3614 }, { 5570, 3615 } }; -// v1.0 -> PAL asset ID remap table. 1311 entries. +// v1.0 -> PAL asset ID remap table. 1314 entries. static const std::unordered_map sV10toPALRemap = { { 2468, 2212 }, { 2469, 2213 }, { 2470, 2214 }, { 2471, 2215 }, { 2472, 2268 }, { 2473, 2269 }, { 2474, 2218 }, { 2475, 2219 }, { 2476, 2220 }, { 2477, 2221 }, { 2478, 2274 }, { 2481, 2277 }, { 2483, 2279 }, { 2484, 2228 }, { 2485, 2229 }, { 2487, 2283 }, { 2488, 2232 }, { 2489, 2233 }, { 2490, 2234 }, { 2491, 2235 }, { 2498, 2294 }, - { 2504, 2248 }, { 2521, 2252 }, { 2524, 2255 }, { 2526, 2257 }, { 2528, 2311 }, { 2529, 2312 }, { 2571, 2315 }, - { 2572, 2316 }, { 2573, 2317 }, { 2574, 2318 }, { 2575, 2319 }, { 2576, 2320 }, { 2577, 2321 }, { 2578, 2322 }, - { 2579, 2323 }, { 2580, 2324 }, { 2581, 2325 }, { 2582, 2326 }, { 2583, 2327 }, { 2584, 2328 }, { 2585, 2329 }, - { 2586, 2330 }, { 2587, 2331 }, { 2588, 2332 }, { 2589, 2333 }, { 2590, 2334 }, { 2591, 2335 }, { 2592, 2336 }, - { 2593, 2337 }, { 2594, 2338 }, { 2595, 2339 }, { 2596, 2340 }, { 2597, 2341 }, { 2598, 2342 }, { 2599, 2343 }, - { 2600, 2344 }, { 2601, 2345 }, { 2602, 2346 }, { 2671, 2347 }, { 2672, 2348 }, { 2673, 2349 }, { 2674, 2350 }, - { 2675, 2351 }, { 2676, 2352 }, { 2677, 2353 }, { 2678, 2354 }, { 2679, 2355 }, { 2680, 2356 }, { 2681, 2357 }, - { 2682, 2358 }, { 2683, 2359 }, { 2684, 2360 }, { 2685, 2361 }, { 2686, 2362 }, { 2687, 2363 }, { 2688, 2364 }, - { 2689, 2365 }, { 2690, 2366 }, { 2691, 2367 }, { 2692, 2368 }, { 2693, 2369 }, { 2694, 2370 }, { 2695, 2371 }, - { 2696, 2372 }, { 2771, 2373 }, { 2772, 2374 }, { 2773, 2375 }, { 2774, 2376 }, { 2775, 2377 }, { 2776, 2378 }, - { 2777, 2379 }, { 2778, 2380 }, { 2779, 2381 }, { 2780, 2382 }, { 2781, 2383 }, { 2782, 2384 }, { 2783, 2385 }, - { 2784, 2386 }, { 2785, 2387 }, { 2786, 2388 }, { 2871, 2389 }, { 2872, 2390 }, { 2873, 2391 }, { 2874, 2392 }, - { 2875, 2393 }, { 2876, 2394 }, { 2877, 2395 }, { 2878, 2396 }, { 2879, 2397 }, { 2880, 2398 }, { 2881, 2399 }, - { 2882, 2400 }, { 2883, 2401 }, { 2884, 2402 }, { 2885, 2403 }, { 2886, 2404 }, { 2887, 2405 }, { 2888, 2406 }, - { 2889, 2407 }, { 2890, 2408 }, { 2891, 2409 }, { 2892, 2410 }, { 2893, 2411 }, { 2894, 2412 }, { 2895, 2413 }, - { 2896, 2414 }, { 2897, 2415 }, { 2971, 2416 }, { 2972, 2417 }, { 2973, 2418 }, { 2974, 2419 }, { 2975, 2420 }, - { 2976, 2421 }, { 2977, 2422 }, { 2978, 2423 }, { 2979, 2424 }, { 3071, 2425 }, { 3072, 2426 }, { 3073, 2427 }, - { 3074, 2428 }, { 3075, 2429 }, { 3076, 2430 }, { 3077, 2431 }, { 3078, 2432 }, { 3079, 2433 }, { 3080, 2434 }, - { 3081, 2435 }, { 3082, 2436 }, { 3083, 2437 }, { 3084, 2438 }, { 3085, 2439 }, { 3086, 2440 }, { 3087, 2441 }, - { 3088, 2442 }, { 3089, 2443 }, { 3090, 2444 }, { 3091, 2445 }, { 3092, 2446 }, { 3093, 2447 }, { 3094, 2448 }, - { 3095, 2449 }, { 3096, 2450 }, { 3097, 2451 }, { 3098, 2452 }, { 3099, 2453 }, { 3100, 2454 }, { 3101, 2455 }, - { 3102, 2456 }, { 3103, 2457 }, { 3104, 2458 }, { 3105, 2459 }, { 3106, 2460 }, { 3107, 2461 }, { 3108, 2462 }, - { 3109, 2463 }, { 3110, 2464 }, { 3111, 2465 }, { 3112, 2466 }, { 3113, 2467 }, { 3114, 2468 }, { 3115, 2469 }, - { 3171, 2470 }, { 3172, 2471 }, { 3173, 2472 }, { 3174, 2473 }, { 3175, 2474 }, { 3176, 2475 }, { 3177, 2476 }, - { 3178, 2477 }, { 3179, 2478 }, { 3180, 2479 }, { 3181, 2480 }, { 3182, 2481 }, { 3183, 2482 }, { 3184, 2483 }, - { 3185, 2484 }, { 3186, 2485 }, { 3187, 2486 }, { 3188, 2487 }, { 3189, 2488 }, { 3190, 2489 }, { 3191, 2490 }, - { 3192, 2491 }, { 3193, 2492 }, { 3194, 2493 }, { 3195, 2494 }, { 3196, 2495 }, { 3197, 2496 }, { 3198, 2497 }, - { 3199, 2498 }, { 3200, 2499 }, { 3201, 2500 }, { 3202, 2501 }, { 3203, 2502 }, { 3204, 2503 }, { 3205, 2504 }, - { 3206, 2505 }, { 3207, 2506 }, { 3208, 2507 }, { 3209, 2508 }, { 3210, 2509 }, { 3211, 2510 }, { 3212, 2511 }, - { 3213, 2512 }, { 3214, 2513 }, { 3215, 2514 }, { 3216, 2515 }, { 3217, 2516 }, { 3218, 2517 }, { 3219, 2518 }, - { 3220, 2519 }, { 3221, 2520 }, { 3222, 2521 }, { 3223, 2522 }, { 3224, 2523 }, { 3271, 2524 }, { 3272, 2525 }, - { 3273, 2526 }, { 3274, 2527 }, { 3275, 2528 }, { 3276, 2529 }, { 3277, 2530 }, { 3278, 2531 }, { 3279, 2532 }, - { 3280, 2533 }, { 3281, 2534 }, { 3282, 2535 }, { 3283, 2536 }, { 3284, 2537 }, { 3285, 2538 }, { 3286, 2539 }, - { 3287, 2540 }, { 3288, 2541 }, { 3289, 2542 }, { 3290, 2543 }, { 3291, 2544 }, { 3292, 2545 }, { 3293, 2546 }, - { 3294, 2547 }, { 3295, 2548 }, { 3296, 2549 }, { 3297, 2550 }, { 3298, 2551 }, { 3299, 2552 }, { 3300, 2553 }, - { 3301, 2554 }, { 3302, 2555 }, { 3303, 2556 }, { 3304, 2557 }, { 3371, 2558 }, { 3372, 2559 }, { 3373, 2560 }, - { 3374, 2561 }, { 3375, 2562 }, { 3376, 2563 }, { 3377, 2564 }, { 3378, 2565 }, { 3379, 2566 }, { 3380, 2567 }, - { 3381, 2568 }, { 3382, 2569 }, { 3383, 2570 }, { 3384, 2571 }, { 3385, 2572 }, { 3471, 2573 }, { 3472, 2574 }, - { 3473, 2575 }, { 3474, 2576 }, { 3475, 2577 }, { 3476, 2578 }, { 3477, 2579 }, { 3478, 2580 }, { 3479, 2581 }, - { 3480, 2582 }, { 3481, 2583 }, { 3482, 2584 }, { 3483, 2585 }, { 3484, 2586 }, { 3485, 2587 }, { 3486, 2588 }, - { 3487, 2589 }, { 3488, 2590 }, { 3489, 2591 }, { 3490, 2592 }, { 3491, 2593 }, { 3492, 2594 }, { 3493, 2595 }, - { 3494, 2596 }, { 3495, 2597 }, { 3496, 2598 }, { 3497, 2599 }, { 3498, 2600 }, { 3499, 2601 }, { 3500, 2602 }, - { 3501, 2603 }, { 3502, 2604 }, { 3503, 2605 }, { 3504, 2606 }, { 3505, 2607 }, { 3506, 2608 }, { 3507, 2609 }, - { 3508, 2610 }, { 3509, 2611 }, { 3510, 2612 }, { 3571, 2613 }, { 3572, 2614 }, { 3573, 2615 }, { 3574, 2616 }, - { 3575, 2617 }, { 3576, 2618 }, { 3577, 2619 }, { 3578, 2620 }, { 3579, 2621 }, { 3580, 2622 }, { 3581, 2623 }, - { 3582, 2624 }, { 3583, 2625 }, { 3584, 2626 }, { 3585, 2627 }, { 3586, 2628 }, { 3587, 2629 }, { 3588, 2630 }, - { 3589, 2631 }, { 3590, 2632 }, { 3591, 2633 }, { 3592, 2634 }, { 3593, 2635 }, { 3594, 2636 }, { 3595, 2637 }, - { 3596, 2638 }, { 3597, 2639 }, { 3598, 2640 }, { 3599, 2641 }, { 3600, 2642 }, { 3601, 2643 }, { 3602, 2644 }, - { 3603, 2645 }, { 3604, 2646 }, { 3605, 2647 }, { 3606, 2648 }, { 3607, 2649 }, { 3608, 2650 }, { 3609, 2651 }, - { 3610, 2652 }, { 3611, 2653 }, { 3612, 2654 }, { 3613, 2655 }, { 3614, 2656 }, { 3615, 2657 }, { 3616, 2658 }, - { 3617, 2659 }, { 3618, 2660 }, { 3619, 2661 }, { 3620, 2662 }, { 3621, 2663 }, { 3622, 2664 }, { 3623, 2665 }, - { 3624, 2666 }, { 3625, 2667 }, { 3626, 2668 }, { 3627, 2669 }, { 3628, 2670 }, { 3629, 2671 }, { 3630, 2672 }, - { 3631, 2673 }, { 3632, 2674 }, { 3633, 2675 }, { 3634, 2676 }, { 3635, 2677 }, { 3636, 2678 }, { 3637, 2679 }, - { 3638, 2680 }, { 3639, 2681 }, { 3640, 2682 }, { 3641, 2683 }, { 3642, 2684 }, { 3643, 2685 }, { 3644, 2686 }, - { 3645, 2687 }, { 3646, 2688 }, { 3671, 2689 }, { 3672, 2690 }, { 3673, 2691 }, { 3674, 2692 }, { 3675, 2693 }, - { 3676, 2694 }, { 3677, 2695 }, { 3678, 2696 }, { 3679, 2697 }, { 3680, 2698 }, { 3681, 2699 }, { 3682, 2700 }, - { 3683, 2701 }, { 3684, 2702 }, { 3685, 2703 }, { 3686, 2704 }, { 3687, 2705 }, { 3688, 2706 }, { 3689, 2707 }, - { 3690, 2708 }, { 3691, 2709 }, { 3692, 2710 }, { 3693, 2711 }, { 3694, 2712 }, { 3695, 2713 }, { 3696, 2714 }, - { 3697, 2715 }, { 3698, 2716 }, { 3699, 2717 }, { 3700, 2718 }, { 3701, 2719 }, { 3702, 2720 }, { 3703, 2721 }, - { 3704, 2722 }, { 3705, 2723 }, { 3706, 2724 }, { 3707, 2725 }, { 3708, 2726 }, { 3709, 2727 }, { 3710, 2728 }, - { 3711, 2729 }, { 3712, 2730 }, { 3713, 2731 }, { 3714, 2732 }, { 3715, 2733 }, { 3716, 2734 }, { 3717, 2735 }, - { 3718, 2736 }, { 3719, 2737 }, { 3720, 2738 }, { 3721, 2739 }, { 3722, 2740 }, { 3723, 2741 }, { 3724, 2742 }, - { 3725, 2743 }, { 3726, 2744 }, { 3727, 2745 }, { 3728, 2746 }, { 3729, 2747 }, { 3730, 2748 }, { 3927, 2749 }, - { 3928, 2750 }, { 3929, 2751 }, { 3930, 2752 }, { 3931, 2753 }, { 3932, 2754 }, { 3933, 2755 }, { 3934, 2756 }, - { 3940, 2762 }, { 3941, 2763 }, { 3942, 2764 }, { 3943, 2765 }, { 3944, 2766 }, { 3945, 2767 }, { 3946, 2768 }, - { 3947, 2769 }, { 3948, 2770 }, { 3949, 2771 }, { 3950, 2772 }, { 3951, 2773 }, { 3952, 2774 }, { 3953, 2775 }, - { 3954, 2776 }, { 3955, 2777 }, { 3956, 2778 }, { 3957, 2779 }, { 3958, 2780 }, { 3959, 2781 }, { 3960, 2782 }, - { 3961, 2783 }, { 3962, 2784 }, { 3963, 2785 }, { 3964, 2786 }, { 3965, 2787 }, { 3966, 2788 }, { 3967, 2789 }, - { 3968, 2790 }, { 3969, 2791 }, { 3970, 2792 }, { 3971, 2793 }, { 3972, 2794 }, { 3973, 2795 }, { 3974, 2796 }, - { 3975, 2797 }, { 3976, 2798 }, { 3977, 2799 }, { 3978, 2800 }, { 3979, 2801 }, { 3980, 2802 }, { 3981, 2803 }, - { 3982, 2804 }, { 3983, 2805 }, { 3984, 2806 }, { 3985, 2807 }, { 3986, 2808 }, { 3987, 2809 }, { 3988, 2810 }, - { 3989, 2811 }, { 3990, 2812 }, { 3991, 2813 }, { 3992, 2814 }, { 3993, 2815 }, { 3994, 2816 }, { 3995, 2817 }, - { 3996, 2818 }, { 3997, 2819 }, { 3998, 2820 }, { 3999, 2821 }, { 4000, 2822 }, { 4001, 2823 }, { 4002, 2824 }, - { 4003, 2825 }, { 4004, 2826 }, { 4005, 2827 }, { 4006, 2828 }, { 4007, 2829 }, { 4008, 2830 }, { 4009, 2831 }, - { 4010, 2832 }, { 4011, 2833 }, { 4012, 2834 }, { 4013, 2835 }, { 4014, 2836 }, { 4015, 2837 }, { 4016, 2838 }, - { 4017, 2839 }, { 4018, 2840 }, { 4019, 2841 }, { 4020, 2842 }, { 4021, 2843 }, { 4022, 2844 }, { 4023, 2845 }, - { 4024, 2846 }, { 4025, 2847 }, { 4026, 2848 }, { 4027, 2849 }, { 4028, 2850 }, { 4029, 2851 }, { 4030, 2852 }, - { 4031, 2853 }, { 4032, 2854 }, { 4127, 2855 }, { 4128, 2856 }, { 4129, 2857 }, { 4130, 2858 }, { 4131, 2859 }, - { 4132, 2860 }, { 4133, 2861 }, { 4134, 2862 }, { 4135, 2863 }, { 4136, 2864 }, { 4137, 2865 }, { 4138, 2866 }, - { 4139, 2867 }, { 4140, 2868 }, { 4145, 2873 }, { 4146, 2874 }, { 4147, 2875 }, { 4148, 2876 }, { 4149, 2877 }, - { 4150, 2878 }, { 4151, 2879 }, { 4152, 2880 }, { 4153, 2881 }, { 4154, 2882 }, { 4155, 2883 }, { 4156, 2884 }, - { 4157, 2885 }, { 4158, 2886 }, { 4159, 2887 }, { 4160, 2888 }, { 4227, 2889 }, { 4228, 2890 }, { 4229, 2891 }, - { 4230, 2892 }, { 4231, 2893 }, { 4232, 2894 }, { 4233, 2895 }, { 4234, 2896 }, { 4235, 2897 }, { 4236, 2898 }, - { 4237, 2899 }, { 4238, 2900 }, { 4239, 2901 }, { 4240, 2902 }, { 4241, 2903 }, { 4242, 2904 }, { 4243, 2905 }, - { 4244, 2906 }, { 4245, 2907 }, { 4246, 2908 }, { 4247, 2909 }, { 4248, 2910 }, { 4249, 2911 }, { 4250, 2912 }, - { 4251, 2913 }, { 4252, 2914 }, { 4253, 2915 }, { 4254, 2916 }, { 4255, 2917 }, { 4256, 2918 }, { 4257, 2919 }, - { 4258, 2920 }, { 4327, 2921 }, { 4328, 2922 }, { 4329, 2923 }, { 4330, 2924 }, { 4331, 2925 }, { 4332, 2926 }, - { 4333, 2927 }, { 4334, 2928 }, { 4335, 2929 }, { 4336, 2930 }, { 4337, 2931 }, { 4338, 2932 }, { 4339, 2933 }, - { 4340, 2934 }, { 4341, 2935 }, { 4342, 2936 }, { 4343, 2937 }, { 4344, 2938 }, { 4345, 2939 }, { 4346, 2940 }, - { 4347, 2941 }, { 4348, 2942 }, { 4349, 2943 }, { 4350, 2944 }, { 4351, 2945 }, { 4352, 2946 }, { 4353, 2947 }, - { 4354, 2948 }, { 4355, 2949 }, { 4356, 2950 }, { 4357, 2951 }, { 4358, 2952 }, { 4359, 2953 }, { 4360, 2954 }, - { 4361, 2955 }, { 4362, 2956 }, { 4363, 2957 }, { 4364, 2958 }, { 4365, 2959 }, { 4366, 2960 }, { 4367, 2961 }, - { 4368, 2962 }, { 4369, 2963 }, { 4370, 2964 }, { 4371, 2965 }, { 4372, 2966 }, { 4373, 2967 }, { 4374, 2968 }, - { 4375, 2969 }, { 4376, 2970 }, { 4377, 2971 }, { 4378, 2972 }, { 4379, 2973 }, { 4380, 2974 }, { 4381, 2975 }, - { 4382, 2976 }, { 4383, 2977 }, { 4384, 2978 }, { 4385, 2979 }, { 4386, 2980 }, { 4387, 2981 }, { 4388, 2982 }, - { 4389, 2983 }, { 4390, 2984 }, { 4391, 2985 }, { 4392, 2986 }, { 4393, 2987 }, { 4394, 2988 }, { 4395, 2989 }, - { 4396, 2990 }, { 4397, 2991 }, { 4398, 2992 }, { 4399, 2993 }, { 4400, 2994 }, { 4401, 2995 }, { 4402, 2996 }, - { 4403, 2997 }, { 4404, 2998 }, { 4405, 2999 }, { 4406, 3000 }, { 4407, 3001 }, { 4408, 3002 }, { 4409, 3003 }, - { 4410, 3004 }, { 4411, 3005 }, { 4412, 3006 }, { 4413, 3007 }, { 4414, 3008 }, { 4415, 3009 }, { 4416, 3010 }, - { 4417, 3011 }, { 4418, 3012 }, { 4419, 3013 }, { 4420, 3014 }, { 4421, 3015 }, { 4422, 3016 }, { 4423, 3017 }, - { 4424, 3018 }, { 4425, 3019 }, { 4426, 3020 }, { 4427, 3021 }, { 4428, 3022 }, { 4429, 3023 }, { 4430, 3024 }, - { 4431, 3025 }, { 4432, 3026 }, { 4433, 3027 }, { 4434, 3028 }, { 4435, 3029 }, { 4436, 3030 }, { 4437, 3031 }, - { 4438, 3032 }, { 4439, 3033 }, { 4440, 3034 }, { 4441, 3035 }, { 4442, 3036 }, { 4443, 3037 }, { 4444, 3038 }, - { 4445, 3039 }, { 4446, 3040 }, { 4447, 3041 }, { 4448, 3042 }, { 4449, 3043 }, { 4450, 3044 }, { 4527, 3045 }, - { 4528, 3046 }, { 4529, 3047 }, { 4530, 3048 }, { 4531, 3049 }, { 4532, 3050 }, { 4533, 3051 }, { 4534, 3052 }, - { 4535, 3053 }, { 4536, 3054 }, { 4537, 3055 }, { 4538, 3056 }, { 4539, 3057 }, { 4540, 3058 }, { 4541, 3059 }, - { 4542, 3060 }, { 4543, 3061 }, { 4544, 3062 }, { 4545, 3063 }, { 4546, 3064 }, { 4547, 3066 }, { 4548, 3067 }, - { 4549, 3068 }, { 4550, 3069 }, { 4551, 3070 }, { 4552, 3071 }, { 4553, 3072 }, { 4627, 3073 }, { 4628, 3074 }, - { 4629, 3075 }, { 4630, 3076 }, { 4631, 3077 }, { 4632, 3078 }, { 4633, 3079 }, { 4634, 3080 }, { 4635, 3081 }, - { 4636, 3082 }, { 4637, 3083 }, { 4638, 3084 }, { 4639, 3085 }, { 4640, 3086 }, { 4641, 3087 }, { 4642, 3088 }, - { 4643, 3089 }, { 4644, 3090 }, { 4645, 3091 }, { 4646, 3092 }, { 4647, 3093 }, { 4648, 3094 }, { 4649, 3095 }, - { 4650, 3096 }, { 4651, 3097 }, { 4652, 3098 }, { 4653, 3099 }, { 4654, 3100 }, { 4655, 3101 }, { 4656, 3102 }, - { 4657, 3103 }, { 4658, 3104 }, { 4659, 3105 }, { 4660, 3106 }, { 4661, 3107 }, { 4662, 3108 }, { 4663, 3109 }, - { 4664, 3110 }, { 4665, 3111 }, { 4666, 3112 }, { 4667, 3113 }, { 4668, 3114 }, { 4669, 3115 }, { 4670, 3116 }, - { 4671, 3117 }, { 4672, 3118 }, { 4673, 3119 }, { 4674, 3120 }, { 4675, 3121 }, { 4676, 3122 }, { 4677, 3123 }, - { 4678, 3124 }, { 4679, 3125 }, { 4680, 3126 }, { 4681, 3127 }, { 4682, 3128 }, { 4683, 3129 }, { 4684, 3130 }, - { 4685, 3131 }, { 4686, 3132 }, { 4687, 3133 }, { 4688, 3134 }, { 4689, 3135 }, { 4690, 3136 }, { 4691, 3137 }, - { 4692, 3138 }, { 4693, 3139 }, { 4694, 3140 }, { 4695, 3141 }, { 4696, 3142 }, { 4697, 3143 }, { 4698, 3144 }, - { 4699, 3145 }, { 4700, 3146 }, { 4701, 3147 }, { 4702, 3148 }, { 4703, 3149 }, { 4704, 3150 }, { 4705, 3151 }, - { 4706, 3152 }, { 4707, 3153 }, { 4708, 3154 }, { 4709, 3155 }, { 4710, 3156 }, { 4711, 3157 }, { 4712, 3158 }, - { 4713, 3159 }, { 4714, 3160 }, { 4715, 3161 }, { 4716, 3162 }, { 4717, 3163 }, { 4718, 3164 }, { 4719, 3165 }, - { 4720, 3166 }, { 4721, 3167 }, { 4722, 3168 }, { 4723, 3169 }, { 4724, 3170 }, { 4725, 3171 }, { 4726, 3172 }, - { 4827, 3173 }, { 4828, 3174 }, { 4829, 3175 }, { 4830, 3176 }, { 4831, 3177 }, { 4832, 3178 }, { 4833, 3179 }, - { 4834, 3180 }, { 4835, 3181 }, { 4836, 3182 }, { 4837, 3183 }, { 4838, 3184 }, { 4839, 3185 }, { 4840, 3186 }, - { 4841, 3187 }, { 4842, 3188 }, { 4843, 3189 }, { 4844, 3190 }, { 4845, 3191 }, { 5027, 3192 }, { 5028, 3193 }, - { 5029, 3194 }, { 5030, 3195 }, { 5031, 3196 }, { 5032, 3197 }, { 5033, 3198 }, { 5034, 3199 }, { 5035, 3200 }, - { 5036, 3201 }, { 5037, 3202 }, { 5038, 3203 }, { 5039, 3204 }, { 5040, 3205 }, { 5041, 3206 }, { 5042, 3207 }, - { 5043, 3208 }, { 5044, 3209 }, { 5045, 3210 }, { 5046, 3211 }, { 5047, 3212 }, { 5048, 3213 }, { 5049, 3214 }, - { 5050, 3215 }, { 5051, 3216 }, { 5052, 3217 }, { 5053, 3218 }, { 5054, 3219 }, { 5055, 3220 }, { 5056, 3221 }, - { 5057, 3222 }, { 5058, 3223 }, { 5059, 3224 }, { 5060, 3225 }, { 5061, 3226 }, { 5062, 3227 }, { 5063, 3228 }, - { 5064, 3229 }, { 5065, 3230 }, { 5066, 3231 }, { 5067, 3232 }, { 5068, 3233 }, { 5069, 3234 }, { 5070, 3235 }, - { 5071, 3236 }, { 5072, 3237 }, { 5073, 3238 }, { 5074, 3239 }, { 5075, 3240 }, { 5076, 3241 }, { 5077, 3242 }, - { 5127, 3243 }, { 5128, 3244 }, { 5129, 3245 }, { 5130, 3246 }, { 5131, 3247 }, { 5132, 3248 }, { 5133, 3249 }, - { 5134, 3250 }, { 5135, 3251 }, { 5136, 3252 }, { 5137, 3253 }, { 5138, 3254 }, { 5139, 3255 }, { 5140, 3256 }, - { 5141, 3257 }, { 5142, 3258 }, { 5143, 3259 }, { 5144, 3260 }, { 5145, 3261 }, { 5146, 3262 }, { 5147, 3263 }, - { 5148, 3264 }, { 5149, 3265 }, { 5150, 3266 }, { 5151, 3267 }, { 5152, 3268 }, { 5153, 3269 }, { 5154, 3270 }, - { 5155, 3271 }, { 5156, 3272 }, { 5227, 3273 }, { 5228, 3274 }, { 5229, 3275 }, { 5230, 3276 }, { 5231, 3277 }, - { 5232, 3278 }, { 5233, 3279 }, { 5234, 3280 }, { 5235, 3281 }, { 5236, 3282 }, { 5237, 3283 }, { 5238, 3284 }, - { 5240, 3286 }, { 5241, 3287 }, { 5242, 3288 }, { 5243, 3289 }, { 5244, 3290 }, { 5245, 3291 }, { 5246, 3292 }, - { 5247, 3293 }, { 5248, 3294 }, { 5249, 3295 }, { 5250, 3296 }, { 5251, 3297 }, { 5252, 3298 }, { 5253, 3299 }, - { 5254, 3300 }, { 5255, 3301 }, { 5256, 3302 }, { 5257, 3303 }, { 5258, 3304 }, { 5259, 3305 }, { 5260, 3306 }, - { 5261, 3307 }, { 5262, 3308 }, { 5263, 3309 }, { 5264, 3310 }, { 5265, 3311 }, { 5266, 3312 }, { 5267, 3313 }, - { 5268, 3314 }, { 5269, 3315 }, { 5270, 3316 }, { 5271, 3317 }, { 5272, 3318 }, { 5273, 3319 }, { 5274, 3320 }, - { 5275, 3321 }, { 5276, 3322 }, { 5277, 3323 }, { 5278, 3324 }, { 5279, 3325 }, { 5280, 3326 }, { 5281, 3327 }, - { 5282, 3328 }, { 5283, 3329 }, { 5284, 3330 }, { 5285, 3331 }, { 5286, 3332 }, { 5288, 3334 }, { 5289, 3335 }, - { 5290, 3336 }, { 5291, 3337 }, { 5292, 3338 }, { 5293, 3339 }, { 5294, 3340 }, { 5296, 3342 }, { 5297, 3343 }, - { 5298, 3344 }, { 5299, 3345 }, { 5300, 3346 }, { 5301, 3347 }, { 5302, 3348 }, { 5303, 3349 }, { 5304, 3350 }, - { 5305, 3351 }, { 5306, 3352 }, { 5307, 3353 }, { 5308, 3354 }, { 5309, 3355 }, { 5310, 3356 }, { 5311, 3357 }, - { 5312, 3358 }, { 5313, 3359 }, { 5314, 3360 }, { 5315, 3361 }, { 5316, 3362 }, { 5317, 3363 }, { 5318, 3364 }, - { 5319, 3365 }, { 5320, 3366 }, { 5321, 3367 }, { 5322, 3368 }, { 5323, 3369 }, { 5324, 3370 }, { 5325, 3371 }, - { 5326, 3372 }, { 5327, 3373 }, { 5328, 3374 }, { 5329, 3375 }, { 5330, 3376 }, { 5331, 3377 }, { 5332, 3378 }, - { 5333, 3379 }, { 5336, 3382 }, { 5337, 3383 }, { 5338, 3384 }, { 5339, 3385 }, { 5340, 3386 }, { 5341, 3387 }, - { 5342, 3388 }, { 5343, 3389 }, { 5344, 3390 }, { 5345, 3391 }, { 5346, 3392 }, { 5347, 3393 }, { 5348, 3394 }, - { 5349, 3395 }, { 5350, 3396 }, { 5351, 3397 }, { 5352, 3398 }, { 5357, 3403 }, { 5358, 3404 }, { 5359, 3405 }, - { 5360, 3406 }, { 5361, 3407 }, { 5362, 3408 }, { 5363, 3409 }, { 5364, 3410 }, { 5365, 3411 }, { 5366, 3412 }, - { 5367, 3413 }, { 5368, 3414 }, { 5369, 3415 }, { 5370, 3416 }, { 5371, 3417 }, { 5372, 3418 }, { 5373, 3419 }, - { 5374, 3420 }, { 5375, 3421 }, { 5376, 3422 }, { 5377, 3423 }, { 5378, 3424 }, { 5379, 3425 }, { 5380, 3426 }, - { 5381, 3427 }, { 5382, 3428 }, { 5383, 3429 }, { 5384, 3430 }, { 5385, 3431 }, { 5386, 3432 }, { 5387, 3433 }, - { 5388, 3434 }, { 5389, 3435 }, { 5390, 3436 }, { 5391, 3437 }, { 5392, 3438 }, { 5393, 3439 }, { 5394, 3440 }, - { 5395, 3441 }, { 5396, 3442 }, { 5397, 3443 }, { 5398, 3444 }, { 5399, 3445 }, { 5400, 3446 }, { 5401, 3447 }, - { 5402, 3448 }, { 5403, 3449 }, { 5404, 3450 }, { 5405, 3451 }, { 5406, 3452 }, { 5407, 3453 }, { 5408, 3454 }, - { 5409, 3455 }, { 5410, 3456 }, { 5411, 3457 }, { 5412, 3458 }, { 5413, 3459 }, { 5414, 3460 }, { 5415, 3461 }, - { 5416, 3462 }, { 5417, 3463 }, { 5418, 3464 }, { 5419, 3465 }, { 5420, 3466 }, { 5421, 3467 }, { 5422, 3468 }, - { 5423, 3469 }, { 5424, 3470 }, { 5425, 3471 }, { 5426, 3472 }, { 5427, 3473 }, { 5428, 3474 }, { 5429, 3475 }, - { 5430, 3476 }, { 5431, 3477 }, { 5432, 3478 }, { 5433, 3479 }, { 5434, 3480 }, { 5435, 3481 }, { 5436, 3482 }, - { 5437, 3483 }, { 5438, 3484 }, { 5439, 3485 }, { 5440, 3486 }, { 5441, 3487 }, { 5442, 3488 }, { 5443, 3489 }, - { 5444, 3490 }, { 5445, 3491 }, { 5446, 3492 }, { 5447, 3493 }, { 5448, 3494 }, { 5449, 3495 }, { 5450, 3496 }, - { 5451, 3497 }, { 5452, 3498 }, { 5453, 3499 }, { 5454, 3500 }, { 5455, 3501 }, { 5456, 3502 }, { 5457, 3503 }, - { 5458, 3504 }, { 5459, 3505 }, { 5460, 3506 }, { 5461, 3507 }, { 5462, 3508 }, { 5463, 3509 }, { 5464, 3510 }, - { 5465, 3511 }, { 5466, 3512 }, { 5467, 3513 }, { 5468, 3514 }, { 5469, 3515 }, { 5470, 3516 }, { 5471, 3517 }, - { 5472, 3518 }, { 5473, 3519 }, { 5474, 3520 }, { 5475, 3521 }, { 5476, 3522 }, { 5477, 3523 }, { 5478, 3524 }, - { 5479, 3525 }, { 5480, 3526 }, { 5481, 3527 }, { 5482, 3528 }, { 5483, 3529 }, { 5484, 3530 }, { 5485, 3531 }, - { 5486, 3532 }, { 5487, 3533 }, { 5488, 3534 }, { 5489, 3535 }, { 5490, 3536 }, { 5491, 3537 }, { 5492, 3538 }, - { 5493, 3539 }, { 5494, 3540 }, { 5495, 3541 }, { 5496, 3542 }, { 5497, 3543 }, { 5498, 3544 }, { 5499, 3545 }, - { 5500, 3546 }, { 5501, 3547 }, { 5502, 3548 }, { 5503, 3549 }, { 5504, 3550 }, { 5505, 3551 }, { 5506, 3552 }, - { 5507, 3553 }, { 5508, 3554 }, { 5509, 3555 }, { 5510, 3556 }, { 5511, 3557 }, { 5512, 3558 }, { 5513, 3559 }, - { 5514, 3560 }, { 5515, 3561 }, { 5516, 3562 }, { 5517, 3563 }, { 5518, 3564 }, { 5519, 3565 }, { 5520, 3566 }, - { 5521, 3567 }, { 5522, 3568 }, { 5523, 3569 }, { 5524, 3570 }, { 5525, 3571 }, { 5526, 3572 }, { 5527, 3573 }, - { 5528, 3574 }, { 5529, 3575 }, { 5530, 3576 }, { 5531, 3577 }, { 5532, 3578 }, { 5533, 3579 }, { 5534, 3580 }, - { 5535, 3581 }, { 5536, 3582 }, { 5537, 3583 }, { 5538, 3584 }, { 5539, 3585 }, { 5540, 3586 }, { 5541, 3587 }, - { 5542, 3588 }, { 5543, 3589 }, { 5544, 3590 }, { 5545, 3591 }, { 5546, 3592 }, { 5547, 3593 }, { 5548, 3594 }, - { 5549, 3595 }, { 5550, 3596 }, { 5551, 3597 }, { 5552, 3598 }, { 5553, 3599 }, { 5554, 3600 }, { 5555, 3601 }, - { 5556, 3602 }, { 5557, 3603 }, { 5558, 3604 }, { 5559, 3605 }, { 5560, 3606 }, { 5561, 3607 }, { 5562, 3608 }, - { 5563, 3609 }, { 5564, 3610 }, { 5565, 3611 }, { 5566, 3612 }, { 5567, 3613 }, { 5568, 3614 }, { 5569, 3615 }, - { 5570, 3616 }, { 4554, 3065 }, + { 2504, 2248 }, { 2508, 2252 }, { 2511, 2255 }, { 2513, 2257 }, { 2521, 2252 }, { 2524, 2255 }, { 2526, 2257 }, + { 2528, 2311 }, { 2529, 2312 }, { 2571, 2315 }, { 2572, 2316 }, { 2573, 2317 }, { 2574, 2318 }, { 2575, 2319 }, + { 2576, 2320 }, { 2577, 2321 }, { 2578, 2322 }, { 2579, 2323 }, { 2580, 2324 }, { 2581, 2325 }, { 2582, 2326 }, + { 2583, 2327 }, { 2584, 2328 }, { 2585, 2329 }, { 2586, 2330 }, { 2587, 2331 }, { 2588, 2332 }, { 2589, 2333 }, + { 2590, 2334 }, { 2591, 2335 }, { 2592, 2336 }, { 2593, 2337 }, { 2594, 2338 }, { 2595, 2339 }, { 2596, 2340 }, + { 2597, 2341 }, { 2598, 2342 }, { 2599, 2343 }, { 2600, 2344 }, { 2601, 2345 }, { 2602, 2346 }, { 2671, 2347 }, + { 2672, 2348 }, { 2673, 2349 }, { 2674, 2350 }, { 2675, 2351 }, { 2676, 2352 }, { 2677, 2353 }, { 2678, 2354 }, + { 2679, 2355 }, { 2680, 2356 }, { 2681, 2357 }, { 2682, 2358 }, { 2683, 2359 }, { 2684, 2360 }, { 2685, 2361 }, + { 2686, 2362 }, { 2687, 2363 }, { 2688, 2364 }, { 2689, 2365 }, { 2690, 2366 }, { 2691, 2367 }, { 2692, 2368 }, + { 2693, 2369 }, { 2694, 2370 }, { 2695, 2371 }, { 2696, 2372 }, { 2771, 2373 }, { 2772, 2374 }, { 2773, 2375 }, + { 2774, 2376 }, { 2775, 2377 }, { 2776, 2378 }, { 2777, 2379 }, { 2778, 2380 }, { 2779, 2381 }, { 2780, 2382 }, + { 2781, 2383 }, { 2782, 2384 }, { 2783, 2385 }, { 2784, 2386 }, { 2785, 2387 }, { 2786, 2388 }, { 2871, 2389 }, + { 2872, 2390 }, { 2873, 2391 }, { 2874, 2392 }, { 2875, 2393 }, { 2876, 2394 }, { 2877, 2395 }, { 2878, 2396 }, + { 2879, 2397 }, { 2880, 2398 }, { 2881, 2399 }, { 2882, 2400 }, { 2883, 2401 }, { 2884, 2402 }, { 2885, 2403 }, + { 2886, 2404 }, { 2887, 2405 }, { 2888, 2406 }, { 2889, 2407 }, { 2890, 2408 }, { 2891, 2409 }, { 2892, 2410 }, + { 2893, 2411 }, { 2894, 2412 }, { 2895, 2413 }, { 2896, 2414 }, { 2897, 2415 }, { 2971, 2416 }, { 2972, 2417 }, + { 2973, 2418 }, { 2974, 2419 }, { 2975, 2420 }, { 2976, 2421 }, { 2977, 2422 }, { 2978, 2423 }, { 2979, 2424 }, + { 3071, 2425 }, { 3072, 2426 }, { 3073, 2427 }, { 3074, 2428 }, { 3075, 2429 }, { 3076, 2430 }, { 3077, 2431 }, + { 3078, 2432 }, { 3079, 2433 }, { 3080, 2434 }, { 3081, 2435 }, { 3082, 2436 }, { 3083, 2437 }, { 3084, 2438 }, + { 3085, 2439 }, { 3086, 2440 }, { 3087, 2441 }, { 3088, 2442 }, { 3089, 2443 }, { 3090, 2444 }, { 3091, 2445 }, + { 3092, 2446 }, { 3093, 2447 }, { 3094, 2448 }, { 3095, 2449 }, { 3096, 2450 }, { 3097, 2451 }, { 3098, 2452 }, + { 3099, 2453 }, { 3100, 2454 }, { 3101, 2455 }, { 3102, 2456 }, { 3103, 2457 }, { 3104, 2458 }, { 3105, 2459 }, + { 3106, 2460 }, { 3107, 2461 }, { 3108, 2462 }, { 3109, 2463 }, { 3110, 2464 }, { 3111, 2465 }, { 3112, 2466 }, + { 3113, 2467 }, { 3114, 2468 }, { 3115, 2469 }, { 3171, 2470 }, { 3172, 2471 }, { 3173, 2472 }, { 3174, 2473 }, + { 3175, 2474 }, { 3176, 2475 }, { 3177, 2476 }, { 3178, 2477 }, { 3179, 2478 }, { 3180, 2479 }, { 3181, 2480 }, + { 3182, 2481 }, { 3183, 2482 }, { 3184, 2483 }, { 3185, 2484 }, { 3186, 2485 }, { 3187, 2486 }, { 3188, 2487 }, + { 3189, 2488 }, { 3190, 2489 }, { 3191, 2490 }, { 3192, 2491 }, { 3193, 2492 }, { 3194, 2493 }, { 3195, 2494 }, + { 3196, 2495 }, { 3197, 2496 }, { 3198, 2497 }, { 3199, 2498 }, { 3200, 2499 }, { 3201, 2500 }, { 3202, 2501 }, + { 3203, 2502 }, { 3204, 2503 }, { 3205, 2504 }, { 3206, 2505 }, { 3207, 2506 }, { 3208, 2507 }, { 3209, 2508 }, + { 3210, 2509 }, { 3211, 2510 }, { 3212, 2511 }, { 3213, 2512 }, { 3214, 2513 }, { 3215, 2514 }, { 3216, 2515 }, + { 3217, 2516 }, { 3218, 2517 }, { 3219, 2518 }, { 3220, 2519 }, { 3221, 2520 }, { 3222, 2521 }, { 3223, 2522 }, + { 3224, 2523 }, { 3271, 2524 }, { 3272, 2525 }, { 3273, 2526 }, { 3274, 2527 }, { 3275, 2528 }, { 3276, 2529 }, + { 3277, 2530 }, { 3278, 2531 }, { 3279, 2532 }, { 3280, 2533 }, { 3281, 2534 }, { 3282, 2535 }, { 3283, 2536 }, + { 3284, 2537 }, { 3285, 2538 }, { 3286, 2539 }, { 3287, 2540 }, { 3288, 2541 }, { 3289, 2542 }, { 3290, 2543 }, + { 3291, 2544 }, { 3292, 2545 }, { 3293, 2546 }, { 3294, 2547 }, { 3295, 2548 }, { 3296, 2549 }, { 3297, 2550 }, + { 3298, 2551 }, { 3299, 2552 }, { 3300, 2553 }, { 3301, 2554 }, { 3302, 2555 }, { 3303, 2556 }, { 3304, 2557 }, + { 3371, 2558 }, { 3372, 2559 }, { 3373, 2560 }, { 3374, 2561 }, { 3375, 2562 }, { 3376, 2563 }, { 3377, 2564 }, + { 3378, 2565 }, { 3379, 2566 }, { 3380, 2567 }, { 3381, 2568 }, { 3382, 2569 }, { 3383, 2570 }, { 3384, 2571 }, + { 3385, 2572 }, { 3471, 2573 }, { 3472, 2574 }, { 3473, 2575 }, { 3474, 2576 }, { 3475, 2577 }, { 3476, 2578 }, + { 3477, 2579 }, { 3478, 2580 }, { 3479, 2581 }, { 3480, 2582 }, { 3481, 2583 }, { 3482, 2584 }, { 3483, 2585 }, + { 3484, 2586 }, { 3485, 2587 }, { 3486, 2588 }, { 3487, 2589 }, { 3488, 2590 }, { 3489, 2591 }, { 3490, 2592 }, + { 3491, 2593 }, { 3492, 2594 }, { 3493, 2595 }, { 3494, 2596 }, { 3495, 2597 }, { 3496, 2598 }, { 3497, 2599 }, + { 3498, 2600 }, { 3499, 2601 }, { 3500, 2602 }, { 3501, 2603 }, { 3502, 2604 }, { 3503, 2605 }, { 3504, 2606 }, + { 3505, 2607 }, { 3506, 2608 }, { 3507, 2609 }, { 3508, 2610 }, { 3509, 2611 }, { 3510, 2612 }, { 3571, 2613 }, + { 3572, 2614 }, { 3573, 2615 }, { 3574, 2616 }, { 3575, 2617 }, { 3576, 2618 }, { 3577, 2619 }, { 3578, 2620 }, + { 3579, 2621 }, { 3580, 2622 }, { 3581, 2623 }, { 3582, 2624 }, { 3583, 2625 }, { 3584, 2626 }, { 3585, 2627 }, + { 3586, 2628 }, { 3587, 2629 }, { 3588, 2630 }, { 3589, 2631 }, { 3590, 2632 }, { 3591, 2633 }, { 3592, 2634 }, + { 3593, 2635 }, { 3594, 2636 }, { 3595, 2637 }, { 3596, 2638 }, { 3597, 2639 }, { 3598, 2640 }, { 3599, 2641 }, + { 3600, 2642 }, { 3601, 2643 }, { 3602, 2644 }, { 3603, 2645 }, { 3604, 2646 }, { 3605, 2647 }, { 3606, 2648 }, + { 3607, 2649 }, { 3608, 2650 }, { 3609, 2651 }, { 3610, 2652 }, { 3611, 2653 }, { 3612, 2654 }, { 3613, 2655 }, + { 3614, 2656 }, { 3615, 2657 }, { 3616, 2658 }, { 3617, 2659 }, { 3618, 2660 }, { 3619, 2661 }, { 3620, 2662 }, + { 3621, 2663 }, { 3622, 2664 }, { 3623, 2665 }, { 3624, 2666 }, { 3625, 2667 }, { 3626, 2668 }, { 3627, 2669 }, + { 3628, 2670 }, { 3629, 2671 }, { 3630, 2672 }, { 3631, 2673 }, { 3632, 2674 }, { 3633, 2675 }, { 3634, 2676 }, + { 3635, 2677 }, { 3636, 2678 }, { 3637, 2679 }, { 3638, 2680 }, { 3639, 2681 }, { 3640, 2682 }, { 3641, 2683 }, + { 3642, 2684 }, { 3643, 2685 }, { 3644, 2686 }, { 3645, 2687 }, { 3646, 2688 }, { 3671, 2689 }, { 3672, 2690 }, + { 3673, 2691 }, { 3674, 2692 }, { 3675, 2693 }, { 3676, 2694 }, { 3677, 2695 }, { 3678, 2696 }, { 3679, 2697 }, + { 3680, 2698 }, { 3681, 2699 }, { 3682, 2700 }, { 3683, 2701 }, { 3684, 2702 }, { 3685, 2703 }, { 3686, 2704 }, + { 3687, 2705 }, { 3688, 2706 }, { 3689, 2707 }, { 3690, 2708 }, { 3691, 2709 }, { 3692, 2710 }, { 3693, 2711 }, + { 3694, 2712 }, { 3695, 2713 }, { 3696, 2714 }, { 3697, 2715 }, { 3698, 2716 }, { 3699, 2717 }, { 3700, 2718 }, + { 3701, 2719 }, { 3702, 2720 }, { 3703, 2721 }, { 3704, 2722 }, { 3705, 2723 }, { 3706, 2724 }, { 3707, 2725 }, + { 3708, 2726 }, { 3709, 2727 }, { 3710, 2728 }, { 3711, 2729 }, { 3712, 2730 }, { 3713, 2731 }, { 3714, 2732 }, + { 3715, 2733 }, { 3716, 2734 }, { 3717, 2735 }, { 3718, 2736 }, { 3719, 2737 }, { 3720, 2738 }, { 3721, 2739 }, + { 3722, 2740 }, { 3723, 2741 }, { 3724, 2742 }, { 3725, 2743 }, { 3726, 2744 }, { 3727, 2745 }, { 3728, 2746 }, + { 3729, 2747 }, { 3730, 2748 }, { 3927, 2749 }, { 3928, 2750 }, { 3929, 2751 }, { 3930, 2752 }, { 3931, 2753 }, + { 3932, 2754 }, { 3933, 2755 }, { 3934, 2756 }, { 3940, 2762 }, { 3941, 2763 }, { 3942, 2764 }, { 3943, 2765 }, + { 3944, 2766 }, { 3945, 2767 }, { 3946, 2768 }, { 3947, 2769 }, { 3948, 2770 }, { 3949, 2771 }, { 3950, 2772 }, + { 3951, 2773 }, { 3952, 2774 }, { 3953, 2775 }, { 3954, 2776 }, { 3955, 2777 }, { 3956, 2778 }, { 3957, 2779 }, + { 3958, 2780 }, { 3959, 2781 }, { 3960, 2782 }, { 3961, 2783 }, { 3962, 2784 }, { 3963, 2785 }, { 3964, 2786 }, + { 3965, 2787 }, { 3966, 2788 }, { 3967, 2789 }, { 3968, 2790 }, { 3969, 2791 }, { 3970, 2792 }, { 3971, 2793 }, + { 3972, 2794 }, { 3973, 2795 }, { 3974, 2796 }, { 3975, 2797 }, { 3976, 2798 }, { 3977, 2799 }, { 3978, 2800 }, + { 3979, 2801 }, { 3980, 2802 }, { 3981, 2803 }, { 3982, 2804 }, { 3983, 2805 }, { 3984, 2806 }, { 3985, 2807 }, + { 3986, 2808 }, { 3987, 2809 }, { 3988, 2810 }, { 3989, 2811 }, { 3990, 2812 }, { 3991, 2813 }, { 3992, 2814 }, + { 3993, 2815 }, { 3994, 2816 }, { 3995, 2817 }, { 3996, 2818 }, { 3997, 2819 }, { 3998, 2820 }, { 3999, 2821 }, + { 4000, 2822 }, { 4001, 2823 }, { 4002, 2824 }, { 4003, 2825 }, { 4004, 2826 }, { 4005, 2827 }, { 4006, 2828 }, + { 4007, 2829 }, { 4008, 2830 }, { 4009, 2831 }, { 4010, 2832 }, { 4011, 2833 }, { 4012, 2834 }, { 4013, 2835 }, + { 4014, 2836 }, { 4015, 2837 }, { 4016, 2838 }, { 4017, 2839 }, { 4018, 2840 }, { 4019, 2841 }, { 4020, 2842 }, + { 4021, 2843 }, { 4022, 2844 }, { 4023, 2845 }, { 4024, 2846 }, { 4025, 2847 }, { 4026, 2848 }, { 4027, 2849 }, + { 4028, 2850 }, { 4029, 2851 }, { 4030, 2852 }, { 4031, 2853 }, { 4032, 2854 }, { 4127, 2855 }, { 4128, 2856 }, + { 4129, 2857 }, { 4130, 2858 }, { 4131, 2859 }, { 4132, 2860 }, { 4133, 2861 }, { 4134, 2862 }, { 4135, 2863 }, + { 4136, 2864 }, { 4137, 2865 }, { 4138, 2866 }, { 4139, 2867 }, { 4140, 2868 }, { 4145, 2873 }, { 4146, 2874 }, + { 4147, 2875 }, { 4148, 2876 }, { 4149, 2877 }, { 4150, 2878 }, { 4151, 2879 }, { 4152, 2880 }, { 4153, 2881 }, + { 4154, 2882 }, { 4155, 2883 }, { 4156, 2884 }, { 4157, 2885 }, { 4158, 2886 }, { 4159, 2887 }, { 4160, 2888 }, + { 4227, 2889 }, { 4228, 2890 }, { 4229, 2891 }, { 4230, 2892 }, { 4231, 2893 }, { 4232, 2894 }, { 4233, 2895 }, + { 4234, 2896 }, { 4235, 2897 }, { 4236, 2898 }, { 4237, 2899 }, { 4238, 2900 }, { 4239, 2901 }, { 4240, 2902 }, + { 4241, 2903 }, { 4242, 2904 }, { 4243, 2905 }, { 4244, 2906 }, { 4245, 2907 }, { 4246, 2908 }, { 4247, 2909 }, + { 4248, 2910 }, { 4249, 2911 }, { 4250, 2912 }, { 4251, 2913 }, { 4252, 2914 }, { 4253, 2915 }, { 4254, 2916 }, + { 4255, 2917 }, { 4256, 2918 }, { 4257, 2919 }, { 4258, 2920 }, { 4327, 2921 }, { 4328, 2922 }, { 4329, 2923 }, + { 4330, 2924 }, { 4331, 2925 }, { 4332, 2926 }, { 4333, 2927 }, { 4334, 2928 }, { 4335, 2929 }, { 4336, 2930 }, + { 4337, 2931 }, { 4338, 2932 }, { 4339, 2933 }, { 4340, 2934 }, { 4341, 2935 }, { 4342, 2936 }, { 4343, 2937 }, + { 4344, 2938 }, { 4345, 2939 }, { 4346, 2940 }, { 4347, 2941 }, { 4348, 2942 }, { 4349, 2943 }, { 4350, 2944 }, + { 4351, 2945 }, { 4352, 2946 }, { 4353, 2947 }, { 4354, 2948 }, { 4355, 2949 }, { 4356, 2950 }, { 4357, 2951 }, + { 4358, 2952 }, { 4359, 2953 }, { 4360, 2954 }, { 4361, 2955 }, { 4362, 2956 }, { 4363, 2957 }, { 4364, 2958 }, + { 4365, 2959 }, { 4366, 2960 }, { 4367, 2961 }, { 4368, 2962 }, { 4369, 2963 }, { 4370, 2964 }, { 4371, 2965 }, + { 4372, 2966 }, { 4373, 2967 }, { 4374, 2968 }, { 4375, 2969 }, { 4376, 2970 }, { 4377, 2971 }, { 4378, 2972 }, + { 4379, 2973 }, { 4380, 2974 }, { 4381, 2975 }, { 4382, 2976 }, { 4383, 2977 }, { 4384, 2978 }, { 4385, 2979 }, + { 4386, 2980 }, { 4387, 2981 }, { 4388, 2982 }, { 4389, 2983 }, { 4390, 2984 }, { 4391, 2985 }, { 4392, 2986 }, + { 4393, 2987 }, { 4394, 2988 }, { 4395, 2989 }, { 4396, 2990 }, { 4397, 2991 }, { 4398, 2992 }, { 4399, 2993 }, + { 4400, 2994 }, { 4401, 2995 }, { 4402, 2996 }, { 4403, 2997 }, { 4404, 2998 }, { 4405, 2999 }, { 4406, 3000 }, + { 4407, 3001 }, { 4408, 3002 }, { 4409, 3003 }, { 4410, 3004 }, { 4411, 3005 }, { 4412, 3006 }, { 4413, 3007 }, + { 4414, 3008 }, { 4415, 3009 }, { 4416, 3010 }, { 4417, 3011 }, { 4418, 3012 }, { 4419, 3013 }, { 4420, 3014 }, + { 4421, 3015 }, { 4422, 3016 }, { 4423, 3017 }, { 4424, 3018 }, { 4425, 3019 }, { 4426, 3020 }, { 4427, 3021 }, + { 4428, 3022 }, { 4429, 3023 }, { 4430, 3024 }, { 4431, 3025 }, { 4432, 3026 }, { 4433, 3027 }, { 4434, 3028 }, + { 4435, 3029 }, { 4436, 3030 }, { 4437, 3031 }, { 4438, 3032 }, { 4439, 3033 }, { 4440, 3034 }, { 4441, 3035 }, + { 4442, 3036 }, { 4443, 3037 }, { 4444, 3038 }, { 4445, 3039 }, { 4446, 3040 }, { 4447, 3041 }, { 4448, 3042 }, + { 4449, 3043 }, { 4450, 3044 }, { 4527, 3045 }, { 4528, 3046 }, { 4529, 3047 }, { 4530, 3048 }, { 4531, 3049 }, + { 4532, 3050 }, { 4533, 3051 }, { 4534, 3052 }, { 4535, 3053 }, { 4536, 3054 }, { 4537, 3055 }, { 4538, 3056 }, + { 4539, 3057 }, { 4540, 3058 }, { 4541, 3059 }, { 4542, 3060 }, { 4543, 3061 }, { 4544, 3062 }, { 4545, 3063 }, + { 4546, 3064 }, { 4547, 3066 }, { 4548, 3067 }, { 4549, 3068 }, { 4550, 3069 }, { 4551, 3070 }, { 4552, 3071 }, + { 4553, 3072 }, { 4627, 3073 }, { 4628, 3074 }, { 4629, 3075 }, { 4630, 3076 }, { 4631, 3077 }, { 4632, 3078 }, + { 4633, 3079 }, { 4634, 3080 }, { 4635, 3081 }, { 4636, 3082 }, { 4637, 3083 }, { 4638, 3084 }, { 4639, 3085 }, + { 4640, 3086 }, { 4641, 3087 }, { 4642, 3088 }, { 4643, 3089 }, { 4644, 3090 }, { 4645, 3091 }, { 4646, 3092 }, + { 4647, 3093 }, { 4648, 3094 }, { 4649, 3095 }, { 4650, 3096 }, { 4651, 3097 }, { 4652, 3098 }, { 4653, 3099 }, + { 4654, 3100 }, { 4655, 3101 }, { 4656, 3102 }, { 4657, 3103 }, { 4658, 3104 }, { 4659, 3105 }, { 4660, 3106 }, + { 4661, 3107 }, { 4662, 3108 }, { 4663, 3109 }, { 4664, 3110 }, { 4665, 3111 }, { 4666, 3112 }, { 4667, 3113 }, + { 4668, 3114 }, { 4669, 3115 }, { 4670, 3116 }, { 4671, 3117 }, { 4672, 3118 }, { 4673, 3119 }, { 4674, 3120 }, + { 4675, 3121 }, { 4676, 3122 }, { 4677, 3123 }, { 4678, 3124 }, { 4679, 3125 }, { 4680, 3126 }, { 4681, 3127 }, + { 4682, 3128 }, { 4683, 3129 }, { 4684, 3130 }, { 4685, 3131 }, { 4686, 3132 }, { 4687, 3133 }, { 4688, 3134 }, + { 4689, 3135 }, { 4690, 3136 }, { 4691, 3137 }, { 4692, 3138 }, { 4693, 3139 }, { 4694, 3140 }, { 4695, 3141 }, + { 4696, 3142 }, { 4697, 3143 }, { 4698, 3144 }, { 4699, 3145 }, { 4700, 3146 }, { 4701, 3147 }, { 4702, 3148 }, + { 4703, 3149 }, { 4704, 3150 }, { 4705, 3151 }, { 4706, 3152 }, { 4707, 3153 }, { 4708, 3154 }, { 4709, 3155 }, + { 4710, 3156 }, { 4711, 3157 }, { 4712, 3158 }, { 4713, 3159 }, { 4714, 3160 }, { 4715, 3161 }, { 4716, 3162 }, + { 4717, 3163 }, { 4718, 3164 }, { 4719, 3165 }, { 4720, 3166 }, { 4721, 3167 }, { 4722, 3168 }, { 4723, 3169 }, + { 4724, 3170 }, { 4725, 3171 }, { 4726, 3172 }, { 4827, 3173 }, { 4828, 3174 }, { 4829, 3175 }, { 4830, 3176 }, + { 4831, 3177 }, { 4832, 3178 }, { 4833, 3179 }, { 4834, 3180 }, { 4835, 3181 }, { 4836, 3182 }, { 4837, 3183 }, + { 4838, 3184 }, { 4839, 3185 }, { 4840, 3186 }, { 4841, 3187 }, { 4842, 3188 }, { 4843, 3189 }, { 4844, 3190 }, + { 4845, 3191 }, { 5027, 3192 }, { 5028, 3193 }, { 5029, 3194 }, { 5030, 3195 }, { 5031, 3196 }, { 5032, 3197 }, + { 5033, 3198 }, { 5034, 3199 }, { 5035, 3200 }, { 5036, 3201 }, { 5037, 3202 }, { 5038, 3203 }, { 5039, 3204 }, + { 5040, 3205 }, { 5041, 3206 }, { 5042, 3207 }, { 5043, 3208 }, { 5044, 3209 }, { 5045, 3210 }, { 5046, 3211 }, + { 5047, 3212 }, { 5048, 3213 }, { 5049, 3214 }, { 5050, 3215 }, { 5051, 3216 }, { 5052, 3217 }, { 5053, 3218 }, + { 5054, 3219 }, { 5055, 3220 }, { 5056, 3221 }, { 5057, 3222 }, { 5058, 3223 }, { 5059, 3224 }, { 5060, 3225 }, + { 5061, 3226 }, { 5062, 3227 }, { 5063, 3228 }, { 5064, 3229 }, { 5065, 3230 }, { 5066, 3231 }, { 5067, 3232 }, + { 5068, 3233 }, { 5069, 3234 }, { 5070, 3235 }, { 5071, 3236 }, { 5072, 3237 }, { 5073, 3238 }, { 5074, 3239 }, + { 5075, 3240 }, { 5076, 3241 }, { 5077, 3242 }, { 5127, 3243 }, { 5128, 3244 }, { 5129, 3245 }, { 5130, 3246 }, + { 5131, 3247 }, { 5132, 3248 }, { 5133, 3249 }, { 5134, 3250 }, { 5135, 3251 }, { 5136, 3252 }, { 5137, 3253 }, + { 5138, 3254 }, { 5139, 3255 }, { 5140, 3256 }, { 5141, 3257 }, { 5142, 3258 }, { 5143, 3259 }, { 5144, 3260 }, + { 5145, 3261 }, { 5146, 3262 }, { 5147, 3263 }, { 5148, 3264 }, { 5149, 3265 }, { 5150, 3266 }, { 5151, 3267 }, + { 5152, 3268 }, { 5153, 3269 }, { 5154, 3270 }, { 5155, 3271 }, { 5156, 3272 }, { 5227, 3273 }, { 5228, 3274 }, + { 5229, 3275 }, { 5230, 3276 }, { 5231, 3277 }, { 5232, 3278 }, { 5233, 3279 }, { 5234, 3280 }, { 5235, 3281 }, + { 5236, 3282 }, { 5237, 3283 }, { 5238, 3284 }, { 5240, 3286 }, { 5241, 3287 }, { 5242, 3288 }, { 5243, 3289 }, + { 5244, 3290 }, { 5245, 3291 }, { 5246, 3292 }, { 5247, 3293 }, { 5248, 3294 }, { 5249, 3295 }, { 5250, 3296 }, + { 5251, 3297 }, { 5252, 3298 }, { 5253, 3299 }, { 5254, 3300 }, { 5255, 3301 }, { 5256, 3302 }, { 5257, 3303 }, + { 5258, 3304 }, { 5259, 3305 }, { 5260, 3306 }, { 5261, 3307 }, { 5262, 3308 }, { 5263, 3309 }, { 5264, 3310 }, + { 5265, 3311 }, { 5266, 3312 }, { 5267, 3313 }, { 5268, 3314 }, { 5269, 3315 }, { 5270, 3316 }, { 5271, 3317 }, + { 5272, 3318 }, { 5273, 3319 }, { 5274, 3320 }, { 5275, 3321 }, { 5276, 3322 }, { 5277, 3323 }, { 5278, 3324 }, + { 5279, 3325 }, { 5280, 3326 }, { 5281, 3327 }, { 5282, 3328 }, { 5283, 3329 }, { 5284, 3330 }, { 5285, 3331 }, + { 5286, 3332 }, { 5288, 3334 }, { 5289, 3335 }, { 5290, 3336 }, { 5291, 3337 }, { 5292, 3338 }, { 5293, 3339 }, + { 5294, 3340 }, { 5296, 3342 }, { 5297, 3343 }, { 5298, 3344 }, { 5299, 3345 }, { 5300, 3346 }, { 5301, 3347 }, + { 5302, 3348 }, { 5303, 3349 }, { 5304, 3350 }, { 5305, 3351 }, { 5306, 3352 }, { 5307, 3353 }, { 5308, 3354 }, + { 5309, 3355 }, { 5310, 3356 }, { 5311, 3357 }, { 5312, 3358 }, { 5313, 3359 }, { 5314, 3360 }, { 5315, 3361 }, + { 5316, 3362 }, { 5317, 3363 }, { 5318, 3364 }, { 5319, 3365 }, { 5320, 3366 }, { 5321, 3367 }, { 5322, 3368 }, + { 5323, 3369 }, { 5324, 3370 }, { 5325, 3371 }, { 5326, 3372 }, { 5327, 3373 }, { 5328, 3374 }, { 5329, 3375 }, + { 5330, 3376 }, { 5331, 3377 }, { 5332, 3378 }, { 5333, 3379 }, { 5336, 3382 }, { 5337, 3383 }, { 5338, 3384 }, + { 5339, 3385 }, { 5340, 3386 }, { 5341, 3387 }, { 5342, 3388 }, { 5343, 3389 }, { 5344, 3390 }, { 5345, 3391 }, + { 5346, 3392 }, { 5347, 3393 }, { 5348, 3394 }, { 5349, 3395 }, { 5350, 3396 }, { 5351, 3397 }, { 5352, 3398 }, + { 5357, 3403 }, { 5358, 3404 }, { 5359, 3405 }, { 5360, 3406 }, { 5361, 3407 }, { 5362, 3408 }, { 5363, 3409 }, + { 5364, 3410 }, { 5365, 3411 }, { 5366, 3412 }, { 5367, 3413 }, { 5368, 3414 }, { 5369, 3415 }, { 5370, 3416 }, + { 5371, 3417 }, { 5372, 3418 }, { 5373, 3419 }, { 5374, 3420 }, { 5375, 3421 }, { 5376, 3422 }, { 5377, 3423 }, + { 5378, 3424 }, { 5379, 3425 }, { 5380, 3426 }, { 5381, 3427 }, { 5382, 3428 }, { 5383, 3429 }, { 5384, 3430 }, + { 5385, 3431 }, { 5386, 3432 }, { 5387, 3433 }, { 5388, 3434 }, { 5389, 3435 }, { 5390, 3436 }, { 5391, 3437 }, + { 5392, 3438 }, { 5393, 3439 }, { 5394, 3440 }, { 5395, 3441 }, { 5396, 3442 }, { 5397, 3443 }, { 5398, 3444 }, + { 5399, 3445 }, { 5400, 3446 }, { 5401, 3447 }, { 5402, 3448 }, { 5403, 3449 }, { 5404, 3450 }, { 5405, 3451 }, + { 5406, 3452 }, { 5407, 3453 }, { 5408, 3454 }, { 5409, 3455 }, { 5410, 3456 }, { 5411, 3457 }, { 5412, 3458 }, + { 5413, 3459 }, { 5414, 3460 }, { 5415, 3461 }, { 5416, 3462 }, { 5417, 3463 }, { 5418, 3464 }, { 5419, 3465 }, + { 5420, 3466 }, { 5421, 3467 }, { 5422, 3468 }, { 5423, 3469 }, { 5424, 3470 }, { 5425, 3471 }, { 5426, 3472 }, + { 5427, 3473 }, { 5428, 3474 }, { 5429, 3475 }, { 5430, 3476 }, { 5431, 3477 }, { 5432, 3478 }, { 5433, 3479 }, + { 5434, 3480 }, { 5435, 3481 }, { 5436, 3482 }, { 5437, 3483 }, { 5438, 3484 }, { 5439, 3485 }, { 5440, 3486 }, + { 5441, 3487 }, { 5442, 3488 }, { 5443, 3489 }, { 5444, 3490 }, { 5445, 3491 }, { 5446, 3492 }, { 5447, 3493 }, + { 5448, 3494 }, { 5449, 3495 }, { 5450, 3496 }, { 5451, 3497 }, { 5452, 3498 }, { 5453, 3499 }, { 5454, 3500 }, + { 5455, 3501 }, { 5456, 3502 }, { 5457, 3503 }, { 5458, 3504 }, { 5459, 3505 }, { 5460, 3506 }, { 5461, 3507 }, + { 5462, 3508 }, { 5463, 3509 }, { 5464, 3510 }, { 5465, 3511 }, { 5466, 3512 }, { 5467, 3513 }, { 5468, 3514 }, + { 5469, 3515 }, { 5470, 3516 }, { 5471, 3517 }, { 5472, 3518 }, { 5473, 3519 }, { 5474, 3520 }, { 5475, 3521 }, + { 5476, 3522 }, { 5477, 3523 }, { 5478, 3524 }, { 5479, 3525 }, { 5480, 3526 }, { 5481, 3527 }, { 5482, 3528 }, + { 5483, 3529 }, { 5484, 3530 }, { 5485, 3531 }, { 5486, 3532 }, { 5487, 3533 }, { 5488, 3534 }, { 5489, 3535 }, + { 5490, 3536 }, { 5491, 3537 }, { 5492, 3538 }, { 5493, 3539 }, { 5494, 3540 }, { 5495, 3541 }, { 5496, 3542 }, + { 5497, 3543 }, { 5498, 3544 }, { 5499, 3545 }, { 5500, 3546 }, { 5501, 3547 }, { 5502, 3548 }, { 5503, 3549 }, + { 5504, 3550 }, { 5505, 3551 }, { 5506, 3552 }, { 5507, 3553 }, { 5508, 3554 }, { 5509, 3555 }, { 5510, 3556 }, + { 5511, 3557 }, { 5512, 3558 }, { 5513, 3559 }, { 5514, 3560 }, { 5515, 3561 }, { 5516, 3562 }, { 5517, 3563 }, + { 5518, 3564 }, { 5519, 3565 }, { 5520, 3566 }, { 5521, 3567 }, { 5522, 3568 }, { 5523, 3569 }, { 5524, 3570 }, + { 5525, 3571 }, { 5526, 3572 }, { 5527, 3573 }, { 5528, 3574 }, { 5529, 3575 }, { 5530, 3576 }, { 5531, 3577 }, + { 5532, 3578 }, { 5533, 3579 }, { 5534, 3580 }, { 5535, 3581 }, { 5536, 3582 }, { 5537, 3583 }, { 5538, 3584 }, + { 5539, 3585 }, { 5540, 3586 }, { 5541, 3587 }, { 5542, 3588 }, { 5543, 3589 }, { 5544, 3590 }, { 5545, 3591 }, + { 5546, 3592 }, { 5547, 3593 }, { 5548, 3594 }, { 5549, 3595 }, { 5550, 3596 }, { 5551, 3597 }, { 5552, 3598 }, + { 5553, 3599 }, { 5554, 3600 }, { 5555, 3601 }, { 5556, 3602 }, { 5557, 3603 }, { 5558, 3604 }, { 5559, 3605 }, + { 5560, 3606 }, { 5561, 3607 }, { 5562, 3608 }, { 5563, 3609 }, { 5564, 3610 }, { 5565, 3611 }, { 5566, 3612 }, + { 5567, 3613 }, { 5568, 3614 }, { 5569, 3615 }, { 5570, 3616 }, { 4554, 3065 }, }; -// v1.0 -> JP asset ID remap table. 1309 entries. +// v1.0 -> JP asset ID remap table. 1312 entries. static const std::unordered_map sV10toJPRemap = { { 2468, 2212 }, { 2469, 2213 }, { 2470, 2214 }, { 2471, 2215 }, { 2472, 2216 }, { 2473, 2217 }, { 2474, 2218 }, { 2475, 2219 }, { 2476, 2220 }, { 2477, 2221 }, { 2478, 2222 }, { 2481, 2225 }, { 2483, 2227 }, { 2484, 2228 }, { 2485, 2229 }, { 2487, 2231 }, { 2488, 2232 }, { 2489, 2233 }, { 2490, 2234 }, { 2491, 2235 }, { 2498, 2242 }, - { 2504, 2248 }, { 2521, 2252 }, { 2524, 2255 }, { 2526, 2257 }, { 2571, 2315 }, { 2572, 2316 }, { 2573, 2317 }, - { 2574, 2318 }, { 2575, 2319 }, { 2576, 2320 }, { 2577, 2321 }, { 2578, 2322 }, { 2579, 2323 }, { 2580, 2324 }, - { 2581, 2325 }, { 2582, 2326 }, { 2583, 2327 }, { 2584, 2328 }, { 2585, 2329 }, { 2586, 2330 }, { 2587, 2331 }, - { 2588, 2332 }, { 2589, 2333 }, { 2590, 2334 }, { 2591, 2335 }, { 2592, 2336 }, { 2593, 2337 }, { 2594, 2338 }, - { 2595, 2339 }, { 2596, 2340 }, { 2597, 2341 }, { 2598, 2342 }, { 2599, 2343 }, { 2600, 2344 }, { 2601, 2345 }, - { 2602, 2346 }, { 2671, 2347 }, { 2672, 2348 }, { 2673, 2349 }, { 2674, 2350 }, { 2675, 2351 }, { 2676, 2352 }, - { 2677, 2353 }, { 2678, 2354 }, { 2679, 2355 }, { 2680, 2356 }, { 2681, 2357 }, { 2682, 2358 }, { 2683, 2359 }, - { 2684, 2360 }, { 2685, 2361 }, { 2686, 2362 }, { 2687, 2363 }, { 2688, 2364 }, { 2689, 2365 }, { 2690, 2366 }, - { 2691, 2367 }, { 2692, 2368 }, { 2693, 2369 }, { 2694, 2370 }, { 2695, 2371 }, { 2696, 2372 }, { 2771, 2373 }, - { 2772, 2374 }, { 2773, 2375 }, { 2774, 2376 }, { 2775, 2377 }, { 2776, 2378 }, { 2777, 2379 }, { 2778, 2380 }, - { 2779, 2381 }, { 2780, 2382 }, { 2781, 2383 }, { 2782, 2384 }, { 2783, 2385 }, { 2784, 2386 }, { 2785, 2387 }, - { 2786, 2388 }, { 2871, 2389 }, { 2872, 2390 }, { 2873, 2391 }, { 2874, 2392 }, { 2875, 2393 }, { 2876, 2394 }, - { 2877, 2395 }, { 2878, 2396 }, { 2879, 2397 }, { 2880, 2398 }, { 2881, 2399 }, { 2882, 2400 }, { 2883, 2401 }, - { 2884, 2402 }, { 2885, 2403 }, { 2886, 2404 }, { 2887, 2405 }, { 2888, 2406 }, { 2889, 2407 }, { 2890, 2408 }, - { 2891, 2409 }, { 2892, 2410 }, { 2893, 2411 }, { 2894, 2412 }, { 2895, 2413 }, { 2896, 2414 }, { 2897, 2415 }, - { 2971, 2416 }, { 2972, 2417 }, { 2973, 2418 }, { 2974, 2419 }, { 2975, 2420 }, { 2976, 2421 }, { 2977, 2422 }, - { 2978, 2423 }, { 2979, 2424 }, { 3071, 2425 }, { 3072, 2426 }, { 3073, 2427 }, { 3074, 2428 }, { 3075, 2429 }, - { 3076, 2430 }, { 3077, 2431 }, { 3078, 2432 }, { 3079, 2433 }, { 3080, 2434 }, { 3081, 2435 }, { 3082, 2436 }, - { 3083, 2437 }, { 3084, 2438 }, { 3085, 2439 }, { 3086, 2440 }, { 3087, 2441 }, { 3088, 2442 }, { 3089, 2443 }, - { 3090, 2444 }, { 3091, 2445 }, { 3092, 2446 }, { 3093, 2447 }, { 3094, 2448 }, { 3095, 2449 }, { 3096, 2450 }, - { 3097, 2451 }, { 3098, 2452 }, { 3099, 2453 }, { 3100, 2454 }, { 3101, 2455 }, { 3102, 2456 }, { 3103, 2457 }, - { 3104, 2463 }, { 3105, 2464 }, { 3106, 2466 }, { 3107, 2467 }, { 3108, 2468 }, { 3109, 2469 }, { 3110, 2470 }, - { 3111, 2471 }, { 3112, 2472 }, { 3113, 2473 }, { 3114, 2474 }, { 3115, 2475 }, { 3171, 2476 }, { 3172, 2477 }, - { 3173, 2478 }, { 3174, 2479 }, { 3175, 2480 }, { 3176, 2481 }, { 3177, 2482 }, { 3178, 2483 }, { 3179, 2484 }, - { 3180, 2485 }, { 3181, 2486 }, { 3182, 2487 }, { 3183, 2488 }, { 3184, 2489 }, { 3185, 2490 }, { 3186, 2491 }, - { 3187, 2492 }, { 3188, 2493 }, { 3189, 2494 }, { 3190, 2495 }, { 3191, 2496 }, { 3192, 2497 }, { 3193, 2498 }, - { 3194, 2499 }, { 3195, 2500 }, { 3196, 2501 }, { 3197, 2502 }, { 3198, 2503 }, { 3199, 2504 }, { 3200, 2505 }, - { 3201, 2506 }, { 3202, 2507 }, { 3203, 2508 }, { 3204, 2509 }, { 3205, 2510 }, { 3206, 2511 }, { 3207, 2512 }, - { 3208, 2513 }, { 3209, 2514 }, { 3210, 2515 }, { 3211, 2516 }, { 3212, 2517 }, { 3213, 2518 }, { 3214, 2519 }, - { 3215, 2520 }, { 3216, 2521 }, { 3217, 2522 }, { 3218, 2523 }, { 3219, 2524 }, { 3220, 2525 }, { 3221, 2526 }, - { 3222, 2527 }, { 3223, 2528 }, { 3224, 2529 }, { 3271, 2530 }, { 3272, 2531 }, { 3273, 2532 }, { 3274, 2533 }, - { 3275, 2534 }, { 3276, 2535 }, { 3277, 2536 }, { 3278, 2537 }, { 3279, 2538 }, { 3280, 2539 }, { 3281, 2540 }, - { 3282, 2541 }, { 3283, 2542 }, { 3284, 2543 }, { 3285, 2544 }, { 3286, 2545 }, { 3287, 2546 }, { 3288, 2547 }, - { 3289, 2548 }, { 3290, 2549 }, { 3291, 2550 }, { 3292, 2551 }, { 3293, 2552 }, { 3294, 2553 }, { 3295, 2554 }, - { 3296, 2555 }, { 3297, 2556 }, { 3298, 2557 }, { 3299, 2558 }, { 3300, 2559 }, { 3301, 2560 }, { 3302, 2561 }, - { 3303, 2562 }, { 3304, 2563 }, { 3371, 2564 }, { 3372, 2565 }, { 3373, 2566 }, { 3374, 2567 }, { 3375, 2568 }, - { 3376, 2569 }, { 3377, 2570 }, { 3378, 2571 }, { 3379, 2572 }, { 3380, 2573 }, { 3381, 2574 }, { 3382, 2575 }, - { 3383, 2576 }, { 3384, 2577 }, { 3385, 2578 }, { 3471, 2579 }, { 3472, 2580 }, { 3473, 2581 }, { 3474, 2582 }, - { 3475, 2583 }, { 3476, 2584 }, { 3477, 2585 }, { 3478, 2586 }, { 3479, 2587 }, { 3480, 2588 }, { 3481, 2589 }, - { 3482, 2590 }, { 3483, 2591 }, { 3484, 2592 }, { 3485, 2593 }, { 3486, 2594 }, { 3487, 2595 }, { 3488, 2596 }, - { 3489, 2597 }, { 3490, 2598 }, { 3491, 2599 }, { 3492, 2600 }, { 3493, 2601 }, { 3494, 2602 }, { 3495, 2603 }, - { 3496, 2604 }, { 3497, 2605 }, { 3498, 2606 }, { 3499, 2607 }, { 3500, 2608 }, { 3501, 2609 }, { 3502, 2610 }, - { 3503, 2611 }, { 3504, 2612 }, { 3505, 2613 }, { 3506, 2614 }, { 3507, 2615 }, { 3508, 2616 }, { 3509, 2617 }, - { 3510, 2618 }, { 3571, 2619 }, { 3572, 2620 }, { 3573, 2621 }, { 3574, 2622 }, { 3575, 2623 }, { 3576, 2624 }, - { 3577, 2625 }, { 3578, 2626 }, { 3579, 2627 }, { 3580, 2628 }, { 3581, 2629 }, { 3582, 2630 }, { 3583, 2631 }, - { 3584, 2632 }, { 3585, 2633 }, { 3586, 2634 }, { 3587, 2635 }, { 3588, 2636 }, { 3589, 2637 }, { 3590, 2638 }, - { 3591, 2639 }, { 3592, 2640 }, { 3593, 2641 }, { 3594, 2642 }, { 3595, 2643 }, { 3596, 2644 }, { 3597, 2645 }, - { 3598, 2646 }, { 3599, 2647 }, { 3600, 2648 }, { 3601, 2649 }, { 3602, 2650 }, { 3603, 2651 }, { 3604, 2652 }, - { 3605, 2653 }, { 3606, 2654 }, { 3607, 2655 }, { 3608, 2656 }, { 3609, 2657 }, { 3610, 2658 }, { 3611, 2659 }, - { 3612, 2660 }, { 3613, 2661 }, { 3614, 2662 }, { 3615, 2663 }, { 3616, 2664 }, { 3617, 2665 }, { 3618, 2666 }, - { 3619, 2667 }, { 3620, 2668 }, { 3621, 2669 }, { 3622, 2670 }, { 3623, 2671 }, { 3624, 2672 }, { 3625, 2673 }, - { 3626, 2674 }, { 3627, 2675 }, { 3628, 2676 }, { 3629, 2677 }, { 3630, 2678 }, { 3631, 2679 }, { 3632, 2680 }, - { 3633, 2681 }, { 3634, 2682 }, { 3635, 2683 }, { 3636, 2684 }, { 3637, 2685 }, { 3638, 2686 }, { 3639, 2687 }, - { 3640, 2688 }, { 3641, 2689 }, { 3642, 2690 }, { 3643, 2691 }, { 3644, 2692 }, { 3645, 2693 }, { 3646, 2694 }, - { 3671, 2696 }, { 3672, 2697 }, { 3673, 2698 }, { 3674, 2699 }, { 3675, 2700 }, { 3676, 2701 }, { 3677, 2702 }, - { 3678, 2703 }, { 3679, 2704 }, { 3680, 2705 }, { 3681, 2706 }, { 3682, 2707 }, { 3683, 2708 }, { 3684, 2709 }, - { 3685, 2710 }, { 3686, 2711 }, { 3687, 2712 }, { 3688, 2713 }, { 3689, 2714 }, { 3690, 2715 }, { 3691, 2716 }, - { 3692, 2717 }, { 3693, 2718 }, { 3694, 2719 }, { 3695, 2720 }, { 3696, 2721 }, { 3697, 2722 }, { 3698, 2723 }, - { 3699, 2724 }, { 3700, 2725 }, { 3701, 2726 }, { 3702, 2727 }, { 3703, 2728 }, { 3704, 2729 }, { 3705, 2730 }, - { 3706, 2731 }, { 3707, 2732 }, { 3708, 2733 }, { 3709, 2734 }, { 3710, 2735 }, { 3711, 2736 }, { 3712, 2737 }, - { 3713, 2738 }, { 3714, 2739 }, { 3715, 2740 }, { 3716, 2741 }, { 3717, 2742 }, { 3718, 2743 }, { 3719, 2744 }, - { 3720, 2745 }, { 3721, 2746 }, { 3722, 2747 }, { 3723, 2748 }, { 3724, 2749 }, { 3725, 2750 }, { 3726, 2751 }, - { 3727, 2752 }, { 3728, 2753 }, { 3729, 2754 }, { 3730, 2755 }, { 3927, 2756 }, { 3928, 2757 }, { 3929, 2758 }, - { 3930, 2759 }, { 3931, 2760 }, { 3932, 2761 }, { 3933, 2762 }, { 3934, 2763 }, { 3940, 2769 }, { 3941, 2770 }, - { 3942, 2771 }, { 3943, 2772 }, { 3944, 2773 }, { 3945, 2774 }, { 3946, 2775 }, { 3947, 2776 }, { 3948, 2777 }, - { 3949, 2778 }, { 3950, 2779 }, { 3951, 2780 }, { 3952, 2781 }, { 3953, 2782 }, { 3954, 2783 }, { 3955, 2784 }, - { 3956, 2785 }, { 3957, 2786 }, { 3958, 2787 }, { 3959, 2788 }, { 3960, 2789 }, { 3961, 2790 }, { 3962, 2791 }, - { 3963, 2792 }, { 3964, 2793 }, { 3965, 2794 }, { 3966, 2795 }, { 3967, 2796 }, { 3968, 2797 }, { 3969, 2798 }, - { 3970, 2799 }, { 3971, 2800 }, { 3972, 2801 }, { 3973, 2802 }, { 3974, 2803 }, { 3975, 2804 }, { 3976, 2805 }, - { 3977, 2806 }, { 3978, 2807 }, { 3979, 2808 }, { 3980, 2809 }, { 3981, 2810 }, { 3982, 2811 }, { 3983, 2812 }, - { 3984, 2813 }, { 3985, 2814 }, { 3986, 2815 }, { 3987, 2816 }, { 3988, 2817 }, { 3989, 2818 }, { 3990, 2819 }, - { 3991, 2820 }, { 3992, 2821 }, { 3993, 2822 }, { 3994, 2823 }, { 3995, 2824 }, { 3996, 2825 }, { 3997, 2826 }, - { 3998, 2827 }, { 3999, 2828 }, { 4000, 2829 }, { 4001, 2830 }, { 4002, 2831 }, { 4003, 2832 }, { 4004, 2833 }, - { 4005, 2834 }, { 4006, 2835 }, { 4007, 2836 }, { 4008, 2837 }, { 4009, 2838 }, { 4010, 2839 }, { 4011, 2840 }, - { 4012, 2841 }, { 4013, 2842 }, { 4014, 2843 }, { 4015, 2844 }, { 4016, 2845 }, { 4017, 2846 }, { 4018, 2847 }, - { 4019, 2848 }, { 4020, 2849 }, { 4021, 2850 }, { 4022, 2851 }, { 4023, 2852 }, { 4024, 2853 }, { 4025, 2854 }, - { 4026, 2855 }, { 4027, 2856 }, { 4028, 2857 }, { 4029, 2858 }, { 4030, 2859 }, { 4031, 2860 }, { 4032, 2861 }, - { 4127, 2863 }, { 4128, 2864 }, { 4129, 2865 }, { 4130, 2866 }, { 4131, 2867 }, { 4132, 2868 }, { 4133, 2869 }, - { 4134, 2870 }, { 4135, 2871 }, { 4136, 2872 }, { 4137, 2873 }, { 4138, 2874 }, { 4139, 2875 }, { 4140, 2876 }, - { 4145, 2881 }, { 4146, 2882 }, { 4147, 2883 }, { 4148, 2884 }, { 4149, 2885 }, { 4150, 2886 }, { 4151, 2887 }, - { 4152, 2888 }, { 4153, 2889 }, { 4154, 2890 }, { 4155, 2891 }, { 4156, 2892 }, { 4157, 2893 }, { 4158, 2894 }, - { 4159, 2895 }, { 4160, 2896 }, { 4227, 2897 }, { 4228, 2898 }, { 4229, 2899 }, { 4230, 2900 }, { 4231, 2901 }, - { 4232, 2902 }, { 4233, 2903 }, { 4234, 2904 }, { 4235, 2905 }, { 4236, 2906 }, { 4237, 2907 }, { 4238, 2908 }, - { 4239, 2909 }, { 4240, 2910 }, { 4241, 2911 }, { 4242, 2912 }, { 4243, 2913 }, { 4244, 2914 }, { 4245, 2915 }, - { 4246, 2916 }, { 4247, 2917 }, { 4248, 2918 }, { 4249, 2919 }, { 4250, 2920 }, { 4251, 2921 }, { 4252, 2922 }, - { 4253, 2923 }, { 4254, 2924 }, { 4255, 2925 }, { 4256, 2926 }, { 4257, 2927 }, { 4258, 2928 }, { 4327, 2929 }, - { 4328, 2930 }, { 4329, 2931 }, { 4330, 2932 }, { 4331, 2933 }, { 4332, 2934 }, { 4333, 2935 }, { 4334, 2936 }, - { 4335, 2937 }, { 4336, 2938 }, { 4337, 2939 }, { 4338, 2940 }, { 4339, 2941 }, { 4340, 2942 }, { 4341, 2943 }, - { 4342, 2944 }, { 4343, 2945 }, { 4344, 2946 }, { 4345, 2947 }, { 4346, 2948 }, { 4347, 2949 }, { 4348, 2950 }, - { 4349, 2951 }, { 4350, 2952 }, { 4351, 2953 }, { 4352, 2954 }, { 4353, 2955 }, { 4354, 2956 }, { 4355, 2957 }, - { 4356, 2958 }, { 4357, 2959 }, { 4358, 2960 }, { 4359, 2961 }, { 4360, 2962 }, { 4361, 2963 }, { 4362, 2964 }, - { 4363, 2965 }, { 4364, 2966 }, { 4365, 2967 }, { 4366, 2968 }, { 4367, 2969 }, { 4368, 2970 }, { 4369, 2971 }, - { 4370, 2972 }, { 4371, 2973 }, { 4372, 2974 }, { 4373, 2975 }, { 4374, 2976 }, { 4375, 2977 }, { 4376, 2978 }, - { 4377, 2979 }, { 4378, 2980 }, { 4379, 2981 }, { 4380, 2982 }, { 4381, 2983 }, { 4382, 2984 }, { 4383, 2985 }, - { 4384, 2986 }, { 4385, 2987 }, { 4386, 2988 }, { 4387, 2989 }, { 4388, 2990 }, { 4389, 2991 }, { 4390, 2992 }, - { 4391, 2993 }, { 4392, 2994 }, { 4393, 2995 }, { 4394, 2996 }, { 4395, 2997 }, { 4396, 2998 }, { 4397, 2999 }, - { 4398, 3000 }, { 4399, 3001 }, { 4400, 3002 }, { 4401, 3003 }, { 4402, 3004 }, { 4403, 3005 }, { 4404, 3006 }, - { 4405, 3007 }, { 4406, 3008 }, { 4407, 3009 }, { 4408, 3010 }, { 4409, 3011 }, { 4410, 3012 }, { 4411, 3013 }, - { 4412, 3014 }, { 4413, 3015 }, { 4414, 3016 }, { 4415, 3017 }, { 4416, 3018 }, { 4417, 3019 }, { 4418, 3020 }, - { 4419, 3021 }, { 4420, 3022 }, { 4421, 3023 }, { 4422, 3024 }, { 4423, 3025 }, { 4424, 3026 }, { 4425, 3027 }, - { 4426, 3028 }, { 4427, 3029 }, { 4428, 3030 }, { 4429, 3031 }, { 4430, 3032 }, { 4431, 3033 }, { 4432, 3034 }, - { 4433, 3035 }, { 4434, 3036 }, { 4435, 3037 }, { 4436, 3038 }, { 4437, 3039 }, { 4438, 3040 }, { 4439, 3041 }, - { 4440, 3042 }, { 4441, 3043 }, { 4442, 3044 }, { 4443, 3045 }, { 4444, 3046 }, { 4445, 3047 }, { 4446, 3048 }, - { 4447, 3049 }, { 4448, 3050 }, { 4449, 3051 }, { 4450, 3052 }, { 4527, 3053 }, { 4528, 3054 }, { 4529, 3055 }, - { 4530, 3056 }, { 4531, 3057 }, { 4532, 3058 }, { 4533, 3059 }, { 4534, 3060 }, { 4535, 3061 }, { 4536, 3062 }, - { 4537, 3063 }, { 4538, 3064 }, { 4539, 3065 }, { 4540, 3066 }, { 4541, 3067 }, { 4542, 3068 }, { 4543, 3069 }, - { 4544, 3070 }, { 4545, 3071 }, { 4546, 3072 }, { 4547, 3074 }, { 4548, 3075 }, { 4549, 3076 }, { 4550, 3077 }, - { 4551, 3078 }, { 4552, 3079 }, { 4553, 3080 }, { 4554, 3073 }, { 4627, 3081 }, { 4628, 3082 }, { 4629, 3083 }, - { 4630, 3084 }, { 4631, 3085 }, { 4632, 3086 }, { 4633, 3087 }, { 4634, 3088 }, { 4635, 3089 }, { 4636, 3090 }, - { 4637, 3091 }, { 4638, 3092 }, { 4639, 3093 }, { 4640, 3094 }, { 4641, 3095 }, { 4642, 3096 }, { 4643, 3097 }, - { 4644, 3098 }, { 4645, 3099 }, { 4646, 3100 }, { 4647, 3101 }, { 4648, 3102 }, { 4649, 3103 }, { 4650, 3104 }, - { 4651, 3105 }, { 4652, 3106 }, { 4653, 3107 }, { 4654, 3108 }, { 4655, 3109 }, { 4656, 3110 }, { 4657, 3111 }, - { 4658, 3112 }, { 4659, 3113 }, { 4660, 3114 }, { 4661, 3115 }, { 4662, 3116 }, { 4663, 3117 }, { 4664, 3118 }, - { 4665, 3119 }, { 4666, 3120 }, { 4667, 3121 }, { 4668, 3122 }, { 4669, 3123 }, { 4670, 3124 }, { 4671, 3125 }, - { 4672, 3126 }, { 4673, 3127 }, { 4674, 3128 }, { 4675, 3129 }, { 4676, 3130 }, { 4677, 3131 }, { 4678, 3132 }, - { 4679, 3133 }, { 4680, 3134 }, { 4681, 3135 }, { 4682, 3136 }, { 4683, 3137 }, { 4684, 3138 }, { 4685, 3139 }, - { 4686, 3140 }, { 4687, 3141 }, { 4688, 3142 }, { 4689, 3143 }, { 4690, 3144 }, { 4691, 3145 }, { 4692, 3146 }, - { 4693, 3147 }, { 4694, 3148 }, { 4695, 3149 }, { 4696, 3150 }, { 4697, 3151 }, { 4698, 3152 }, { 4699, 3153 }, - { 4700, 3154 }, { 4701, 3155 }, { 4702, 3156 }, { 4703, 3157 }, { 4704, 3158 }, { 4705, 3159 }, { 4706, 3160 }, - { 4707, 3161 }, { 4708, 3162 }, { 4709, 3163 }, { 4710, 3164 }, { 4711, 3165 }, { 4712, 3166 }, { 4713, 3167 }, - { 4714, 3168 }, { 4715, 3169 }, { 4716, 3170 }, { 4717, 3171 }, { 4718, 3172 }, { 4719, 3173 }, { 4720, 3174 }, - { 4721, 3175 }, { 4722, 3176 }, { 4723, 3177 }, { 4724, 3178 }, { 4725, 3179 }, { 4726, 3180 }, { 4827, 3181 }, - { 4828, 3182 }, { 4829, 3183 }, { 4830, 3184 }, { 4831, 3185 }, { 4832, 3186 }, { 4833, 3187 }, { 4834, 3188 }, - { 4835, 3189 }, { 4836, 3190 }, { 4837, 3191 }, { 4838, 3192 }, { 4839, 3193 }, { 4840, 3194 }, { 4841, 3195 }, - { 4842, 3196 }, { 4843, 3197 }, { 4844, 3198 }, { 4845, 3199 }, { 5027, 3200 }, { 5028, 3201 }, { 5029, 3202 }, - { 5030, 3203 }, { 5031, 3204 }, { 5032, 3205 }, { 5033, 3206 }, { 5034, 3207 }, { 5035, 3208 }, { 5036, 3209 }, - { 5037, 3210 }, { 5038, 3211 }, { 5039, 3212 }, { 5040, 3213 }, { 5041, 3214 }, { 5042, 3215 }, { 5043, 3216 }, - { 5044, 3217 }, { 5045, 3218 }, { 5046, 3219 }, { 5047, 3220 }, { 5048, 3221 }, { 5049, 3222 }, { 5050, 3223 }, - { 5051, 3224 }, { 5052, 3225 }, { 5053, 3226 }, { 5054, 3227 }, { 5055, 3228 }, { 5056, 3229 }, { 5057, 3230 }, - { 5058, 3231 }, { 5059, 3232 }, { 5060, 3233 }, { 5061, 3234 }, { 5062, 3235 }, { 5063, 3236 }, { 5064, 3237 }, - { 5065, 3238 }, { 5066, 3239 }, { 5067, 3240 }, { 5068, 3241 }, { 5069, 3242 }, { 5070, 3243 }, { 5071, 3244 }, - { 5072, 3245 }, { 5073, 3246 }, { 5074, 3247 }, { 5075, 3248 }, { 5076, 3249 }, { 5077, 3250 }, { 5127, 3251 }, - { 5128, 3252 }, { 5129, 3253 }, { 5130, 3254 }, { 5131, 3255 }, { 5132, 3256 }, { 5133, 3257 }, { 5134, 3258 }, - { 5135, 3259 }, { 5136, 3260 }, { 5137, 3261 }, { 5138, 3262 }, { 5139, 3263 }, { 5140, 3264 }, { 5141, 3265 }, - { 5142, 3266 }, { 5143, 3267 }, { 5144, 3268 }, { 5145, 3269 }, { 5146, 3270 }, { 5147, 3271 }, { 5148, 3272 }, - { 5149, 3273 }, { 5150, 3274 }, { 5151, 3275 }, { 5152, 3276 }, { 5153, 3277 }, { 5154, 3278 }, { 5155, 3279 }, - { 5156, 3280 }, { 5227, 3281 }, { 5228, 3282 }, { 5229, 3283 }, { 5230, 3284 }, { 5231, 3285 }, { 5232, 3286 }, - { 5233, 3287 }, { 5234, 3288 }, { 5235, 3289 }, { 5236, 3290 }, { 5237, 3291 }, { 5238, 3292 }, { 5240, 3294 }, - { 5241, 3295 }, { 5242, 3296 }, { 5243, 3297 }, { 5244, 3298 }, { 5245, 3299 }, { 5246, 3300 }, { 5247, 3301 }, - { 5248, 3302 }, { 5249, 3303 }, { 5250, 3304 }, { 5251, 3305 }, { 5252, 3306 }, { 5253, 3307 }, { 5254, 3308 }, - { 5255, 3309 }, { 5256, 3310 }, { 5257, 3311 }, { 5258, 3312 }, { 5259, 3313 }, { 5260, 3314 }, { 5261, 3315 }, - { 5262, 3316 }, { 5263, 3317 }, { 5264, 3318 }, { 5265, 3319 }, { 5266, 3320 }, { 5267, 3321 }, { 5268, 3322 }, - { 5269, 3323 }, { 5270, 3324 }, { 5271, 3325 }, { 5272, 3326 }, { 5273, 3327 }, { 5274, 3328 }, { 5275, 3329 }, - { 5276, 3330 }, { 5277, 3331 }, { 5278, 3332 }, { 5279, 3333 }, { 5280, 3334 }, { 5281, 3335 }, { 5282, 3336 }, - { 5283, 3337 }, { 5284, 3338 }, { 5285, 3339 }, { 5286, 3340 }, { 5288, 3342 }, { 5289, 3343 }, { 5290, 3344 }, - { 5291, 3345 }, { 5292, 3346 }, { 5293, 3347 }, { 5294, 3348 }, { 5296, 3350 }, { 5297, 3351 }, { 5298, 3352 }, - { 5299, 3353 }, { 5300, 3354 }, { 5301, 3355 }, { 5302, 3356 }, { 5303, 3357 }, { 5304, 3358 }, { 5305, 3359 }, - { 5306, 3360 }, { 5307, 3361 }, { 5308, 3362 }, { 5309, 3363 }, { 5310, 3364 }, { 5311, 3365 }, { 5312, 3366 }, - { 5313, 3367 }, { 5314, 3368 }, { 5315, 3369 }, { 5316, 3370 }, { 5317, 3371 }, { 5318, 3372 }, { 5319, 3373 }, - { 5320, 3374 }, { 5321, 3375 }, { 5322, 3376 }, { 5323, 3377 }, { 5324, 3378 }, { 5325, 3379 }, { 5326, 3380 }, - { 5327, 3381 }, { 5328, 3382 }, { 5329, 3383 }, { 5330, 3384 }, { 5331, 3385 }, { 5332, 3386 }, { 5333, 3387 }, - { 5336, 3390 }, { 5337, 3391 }, { 5338, 3392 }, { 5339, 3393 }, { 5340, 3394 }, { 5341, 3395 }, { 5342, 3396 }, - { 5343, 3397 }, { 5344, 3398 }, { 5345, 3399 }, { 5346, 3400 }, { 5347, 3401 }, { 5348, 3402 }, { 5349, 3403 }, - { 5350, 3404 }, { 5351, 3405 }, { 5352, 3406 }, { 5357, 3411 }, { 5358, 3412 }, { 5359, 3413 }, { 5360, 3414 }, - { 5361, 3415 }, { 5362, 3416 }, { 5363, 3417 }, { 5364, 3418 }, { 5365, 3419 }, { 5366, 3420 }, { 5367, 3421 }, - { 5368, 3422 }, { 5369, 3423 }, { 5370, 3424 }, { 5371, 3425 }, { 5372, 3426 }, { 5373, 3427 }, { 5374, 3428 }, - { 5375, 3429 }, { 5376, 3430 }, { 5377, 3431 }, { 5378, 3432 }, { 5379, 3433 }, { 5380, 3434 }, { 5381, 3435 }, - { 5382, 3436 }, { 5383, 3437 }, { 5384, 3438 }, { 5385, 3439 }, { 5386, 3440 }, { 5387, 3441 }, { 5388, 3442 }, - { 5389, 3443 }, { 5390, 3444 }, { 5391, 3445 }, { 5392, 3446 }, { 5393, 3447 }, { 5394, 3448 }, { 5395, 3449 }, - { 5396, 3450 }, { 5397, 3451 }, { 5398, 3452 }, { 5399, 3453 }, { 5400, 3454 }, { 5401, 3455 }, { 5402, 3456 }, - { 5403, 3457 }, { 5404, 3458 }, { 5405, 3459 }, { 5406, 3460 }, { 5407, 3461 }, { 5408, 3462 }, { 5409, 3463 }, - { 5410, 3464 }, { 5411, 3465 }, { 5412, 3466 }, { 5413, 3467 }, { 5414, 3468 }, { 5415, 3469 }, { 5416, 3470 }, - { 5417, 3471 }, { 5418, 3472 }, { 5419, 3473 }, { 5420, 3474 }, { 5421, 3475 }, { 5422, 3476 }, { 5423, 3477 }, - { 5424, 3478 }, { 5425, 3479 }, { 5426, 3480 }, { 5427, 3481 }, { 5428, 3482 }, { 5429, 3483 }, { 5430, 3484 }, - { 5431, 3485 }, { 5432, 3486 }, { 5433, 3487 }, { 5434, 3488 }, { 5435, 3489 }, { 5436, 3490 }, { 5437, 3491 }, - { 5438, 3492 }, { 5439, 3493 }, { 5440, 3494 }, { 5441, 3495 }, { 5442, 3496 }, { 5443, 3497 }, { 5444, 3498 }, - { 5445, 3499 }, { 5446, 3500 }, { 5447, 3501 }, { 5448, 3502 }, { 5449, 3503 }, { 5450, 3504 }, { 5451, 3505 }, - { 5452, 3506 }, { 5453, 3507 }, { 5454, 3508 }, { 5455, 3509 }, { 5456, 3510 }, { 5457, 3511 }, { 5458, 3512 }, - { 5459, 3513 }, { 5460, 3514 }, { 5461, 3515 }, { 5462, 3516 }, { 5463, 3517 }, { 5464, 3518 }, { 5465, 3519 }, - { 5466, 3520 }, { 5467, 3521 }, { 5468, 3522 }, { 5469, 3523 }, { 5470, 3524 }, { 5471, 3525 }, { 5472, 3526 }, - { 5473, 3527 }, { 5474, 3528 }, { 5475, 3529 }, { 5476, 3530 }, { 5477, 3531 }, { 5478, 3532 }, { 5479, 3533 }, - { 5480, 3534 }, { 5481, 3535 }, { 5482, 3536 }, { 5483, 3537 }, { 5484, 3538 }, { 5485, 3539 }, { 5486, 3540 }, - { 5487, 3541 }, { 5488, 3542 }, { 5489, 3543 }, { 5490, 3544 }, { 5491, 3545 }, { 5492, 3546 }, { 5493, 3547 }, - { 5494, 3548 }, { 5495, 3549 }, { 5496, 3550 }, { 5497, 3551 }, { 5498, 3552 }, { 5499, 3553 }, { 5500, 3554 }, - { 5501, 3555 }, { 5502, 3556 }, { 5503, 3557 }, { 5504, 3558 }, { 5505, 3559 }, { 5506, 3560 }, { 5507, 3561 }, - { 5508, 3562 }, { 5509, 3563 }, { 5510, 3564 }, { 5511, 3565 }, { 5512, 3566 }, { 5513, 3567 }, { 5514, 3568 }, - { 5515, 3569 }, { 5516, 3570 }, { 5517, 3571 }, { 5518, 3572 }, { 5519, 3573 }, { 5520, 3574 }, { 5521, 3575 }, - { 5522, 3576 }, { 5523, 3577 }, { 5524, 3578 }, { 5525, 3579 }, { 5526, 3580 }, { 5527, 3581 }, { 5528, 3582 }, - { 5529, 3583 }, { 5530, 3584 }, { 5531, 3585 }, { 5532, 3586 }, { 5533, 3587 }, { 5534, 3588 }, { 5535, 3589 }, - { 5536, 3590 }, { 5537, 3591 }, { 5538, 3592 }, { 5539, 3593 }, { 5540, 3594 }, { 5541, 3595 }, { 5542, 3596 }, - { 5543, 3597 }, { 5544, 3598 }, { 5545, 3599 }, { 5546, 3600 }, { 5547, 3601 }, { 5548, 3602 }, { 5549, 3603 }, - { 5550, 3604 }, { 5551, 3605 }, { 5552, 3606 }, { 5553, 3607 }, { 5554, 3608 }, { 5555, 3609 }, { 5556, 3610 }, - { 5557, 3611 }, { 5558, 3612 }, { 5559, 3613 }, { 5560, 3614 }, { 5561, 3615 }, { 5562, 3616 }, { 5563, 3617 }, - { 5564, 3618 }, { 5565, 3619 }, { 5566, 3620 }, { 5567, 3621 }, { 5568, 3622 }, { 5569, 3623 }, { 5570, 3624 }, + { 2504, 2248 }, { 2508, 2252 }, { 2511, 2255 }, { 2513, 2257 }, { 2521, 2252 }, { 2524, 2255 }, { 2526, 2257 }, + { 2571, 2315 }, { 2572, 2316 }, { 2573, 2317 }, { 2574, 2318 }, { 2575, 2319 }, { 2576, 2320 }, { 2577, 2321 }, + { 2578, 2322 }, { 2579, 2323 }, { 2580, 2324 }, { 2581, 2325 }, { 2582, 2326 }, { 2583, 2327 }, { 2584, 2328 }, + { 2585, 2329 }, { 2586, 2330 }, { 2587, 2331 }, { 2588, 2332 }, { 2589, 2333 }, { 2590, 2334 }, { 2591, 2335 }, + { 2592, 2336 }, { 2593, 2337 }, { 2594, 2338 }, { 2595, 2339 }, { 2596, 2340 }, { 2597, 2341 }, { 2598, 2342 }, + { 2599, 2343 }, { 2600, 2344 }, { 2601, 2345 }, { 2602, 2346 }, { 2671, 2347 }, { 2672, 2348 }, { 2673, 2349 }, + { 2674, 2350 }, { 2675, 2351 }, { 2676, 2352 }, { 2677, 2353 }, { 2678, 2354 }, { 2679, 2355 }, { 2680, 2356 }, + { 2681, 2357 }, { 2682, 2358 }, { 2683, 2359 }, { 2684, 2360 }, { 2685, 2361 }, { 2686, 2362 }, { 2687, 2363 }, + { 2688, 2364 }, { 2689, 2365 }, { 2690, 2366 }, { 2691, 2367 }, { 2692, 2368 }, { 2693, 2369 }, { 2694, 2370 }, + { 2695, 2371 }, { 2696, 2372 }, { 2771, 2373 }, { 2772, 2374 }, { 2773, 2375 }, { 2774, 2376 }, { 2775, 2377 }, + { 2776, 2378 }, { 2777, 2379 }, { 2778, 2380 }, { 2779, 2381 }, { 2780, 2382 }, { 2781, 2383 }, { 2782, 2384 }, + { 2783, 2385 }, { 2784, 2386 }, { 2785, 2387 }, { 2786, 2388 }, { 2871, 2389 }, { 2872, 2390 }, { 2873, 2391 }, + { 2874, 2392 }, { 2875, 2393 }, { 2876, 2394 }, { 2877, 2395 }, { 2878, 2396 }, { 2879, 2397 }, { 2880, 2398 }, + { 2881, 2399 }, { 2882, 2400 }, { 2883, 2401 }, { 2884, 2402 }, { 2885, 2403 }, { 2886, 2404 }, { 2887, 2405 }, + { 2888, 2406 }, { 2889, 2407 }, { 2890, 2408 }, { 2891, 2409 }, { 2892, 2410 }, { 2893, 2411 }, { 2894, 2412 }, + { 2895, 2413 }, { 2896, 2414 }, { 2897, 2415 }, { 2971, 2416 }, { 2972, 2417 }, { 2973, 2418 }, { 2974, 2419 }, + { 2975, 2420 }, { 2976, 2421 }, { 2977, 2422 }, { 2978, 2423 }, { 2979, 2424 }, { 3071, 2425 }, { 3072, 2426 }, + { 3073, 2427 }, { 3074, 2428 }, { 3075, 2429 }, { 3076, 2430 }, { 3077, 2431 }, { 3078, 2432 }, { 3079, 2433 }, + { 3080, 2434 }, { 3081, 2435 }, { 3082, 2436 }, { 3083, 2437 }, { 3084, 2438 }, { 3085, 2439 }, { 3086, 2440 }, + { 3087, 2441 }, { 3088, 2442 }, { 3089, 2443 }, { 3090, 2444 }, { 3091, 2445 }, { 3092, 2446 }, { 3093, 2447 }, + { 3094, 2448 }, { 3095, 2449 }, { 3096, 2450 }, { 3097, 2451 }, { 3098, 2452 }, { 3099, 2453 }, { 3100, 2454 }, + { 3101, 2455 }, { 3102, 2456 }, { 3103, 2457 }, { 3104, 2463 }, { 3105, 2464 }, { 3106, 2466 }, { 3107, 2467 }, + { 3108, 2468 }, { 3109, 2469 }, { 3110, 2470 }, { 3111, 2471 }, { 3112, 2472 }, { 3113, 2473 }, { 3114, 2474 }, + { 3115, 2475 }, { 3171, 2476 }, { 3172, 2477 }, { 3173, 2478 }, { 3174, 2479 }, { 3175, 2480 }, { 3176, 2481 }, + { 3177, 2482 }, { 3178, 2483 }, { 3179, 2484 }, { 3180, 2485 }, { 3181, 2486 }, { 3182, 2487 }, { 3183, 2488 }, + { 3184, 2489 }, { 3185, 2490 }, { 3186, 2491 }, { 3187, 2492 }, { 3188, 2493 }, { 3189, 2494 }, { 3190, 2495 }, + { 3191, 2496 }, { 3192, 2497 }, { 3193, 2498 }, { 3194, 2499 }, { 3195, 2500 }, { 3196, 2501 }, { 3197, 2502 }, + { 3198, 2503 }, { 3199, 2504 }, { 3200, 2505 }, { 3201, 2506 }, { 3202, 2507 }, { 3203, 2508 }, { 3204, 2509 }, + { 3205, 2510 }, { 3206, 2511 }, { 3207, 2512 }, { 3208, 2513 }, { 3209, 2514 }, { 3210, 2515 }, { 3211, 2516 }, + { 3212, 2517 }, { 3213, 2518 }, { 3214, 2519 }, { 3215, 2520 }, { 3216, 2521 }, { 3217, 2522 }, { 3218, 2523 }, + { 3219, 2524 }, { 3220, 2525 }, { 3221, 2526 }, { 3222, 2527 }, { 3223, 2528 }, { 3224, 2529 }, { 3271, 2530 }, + { 3272, 2531 }, { 3273, 2532 }, { 3274, 2533 }, { 3275, 2534 }, { 3276, 2535 }, { 3277, 2536 }, { 3278, 2537 }, + { 3279, 2538 }, { 3280, 2539 }, { 3281, 2540 }, { 3282, 2541 }, { 3283, 2542 }, { 3284, 2543 }, { 3285, 2544 }, + { 3286, 2545 }, { 3287, 2546 }, { 3288, 2547 }, { 3289, 2548 }, { 3290, 2549 }, { 3291, 2550 }, { 3292, 2551 }, + { 3293, 2552 }, { 3294, 2553 }, { 3295, 2554 }, { 3296, 2555 }, { 3297, 2556 }, { 3298, 2557 }, { 3299, 2558 }, + { 3300, 2559 }, { 3301, 2560 }, { 3302, 2561 }, { 3303, 2562 }, { 3304, 2563 }, { 3371, 2564 }, { 3372, 2565 }, + { 3373, 2566 }, { 3374, 2567 }, { 3375, 2568 }, { 3376, 2569 }, { 3377, 2570 }, { 3378, 2571 }, { 3379, 2572 }, + { 3380, 2573 }, { 3381, 2574 }, { 3382, 2575 }, { 3383, 2576 }, { 3384, 2577 }, { 3385, 2578 }, { 3471, 2579 }, + { 3472, 2580 }, { 3473, 2581 }, { 3474, 2582 }, { 3475, 2583 }, { 3476, 2584 }, { 3477, 2585 }, { 3478, 2586 }, + { 3479, 2587 }, { 3480, 2588 }, { 3481, 2589 }, { 3482, 2590 }, { 3483, 2591 }, { 3484, 2592 }, { 3485, 2593 }, + { 3486, 2594 }, { 3487, 2595 }, { 3488, 2596 }, { 3489, 2597 }, { 3490, 2598 }, { 3491, 2599 }, { 3492, 2600 }, + { 3493, 2601 }, { 3494, 2602 }, { 3495, 2603 }, { 3496, 2604 }, { 3497, 2605 }, { 3498, 2606 }, { 3499, 2607 }, + { 3500, 2608 }, { 3501, 2609 }, { 3502, 2610 }, { 3503, 2611 }, { 3504, 2612 }, { 3505, 2613 }, { 3506, 2614 }, + { 3507, 2615 }, { 3508, 2616 }, { 3509, 2617 }, { 3510, 2618 }, { 3571, 2619 }, { 3572, 2620 }, { 3573, 2621 }, + { 3574, 2622 }, { 3575, 2623 }, { 3576, 2624 }, { 3577, 2625 }, { 3578, 2626 }, { 3579, 2627 }, { 3580, 2628 }, + { 3581, 2629 }, { 3582, 2630 }, { 3583, 2631 }, { 3584, 2632 }, { 3585, 2633 }, { 3586, 2634 }, { 3587, 2635 }, + { 3588, 2636 }, { 3589, 2637 }, { 3590, 2638 }, { 3591, 2639 }, { 3592, 2640 }, { 3593, 2641 }, { 3594, 2642 }, + { 3595, 2643 }, { 3596, 2644 }, { 3597, 2645 }, { 3598, 2646 }, { 3599, 2647 }, { 3600, 2648 }, { 3601, 2649 }, + { 3602, 2650 }, { 3603, 2651 }, { 3604, 2652 }, { 3605, 2653 }, { 3606, 2654 }, { 3607, 2655 }, { 3608, 2656 }, + { 3609, 2657 }, { 3610, 2658 }, { 3611, 2659 }, { 3612, 2660 }, { 3613, 2661 }, { 3614, 2662 }, { 3615, 2663 }, + { 3616, 2664 }, { 3617, 2665 }, { 3618, 2666 }, { 3619, 2667 }, { 3620, 2668 }, { 3621, 2669 }, { 3622, 2670 }, + { 3623, 2671 }, { 3624, 2672 }, { 3625, 2673 }, { 3626, 2674 }, { 3627, 2675 }, { 3628, 2676 }, { 3629, 2677 }, + { 3630, 2678 }, { 3631, 2679 }, { 3632, 2680 }, { 3633, 2681 }, { 3634, 2682 }, { 3635, 2683 }, { 3636, 2684 }, + { 3637, 2685 }, { 3638, 2686 }, { 3639, 2687 }, { 3640, 2688 }, { 3641, 2689 }, { 3642, 2690 }, { 3643, 2691 }, + { 3644, 2692 }, { 3645, 2693 }, { 3646, 2694 }, { 3671, 2696 }, { 3672, 2697 }, { 3673, 2698 }, { 3674, 2699 }, + { 3675, 2700 }, { 3676, 2701 }, { 3677, 2702 }, { 3678, 2703 }, { 3679, 2704 }, { 3680, 2705 }, { 3681, 2706 }, + { 3682, 2707 }, { 3683, 2708 }, { 3684, 2709 }, { 3685, 2710 }, { 3686, 2711 }, { 3687, 2712 }, { 3688, 2713 }, + { 3689, 2714 }, { 3690, 2715 }, { 3691, 2716 }, { 3692, 2717 }, { 3693, 2718 }, { 3694, 2719 }, { 3695, 2720 }, + { 3696, 2721 }, { 3697, 2722 }, { 3698, 2723 }, { 3699, 2724 }, { 3700, 2725 }, { 3701, 2726 }, { 3702, 2727 }, + { 3703, 2728 }, { 3704, 2729 }, { 3705, 2730 }, { 3706, 2731 }, { 3707, 2732 }, { 3708, 2733 }, { 3709, 2734 }, + { 3710, 2735 }, { 3711, 2736 }, { 3712, 2737 }, { 3713, 2738 }, { 3714, 2739 }, { 3715, 2740 }, { 3716, 2741 }, + { 3717, 2742 }, { 3718, 2743 }, { 3719, 2744 }, { 3720, 2745 }, { 3721, 2746 }, { 3722, 2747 }, { 3723, 2748 }, + { 3724, 2749 }, { 3725, 2750 }, { 3726, 2751 }, { 3727, 2752 }, { 3728, 2753 }, { 3729, 2754 }, { 3730, 2755 }, + { 3927, 2756 }, { 3928, 2757 }, { 3929, 2758 }, { 3930, 2759 }, { 3931, 2760 }, { 3932, 2761 }, { 3933, 2762 }, + { 3934, 2763 }, { 3940, 2769 }, { 3941, 2770 }, { 3942, 2771 }, { 3943, 2772 }, { 3944, 2773 }, { 3945, 2774 }, + { 3946, 2775 }, { 3947, 2776 }, { 3948, 2777 }, { 3949, 2778 }, { 3950, 2779 }, { 3951, 2780 }, { 3952, 2781 }, + { 3953, 2782 }, { 3954, 2783 }, { 3955, 2784 }, { 3956, 2785 }, { 3957, 2786 }, { 3958, 2787 }, { 3959, 2788 }, + { 3960, 2789 }, { 3961, 2790 }, { 3962, 2791 }, { 3963, 2792 }, { 3964, 2793 }, { 3965, 2794 }, { 3966, 2795 }, + { 3967, 2796 }, { 3968, 2797 }, { 3969, 2798 }, { 3970, 2799 }, { 3971, 2800 }, { 3972, 2801 }, { 3973, 2802 }, + { 3974, 2803 }, { 3975, 2804 }, { 3976, 2805 }, { 3977, 2806 }, { 3978, 2807 }, { 3979, 2808 }, { 3980, 2809 }, + { 3981, 2810 }, { 3982, 2811 }, { 3983, 2812 }, { 3984, 2813 }, { 3985, 2814 }, { 3986, 2815 }, { 3987, 2816 }, + { 3988, 2817 }, { 3989, 2818 }, { 3990, 2819 }, { 3991, 2820 }, { 3992, 2821 }, { 3993, 2822 }, { 3994, 2823 }, + { 3995, 2824 }, { 3996, 2825 }, { 3997, 2826 }, { 3998, 2827 }, { 3999, 2828 }, { 4000, 2829 }, { 4001, 2830 }, + { 4002, 2831 }, { 4003, 2832 }, { 4004, 2833 }, { 4005, 2834 }, { 4006, 2835 }, { 4007, 2836 }, { 4008, 2837 }, + { 4009, 2838 }, { 4010, 2839 }, { 4011, 2840 }, { 4012, 2841 }, { 4013, 2842 }, { 4014, 2843 }, { 4015, 2844 }, + { 4016, 2845 }, { 4017, 2846 }, { 4018, 2847 }, { 4019, 2848 }, { 4020, 2849 }, { 4021, 2850 }, { 4022, 2851 }, + { 4023, 2852 }, { 4024, 2853 }, { 4025, 2854 }, { 4026, 2855 }, { 4027, 2856 }, { 4028, 2857 }, { 4029, 2858 }, + { 4030, 2859 }, { 4031, 2860 }, { 4032, 2861 }, { 4127, 2863 }, { 4128, 2864 }, { 4129, 2865 }, { 4130, 2866 }, + { 4131, 2867 }, { 4132, 2868 }, { 4133, 2869 }, { 4134, 2870 }, { 4135, 2871 }, { 4136, 2872 }, { 4137, 2873 }, + { 4138, 2874 }, { 4139, 2875 }, { 4140, 2876 }, { 4145, 2881 }, { 4146, 2882 }, { 4147, 2883 }, { 4148, 2884 }, + { 4149, 2885 }, { 4150, 2886 }, { 4151, 2887 }, { 4152, 2888 }, { 4153, 2889 }, { 4154, 2890 }, { 4155, 2891 }, + { 4156, 2892 }, { 4157, 2893 }, { 4158, 2894 }, { 4159, 2895 }, { 4160, 2896 }, { 4227, 2897 }, { 4228, 2898 }, + { 4229, 2899 }, { 4230, 2900 }, { 4231, 2901 }, { 4232, 2902 }, { 4233, 2903 }, { 4234, 2904 }, { 4235, 2905 }, + { 4236, 2906 }, { 4237, 2907 }, { 4238, 2908 }, { 4239, 2909 }, { 4240, 2910 }, { 4241, 2911 }, { 4242, 2912 }, + { 4243, 2913 }, { 4244, 2914 }, { 4245, 2915 }, { 4246, 2916 }, { 4247, 2917 }, { 4248, 2918 }, { 4249, 2919 }, + { 4250, 2920 }, { 4251, 2921 }, { 4252, 2922 }, { 4253, 2923 }, { 4254, 2924 }, { 4255, 2925 }, { 4256, 2926 }, + { 4257, 2927 }, { 4258, 2928 }, { 4327, 2929 }, { 4328, 2930 }, { 4329, 2931 }, { 4330, 2932 }, { 4331, 2933 }, + { 4332, 2934 }, { 4333, 2935 }, { 4334, 2936 }, { 4335, 2937 }, { 4336, 2938 }, { 4337, 2939 }, { 4338, 2940 }, + { 4339, 2941 }, { 4340, 2942 }, { 4341, 2943 }, { 4342, 2944 }, { 4343, 2945 }, { 4344, 2946 }, { 4345, 2947 }, + { 4346, 2948 }, { 4347, 2949 }, { 4348, 2950 }, { 4349, 2951 }, { 4350, 2952 }, { 4351, 2953 }, { 4352, 2954 }, + { 4353, 2955 }, { 4354, 2956 }, { 4355, 2957 }, { 4356, 2958 }, { 4357, 2959 }, { 4358, 2960 }, { 4359, 2961 }, + { 4360, 2962 }, { 4361, 2963 }, { 4362, 2964 }, { 4363, 2965 }, { 4364, 2966 }, { 4365, 2967 }, { 4366, 2968 }, + { 4367, 2969 }, { 4368, 2970 }, { 4369, 2971 }, { 4370, 2972 }, { 4371, 2973 }, { 4372, 2974 }, { 4373, 2975 }, + { 4374, 2976 }, { 4375, 2977 }, { 4376, 2978 }, { 4377, 2979 }, { 4378, 2980 }, { 4379, 2981 }, { 4380, 2982 }, + { 4381, 2983 }, { 4382, 2984 }, { 4383, 2985 }, { 4384, 2986 }, { 4385, 2987 }, { 4386, 2988 }, { 4387, 2989 }, + { 4388, 2990 }, { 4389, 2991 }, { 4390, 2992 }, { 4391, 2993 }, { 4392, 2994 }, { 4393, 2995 }, { 4394, 2996 }, + { 4395, 2997 }, { 4396, 2998 }, { 4397, 2999 }, { 4398, 3000 }, { 4399, 3001 }, { 4400, 3002 }, { 4401, 3003 }, + { 4402, 3004 }, { 4403, 3005 }, { 4404, 3006 }, { 4405, 3007 }, { 4406, 3008 }, { 4407, 3009 }, { 4408, 3010 }, + { 4409, 3011 }, { 4410, 3012 }, { 4411, 3013 }, { 4412, 3014 }, { 4413, 3015 }, { 4414, 3016 }, { 4415, 3017 }, + { 4416, 3018 }, { 4417, 3019 }, { 4418, 3020 }, { 4419, 3021 }, { 4420, 3022 }, { 4421, 3023 }, { 4422, 3024 }, + { 4423, 3025 }, { 4424, 3026 }, { 4425, 3027 }, { 4426, 3028 }, { 4427, 3029 }, { 4428, 3030 }, { 4429, 3031 }, + { 4430, 3032 }, { 4431, 3033 }, { 4432, 3034 }, { 4433, 3035 }, { 4434, 3036 }, { 4435, 3037 }, { 4436, 3038 }, + { 4437, 3039 }, { 4438, 3040 }, { 4439, 3041 }, { 4440, 3042 }, { 4441, 3043 }, { 4442, 3044 }, { 4443, 3045 }, + { 4444, 3046 }, { 4445, 3047 }, { 4446, 3048 }, { 4447, 3049 }, { 4448, 3050 }, { 4449, 3051 }, { 4450, 3052 }, + { 4527, 3053 }, { 4528, 3054 }, { 4529, 3055 }, { 4530, 3056 }, { 4531, 3057 }, { 4532, 3058 }, { 4533, 3059 }, + { 4534, 3060 }, { 4535, 3061 }, { 4536, 3062 }, { 4537, 3063 }, { 4538, 3064 }, { 4539, 3065 }, { 4540, 3066 }, + { 4541, 3067 }, { 4542, 3068 }, { 4543, 3069 }, { 4544, 3070 }, { 4545, 3071 }, { 4546, 3072 }, { 4547, 3074 }, + { 4548, 3075 }, { 4549, 3076 }, { 4550, 3077 }, { 4551, 3078 }, { 4552, 3079 }, { 4553, 3080 }, { 4554, 3073 }, + { 4627, 3081 }, { 4628, 3082 }, { 4629, 3083 }, { 4630, 3084 }, { 4631, 3085 }, { 4632, 3086 }, { 4633, 3087 }, + { 4634, 3088 }, { 4635, 3089 }, { 4636, 3090 }, { 4637, 3091 }, { 4638, 3092 }, { 4639, 3093 }, { 4640, 3094 }, + { 4641, 3095 }, { 4642, 3096 }, { 4643, 3097 }, { 4644, 3098 }, { 4645, 3099 }, { 4646, 3100 }, { 4647, 3101 }, + { 4648, 3102 }, { 4649, 3103 }, { 4650, 3104 }, { 4651, 3105 }, { 4652, 3106 }, { 4653, 3107 }, { 4654, 3108 }, + { 4655, 3109 }, { 4656, 3110 }, { 4657, 3111 }, { 4658, 3112 }, { 4659, 3113 }, { 4660, 3114 }, { 4661, 3115 }, + { 4662, 3116 }, { 4663, 3117 }, { 4664, 3118 }, { 4665, 3119 }, { 4666, 3120 }, { 4667, 3121 }, { 4668, 3122 }, + { 4669, 3123 }, { 4670, 3124 }, { 4671, 3125 }, { 4672, 3126 }, { 4673, 3127 }, { 4674, 3128 }, { 4675, 3129 }, + { 4676, 3130 }, { 4677, 3131 }, { 4678, 3132 }, { 4679, 3133 }, { 4680, 3134 }, { 4681, 3135 }, { 4682, 3136 }, + { 4683, 3137 }, { 4684, 3138 }, { 4685, 3139 }, { 4686, 3140 }, { 4687, 3141 }, { 4688, 3142 }, { 4689, 3143 }, + { 4690, 3144 }, { 4691, 3145 }, { 4692, 3146 }, { 4693, 3147 }, { 4694, 3148 }, { 4695, 3149 }, { 4696, 3150 }, + { 4697, 3151 }, { 4698, 3152 }, { 4699, 3153 }, { 4700, 3154 }, { 4701, 3155 }, { 4702, 3156 }, { 4703, 3157 }, + { 4704, 3158 }, { 4705, 3159 }, { 4706, 3160 }, { 4707, 3161 }, { 4708, 3162 }, { 4709, 3163 }, { 4710, 3164 }, + { 4711, 3165 }, { 4712, 3166 }, { 4713, 3167 }, { 4714, 3168 }, { 4715, 3169 }, { 4716, 3170 }, { 4717, 3171 }, + { 4718, 3172 }, { 4719, 3173 }, { 4720, 3174 }, { 4721, 3175 }, { 4722, 3176 }, { 4723, 3177 }, { 4724, 3178 }, + { 4725, 3179 }, { 4726, 3180 }, { 4827, 3181 }, { 4828, 3182 }, { 4829, 3183 }, { 4830, 3184 }, { 4831, 3185 }, + { 4832, 3186 }, { 4833, 3187 }, { 4834, 3188 }, { 4835, 3189 }, { 4836, 3190 }, { 4837, 3191 }, { 4838, 3192 }, + { 4839, 3193 }, { 4840, 3194 }, { 4841, 3195 }, { 4842, 3196 }, { 4843, 3197 }, { 4844, 3198 }, { 4845, 3199 }, + { 5027, 3200 }, { 5028, 3201 }, { 5029, 3202 }, { 5030, 3203 }, { 5031, 3204 }, { 5032, 3205 }, { 5033, 3206 }, + { 5034, 3207 }, { 5035, 3208 }, { 5036, 3209 }, { 5037, 3210 }, { 5038, 3211 }, { 5039, 3212 }, { 5040, 3213 }, + { 5041, 3214 }, { 5042, 3215 }, { 5043, 3216 }, { 5044, 3217 }, { 5045, 3218 }, { 5046, 3219 }, { 5047, 3220 }, + { 5048, 3221 }, { 5049, 3222 }, { 5050, 3223 }, { 5051, 3224 }, { 5052, 3225 }, { 5053, 3226 }, { 5054, 3227 }, + { 5055, 3228 }, { 5056, 3229 }, { 5057, 3230 }, { 5058, 3231 }, { 5059, 3232 }, { 5060, 3233 }, { 5061, 3234 }, + { 5062, 3235 }, { 5063, 3236 }, { 5064, 3237 }, { 5065, 3238 }, { 5066, 3239 }, { 5067, 3240 }, { 5068, 3241 }, + { 5069, 3242 }, { 5070, 3243 }, { 5071, 3244 }, { 5072, 3245 }, { 5073, 3246 }, { 5074, 3247 }, { 5075, 3248 }, + { 5076, 3249 }, { 5077, 3250 }, { 5127, 3251 }, { 5128, 3252 }, { 5129, 3253 }, { 5130, 3254 }, { 5131, 3255 }, + { 5132, 3256 }, { 5133, 3257 }, { 5134, 3258 }, { 5135, 3259 }, { 5136, 3260 }, { 5137, 3261 }, { 5138, 3262 }, + { 5139, 3263 }, { 5140, 3264 }, { 5141, 3265 }, { 5142, 3266 }, { 5143, 3267 }, { 5144, 3268 }, { 5145, 3269 }, + { 5146, 3270 }, { 5147, 3271 }, { 5148, 3272 }, { 5149, 3273 }, { 5150, 3274 }, { 5151, 3275 }, { 5152, 3276 }, + { 5153, 3277 }, { 5154, 3278 }, { 5155, 3279 }, { 5156, 3280 }, { 5227, 3281 }, { 5228, 3282 }, { 5229, 3283 }, + { 5230, 3284 }, { 5231, 3285 }, { 5232, 3286 }, { 5233, 3287 }, { 5234, 3288 }, { 5235, 3289 }, { 5236, 3290 }, + { 5237, 3291 }, { 5238, 3292 }, { 5240, 3294 }, { 5241, 3295 }, { 5242, 3296 }, { 5243, 3297 }, { 5244, 3298 }, + { 5245, 3299 }, { 5246, 3300 }, { 5247, 3301 }, { 5248, 3302 }, { 5249, 3303 }, { 5250, 3304 }, { 5251, 3305 }, + { 5252, 3306 }, { 5253, 3307 }, { 5254, 3308 }, { 5255, 3309 }, { 5256, 3310 }, { 5257, 3311 }, { 5258, 3312 }, + { 5259, 3313 }, { 5260, 3314 }, { 5261, 3315 }, { 5262, 3316 }, { 5263, 3317 }, { 5264, 3318 }, { 5265, 3319 }, + { 5266, 3320 }, { 5267, 3321 }, { 5268, 3322 }, { 5269, 3323 }, { 5270, 3324 }, { 5271, 3325 }, { 5272, 3326 }, + { 5273, 3327 }, { 5274, 3328 }, { 5275, 3329 }, { 5276, 3330 }, { 5277, 3331 }, { 5278, 3332 }, { 5279, 3333 }, + { 5280, 3334 }, { 5281, 3335 }, { 5282, 3336 }, { 5283, 3337 }, { 5284, 3338 }, { 5285, 3339 }, { 5286, 3340 }, + { 5288, 3342 }, { 5289, 3343 }, { 5290, 3344 }, { 5291, 3345 }, { 5292, 3346 }, { 5293, 3347 }, { 5294, 3348 }, + { 5296, 3350 }, { 5297, 3351 }, { 5298, 3352 }, { 5299, 3353 }, { 5300, 3354 }, { 5301, 3355 }, { 5302, 3356 }, + { 5303, 3357 }, { 5304, 3358 }, { 5305, 3359 }, { 5306, 3360 }, { 5307, 3361 }, { 5308, 3362 }, { 5309, 3363 }, + { 5310, 3364 }, { 5311, 3365 }, { 5312, 3366 }, { 5313, 3367 }, { 5314, 3368 }, { 5315, 3369 }, { 5316, 3370 }, + { 5317, 3371 }, { 5318, 3372 }, { 5319, 3373 }, { 5320, 3374 }, { 5321, 3375 }, { 5322, 3376 }, { 5323, 3377 }, + { 5324, 3378 }, { 5325, 3379 }, { 5326, 3380 }, { 5327, 3381 }, { 5328, 3382 }, { 5329, 3383 }, { 5330, 3384 }, + { 5331, 3385 }, { 5332, 3386 }, { 5333, 3387 }, { 5336, 3390 }, { 5337, 3391 }, { 5338, 3392 }, { 5339, 3393 }, + { 5340, 3394 }, { 5341, 3395 }, { 5342, 3396 }, { 5343, 3397 }, { 5344, 3398 }, { 5345, 3399 }, { 5346, 3400 }, + { 5347, 3401 }, { 5348, 3402 }, { 5349, 3403 }, { 5350, 3404 }, { 5351, 3405 }, { 5352, 3406 }, { 5357, 3411 }, + { 5358, 3412 }, { 5359, 3413 }, { 5360, 3414 }, { 5361, 3415 }, { 5362, 3416 }, { 5363, 3417 }, { 5364, 3418 }, + { 5365, 3419 }, { 5366, 3420 }, { 5367, 3421 }, { 5368, 3422 }, { 5369, 3423 }, { 5370, 3424 }, { 5371, 3425 }, + { 5372, 3426 }, { 5373, 3427 }, { 5374, 3428 }, { 5375, 3429 }, { 5376, 3430 }, { 5377, 3431 }, { 5378, 3432 }, + { 5379, 3433 }, { 5380, 3434 }, { 5381, 3435 }, { 5382, 3436 }, { 5383, 3437 }, { 5384, 3438 }, { 5385, 3439 }, + { 5386, 3440 }, { 5387, 3441 }, { 5388, 3442 }, { 5389, 3443 }, { 5390, 3444 }, { 5391, 3445 }, { 5392, 3446 }, + { 5393, 3447 }, { 5394, 3448 }, { 5395, 3449 }, { 5396, 3450 }, { 5397, 3451 }, { 5398, 3452 }, { 5399, 3453 }, + { 5400, 3454 }, { 5401, 3455 }, { 5402, 3456 }, { 5403, 3457 }, { 5404, 3458 }, { 5405, 3459 }, { 5406, 3460 }, + { 5407, 3461 }, { 5408, 3462 }, { 5409, 3463 }, { 5410, 3464 }, { 5411, 3465 }, { 5412, 3466 }, { 5413, 3467 }, + { 5414, 3468 }, { 5415, 3469 }, { 5416, 3470 }, { 5417, 3471 }, { 5418, 3472 }, { 5419, 3473 }, { 5420, 3474 }, + { 5421, 3475 }, { 5422, 3476 }, { 5423, 3477 }, { 5424, 3478 }, { 5425, 3479 }, { 5426, 3480 }, { 5427, 3481 }, + { 5428, 3482 }, { 5429, 3483 }, { 5430, 3484 }, { 5431, 3485 }, { 5432, 3486 }, { 5433, 3487 }, { 5434, 3488 }, + { 5435, 3489 }, { 5436, 3490 }, { 5437, 3491 }, { 5438, 3492 }, { 5439, 3493 }, { 5440, 3494 }, { 5441, 3495 }, + { 5442, 3496 }, { 5443, 3497 }, { 5444, 3498 }, { 5445, 3499 }, { 5446, 3500 }, { 5447, 3501 }, { 5448, 3502 }, + { 5449, 3503 }, { 5450, 3504 }, { 5451, 3505 }, { 5452, 3506 }, { 5453, 3507 }, { 5454, 3508 }, { 5455, 3509 }, + { 5456, 3510 }, { 5457, 3511 }, { 5458, 3512 }, { 5459, 3513 }, { 5460, 3514 }, { 5461, 3515 }, { 5462, 3516 }, + { 5463, 3517 }, { 5464, 3518 }, { 5465, 3519 }, { 5466, 3520 }, { 5467, 3521 }, { 5468, 3522 }, { 5469, 3523 }, + { 5470, 3524 }, { 5471, 3525 }, { 5472, 3526 }, { 5473, 3527 }, { 5474, 3528 }, { 5475, 3529 }, { 5476, 3530 }, + { 5477, 3531 }, { 5478, 3532 }, { 5479, 3533 }, { 5480, 3534 }, { 5481, 3535 }, { 5482, 3536 }, { 5483, 3537 }, + { 5484, 3538 }, { 5485, 3539 }, { 5486, 3540 }, { 5487, 3541 }, { 5488, 3542 }, { 5489, 3543 }, { 5490, 3544 }, + { 5491, 3545 }, { 5492, 3546 }, { 5493, 3547 }, { 5494, 3548 }, { 5495, 3549 }, { 5496, 3550 }, { 5497, 3551 }, + { 5498, 3552 }, { 5499, 3553 }, { 5500, 3554 }, { 5501, 3555 }, { 5502, 3556 }, { 5503, 3557 }, { 5504, 3558 }, + { 5505, 3559 }, { 5506, 3560 }, { 5507, 3561 }, { 5508, 3562 }, { 5509, 3563 }, { 5510, 3564 }, { 5511, 3565 }, + { 5512, 3566 }, { 5513, 3567 }, { 5514, 3568 }, { 5515, 3569 }, { 5516, 3570 }, { 5517, 3571 }, { 5518, 3572 }, + { 5519, 3573 }, { 5520, 3574 }, { 5521, 3575 }, { 5522, 3576 }, { 5523, 3577 }, { 5524, 3578 }, { 5525, 3579 }, + { 5526, 3580 }, { 5527, 3581 }, { 5528, 3582 }, { 5529, 3583 }, { 5530, 3584 }, { 5531, 3585 }, { 5532, 3586 }, + { 5533, 3587 }, { 5534, 3588 }, { 5535, 3589 }, { 5536, 3590 }, { 5537, 3591 }, { 5538, 3592 }, { 5539, 3593 }, + { 5540, 3594 }, { 5541, 3595 }, { 5542, 3596 }, { 5543, 3597 }, { 5544, 3598 }, { 5545, 3599 }, { 5546, 3600 }, + { 5547, 3601 }, { 5548, 3602 }, { 5549, 3603 }, { 5550, 3604 }, { 5551, 3605 }, { 5552, 3606 }, { 5553, 3607 }, + { 5554, 3608 }, { 5555, 3609 }, { 5556, 3610 }, { 5557, 3611 }, { 5558, 3612 }, { 5559, 3613 }, { 5560, 3614 }, + { 5561, 3615 }, { 5562, 3616 }, { 5563, 3617 }, { 5564, 3618 }, { 5565, 3619 }, { 5566, 3620 }, { 5567, 3621 }, + { 5568, 3622 }, { 5569, 3623 }, { 5570, 3624 }, }; #endif // ASSET_VERSION_REMAP_H diff --git a/src/port/OS/OS_AI.cpp b/src/port/OS/OS_AI.cpp index c74047c84..ac072f54e 100644 --- a/src/port/OS/OS_AI.cpp +++ b/src/port/OS/OS_AI.cpp @@ -25,6 +25,19 @@ extern "C" u32 osAiGetLength(void) { return excess > 0 ? (u32)excess * 4 : 0; } +// How many extra synth frames the audio pump should queue this cycle to +// rebuild the playback cushion. +extern "C" int32_t port_audioCatchupFrames(void) { + constexpr int32_t kFrameSamples = 736; + constexpr int32_t kMaxCatchup = 3; + int32_t deficit = AudioPlayerGetDesiredBuffered() - AudioPlayerBuffered(); + if (deficit < kFrameSamples) { + return 0; + } + int32_t frames = deficit / kFrameSamples; + return frames > kMaxCatchup ? kMaxCatchup : frames; +} + extern "C" s32 osAiSetNextBuffer(void* buff, size_t len) { static bool sPrimed = false; if (!sPrimed) { diff --git a/src/port/Patches/Patches.h b/src/port/Patches/Patches.h index 52a06b339..bb77404c1 100644 --- a/src/port/Patches/Patches.h +++ b/src/port/Patches/Patches.h @@ -128,6 +128,9 @@ void romhack_RewriteActorSpawn(void* actorInfo, u32* flags); void port_beginDemoAudioHold(void); void port_tickDemoAudioHold(void); int port_audioHeld(void); +void port_noteMainLoopAlive(void); +int port_audioStallHold(void); +int32_t port_audioCatchupFrames(void); // One-shot cues when a teammate's file-progress flag arrives void port_progressFlag_remoteCue(int32_t progressFlag); diff --git a/src/port/ResourceHelpers.cpp b/src/port/ResourceHelpers.cpp index 6f20d5836..a350a0f86 100644 --- a/src/port/ResourceHelpers.cpp +++ b/src/port/ResourceHelpers.cpp @@ -31,6 +31,15 @@ extern "C" void func_8031B5C4(int32_t lang); // decomp: set dialog language index +extern "C" { +// SNS picture demo table (core2/map/exit.c, Struct_core2_C4320_0). unk2 is both +// the demo file slot and the map exit/entry-point id used for the warp. +typedef struct { + uint8_t map, unk1, exit, unk3, unk4, unk5; +} BKSnsDemoEntry; +extern BKSnsDemoEntry D_80371F78[3]; +} + // Dialog language state — detected at boot from o2r version static int sDialogLanguageCount = 1; // 1 for US/JP, 3 for PAL (EN/FR/DE) static int sDialogLanguage = 0; // 0=English, 1=French, 2=German @@ -120,6 +129,17 @@ const std::unordered_map& GetAssetSymbolMap() { break; } + // Non-v1.0 ROMs keep the SNS picture demos one slot lower (0x5E, matching + // the PAL VER_SELECT in the decomp) and their map setups place the demo + // entry points at that exit id too. The compiled v1.0 value (0x5F) would + // load the right demo file via the alias but warp to a nonexistent exit, + // so retarget the table; the 2508/2511/2513 aliases cover the asset side. + if (remapTable) { + for (auto& entry : D_80371F78) { + entry.exit = 0x5E; + } + } + // Relocate the JP world-name banners to their 0x1600 aliases for a JP // base (a JP pack does this re-point at language-select time instead). if (Lighthouse::GetBaseVersion() == BK_VER_JP) { diff --git a/src/port/UI/LighthouseMenuDevTools.cpp b/src/port/UI/LighthouseMenuDevTools.cpp index c72e60bf2..6ce8a96f8 100644 --- a/src/port/UI/LighthouseMenuDevTools.cpp +++ b/src/port/UI/LighthouseMenuDevTools.cpp @@ -101,6 +101,11 @@ void LighthouseMenu::AddMenuDevTools() { AddWidget(path, "Spiral Mountain Ending Sequence", WIDGET_BUTTON) .Callback([](WidgetInfo&) { RequestSequence(SEQ_MODE9_BK); }) .Options(ButtonOptions().Size(Sizes::Inline).Tooltip("Jump to the post-parade demo.")); + AddWidget(path, "All 100 Ending Scene", WIDGET_BUTTON) + .Callback([](WidgetInfo&) { RequestSequence(SEQ_ENDING_ALL_100); }) + .Options(ButtonOptions() + .Size(Sizes::Inline) + .Tooltip("Jump to the 100-jiggy ending cutscene (normally shown after the final parade).")); AddWidget(path, "Attract Demos", WIDGET_SEPARATOR_TEXT); // Demo index = slot in the decomp attract table (D_80371F00); 4 and 9 are the From e598cfcc21e21b6ff5cdf533098f22539246c770 Mon Sep 17 00:00:00 2001 From: Malkierian Date: Wed, 5 Aug 2026 10:34:01 -0700 Subject: [PATCH 118/131] 1.0.2. (#403) --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b425c8ead..b4e2ec1ad 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 3.26.0 FATAL_ERROR) set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>") # Set the project version and language -project(Lighthouse VERSION 1.0.1 LANGUAGES C CXX ASM) +project(Lighthouse VERSION 1.0.2 LANGUAGES C CXX ASM) include(FetchContent) include(cmake/lighthouse-cvars.cmake) From 958fc343157a3ecfde40bee6fcd51f7bb41b2fc1 Mon Sep 17 00:00:00 2001 From: aMannus Date: Wed, 5 Aug 2026 20:23:45 +0200 Subject: [PATCH 119/131] Clean up rando molehills --- src/port/Rando/ObjectBehavior/Molehill.cpp | 185 ++---------------- .../Rando/ObjectBehavior/ObjectBehavior.cpp | 1 - .../Rando/ObjectBehavior/ObjectBehavior.h | 1 - src/port/Rando/StaticData/Flags.cpp | 1 - src/port/Rando/Types.h | 1 - 5 files changed, 17 insertions(+), 172 deletions(-) diff --git a/src/port/Rando/ObjectBehavior/Molehill.cpp b/src/port/Rando/ObjectBehavior/Molehill.cpp index 9984e0ec4..3596aa6ba 100644 --- a/src/port/Rando/ObjectBehavior/Molehill.cpp +++ b/src/port/Rando/ObjectBehavior/Molehill.cpp @@ -1,56 +1,16 @@ -#include "ObjectBehavior.h" -#include "port/Rando/Logic/Logic.h" -#include "port/Rando/CustomObject/CustomObject.h" - #include -#include "port/UI/cvar_prefixes.h" -#include -#include "port/Enhancements/Events/PortEnhancements.h" -#include "port/Enhancements/Events/Hooks/Events.h" #include "port/ShipInit.hpp" - +#include "port/Enhancements/Events/Hooks/Events.h" +#include "port/Rando/Logic/Logic.h" #include "port/Rando/CustomCollectible/CustomCollectible.h" -#define MOLETABLE_SIZE 16 #define BRIDGE_REQUIREMENT 6 -typedef struct { - s16 teach_text_id; - s16 refresher_text_id; - s8 camera_node; - s8 ability; -} ChMoleDescription; - extern "C" { -void func_80347A14(s32 arg0); -s32 item_adjustByDiffWithHud(enum item_e item, s32 diff); -void ability_unlock(enum ability_e); s32 mapSpecificFlags_get(s32 i); void mapSpecificFlags_set(s32 i, s32 val); } -// clang-format off -ChMoleDescription moleDialogTable[MOLETABLE_SIZE] = { - //{ ASSET_DF3_DIALOG_BOTTLES_INTRODUCTION, ASSET_E08_DIALOG_BOTTLES_FIND_ANOTHER_MOLEHILL, 0x1, -1 }, - { ASSET_DF4_DIALOG_BOTTLES_CAMERA_CONTROL_LEARN, ASSET_DF5_DIALOG_BOTTLES_CAMERA_CONTROL_REFRESHER, 0x3, ABILITY_3_CAMERA_CONTROL }, - { ASSET_DFB_DIALOG_BOTTLES_DIVE_LEARN, ASSET_DFE_DIALOG_BOTTLES_DIVE_REFRESHER, 0x5, ABILITY_F_DIVE }, - { -1, ASSET_E00_DIALOG_BOTTLES_ATTACK_REFRESHER, 0x6, ABILITY_4_CLAW_SWIPE }, - { ASSET_E04_DIALOG_BOTTLES_BEAK_BARGE_LEARN, ASSET_E06_DIALOG_BOTTLES_BEAK_BARGE_REFRESHER, 0x8, ABILITY_0_BARGE }, - { -1, ASSET_DFA_DIALOG_BOTTLES_JUMP_REFRESHER, 0x4, ABILITY_8_FLAP_FLIP }, - { ASSET_E01_DIALOG_BOTTLES_CLIMB_LEARN, ASSET_E03_DIALOG_BOTTLES_CLIMB_REFRESHER, 0x7, ABILITY_5_CLIMB }, - //{ ASSET_E10_DIALOG_BOTTLES_BRIDGE_BROKEN, ASSET_E11_DIALOG_BOTTLES_BRIDGE_STILL_BROKEN, 0x11, -1 }, - { ASSET_C23_DIALOG_BEAKBOMB_LEARN, ASSET_C24_DIALOG_BEAKBOMB_REFRESHER, 0x0F, ABILITY_1_BEAK_BOMB }, - { ASSET_B47_DIALOG_EGGS_LEARN, ASSET_B4B_DIALOG_EGGS_REFRESHER, 0x16, ABILITY_6_EGGS }, - { ASSET_B48_DIALOG_BEAKBUSTER_LEARN, ASSET_B4C_DIALOG_BEAKBUSTER_REFRESHER, 0x17, ABILITY_2_BEAK_BUSTER }, - { ASSET_B49_DIALOG_TALON_TROT_LEARN, ASSET_B4A_DIALOG_TALON_TROT_REFRESHER, 0x18, ABILITY_10_TALON_TROT }, - { ASSET_A1F_DIALOG_SHOCKJUMP_LEARN, ASSET_A23_DIALOG_SHOCKJUMP_REFRESHER, 0x0C, ABILITY_D_SHOCK_JUMP }, - { ASSET_A20_DIALOG_FLY_LEARN, ASSET_A22_DIALOG_FLY_REFRESHER, 0x0D, ABILITY_9_FLIGHT }, - { ASSET_D35_DIALOG_WONDERWING_LEARN, ASSET_D36_DIALOG_WONDERWING_REFRESHER, 0x01, ABILITY_12_WONDERWING }, - { ASSET_C88_DIALOG_WADING_BOOTS_LEARN, ASSET_C89_DIALOG_WADING_BOOTS_REFRESHER, 0x10, ABILITY_E_WADING_BOOTS }, - { ASSET_A84_DIALOG_TURBOTRAINERS_LEARN, ASSET_A85_DIALOG_TURBOTRAINERS_REFRESHER, 0x19, ABILITY_11_TURBO_TALON }, - { ASSET_F64_DIALOG_NOTEDOORS_LEARN, ASSET_F65_DIALOG_NOTEDOORS_REFRESHER, 0x0E, ABILITY_13_1ST_NOTEDOOR }, -}; - std::vector spiralMountainBridge = { RC_SM_MOLEHILL_JUMP, RC_SM_MOLEHILL_CAMERA_CONTROL, @@ -61,27 +21,13 @@ std::vector spiralMountainBridge = { }; // clang-format on -ChMoleDescription result; - #define OPTION_ENABLED RANDO_SAVE_OPTIONS[RO_SHUFFLE_MOLEHILLS].optionValue -ChMoleDescription GetMoleDescriptionByAbility(int16_t abilityId) { - result.ability = -1; - for (int i = 0; i < MOLETABLE_SIZE; i++) { - if (moleDialogTable[i].ability == abilityId) { - result = moleDialogTable[i]; - break; - } - } - - return result; -} - bool CheckBridgeState() { int32_t smBridgeCheck = 0; if (!mapSpecificFlags_get(SM_SPECIFIC_FLAG_3_ALL_SM_ABILITIES_LEARNED)) { for (auto& check : spiralMountainBridge) { - if (Rando::Logic::GetShuffledObject(check).eligible) { + if (RANDO_SAVE_CHECKS[check].eligible) { smBridgeCheck++; } } @@ -94,117 +40,6 @@ void SetSpiralMountainFlags() { mapSpecificFlags_set(SM_SPECIFIC_FLAG_1_TALKED_TO_BOTTLES, true); } -static void MarkBridgeRepairedDialogComplete() { - CALL_EVENT(SetRandoInfFlag, RANDO_INF_BRIDGE_REPAIRED_DIALOG_COMPLETE, true); -} - -void Rando::ObjectBehavior::InitMolehillBehavior() { - COND_VB_SHOULD(VB_OVERRIDE_MOLEHILL_ABILITY, EVENT_PRIORITY_NORMAL, true, { - Actor* molehillActor = va_arg(args, Actor*); - s32* textId = va_arg(args, s32*); - s32* isLearned = va_arg(args, s32*); - - if (!IS_RANDO && !OPTION_ENABLED) { - return; - } - - if (molehillActor->actorTypeSpecificField == 8) { - return; - } - - RandoCheckId randoCheckId = Rando::StaticData::GetCheckByPosition( - molehillActor->position_x, molehillActor->position_y, molehillActor->position_z); - - if (randoCheckId == RC_UNKNOWN) { - return; - } - - RandoSaveCheck shuffledMolehill = Rando::Logic::GetShuffledObject(randoCheckId); - ChMoleDescription moleInfo = GetMoleDescriptionByAbility(shuffledMolehill.randoCollectionId); - - if (moleInfo.ability >= ABILITY_0_BARGE) { - *should = true; - - func_80347A14(0); - molehillActor->has_met_before = true; - - switch (moleInfo.ability) { - case ABILITY_4_CLAW_SWIPE: - *textId = (s32)moleInfo.refresher_text_id; - ability_unlock(ABILITY_4_CLAW_SWIPE); - ability_unlock(ABILITY_C_ROLL); - ability_unlock(ABILITY_B_RATATAT_RAP); - break; - case ABILITY_6_EGGS: - *textId = (s32)moleInfo.refresher_text_id; - ability_unlock((ability_e)moleInfo.ability); - item_adjustByDiffWithHud(ITEM_D_EGGS, 50); - break; - case ABILITY_8_FLAP_FLIP: - *textId = (s32)moleInfo.refresher_text_id; - ability_unlock(ABILITY_A_HOLD_A_JUMP_HIGHER); - ability_unlock(ABILITY_7_FEATHERY_FLAP); - ability_unlock(ABILITY_8_FLAP_FLIP); - break; - case ABILITY_9_FLIGHT: - *textId = (s32)moleInfo.refresher_text_id; - ability_unlock((ability_e)moleInfo.ability); - item_adjustByDiffWithHud(ITEM_F_RED_FEATHER, 25); - break; - case ABILITY_12_WONDERWING: - *textId = (s32)moleInfo.refresher_text_id; - ability_unlock((ability_e)moleInfo.ability); - item_adjustByDiffWithHud(ITEM_10_GOLD_FEATHER, 5); - break; - default: - *textId = (s32)moleInfo.refresher_text_id; - ability_unlock((ability_e)moleInfo.ability); - break; - } - - CustomObject::CheckObtainedEX(shuffledMolehill.randoCheckId); - - if (map_getLevel(gsworld_getMap()) == LEVEL_B_SPIRAL_MOUNTAIN) { - if (CheckBridgeState()) { - SetSpiralMountainFlags(); - } - } - } - }) - - COND_VB_SHOULD(VB_OVERRIDE_BOTTLES_TEXT_CALLBACK, EVENT_PRIORITY_NORMAL, true, { - Actor* molehillActor = va_arg(args, Actor*); - - if (!IS_RANDO && !OPTION_ENABLED) { - return; - } - - if (CheckBridgeState() && !RANDO_SAVE_FLAGS[RANDO_INF_BRIDGE_REPAIRED_DIALOG_COMPLETE].flagState) { - *should = true; - } - }) - - COND_HOOK(OnCheckSpiralMountainAbilities, EVENT_PRIORITY_NORMAL, IS_RANDO, [](IEvent* event) { - OnCheckSpiralMountainAbilities* ev = (OnCheckSpiralMountainAbilities*)event; - if (!IS_RANDO && !OPTION_ENABLED) { - return; - } - - if (mapSpecificFlags_get(SM_SPECIFIC_FLAG_3_ALL_SM_ABILITIES_LEARNED)) { - mapSpecificFlags_set(SM_SPECIFIC_FLAG_3_ALL_SM_ABILITIES_LEARNED, false); - } - - if (CheckBridgeState()) { - mapSpecificFlags_set(SM_SPECIFIC_FLAG_3_ALL_SM_ABILITIES_LEARNED, true); - if (!RANDO_SAVE_FLAGS[RANDO_INF_BRIDGE_REPAIRED_DIALOG_COMPLETE].flagState) { - MarkBridgeRepairedDialogComplete(); - } - event->Cancelled = true; - ev->result = true; - } - }) -} - bool OverrideMoleSpawn(OnActorSpawn* ev) { if (ev->actorId != ACTOR_12B_TUTORIAL_BOTTLES) { return false; @@ -226,6 +61,20 @@ bool OverrideMoleSpawn(OnActorSpawn* ev) { } void RegisterRandoMolehills() { + COND_HOOK(OnCheckSpiralMountainAbilities, EVENT_PRIORITY_NORMAL, IS_RANDO && OPTION_ENABLED, [](IEvent* event) { + OnCheckSpiralMountainAbilities* ev = (OnCheckSpiralMountainAbilities*)event; + if (mapSpecificFlags_get(SM_SPECIFIC_FLAG_3_ALL_SM_ABILITIES_LEARNED)) { + mapSpecificFlags_set(SM_SPECIFIC_FLAG_3_ALL_SM_ABILITIES_LEARNED, false); + } + + if (CheckBridgeState()) { + mapSpecificFlags_set(SM_SPECIFIC_FLAG_3_ALL_SM_ABILITIES_LEARNED, true); + mapSpecificFlags_set(SM_SPECIFIC_FLAG_1_TALKED_TO_BOTTLES, true); + event->Cancelled = true; + ev->result = true; + } + }); + COND_HOOK(OnActorSpawn, EVENT_PRIORITY_NORMAL, IS_RANDO && OPTION_ENABLED, [](IEvent* event) { OnActorSpawn* ev = (OnActorSpawn*)event; diff --git a/src/port/Rando/ObjectBehavior/ObjectBehavior.cpp b/src/port/Rando/ObjectBehavior/ObjectBehavior.cpp index 6215487a7..a5fbe3eff 100644 --- a/src/port/Rando/ObjectBehavior/ObjectBehavior.cpp +++ b/src/port/Rando/ObjectBehavior/ObjectBehavior.cpp @@ -246,7 +246,6 @@ void Rando::ObjectBehavior::Init() { InitBundleBehavior(); InitJiggyBehavior(); InitJinjoBehavior(); - InitMolehillBehavior(); InitStopNSwopBehavior(); UpdateJunkList(); diff --git a/src/port/Rando/ObjectBehavior/ObjectBehavior.h b/src/port/Rando/ObjectBehavior/ObjectBehavior.h index bb1cd4437..e1bc21f50 100644 --- a/src/port/Rando/ObjectBehavior/ObjectBehavior.h +++ b/src/port/Rando/ObjectBehavior/ObjectBehavior.h @@ -16,7 +16,6 @@ void Init(); void InitBundleBehavior(); void InitJiggyBehavior(); void InitJinjoBehavior(); -void InitMolehillBehavior(); void InitStopNSwopBehavior(); void ModifySwitchBehavior(int32_t switchActorId); diff --git a/src/port/Rando/StaticData/Flags.cpp b/src/port/Rando/StaticData/Flags.cpp index 4f807dd28..0fad9ae3d 100644 --- a/src/port/Rando/StaticData/Flags.cpp +++ b/src/port/Rando/StaticData/Flags.cpp @@ -17,7 +17,6 @@ namespace StaticData { std::map Flags = { RF(RANDO_INF_UNKNOWN, RO_GENERIC_OFF), RF(RANDO_INF_ANCHOR_RAISED, RO_GENERIC_OFF), - RF(RANDO_INF_BRIDGE_REPAIRED_DIALOG_COMPLETE, RO_GENERIC_OFF), RF(RANDO_INF_CLANKER_RAISED, RO_GENERIC_OFF), RF(RANDO_INF_MINIGAME_RINGS_COMPLETED, RO_GENERIC_OFF), RF(RANDO_INF_WATER_PYRAMID_DRAINED, RO_GENERIC_OFF), diff --git a/src/port/Rando/Types.h b/src/port/Rando/Types.h index bf46e164d..146d7c8cc 100644 --- a/src/port/Rando/Types.h +++ b/src/port/Rando/Types.h @@ -2382,7 +2382,6 @@ typedef enum { typedef enum { RANDO_INF_UNKNOWN, RANDO_INF_ANCHOR_RAISED, - RANDO_INF_BRIDGE_REPAIRED_DIALOG_COMPLETE, RANDO_INF_CLANKER_RAISED, RANDO_INF_MINIGAME_RINGS_COMPLETED, RANDO_INF_WATER_PYRAMID_DRAINED, From 9814d53a60a3c0b9d6233712e423dd11723fd39a Mon Sep 17 00:00:00 2001 From: aMannus Date: Wed, 5 Aug 2026 21:14:03 +0200 Subject: [PATCH 120/131] Implemented jiggies --- src/port/Rando/ItemQueue.cpp | 8 +- src/port/Rando/ObjectBehavior/Jiggy.cpp | 74 +++++++++---------- src/port/Rando/ObjectBehavior/Molehill.cpp | 4 - .../Rando/ObjectBehavior/ObjectBehavior.cpp | 1 - .../Rando/ObjectBehavior/ObjectBehavior.h | 1 - 5 files changed, 39 insertions(+), 49 deletions(-) diff --git a/src/port/Rando/ItemQueue.cpp b/src/port/Rando/ItemQueue.cpp index 3e25558bf..cbc7e966d 100644 --- a/src/port/Rando/ItemQueue.cpp +++ b/src/port/Rando/ItemQueue.cpp @@ -65,9 +65,11 @@ void ItemQueue::Process() { // Grant item RandoSaveCheck randoSaveCheck = RANDO_SAVE_CHECKS[randoCheckId]; - ItemQueue::GiveItem(randoSaveCheck.randoItemId); - ItemQueue::SendNotification(randoSaveCheck.randoItemId); - randoSaveCheck.received = true; + if (!randoSaveCheck.received) { + ItemQueue::GiveItem(randoSaveCheck.randoItemId); + ItemQueue::SendNotification(randoSaveCheck.randoItemId); + randoSaveCheck.received = true; + } itemQueue.pop(); } diff --git a/src/port/Rando/ObjectBehavior/Jiggy.cpp b/src/port/Rando/ObjectBehavior/Jiggy.cpp index b703a771c..4635b564c 100644 --- a/src/port/Rando/ObjectBehavior/Jiggy.cpp +++ b/src/port/Rando/ObjectBehavior/Jiggy.cpp @@ -1,56 +1,50 @@ #include "ObjectBehavior.h" +#include "port/ShipInit.hpp" +#include "port/Enhancements/Events/Hooks/Events.h" #include "port/Rando/Logic/Logic.h" #include "port/Rando/CustomObject/CustomObject.h" -#include "port/Enhancements/Events/Hooks/Events.h" - -#include "spdlog/spdlog.h" +#include "port/Rando/CustomCollectible/CustomCollectible.h" #define OPTION_ENABLED RANDO_SAVE_OPTIONS[RO_SHUFFLE_JIGGIES].optionValue -void Rando::ObjectBehavior::InitJiggyBehavior() { - COND_VB_SHOULD(VB_NAPPER_SET_JIGGY_POSITION, EVENT_PRIORITY_NORMAL, true, { - if (!IS_RANDO && !OPTION_ENABLED) { - return; - } - - if (RANDO_SAVE_CHECKS[RC_MMM_JIGGY_MANSION_TABLE].eligible) { - *should = false; - } - }) +bool OverrideJiggySpawn(f32 position[3], jiggy_e jiggyId) { + RandoCheckId randoCheckId = Rando::StaticData::GetCheckByJiggyId(jiggyId); - COND_VB_SHOULD(VB_OVERRIDE_JIGGY_SPAWN, EVENT_PRIORITY_NORMAL, true, { - jiggy_e jiggyId = (jiggy_e)va_arg(args, int); - f32* position = va_arg(args, f32*); + if (randoCheckId == RC_UNKNOWN || !Rando::Logic::IsCheckShuffled(randoCheckId)) { + return false; + } - if (!IS_RANDO && !OPTION_ENABLED) { - return; - } + int32_t spawnPosition[3] = { (int32_t)position[0], (int32_t)position[1], (int32_t)position[2] }; - RandoCheckId randoCheckId = Rando::StaticData::GetCheckByJiggyId(jiggyId); + if (jiggyId == JIGGY_26_BGS_TANKTUP) { + spawnPosition[0] -= 300; + spawnPosition[1] += 100; + spawnPosition[2] -= 300; + } - if (randoCheckId == RC_UNKNOWN) { - return; - } + Actor* actor = CustomCollectible::Spawn(spawnPosition, randoCheckId); + if (jiggyId != JIGGY_17_CC_CLANKER_RAISED && jiggyId != JIGGY_1B_CC_TOOTH) { + ApplyCustomActorPhysics(randoCheckId, actor, false); + } + return true; +} - if (!Rando::Logic::IsCheckShuffled(randoCheckId)) { - return; +void RegisterRandoJiggies() { + COND_VB_SHOULD(VB_NAPPER_SET_JIGGY_POSITION, EVENT_PRIORITY_NORMAL, IS_RANDO && OPTION_ENABLED, { + if (RANDO_SAVE_CHECKS[RC_MMM_JIGGY_MANSION_TABLE].eligible) { + *should = false; } + }); - int32_t spawnPosition[3]; - spawnPosition[0] = (int32_t)position[0]; - spawnPosition[1] = (int32_t)position[1]; - spawnPosition[2] = (int32_t)position[2]; - - if (jiggyId == JIGGY_26_BGS_TANKTUP) { - spawnPosition[0] -= 300; - spawnPosition[1] += 100; - spawnPosition[2] -= 300; - } + COND_VB_SHOULD(VB_OVERRIDE_JIGGY_SPAWN, EVENT_PRIORITY_NORMAL, IS_RANDO && OPTION_ENABLED, { + jiggy_e jiggyId = (jiggy_e)va_arg(args, int); + f32* position = va_arg(args, f32*); - Actor* randoCustomActor = CustomObject::ShouldCreateCustomActorEX(randoCheckId, spawnPosition, false); - if (jiggyId != JIGGY_17_CC_CLANKER_RAISED && jiggyId != JIGGY_1B_CC_TOOTH) { - ApplyCustomActorPhysics(randoCheckId, randoCustomActor, false); + bool replaceJiggy = OverrideJiggySpawn(position, jiggyId); + if (replaceJiggy) { + *should = true; } - *should = true; - }) + }); } + +static RegisterShipInitFunc initFunc(RegisterRandoJiggies, { "IS_RANDO" }); diff --git a/src/port/Rando/ObjectBehavior/Molehill.cpp b/src/port/Rando/ObjectBehavior/Molehill.cpp index 3596aa6ba..a258cafe4 100644 --- a/src/port/Rando/ObjectBehavior/Molehill.cpp +++ b/src/port/Rando/ObjectBehavior/Molehill.cpp @@ -36,10 +36,6 @@ bool CheckBridgeState() { return smBridgeCheck == BRIDGE_REQUIREMENT ? true : false; } -void SetSpiralMountainFlags() { - mapSpecificFlags_set(SM_SPECIFIC_FLAG_1_TALKED_TO_BOTTLES, true); -} - bool OverrideMoleSpawn(OnActorSpawn* ev) { if (ev->actorId != ACTOR_12B_TUTORIAL_BOTTLES) { return false; diff --git a/src/port/Rando/ObjectBehavior/ObjectBehavior.cpp b/src/port/Rando/ObjectBehavior/ObjectBehavior.cpp index a5fbe3eff..c4bc086de 100644 --- a/src/port/Rando/ObjectBehavior/ObjectBehavior.cpp +++ b/src/port/Rando/ObjectBehavior/ObjectBehavior.cpp @@ -244,7 +244,6 @@ static void FireClearBundleDespawnQueue() { // Entry point for the module, run once on game boot void Rando::ObjectBehavior::Init() { InitBundleBehavior(); - InitJiggyBehavior(); InitJinjoBehavior(); InitStopNSwopBehavior(); diff --git a/src/port/Rando/ObjectBehavior/ObjectBehavior.h b/src/port/Rando/ObjectBehavior/ObjectBehavior.h index e1bc21f50..937242c68 100644 --- a/src/port/Rando/ObjectBehavior/ObjectBehavior.h +++ b/src/port/Rando/ObjectBehavior/ObjectBehavior.h @@ -14,7 +14,6 @@ namespace ObjectBehavior { void Init(); void InitBundleBehavior(); -void InitJiggyBehavior(); void InitJinjoBehavior(); void InitStopNSwopBehavior(); From 3ea92cda46a6405810b4ad146a599c69753d14de Mon Sep 17 00:00:00 2001 From: aMannus Date: Wed, 5 Aug 2026 22:14:46 +0200 Subject: [PATCH 121/131] Fix build post merge --- include/functions.h | 3 --- src/port/Network/Anchor/HookHandlers.cpp | 18 ------------------ .../Network/Anchor/Packets/SetCheckStatus.cpp | 4 ++-- .../Network/Anchor/Packets/UpdateTeamState.cpp | 2 +- .../CustomCollectible/CustomCollectible.cpp | 4 ++-- src/port/Rando/ItemQueue.cpp | 1 + src/port/Rando/Logic/GenerateSaveData.cpp | 2 +- src/port/Rando/MiscBehavior/WorldState.cpp | 4 ++-- .../Rando/ObjectBehavior/ObjectBehavior.cpp | 8 +++++--- 9 files changed, 14 insertions(+), 32 deletions(-) diff --git a/include/functions.h b/include/functions.h index c2c425052..8222da5b3 100644 --- a/include/functions.h +++ b/include/functions.h @@ -3492,7 +3492,4 @@ void codeCF5F0_triggerAntiTamperMeasurement(void); } #endif -// --- port/TooieJiggyDance.cpp -void spawnOrbit(); - #endif // FUNCTIONS_H diff --git a/src/port/Network/Anchor/HookHandlers.cpp b/src/port/Network/Anchor/HookHandlers.cpp index 58f1c8921..6963775f7 100644 --- a/src/port/Network/Anchor/HookHandlers.cpp +++ b/src/port/Network/Anchor/HookHandlers.cpp @@ -517,24 +517,6 @@ void Anchor::RegisterHooks() { anchor->SendPacket_SetCheckStatus((s32)ev->randoCheckId, (s32)ev->map); }); - COND_HOOK(SetRandoInfFlag, EVENT_PRIORITY_NORMAL, isConnected, [](IEvent* event) { - auto* anchor = Anchor::GetInstance(); - if (!anchor->IsSaveLoaded() || !anchor->roomState.syncItemsAndFlags) { - return; - } - auto ev = reinterpret_cast(event); - if (!ev->flagState) { - return; - } - switch (ev->flagId) { - case RANDO_INF_BRIDGE_REPAIRED_DIALOG_COMPLETE: - anchor->SendPacket_SetFlag((u8)ANCHOR_FLAGSPACE_RANDO_INF, (s16)ev->flagId); - break; - default: - break; - } - }); - COND_HOOK(OnJiggySpawned, EVENT_PRIORITY_NORMAL, isConnected, [](IEvent* event) { auto* anchor = Anchor::GetInstance(); if (!anchor->IsSaveLoaded() || !anchor->roomState.syncItemsAndFlags) { diff --git a/src/port/Network/Anchor/Packets/SetCheckStatus.cpp b/src/port/Network/Anchor/Packets/SetCheckStatus.cpp index 38c992f12..74e9a4698 100644 --- a/src/port/Network/Anchor/Packets/SetCheckStatus.cpp +++ b/src/port/Network/Anchor/Packets/SetCheckStatus.cpp @@ -40,7 +40,7 @@ void Anchor::SendPacket_SetCheckStatus(s32 rc, s32 map) { // notification, or re-broadcast). void Anchor::AdoptRemoteCheck(s32 rcRaw) { RandoCheckId rc = (RandoCheckId)rcRaw; - if (rc <= RC_UNKNOWN || rc >= RC_MAX || RANDO_SAVE_CHECKS[rc].obtained) { + if (rc <= RC_UNKNOWN || rc >= RC_MAX || RANDO_SAVE_CHECKS[rc].eligible) { return; } if (CustomObject::CheckSpawnedIdList(rc)) { @@ -63,7 +63,7 @@ void Anchor::HandlePacket_SetCheckStatus(nlohmann::json& payload) { if (rc <= RC_UNKNOWN || rc >= RC_MAX) { return; } - if (RANDO_SAVE_CHECKS[rc].obtained) { + if (RANDO_SAVE_CHECKS[rc].eligible) { return; } diff --git a/src/port/Network/Anchor/Packets/UpdateTeamState.cpp b/src/port/Network/Anchor/Packets/UpdateTeamState.cpp index f2e568bd4..380097a40 100644 --- a/src/port/Network/Anchor/Packets/UpdateTeamState.cpp +++ b/src/port/Network/Anchor/Packets/UpdateTeamState.cpp @@ -81,7 +81,7 @@ void Anchor::SendPacket_UpdateTeamState() { if (IS_RANDO) { std::vector checks(RC_MAX, 0); for (s32 rc = RC_UNKNOWN + 1; rc < RC_MAX; rc++) { - checks[rc] = RANDO_SAVE_CHECKS[rc].obtained ? 1 : 0; + checks[rc] = RANDO_SAVE_CHECKS[rc].eligible ? 1 : 0; } payload["state"]["randoChecks"] = checks; diff --git a/src/port/Rando/CustomCollectible/CustomCollectible.cpp b/src/port/Rando/CustomCollectible/CustomCollectible.cpp index 63eee11ce..af64e9f1e 100644 --- a/src/port/Rando/CustomCollectible/CustomCollectible.cpp +++ b/src/port/Rando/CustomCollectible/CustomCollectible.cpp @@ -11,7 +11,7 @@ extern "C" { #include "actor.h" void __chJinjo_802CDC9C(Actor* thisx, s16 arg1); Actor* func_802D94B4(ActorMarker* marker, Gfx** gfx, Mtx** mtx, Vtx** vtx); -Actor* func_802D41C4(ActorMarker* marker, Gfx** gfx, Mtx** mtx, Vtx** vtx); +Actor* chSnsEgg_draw(ActorMarker* marker, Gfx** gfx, Mtx** mtx, Vtx** vtx); } static std::queue propQueue; @@ -212,7 +212,7 @@ ActorInfo CustomCollectible::GetActorAndDrawInfo(RandoItemId randoItemId) { collectibleInfo.startAnimation = 3; break; case CCT_VANILLA_SNS_EGG: - collectibleInfo.draw_func = func_802D41C4; + collectibleInfo.draw_func = chSnsEgg_draw; break; case CCT_CUSTOM_MODEL: collectibleInfo.draw_func = CustomCollectible_DrawCustomModel; diff --git a/src/port/Rando/ItemQueue.cpp b/src/port/Rando/ItemQueue.cpp index cbc7e966d..eb56829b2 100644 --- a/src/port/Rando/ItemQueue.cpp +++ b/src/port/Rando/ItemQueue.cpp @@ -28,6 +28,7 @@ extern ActorInfo chJinjoGreen; extern ActorInfo chJinjoYellow; extern ActorInfo chJinjoPink; extern ActorInfo chJinjoOrange; +extern void spawnOrbit(); } #define CVAR_NAME_SHOW_COLLISION_NOTIFICATIONS "gRandoSettings.RandoNotifications" diff --git a/src/port/Rando/Logic/GenerateSaveData.cpp b/src/port/Rando/Logic/GenerateSaveData.cpp index 00210e042..2106f2302 100644 --- a/src/port/Rando/Logic/GenerateSaveData.cpp +++ b/src/port/Rando/Logic/GenerateSaveData.cpp @@ -191,7 +191,7 @@ void Rando::Logic::GrantSpiralMountainChecks() { } CustomObject::CheckObtainedEX(smCheckId, true); - if (randoSaveCheck.randoItemId == RI_MOLEHILL) { + if (Rando::StaticData::Items[randoSaveCheck.randoItemId].randoItemType == RITYPE_MOLEHILL) { ability_setLearned((ability_e)randoSaveCheck.randoCollectionId, true); ability_setHasUsed((ability_e)randoSaveCheck.randoCollectionId); } diff --git a/src/port/Rando/MiscBehavior/WorldState.cpp b/src/port/Rando/MiscBehavior/WorldState.cpp index ed7869bd2..e42d8c144 100644 --- a/src/port/Rando/MiscBehavior/WorldState.cpp +++ b/src/port/Rando/MiscBehavior/WorldState.cpp @@ -176,7 +176,7 @@ void Rando::MiscBehavior::InitWorldStateBehavior() { if (ev->jiggyId == JIGGY_37_LAIR_BGS_WITCH_SWITCH) { if (currenLevel == LEVEL_6_LAIR) { event->Cancelled = true; - ev->result = RANDO_SAVE_CHECKS[RC_GL_JIGGY_WITCH_SWITCH_BUBBLEGLOOP_SWAMP].obtained; + ev->result = RANDO_SAVE_CHECKS[RC_GL_JIGGY_WITCH_SWITCH_BUBBLEGLOOP_SWAMP].eligible; break; } } @@ -211,7 +211,7 @@ void Rando::MiscBehavior::InitWorldStateBehavior() { ev->result = RANDO_SAVE_FLAGS[RANDO_INF_MINIGAME_RINGS_COMPLETED].flagState || CustomObject::CheckSpawnedIdList(randoCheckId); } else { - ev->result = CustomObject::CheckSpawnedIdList(randoCheckId) || RANDO_SAVE_CHECKS[randoCheckId].obtained; + ev->result = CustomObject::CheckSpawnedIdList(randoCheckId) || RANDO_SAVE_CHECKS[randoCheckId].eligible; } } }) diff --git a/src/port/Rando/ObjectBehavior/ObjectBehavior.cpp b/src/port/Rando/ObjectBehavior/ObjectBehavior.cpp index 22a75bb77..2ee25e137 100644 --- a/src/port/Rando/ObjectBehavior/ObjectBehavior.cpp +++ b/src/port/Rando/ObjectBehavior/ObjectBehavior.cpp @@ -164,12 +164,14 @@ static void EmitCheckNotification(RandoCheckId randoCheckId, const std::string& std::string prefix; std::string message; std::string suffix = ""; - ImVec4 itemColor = WIDGET_TEXT_COLOR(randoItemColors.at(randoSaveCheck.randoItemId)); + ImVec4 itemColor = + WIDGET_TEXT_COLOR(randoItemColors.at((actor_e)Rando::StaticData::Items[randoSaveCheck.randoItemId].actorId)); + RandoItemType itemType = Rando::StaticData::Items[randoSaveCheck.randoItemId].randoItemType; - if (randoSaveCheck.randoItemId == RI_MOLEHILL) { + if (itemType == RITYPE_MOLEHILL) { prefix = subject + " learned"; message = abilityNameList[randoSaveCheck.randoCollectionId].c_str(); - } else if (randoSaveCheck.randoItemId == RI_STOP_N_SWOP_EGG || randoSaveCheck.randoItemId == RI_STOP_N_SWOP_KEY) { + } else if (itemType == RITYPE_SNS_EGG || itemType == RITYPE_SNS_KEY) { int32_t totalsnsItems = Rando::Logic::GetTotalSnsItemsCollected(); prefix = subject + " collected "; prefix += Rando::StaticData::Items[randoSaveCheck.randoItemId].article; From a0a335d66c818139a747faa706645c31566f0367 Mon Sep 17 00:00:00 2001 From: aMannus Date: Thu, 6 Aug 2026 18:28:14 +0200 Subject: [PATCH 122/131] Fix jiggies, implement jinjos --- .../CustomCollectible/CustomCollectible.cpp | 21 +------ src/port/Rando/ItemQueue.cpp | 1 + src/port/Rando/ObjectBehavior/Jiggy.cpp | 54 ++++++++++-------- src/port/Rando/ObjectBehavior/Jinjo.cpp | 57 +++++++++++-------- src/port/Rando/ObjectBehavior/Molehill.cpp | 2 +- .../Rando/ObjectBehavior/ObjectBehavior.cpp | 10 ---- .../Rando/ObjectBehavior/ObjectBehavior.h | 1 - 7 files changed, 68 insertions(+), 78 deletions(-) diff --git a/src/port/Rando/CustomCollectible/CustomCollectible.cpp b/src/port/Rando/CustomCollectible/CustomCollectible.cpp index af64e9f1e..6975abb6e 100644 --- a/src/port/Rando/CustomCollectible/CustomCollectible.cpp +++ b/src/port/Rando/CustomCollectible/CustomCollectible.cpp @@ -36,30 +36,17 @@ std::unordered_map customCollectibleDrawInfo }; ActorAnimationInfo moleAnimations[] = { - { 0, 0.0f }, - { ASSET_13A_ANIM_BOTTLES_ENTER, 2000000000.0f }, - { ASSET_13A_ANIM_BOTTLES_ENTER, 4.5f }, { ASSET_13B_ANIM_BOTTLES_IDLE, 7.0f }, - { ASSET_139_ANIM_BOTTLES_EXIT, 1.7f }, - { ASSET_13A_ANIM_BOTTLES_ENTER, 2000000000.0f }, }; -ActorAnimationInfo chJinjoAnimations[] = { { 0, 0.0f }, - { ASSET_2D_ANIM_JINJO_IDLE, 1000000.0f }, - { ASSET_2D_ANIM_JINJO_IDLE, 1.5f }, - { ASSET_2F_ANIM_JINJO_HELP, 1.5f }, - { ASSET_31_ANIM_JINJO_JUMP, 0.75f }, - { ASSET_2D_ANIM_JINJO_IDLE, 1000000.0f }, - { ASSET_31_ANIM_JINJO_JUMP, 0.4f }, - { ASSET_130_ANIM_JINJO_FLY_START, 1.75f }, - { ASSET_131_ANIM_JINJO_FLY_END, 2.13333f }, - { ASSET_31_ANIM_JINJO_JUMP, 0.75f }, +ActorAnimationInfo chJinjoAnimations[] = { + { ASSET_2F_ANIM_JINJO_HELP, 1.5f }, }; ActorInfo customActorInfo = { MARKER_300_CUSTOM_COLLECTIBLE, ACTOR_3CD_CUSTOM_COLLECTIBLE, ASSET_0_NONE, - 1, + 0, NULL, CustomCollectible_Update, NULL, @@ -204,12 +191,10 @@ ActorInfo CustomCollectible::GetActorAndDrawInfo(RandoItemId randoItemId) { case CCT_JINJO: collectibleInfo.draw_func = actor_draw; collectibleInfo.animations = chJinjoAnimations; - collectibleInfo.startAnimation = 3; break; case CCT_MOLEHILL: collectibleInfo.draw_func = func_802D94B4; collectibleInfo.animations = moleAnimations; - collectibleInfo.startAnimation = 3; break; case CCT_VANILLA_SNS_EGG: collectibleInfo.draw_func = chSnsEgg_draw; diff --git a/src/port/Rando/ItemQueue.cpp b/src/port/Rando/ItemQueue.cpp index eb56829b2..489366502 100644 --- a/src/port/Rando/ItemQueue.cpp +++ b/src/port/Rando/ItemQueue.cpp @@ -69,6 +69,7 @@ void ItemQueue::Process() { if (!randoSaveCheck.received) { ItemQueue::GiveItem(randoSaveCheck.randoItemId); ItemQueue::SendNotification(randoSaveCheck.randoItemId); + Rando::StaticData::ModifyRandoInfFlagState(randoCheckId); randoSaveCheck.received = true; } diff --git a/src/port/Rando/ObjectBehavior/Jiggy.cpp b/src/port/Rando/ObjectBehavior/Jiggy.cpp index 2d7815c99..f473113af 100644 --- a/src/port/Rando/ObjectBehavior/Jiggy.cpp +++ b/src/port/Rando/ObjectBehavior/Jiggy.cpp @@ -7,26 +7,6 @@ #define OPTION_ENABLED RANDO_SAVE_OPTIONS[RO_SHUFFLE_JIGGIES].optionValue -// Some jiggies double as the world's only memory of what opened them up: raising -// Clanker and finishing his rings are both recalled purely from -// jiggyscore_isSpawned on the jiggy that appeared. Vanilla records that in -// jiggy_spawn via jiggyscore_setSpawned, which the override below never reaches, -// and the check-obtained path only fires once the reward is actually picked up. -static void MarkWorldStateFromJiggySpawn(RandoCheckId randoCheckId) { - RandoInf randoInfFlag = RANDO_INF_UNKNOWN; - switch (randoCheckId) { - case RC_CC_JIGGY_CLANKER_RAISED: - randoInfFlag = RANDO_INF_CLANKER_RAISED; - break; - case RC_CC_JIGGY_RINGS: - randoInfFlag = RANDO_INF_MINIGAME_RINGS_COMPLETED; - break; - default: - return; - } - CALL_EVENT(SetRandoInfFlag, randoInfFlag, 1); -} - bool OverrideJiggySpawn(f32 position[3], jiggy_e jiggyId) { RandoCheckId randoCheckId = Rando::StaticData::GetCheckByJiggyId(jiggyId); @@ -46,9 +26,26 @@ bool OverrideJiggySpawn(f32 position[3], jiggy_e jiggyId) { if (jiggyId != JIGGY_17_CC_CLANKER_RAISED && jiggyId != JIGGY_1B_CC_TOOTH) { ApplyCustomActorPhysics(randoCheckId, actor, false); } - // Stand in for the jiggyscore_setSpawned this override skips, for the - // jiggies the world reads back as state rather than as a collectable. - MarkWorldStateFromJiggySpawn(randoCheckId); + return true; +} + +bool OverrideJiggyActorSpawn(OnActorSpawn* ev) { + if (ev->actorId != ACTOR_46_JIGGY) { + return false; + } + + int32_t spawnPosition[3] = { ev->posX, ev->posY, ev->posZ }; + RandoCheckId randoCheckId = Rando::StaticData::GetCheckByPosition(ev->posX, ev->posY, ev->posZ); + + if (randoCheckId == RC_UNKNOWN || !Rando::Logic::IsCheckShuffled(randoCheckId)) { + return false; + } + + if (Rando::Logic::IsCheckObtained(randoCheckId)) { + return true; + } + + CustomCollectible::Spawn(spawnPosition, randoCheckId); return true; } @@ -59,6 +56,8 @@ void RegisterRandoJiggies() { } }); + // Jiggies can be spawned through 2 separate code paths, that's why there's 2 hooks with slight + // variations on how it identifies the jiggy. COND_VB_SHOULD(VB_OVERRIDE_JIGGY_SPAWN, EVENT_PRIORITY_NORMAL, IS_RANDO && OPTION_ENABLED, { jiggy_e jiggyId = (jiggy_e)va_arg(args, int); f32* position = va_arg(args, f32*); @@ -68,6 +67,15 @@ void RegisterRandoJiggies() { *should = true; } }); + + COND_HOOK(OnActorSpawn, EVENT_PRIORITY_NORMAL, IS_RANDO && OPTION_ENABLED, [](IEvent* event) { + OnActorSpawn* ev = (OnActorSpawn*)event; + + bool replaceJiggy = OverrideJiggyActorSpawn(ev); + if (replaceJiggy) { + event->Cancelled = true; + } + }); } static RegisterShipInitFunc initFunc(RegisterRandoJiggies, { "IS_RANDO" }); diff --git a/src/port/Rando/ObjectBehavior/Jinjo.cpp b/src/port/Rando/ObjectBehavior/Jinjo.cpp index 026e61f39..e65930bcd 100644 --- a/src/port/Rando/ObjectBehavior/Jinjo.cpp +++ b/src/port/Rando/ObjectBehavior/Jinjo.cpp @@ -1,12 +1,7 @@ -#include "ObjectBehavior.h" -#include "port/Rando/Logic/Logic.h" -#include "port/Rando/CustomObject/CustomObject.h" - -#include -#include "port/UI/cvar_prefixes.h" -#include -#include "port/Enhancements/Events/PortEnhancements.h" +#include "port/ShipInit.hpp" #include "port/Enhancements/Events/Hooks/Events.h" +#include "port/Rando/Logic/Logic.h" +#include "port/Rando/CustomCollectible/CustomCollectible.h" extern "C" { s32 item_adjustByDiffWithHud(enum item_e item, s32 diff); @@ -14,29 +9,41 @@ s32 item_adjustByDiffWithHud(enum item_e item, s32 diff); #define OPTION_ENABLED RANDO_SAVE_OPTIONS[RO_SHUFFLE_JINJOS].optionValue -void Rando::ObjectBehavior::InitJinjoBehavior() { - COND_HOOK(OnSetJiggyList, EVENT_PRIORITY_NORMAL, IS_RANDO && OPTION_ENABLED, [](IEvent* event) { - OnSetJiggyList* ev = (OnSetJiggyList*)event; +bool OverrideJinjoSpawn(OnActorSpawn* ev) { + if (ev->actorId != ACTOR_5E_JINJO_YELLOW && ev->actorId != ACTOR_5F_JINJO_ORANGE && + ev->actorId != ACTOR_60_JINJO_BLUE && ev->actorId != ACTOR_61_JINJO_PINK && + ev->actorId != ACTOR_62_JINJO_GREEN) { + return false; + } - for (auto& location : Rando::Logic::shuffledPool) { - if (!location.eligible) { - continue; - } + int32_t spawnPosition[3] = { ev->posX, ev->posY, ev->posZ }; + RandoCheckId randoCheckId = Rando::StaticData::GetCheckByPosition(ev->posX, ev->posY, ev->posZ); - Rando::StaticData::RandoStaticItem randoItem = Rando::StaticData::Items[location.randoItemId]; + if (randoCheckId == RC_UNKNOWN || !Rando::Logic::IsCheckShuffled(randoCheckId)) { + return false; + } - if (randoItem.worldId != ev->levelId) { - continue; - } + if (Rando::Logic::IsCheckObtained(randoCheckId)) { + return true; + } - if (randoItem.randoItemType == RITYPE_JINJO) { - int32_t jinjoMarkerId = GetJinjoActorMarkerId((actor_e)randoItem.actorId); - item_adjustByDiffWithHud(ITEM_12_JINJOS, (1 << ((jinjoMarkerId + 6) & 0x1F))); - } - } - }) + CustomCollectible::Spawn(spawnPosition, randoCheckId); + return true; +} +void RegisterRandoJinjos() { COND_VB_SHOULD(VB_UPDATE_JINJO_HUD, EVENT_PRIORITY_NORMAL, IS_RANDO && OPTION_ENABLED, { *should = true; }) COND_VB_SHOULD(VB_SET_JINJO_COUNT, EVENT_PRIORITY_NORMAL, IS_RANDO && OPTION_ENABLED, { *should = true; }) + + COND_HOOK(OnActorSpawn, EVENT_PRIORITY_NORMAL, IS_RANDO && OPTION_ENABLED, [](IEvent* event) { + OnActorSpawn* ev = (OnActorSpawn*)event; + + bool replaceJinjo = OverrideJinjoSpawn(ev); + if (replaceJinjo) { + event->Cancelled = true; + } + }); } + +static RegisterShipInitFunc initFunc(RegisterRandoJinjos, { "IS_RANDO" }); diff --git a/src/port/Rando/ObjectBehavior/Molehill.cpp b/src/port/Rando/ObjectBehavior/Molehill.cpp index 581dafb22..477d44505 100644 --- a/src/port/Rando/ObjectBehavior/Molehill.cpp +++ b/src/port/Rando/ObjectBehavior/Molehill.cpp @@ -38,7 +38,7 @@ bool CheckBridgeState() { } bool OverrideMoleSpawn(OnActorSpawn* ev) { - if (ev->actorId != ACTOR_12B_TUTORIAL_BOTTLES) { + if (ev->actorId != ACTOR_12B_TUTORIAL_BOTTLES && ev->actorId != ACTOR_37A_BOTTLES) { return false; } diff --git a/src/port/Rando/ObjectBehavior/ObjectBehavior.cpp b/src/port/Rando/ObjectBehavior/ObjectBehavior.cpp index 2ee25e137..744a71fe2 100644 --- a/src/port/Rando/ObjectBehavior/ObjectBehavior.cpp +++ b/src/port/Rando/ObjectBehavior/ObjectBehavior.cpp @@ -20,18 +20,9 @@ std::map> randoSaveState; // clang-format off std::vector actorSpawnWhitelist = { - ACTOR_2D_MUMBO_TOKEN, - ACTOR_46_JIGGY, ACTOR_47_EMPTY_HONEYCOMB, ACTOR_49_EXTRA_LIFE, ACTOR_50_HONEYCOMB, - ACTOR_51_MUSIC_NOTE, - ACTOR_52_BLUE_EGG, - ACTOR_5E_JINJO_YELLOW, - ACTOR_5F_JINJO_ORANGE, - ACTOR_60_JINJO_BLUE, - ACTOR_61_JINJO_PINK, - ACTOR_62_JINJO_GREEN, ACTOR_25E_SNS_EGG, ACTOR_25D_ICE_KEY, //ACTOR_12C_MOLEHILL, @@ -251,7 +242,6 @@ static void FireClearBundleDespawnQueue() { // Entry point for the module, run once on game boot void Rando::ObjectBehavior::Init() { InitBundleBehavior(); - InitJinjoBehavior(); InitStopNSwopBehavior(); UpdateJunkList(); diff --git a/src/port/Rando/ObjectBehavior/ObjectBehavior.h b/src/port/Rando/ObjectBehavior/ObjectBehavior.h index 937242c68..a0ecfff3e 100644 --- a/src/port/Rando/ObjectBehavior/ObjectBehavior.h +++ b/src/port/Rando/ObjectBehavior/ObjectBehavior.h @@ -14,7 +14,6 @@ namespace ObjectBehavior { void Init(); void InitBundleBehavior(); -void InitJinjoBehavior(); void InitStopNSwopBehavior(); void ModifySwitchBehavior(int32_t switchActorId); From 8de6f2f647334135834f8b38dee8bd60ccadf4e2 Mon Sep 17 00:00:00 2001 From: aMannus Date: Fri, 7 Aug 2026 12:30:55 +0200 Subject: [PATCH 123/131] Finish jinjos --- .../Enhancements/Retention/JinjoRetention.cpp | 6 ++-- src/port/Enhancements/Retention/Retention.h | 4 +++ src/port/Rando/ItemQueue.cpp | 33 ++++++++++++++++--- src/port/Rando/ObjectBehavior/Jinjo.cpp | 9 +++++ 4 files changed, 44 insertions(+), 8 deletions(-) diff --git a/src/port/Enhancements/Retention/JinjoRetention.cpp b/src/port/Enhancements/Retention/JinjoRetention.cpp index d820e8510..e280ed9e5 100644 --- a/src/port/Enhancements/Retention/JinjoRetention.cpp +++ b/src/port/Enhancements/Retention/JinjoRetention.cpp @@ -58,12 +58,12 @@ static bool levelInRange(int32_t level) { return level > 0 && level < JINJO_RETENTION_LEVEL_SLOTS; } -static u8 collectedBits(int32_t level) { +uint8_t collectedBits(int32_t level) { JinjoRetentionSaveData* s = store(); return (s != nullptr && levelInRange(level)) ? s->collected[level] : 0; } -static void setCollectedBits(int32_t level, u8 bits) { +void setCollectedBits(int32_t level, u8 bits) { JinjoRetentionSaveData* s = store(); if (s != nullptr && levelInRange(level)) { s->collected[level] = bits; @@ -87,7 +87,7 @@ static u8 jinjoBitFromMarker(int32_t markerId) { } } -static u8 jinjoBitFromActor(int32_t actorId) { +uint8_t jinjoBitFromActor(int32_t actorId) { switch (actorId) { case ACTOR_60_JINJO_BLUE: return 1 << 0; diff --git a/src/port/Enhancements/Retention/Retention.h b/src/port/Enhancements/Retention/Retention.h index 140dbbc7b..63a19352a 100644 --- a/src/port/Enhancements/Retention/Retention.h +++ b/src/port/Enhancements/Retention/Retention.h @@ -62,6 +62,10 @@ int32_t port_carriedSync_consumeRemoteDespawn(int32_t kind, void* marker); int32_t port_carriedSync_collectedCount(int32_t kind); +void setCollectedBits(int32_t level, u8 bits); +uint8_t jinjoBitFromActor(int32_t actorId); +uint8_t collectedBits(int32_t level); + #ifdef __cplusplus } diff --git a/src/port/Rando/ItemQueue.cpp b/src/port/Rando/ItemQueue.cpp index 489366502..44b2a4a39 100644 --- a/src/port/Rando/ItemQueue.cpp +++ b/src/port/Rando/ItemQueue.cpp @@ -10,6 +10,7 @@ #include "port/ShipInit.hpp" #include "port/Rando/Logic/Logic.h" #include "actor.h" +#include "port/Enhancements/Retention/Retention.h" extern "C" { #include "functions.h" @@ -31,6 +32,8 @@ extern ActorInfo chJinjoOrange; extern void spawnOrbit(); } +constexpr u8 kAllJinjos = 0x1F; // all five color bits collected + #define CVAR_NAME_SHOW_COLLISION_NOTIFICATIONS "gRandoSettings.RandoNotifications" #define CVAR_SHOW_COLLISION_NOTIFICATIONS CVarGetInteger(CVAR_NAME_SHOW_COLLISION_NOTIFICATIONS, 0) @@ -39,7 +42,7 @@ extern void spawnOrbit(); static std::queue itemQueue; -std::map itemColors = { +std::unordered_map itemColors = { { ACTOR_1_UNKNOWN, UIWidgets::Colors::Brown }, { ACTOR_52_BLUE_EGG, UIWidgets::Colors::Cyan }, { ACTOR_47_EMPTY_HONEYCOMB, UIWidgets::Colors::Yellow }, { ACTOR_49_EXTRA_LIFE, UIWidgets::Colors::Yellow }, { ACTOR_50_HONEYCOMB, UIWidgets::Colors::Yellow }, { ACTOR_46_JIGGY, UIWidgets::Colors::Yellow }, @@ -50,13 +53,21 @@ std::map itemColors = { { ACTOR_25E_SNS_EGG, UIWidgets::Colors::Pink }, { ACTOR_25D_ICE_KEY, UIWidgets::Colors::White }, }; -std::map snsColors = { +std::unordered_map snsColors = { { RI_STOP_N_SWOP_EGG_YELLOW, UIWidgets::Colors::Yellow }, { RI_STOP_N_SWOP_EGG_RED, UIWidgets::Colors::Red }, { RI_STOP_N_SWOP_EGG_GREEN, UIWidgets::Colors::Green }, { RI_STOP_N_SWOP_EGG_BLUE, UIWidgets::Colors::Blue }, { RI_STOP_N_SWOP_EGG_PINK, UIWidgets::Colors::Pink }, { RI_STOP_N_SWOP_EGG_CYAN, UIWidgets::Colors::Cyan }, { RI_STOP_N_SWOP_ICE_KEY, UIWidgets::Colors::White }, }; +std::unordered_map jinjoJiggyChecks = { + { LEVEL_1_MUMBOS_MOUNTAIN, RC_MM_JIGGY_JINJO }, { LEVEL_2_TREASURE_TROVE_COVE, RC_TTC_JIGGY_JINJO }, + { LEVEL_3_CLANKERS_CAVERN, RC_CC_JIGGY_JINJO }, { LEVEL_4_BUBBLEGLOOP_SWAMP, RC_BGS_JIGGY_JINJO }, + { LEVEL_5_FREEZEEZY_PEAK, RC_FP_JIGGY_JINJO }, { LEVEL_7_GOBIS_VALLEY, RC_GV_JIGGY_JINJO }, + { LEVEL_8_CLICK_CLOCK_WOOD, RC_CCW_JIGGY_JINJO }, { LEVEL_9_RUSTY_BUCKET_BAY, RC_RBB_JIGGY_JINJO }, + { LEVEL_A_MAD_MONSTER_MANSION, RC_MMM_JIGGY_JINJO }, +}; + void ItemQueue::Process() { if (itemQueue.size() < 1) { return; @@ -70,7 +81,7 @@ void ItemQueue::Process() { ItemQueue::GiveItem(randoSaveCheck.randoItemId); ItemQueue::SendNotification(randoSaveCheck.randoItemId); Rando::StaticData::ModifyRandoInfFlagState(randoCheckId); - randoSaveCheck.received = true; + //RANDO_SAVE_CHECKS[randoCheckId].received = true; } itemQueue.pop(); @@ -86,6 +97,7 @@ void ItemQueue::GiveItem(RandoItemId randoItemId) { ActorInfo* actorInfo; int32_t playerPosition[3]; Actor* customActor; + uint8_t collectedJinjos; switch (itemType) { case RITYPE_BLUE_EGG: @@ -131,6 +143,17 @@ void ItemQueue::GiveItem(RandoItemId randoItemId) { spawnOrbit(); break; case RITYPE_JINJO: + if (worldId == map_getLevel(gsworld_getMap())) { + item_adjustByDiffWithHud(ITEM_12_JINJOS, jinjoBitFromActor(actorId)); + } + collectedJinjos = collectedBits(worldId); + collectedJinjos |= jinjoBitFromActor(actorId); + if (collectedJinjos == kAllJinjos) { + ItemQueue::AddCheck(jinjoJiggyChecks[worldId]); + } + setCollectedBits(worldId, collectedJinjos); + // Spawn vanilla jinjo on top of the player because the animation is too complex to handle without doing + // this. Collection behaviour is canceled in Jinjo.cpp so that part can all be handled here in the ItemQueue. switch (actorId) { case ACTOR_5E_JINJO_YELLOW: actorInfo = &chJinjoYellow; @@ -270,7 +293,7 @@ void ItemQueue::SendNotification(RandoItemId randoItemId) { std::string prefix = ""; std::string message = Rando::StaticData::Items[randoItemId].name; std::string suffix = ""; - ImVec4 itemColor = UIWidgets::ColorValues.at(itemColors.at(actorId)); + ImVec4 itemColor = UIWidgets::ColorValues.at(itemColors[actorId]); if (itemType == RITYPE_MOLEHILL) { prefix = "You learned"; @@ -282,7 +305,7 @@ void ItemQueue::SendNotification(RandoItemId randoItemId) { suffix += std::to_string(totalsnsItems); suffix += " / 7)"; - itemColor = UIWidgets::ColorValues.at(snsColors.at(randoItemId)); + itemColor = UIWidgets::ColorValues.at(snsColors[randoItemId]); } else { prefix = "You collected "; prefix += Rando::StaticData::Items[randoItemId].article; diff --git a/src/port/Rando/ObjectBehavior/Jinjo.cpp b/src/port/Rando/ObjectBehavior/Jinjo.cpp index e65930bcd..af6f4134d 100644 --- a/src/port/Rando/ObjectBehavior/Jinjo.cpp +++ b/src/port/Rando/ObjectBehavior/Jinjo.cpp @@ -2,6 +2,7 @@ #include "port/Enhancements/Events/Hooks/Events.h" #include "port/Rando/Logic/Logic.h" #include "port/Rando/CustomCollectible/CustomCollectible.h" +#include "port/Enhancements/Retention/Retention.h" extern "C" { s32 item_adjustByDiffWithHud(enum item_e item, s32 diff); @@ -36,6 +37,14 @@ void RegisterRandoJinjos() { COND_VB_SHOULD(VB_SET_JINJO_COUNT, EVENT_PRIORITY_NORMAL, IS_RANDO && OPTION_ENABLED, { *should = true; }) + COND_HOOK(OnSetJiggyList, EVENT_PRIORITY_NORMAL, IS_RANDO && OPTION_ENABLED, [](IEvent* event) { + OnSetJiggyList* ev = (OnSetJiggyList*)event; + u8 bits = collectedBits(ev->levelId); + if (bits != 0) { + item_adjustByDiffWithoutHud(ITEM_12_JINJOS, bits - item_getCount(ITEM_12_JINJOS)); + } + }); + COND_HOOK(OnActorSpawn, EVENT_PRIORITY_NORMAL, IS_RANDO && OPTION_ENABLED, [](IEvent* event) { OnActorSpawn* ev = (OnActorSpawn*)event; From 55d17e54e33c5d6d803b78c8526c44736dba9abe Mon Sep 17 00:00:00 2001 From: aMannus Date: Fri, 7 Aug 2026 14:38:54 +0200 Subject: [PATCH 124/131] implement bundles + mumbo tokens --- src/port/Rando/ObjectBehavior/Bundle.cpp | 1048 ++++++++--------- src/port/Rando/ObjectBehavior/Jinjo.cpp | 7 +- src/port/Rando/ObjectBehavior/MumboToken.cpp | 38 + .../Rando/ObjectBehavior/ObjectBehavior.cpp | 2 - .../Rando/ObjectBehavior/ObjectBehavior.h | 2 - 5 files changed, 545 insertions(+), 552 deletions(-) create mode 100644 src/port/Rando/ObjectBehavior/MumboToken.cpp diff --git a/src/port/Rando/ObjectBehavior/Bundle.cpp b/src/port/Rando/ObjectBehavior/Bundle.cpp index ccf206471..ce2576879 100644 --- a/src/port/Rando/ObjectBehavior/Bundle.cpp +++ b/src/port/Rando/ObjectBehavior/Bundle.cpp @@ -1,573 +1,533 @@ #include "ObjectBehavior.h" #include "port/Rando/Logic/Logic.h" #include "port/Rando/CustomObject/CustomObject.h" - -#include -#include "port/UI/cvar_prefixes.h" -#include -#include "port/Enhancements/Events/PortEnhancements.h" #include "port/Enhancements/Events/Hooks/Events.h" -#include "spdlog/spdlog.h" + +#include "port/ShipInit.hpp" +#include "port/Rando/CustomCollectible/CustomCollectible.h" extern "C" { extern f32 gBundle_yaw; - bool fileProgressFlag_get(enum file_progress_e index); -void marker_despawn(ActorMarker* marker); } -bool applyCustomPhysics = false; -std::vector bundleDespawnQueue; +typedef struct { + RandoCheckId randoCheckId; + bool customPhysics; +} RandoBundleInfo; + int32_t vileCount = 0; -void Rando::ObjectBehavior::DespawnCollectedBundles() { - if (bundleDespawnQueue.empty()) { - return; - } +RandoBundleInfo + IdentifyBundle(bundle_e bundleId, BundleInfo* bundleInfo, s32 bundleCount, f32 spawnPosition[3]) { + map_e currentMap = gsworld_getMap(); + level_e currentLevel = map_getLevel(currentMap); + s32 position[3] = { (int32_t)spawnPosition[0], (int32_t)spawnPosition[1], (int32_t)spawnPosition[2] }; + RandoBundleInfo randoBundleInfo; + randoBundleInfo.randoCheckId = RC_UNKNOWN; + randoBundleInfo.customPhysics = false; - for (auto& bundle : bundleDespawnQueue) { - marker_despawn(bundle); + switch (currentLevel) { + case LEVEL_1_MUMBOS_MOUNTAIN: + switch (bundleId) { + case BUNDLE_0_MM_HUT_MUSIC_NOTE: + randoBundleInfo.randoCheckId = (RandoCheckId)((int32_t)RC_MM_NOTE_HUT_BUNDLE_1 + bundleCount); + randoBundleInfo.customPhysics = true; + break; + case BUNDLE_1_MM_HUT_BLUE_EGG: + randoBundleInfo.randoCheckId = (RandoCheckId)((int32_t)RC_MM_BLUE_EGG_HUT_BUNDLE_1 + bundleCount); + randoBundleInfo.customPhysics = true; + break; + case BUNDLE_3_MM_HUT_JINJO_GREEN: + randoBundleInfo.randoCheckId = RC_MM_JINJO_GREEN; + randoBundleInfo.customPhysics = true; + break; + case BUNDLE_4_MM_HUT_JIGGY: + if (position[1] < 2000) { + randoBundleInfo.randoCheckId = RC_MM_JIGGY_ORANGE_PADS; + } else { + randoBundleInfo.randoCheckId = RC_MM_JIGGY_HUTS; + randoBundleInfo.customPhysics = true; + } + break; + case BUNDLE_6_MM_HUT_EXTRA_LIFE: + randoBundleInfo.randoCheckId = RC_MM_EXTRA_LIFE_HUT; + randoBundleInfo.customPhysics = true; + break; + case BUNDLE_7__JIGGY: + randoBundleInfo.randoCheckId = RC_MM_JIGGY_CHIMPY; + break; + case BUNDLE_10__JIGGY: + randoBundleInfo.randoCheckId = RC_MM_JIGGY_JUJU; + break; + case BUNDLE_15__JIGGY: + randoBundleInfo.randoCheckId = RC_MM_JIGGY_CONGA; + break; + case BUNDLE_18__HONEYCOMB: + if (position[1] < 400) { + randoBundleInfo.randoCheckId = + (RandoCheckId)((int32_t)RC_MM_HONEYCOMB_BEEHIVE_BY_BIG_BUTT_1 + bundleCount); + } else { + randoBundleInfo.randoCheckId = + (RandoCheckId)((int32_t)RC_MM_HONEYCOMB_BEEHIVE_BY_THE_HUTS_1 + bundleCount); + } + break; + default: + break; + } + break; + case LEVEL_2_TREASURE_TROVE_COVE: + switch (bundleId) { + case BUNDLE_4_MM_HUT_JIGGY: + randoBundleInfo.randoCheckId = RC_TTC_JIGGY_RED_X; + break; + case BUNDLE_7__JIGGY: + randoBundleInfo.randoCheckId = RC_TTC_JIGGY_BLUBBER; + break; + default: + break; + case BUNDLE_18__HONEYCOMB: + if (position[1] < 900 && position[1] > 890) { + randoBundleInfo.randoCheckId = + (RandoCheckId)((int32_t)RC_TTC_HONEYCOMB_BEEHIVE_NEAR_BLUBBERS_SHIP_1 + bundleCount); + } else if (position[1] < 1770 && position[1] > 1765) { + randoBundleInfo.randoCheckId = + (RandoCheckId)((int32_t)RC_TTC_HONEYCOMB_BEEHIVE_NEAR_THE_BACK_STAIRS_1 + bundleCount); + } else if (position[1] < 1910 && position[1] > 1905) { + randoBundleInfo.randoCheckId = + (RandoCheckId)((int32_t)RC_TTC_HONEYCOMB_BEEHIVE_IN_THE_CLIFFSIDE_POOL_1 + bundleCount); + } else if (position[1] < 875 && position[1] > 870) { + randoBundleInfo.randoCheckId = (RandoCheckId)((int32_t)RC_TTC_HONEYCOMB_BEEHIVE_ON_THE_BEACH_1 + bundleCount); + } + break; + } + break; + case LEVEL_3_CLANKERS_CAVERN: + switch (bundleId) { + case BUNDLE_10__JIGGY: + switch (position[1]) { + case 1536: + randoBundleInfo.randoCheckId = RC_CC_JIGGY_TOOTH; + break; + default: + randoBundleInfo.randoCheckId = RC_CC_JIGGY_RINGS; + break; + } + break; + case BUNDLE_18__HONEYCOMB: + if (position[1] < 1405 && position[1] > 1395) { + randoBundleInfo.randoCheckId = (RandoCheckId)((int32_t)RC_CC_HONEYCOMB_BEEHIVE_INSIDE_CLANKER_1 + bundleCount); + } else if (position[1] < 5495 && position[1] > 5490) { + randoBundleInfo.randoCheckId = + (RandoCheckId)((int32_t)RC_CC_HONEYCOMB_BEEHIVE_NEAR_THE_ENTRANCE_1 + bundleCount); + } else if (position[1] < 3820 && position[1] > 3810) { + randoBundleInfo.randoCheckId = + (RandoCheckId)((int32_t)RC_CC_HONEYCOMB_BEEHIVE_NEAR_THE_YELLOW_GRATES_1 + bundleCount); + } + break; + default: + break; + } + break; + case LEVEL_4_BUBBLEGLOOP_SWAMP: + switch (bundleId) { + case BUNDLE_6_MM_HUT_EXTRA_LIFE: + randoBundleInfo.randoCheckId = (RandoCheckId)((int32_t)RC_BGS_EXTRA_LIFE_MR_VILE_1 + vileCount); + vileCount++; + randoBundleInfo.customPhysics = true; + if (vileCount >= 3) { + vileCount = 0; + } + break; + case BUNDLE_7__JIGGY: + randoBundleInfo.randoCheckId = RC_BGS_JIGGY_CROCTUS; + break; + case BUNDLE_8__JIGGY: + randoBundleInfo.randoCheckId = RC_BGS_JIGGY_MR_VILE; + break; + case BUNDLE_9__JIGGY: + randoBundleInfo.randoCheckId = RC_BGS_JIGGY_TANKTUP; + break; + case BUNDLE_B_BGS_HUT_MUSIC_NOTE: + randoBundleInfo.randoCheckId = (RandoCheckId)((int32_t)RC_BGS_NOTE_HUT_BUNDLE_1 + bundleCount); + break; + case BUNDLE_C_BGS_HUT_JIGGY: + randoBundleInfo.randoCheckId = RC_BGS_JIGGY_HUTS; + break; + case BUNDLE_10__JIGGY: + switch (position[2]) { + case 49: + randoBundleInfo.randoCheckId = RC_BGS_JIGGY_ELEVATED_WALKWAY; + break; + case -1386: + randoBundleInfo.randoCheckId = RC_BGS_JIGGY_FLIBBITS; + break; + case 2799: + randoBundleInfo.randoCheckId = RC_BGS_JIGGY_PINKEGG; + break; + case -1020: + randoBundleInfo.randoCheckId = RC_BGS_JIGGY_TIPTUP; + break; + case -6148: + randoBundleInfo.randoCheckId = RC_BGS_JIGGY_MAZE; + break; + default: + break; + } + break; + case BUNDLE_18__HONEYCOMB: + if (position[1] < 1260 && position[1] > 1250) { + randoBundleInfo.randoCheckId = + (RandoCheckId)((int32_t)RC_BGS_HONEYCOMB_BEEHIVE_ELEVATED_WALKWAY_1 + bundleCount); + } else if (position[1] < 1160 && position[1] > 1150) { + randoBundleInfo.randoCheckId = + (RandoCheckId)((int32_t)RC_BGS_HONEYCOMB_BEEHIVE_NEAR_MAZE_ENTRANCE_1 + bundleCount); + } else if (position[0] < 4390 && position[0] > 4385) { + randoBundleInfo.randoCheckId = (RandoCheckId)((int32_t)RC_BGS_HONEYCOMB_BEEHIVE_NEAR_TANKTUP_1 + bundleCount); + } else if (position[0] < 2565 && position[0] > 2560) { + randoBundleInfo.randoCheckId = (RandoCheckId)((int32_t)RC_BGS_HONEYCOMB_BEEHIVE_NEAR_WARP_PAD_1 + bundleCount); + } + break; + default: + break; + } + break; + case LEVEL_5_FREEZEEZY_PEAK: + switch (bundleId) { + case BUNDLE_9__JIGGY: + randoBundleInfo.randoCheckId = RC_FP_JIGGY_SLED_TO_BOGGY; + break; + case BUNDLE_10__JIGGY: + if (position[1] > 1900) { + randoBundleInfo.randoCheckId = RC_FP_JIGGY_BOGGY_RACE_1; + } else if (position[1] < 850) { + randoBundleInfo.randoCheckId = RC_FP_JIGGY_WOZZA; + } + break; + case BUNDLE_7__JIGGY: + randoBundleInfo.randoCheckId = RC_FP_JIGGY_BOGGY_RACE_2; + break; + case BUNDLE_18__HONEYCOMB: + if (position[1] < 820 && position[1] > 810) { + randoBundleInfo.randoCheckId = (RandoCheckId)((int32_t)RC_FP_HONEYCOMB_BEEHIVE_NEAR_RACE_START_1 + bundleCount); + } else if (position[1] < 590 && position[1] > 580) { + randoBundleInfo.randoCheckId = (RandoCheckId)((int32_t)RC_FP_HONEYCOMB_BEEHIVE_PRESENT_STACK_1 + bundleCount); + } else if (position[1] < 1755 && position[1] > 1745) { + randoBundleInfo.randoCheckId = (RandoCheckId)((int32_t)RC_FP_HONEYCOMB_BEEHIVE_SCARF_END_1 + bundleCount); + } else if (position[1] < 5760 && position[1] > 5750) { + randoBundleInfo.randoCheckId = (RandoCheckId)((int32_t)RC_FP_HONEYCOMB_BEEHIVE_SCARF_START_1 + bundleCount); + } + break; + default: + break; + } + break; + case LEVEL_6_LAIR: + switch (bundleId) { + case BUNDLE_C_BGS_HUT_JIGGY: + if (position[1] == Rando::StaticData::Checks[RC_GL_JIGGY_WITCH_SWITCH_MUMBOS_MOUNTAIN].posY) { + randoBundleInfo.randoCheckId = RC_GL_JIGGY_WITCH_SWITCH_MUMBOS_MOUNTAIN; + break; + } + if (position[1] == Rando::StaticData::Checks[RC_GL_JIGGY_WITCH_SWITCH_RUSTY_BUCKET_BAY].posY) { + randoBundleInfo.randoCheckId = RC_GL_JIGGY_WITCH_SWITCH_RUSTY_BUCKET_BAY; + break; + } + if (position[1] == Rando::StaticData::Checks[RC_GL_JIGGY_WITCH_SWITCH_CLICK_CLOCK_WOOD].posY) { + randoBundleInfo.randoCheckId = RC_GL_JIGGY_WITCH_SWITCH_CLICK_CLOCK_WOOD; + break; + } + if (position[1] == Rando::StaticData::Checks[RC_GL_JIGGY_WITCH_SWITCH_CLANKERS_CAVERN].posY) { + randoBundleInfo.randoCheckId = RC_GL_JIGGY_WITCH_SWITCH_CLANKERS_CAVERN; + break; + } + break; + case BUNDLE_10__JIGGY: + if (fileProgressFlag_get(FILEPROG_1A_TTC_WITCH_SWITCH_JIGGY_PRESSED) && + gsworld_getMap() == MAP_6D_GL_TTC_LOBBY) { + randoBundleInfo.randoCheckId = RC_GL_JIGGY_WITCH_SWITCH_TREASURE_TROVE_COVE; + auto spawnTuple = Rando::StaticData::multiSpawnCheckMap.at(randoBundleInfo.randoCheckId); + position[0] = std::get<0>(spawnTuple); + position[1] = std::get<1>(spawnTuple); + position[2] = std::get<2>(spawnTuple); + } else { + randoBundleInfo.customPhysics = true; + randoBundleInfo.randoCheckId = + Rando::StaticData::GetCheckByPosition(position[0], position[1], position[2]); + } + break; + case BUNDLE_18__HONEYCOMB: + switch (currentMap) { + case MAP_69_GL_MM_LOBBY: + randoBundleInfo.randoCheckId = + (RandoCheckId)((int32_t)RC_GL_HONEYCOMB_BEEHIVE_NEAR_50_NOTE_DOOR_1 + bundleCount); + break; + case MAP_6D_GL_TTC_LOBBY: + randoBundleInfo.randoCheckId = + (RandoCheckId)((int32_t)RC_GL_HONEYCOMB_BEEHIVE_NEAR_TTC_ENTRANCE_1 + bundleCount); + break; + case MAP_6F_GL_FP_LOBBY: + if (position[1] < 295 && position[1] > 285) { + randoBundleInfo.randoCheckId = + (RandoCheckId)((int32_t)RC_GL_HONEYCOMB_BEEHIVE_BIG_GRUNTY_STATUE_LEFT_1 + + bundleCount); + } else if (position[1] < 255 && position[1] > 245) { + randoBundleInfo.randoCheckId = + (RandoCheckId)((int32_t)RC_GL_HONEYCOMB_BEEHIVE_BIG_GRUNTY_STATUE_RIGHT_1 + + bundleCount); + } + break; + case MAP_70_GL_CC_LOBBY: + randoBundleInfo.randoCheckId = + (RandoCheckId)((int32_t)RC_GL_HONEYCOMB_BEEHIVE_NEAR_CC_ENTRANCE_1 + bundleCount); + break; + case MAP_71_GL_STATUE_ROOM: + randoBundleInfo.randoCheckId = (RandoCheckId)((int32_t)RC_GL_HONEYCOMB_BEEHIVE_NEAR_FIRST_GRUNTY_STATUE_1 + + bundleCount); + break; + case MAP_72_GL_BGS_LOBBY: + randoBundleInfo.randoCheckId = + (RandoCheckId)((int32_t)RC_GL_HONEYCOMB_BEEHIVE_BEHIND_BGS_ENTRANCE_1 + bundleCount); + break; + case MAP_75_GL_MMM_LOBBY: + randoBundleInfo.randoCheckId = + (RandoCheckId)((int32_t)RC_GL_HONEYCOMB_BEEHIVE_BEHIND_MMM_ENTRANCE_1 + bundleCount); + break; + case MAP_78_GL_RBB_AND_MMM_PUZZLE: + randoBundleInfo.randoCheckId = + (RandoCheckId)((int32_t)RC_GL_HONEYCOMB_BEEHIVE_NEAR_RBB_PUZZLE_1 + bundleCount); + break; + case MAP_79_GL_CCW_LOBBY: + randoBundleInfo.randoCheckId = + (RandoCheckId)((int32_t)RC_GL_HONEYCOMB_BEEHIVE_NEAR_CCW_PUZZLE_SWITCH_1 + bundleCount); + break; + } + break; + default: + break; + } + break; + case LEVEL_7_GOBIS_VALLEY: + switch (bundleId) { + case BUNDLE_10__JIGGY: + randoBundleInfo.randoCheckId = + Rando::StaticData::GetCheckByPosition(position[0], position[1], position[2]); + break; + case BUNDLE_D__EMPTY_HONEYCOMB: + randoBundleInfo.randoCheckId = RC_GV_EMPTY_HONEYCOMB_GOBI; + break; + case BUNDLE_18__HONEYCOMB: + if (position[1] < 2990 && position[1] > 2980) { + randoBundleInfo.randoCheckId = + (RandoCheckId)((int32_t)RC_GV_HONEYCOMB_BEEHIVE_BEHIND_WATER_PYRAMID_1 + bundleCount); + } else if (position[1] < 1990 && position[1] > 1980) { + randoBundleInfo.randoCheckId = + (RandoCheckId)((int32_t)RC_GV_HONEYCOMB_BEEHIVE_NEAR_PUZZLE_PYRAMID_1 + bundleCount); + } else if (position[1] < 610 && position[1] > 600) { + randoBundleInfo.randoCheckId = (RandoCheckId)((int32_t)RC_GV_HONEYCOMB_BEEHIVE_NEAR_WARP_PAD_1 + bundleCount); + } + break; + default: + break; + } + break; + case LEVEL_8_CLICK_CLOCK_WOOD: + switch (bundleId) { + case BUNDLE_18__HONEYCOMB: + switch (currentMap) { + case MAP_40_CCW_HUB: + if (position[1] < 150 && position[1] > 140) { + randoBundleInfo.randoCheckId = + (RandoCheckId)((int32_t)RC_CCW_HONEYCOMB_BEEHIVE_ENTRANCE_LEFT_OF_SUMMER_DOOR_1 + + bundleCount); + } else if (position[1] < 160 && position[1] > 150) { + randoBundleInfo.randoCheckId = + (RandoCheckId)((int32_t)RC_CCW_HONEYCOMB_BEEHIVE_ENTRANCE_RIGHT_OF_SUMMER_DOOR_1 + + bundleCount); + } + break; + case MAP_43_CCW_SPRING: + if (position[0] < 5 && position[0] > -5) { + randoBundleInfo.randoCheckId = + (RandoCheckId)((int32_t)RC_CCW_HONEYCOMB_BEEHIVE_SPRING_BY_THE_BIG_FLOWER_1 + + bundleCount); + } else if (position[0] < -1545 && position[0] > -1555) { + randoBundleInfo.randoCheckId = + (RandoCheckId)((int32_t)RC_CCW_HONEYCOMB_BEEHIVE_SPRING_GRASS_NEAR_THE_ENTRANCE_1 + + bundleCount); + } else if (position[0] < 4345 && position[0] > 4340) { + randoBundleInfo.randoCheckId = + (RandoCheckId)((int32_t)RC_CCW_HONEYCOMB_BEEHIVE_SPRING_UNDER_THE_TREEHOUSE_1 + + bundleCount); + } + break; + case MAP_44_CCW_SUMMER: + if (position[1] < -440 && position[1] > -450) { + randoBundleInfo.randoCheckId = (RandoCheckId)((int32_t)RC_CCW_HONEYCOMB_BEEHIVE_SUMMER_DRIED_UP_LAKE_1 + + bundleCount); + } else if (position[1] < 160 && position[1] > 150) { + randoBundleInfo.randoCheckId = + (RandoCheckId)((int32_t)RC_CCW_HONEYCOMB_BEEHIVE_SUMMER_GRASS_NEAR_THE_ENTRANCE_1 + + bundleCount); + } else if (position[1] < 4580 && position[1] > 4570) { + randoBundleInfo.randoCheckId = + (RandoCheckId)((int32_t)RC_CCW_HONEYCOMB_BEEHIVE_SUMMER_OUTSIDE_NABNUTS_1 + + bundleCount); + } + break; + case MAP_45_CCW_AUTUMN: + if (position[1] < 1435 && position[1] > 1425) { + randoBundleInfo.randoCheckId = + (RandoCheckId)((int32_t)RC_CCW_HONEYCOMB_BEEHIVE_AUTUMN_ABOVE_THE_LAKE_1 + + bundleCount); + } else if (position[1] < 160 && position[1] > 150) { + randoBundleInfo.randoCheckId = + (RandoCheckId)((int32_t)RC_CCW_HONEYCOMB_BEEHIVE_AUTUMN_GRASS_NEAR_THE_ENTRANCE_1 + + bundleCount); + } else if (position[1] < 4405 && position[1] > 4395) { + randoBundleInfo.randoCheckId = + (RandoCheckId)((int32_t)RC_CCW_HONEYCOMB_BEEHIVE_AUTUMN_IN_THE_TREEHOUSE_1 + + bundleCount); + } + break; + case MAP_46_CCW_WINTER: + if (position[1] < 1060 && position[1] > 1050) { + randoBundleInfo.randoCheckId = + (RandoCheckId)((int32_t)RC_CCW_HONEYCOMB_BEEHIVE_WINTER_AROUND_THE_TREE_BASE_1 + + bundleCount); + } else if (position[1] < 4405 && position[1] > 4395) { + randoBundleInfo.randoCheckId = + (RandoCheckId)((int32_t)RC_CCW_HONEYCOMB_BEEHIVE_WINTER_OUTSIDE_THE_TREEHOUSE_1 + + bundleCount); + } + break; + case MAP_4D_CCW_WINTER_MUMBOS_SKULL: + randoBundleInfo.randoCheckId = + (RandoCheckId)((int32_t)RC_CCW_HONEYCOMB_BEEHIVE_WINTER_INSIDE_MUMBOS_SKULL_1 + + bundleCount); + break; + } + default: + break; + } + break; + case LEVEL_9_RUSTY_BUCKET_BAY: + switch (bundleId) { + case BUNDLE_6_MM_HUT_EXTRA_LIFE: + randoBundleInfo.randoCheckId = RC_RBB_EXTRA_LIFE_BOOM_BOXES; + randoBundleInfo.customPhysics = true; + break; + case BUNDLE_18__HONEYCOMB: + if (position[0] == 0 && position[1] == 156 && position[2] == 4800) { + randoBundleInfo.randoCheckId = + (RandoCheckId)((int32_t)RC_RBB_HONEYCOMB_BEEHIVE_ENGINE_ROOM_ENTRANCE_1 + bundleCount); + } else if (position[0] == 0 && position[1] == 156 && position[2] == -178) { + randoBundleInfo.randoCheckId = + (RandoCheckId)((int32_t)RC_RBB_HONEYCOMB_BEEHIVE_FIRST_SHIPPING_CONTAINER_1 + bundleCount); + } else if (position[0] == 7850 && position[1] == -1019 && position[2] == 3550) { + randoBundleInfo.randoCheckId = + (RandoCheckId)((int32_t)RC_RBB_HONEYCOMB_BEEHIVE_GRATE_ABOVE_PINK_JINJO_1 + bundleCount); + } + break; + default: + break; + } + case LEVEL_A_MAD_MONSTER_MANSION: + switch (bundleId) { + case BUNDLE_18__HONEYCOMB: + switch (currentMap) { + case MAP_1C_MMM_CHURCH: + if (position[0] < 1880 && position[0] > 1870) { + randoBundleInfo.randoCheckId = (RandoCheckId)((int32_t)RC_MMM_HONEYCOMB_BEEHIVE_CHURCH_ORGAN_RIGHT_1 + + bundleCount); + } else if (position[0] < -1870 && position[0] > -1880) { + randoBundleInfo.randoCheckId = + (RandoCheckId)((int32_t)RC_MMM_HONEYCOMB_BEEHIVE_CHURCH_ORGAN_LEFT_1 + bundleCount); + } + break; + case MAP_1B_MMM_MAD_MONSTER_MANSION: + if (position[1] < 160 && position[1] > 150) { + randoBundleInfo.randoCheckId = + (RandoCheckId)((int32_t)RC_MMM_HONEYCOMB_BEEHIVE_IN_THE_MAZE_1 + bundleCount); + } else if (position[1] < 335 && position[1] > 325) { + randoBundleInfo.randoCheckId = + (RandoCheckId)((int32_t)RC_MMM_HONEYCOMB_BEEHIVE_IN_THE_TALL_GRASS_1 + bundleCount); + } + break; + default: + break; + } + break; + default: + break; + } + break; + case LEVEL_B_SPIRAL_MOUNTAIN: + switch (bundleId) { + case BUNDLE_1F_SM_EMPTY_HONEYCOMB: + if (position[1] >= 500 && position[1] <= 800) { + randoBundleInfo.randoCheckId = RC_SM_EMPTY_HONEYCOMB_COLLIWOBBLE; + } else { + randoBundleInfo.randoCheckId = RC_SM_EMPTY_HONEYCOMB_QUARRIES; + } + break; + case BUNDLE_18__HONEYCOMB: + break; + default: + break; + } + break; + default: + return randoBundleInfo; } - bundleDespawnQueue.clear(); + return randoBundleInfo; } -void Rando::ObjectBehavior::InitBundleBehavior() { - COND_HOOK(ClearBundleDespawnQueue, EVENT_PRIORITY_NORMAL, IS_RANDO, - [](IEvent* event) { bundleDespawnQueue.clear(); }) +bool OverrideBundleSpawn(bundle_e bundleId, BundleInfo* bundleInfo, s32 bundleCount, f32 spawnPosition[3]) { - COND_VB_SHOULD(VB_BUNDLE_SPAWN_SET_ACTOR_DATA, EVENT_PRIORITY_NORMAL, IS_RANDO, { - Actor* refActor = va_arg(args, Actor*); + s32 position[3] = { (int32_t)spawnPosition[0], (int32_t)spawnPosition[1], (int32_t)spawnPosition[2] }; - if (refActor == NULL) { - *should = true; + if (bundleId == BUNDLE_16__HONEYCOMB && + (gsworld_getMap() == MAP_43_CCW_SPRING || gsworld_getMap() == MAP_B_CC_CLANKERS_CAVERN)) { + if (CheckEnemyOverlapPosition(position)) { + return false; } - }) - - COND_VB_SHOULD(VB_OVERRIDE_BUNDLE_SPAWN, EVENT_PRIORITY_NORMAL, IS_RANDO, { - bundle_e bundleId = (bundle_e)va_arg(args, int); - BundleInfo* bundleInfo = va_arg(args, BundleInfo*); - s32 bundleCount = va_arg(args, s32); - f32* position = va_arg(args, f32*); - Actor** actor = va_arg(args, Actor**); - - map_e currentMap = gsworld_getMap(); - level_e currentLevel = map_getLevel(currentMap); - - int32_t spawnPosition[3]; - spawnPosition[0] = (int32_t)position[0]; - spawnPosition[1] = (int32_t)position[1]; - spawnPosition[2] = (int32_t)position[2]; - - if (bundleId == BUNDLE_16__HONEYCOMB && - (currentMap == MAP_43_CCW_SPRING || currentMap == MAP_B_CC_CLANKERS_CAVERN)) { - if (CheckEnemyOverlapPosition(spawnPosition)) { - *should = false; - return; - } - } - - RandoCheckId randoCheckId = RC_UNKNOWN; - applyCustomPhysics = false; + } - switch (currentLevel) { - case LEVEL_1_MUMBOS_MOUNTAIN: - switch (bundleId) { - case BUNDLE_0_MM_HUT_MUSIC_NOTE: - randoCheckId = (RandoCheckId)((int32_t)RC_MM_NOTE_HUT_BUNDLE_1 + bundleCount); - applyCustomPhysics = true; - break; - case BUNDLE_1_MM_HUT_BLUE_EGG: - randoCheckId = (RandoCheckId)((int32_t)RC_MM_BLUE_EGG_HUT_BUNDLE_1 + bundleCount); - applyCustomPhysics = true; - break; - case BUNDLE_3_MM_HUT_JINJO_GREEN: - randoCheckId = RC_MM_JINJO_GREEN; - applyCustomPhysics = true; - break; - case BUNDLE_4_MM_HUT_JIGGY: - if (spawnPosition[1] < 2000) { - randoCheckId = RC_MM_JIGGY_ORANGE_PADS; - } else { - randoCheckId = RC_MM_JIGGY_HUTS; - applyCustomPhysics = true; - } - break; - case BUNDLE_6_MM_HUT_EXTRA_LIFE: - randoCheckId = RC_MM_EXTRA_LIFE_HUT; - applyCustomPhysics = true; - break; - case BUNDLE_7__JIGGY: - randoCheckId = RC_MM_JIGGY_CHIMPY; - break; - case BUNDLE_10__JIGGY: - randoCheckId = RC_MM_JIGGY_JUJU; - break; - case BUNDLE_15__JIGGY: - randoCheckId = RC_MM_JIGGY_CONGA; - break; - case BUNDLE_18__HONEYCOMB: - if (spawnPosition[1] < 400) { - randoCheckId = - (RandoCheckId)((int32_t)RC_MM_HONEYCOMB_BEEHIVE_BY_BIG_BUTT_1 + bundleCount); - } else { - randoCheckId = - (RandoCheckId)((int32_t)RC_MM_HONEYCOMB_BEEHIVE_BY_THE_HUTS_1 + bundleCount); - } - break; - default: - break; - } - break; - case LEVEL_2_TREASURE_TROVE_COVE: - switch (bundleId) { - case BUNDLE_4_MM_HUT_JIGGY: - randoCheckId = RC_TTC_JIGGY_RED_X; - break; - case BUNDLE_7__JIGGY: - randoCheckId = RC_TTC_JIGGY_BLUBBER; - break; - default: - break; - case BUNDLE_18__HONEYCOMB: - if (position[1] < 900 && position[1] > 890) { - randoCheckId = - (RandoCheckId)((int32_t)RC_TTC_HONEYCOMB_BEEHIVE_NEAR_BLUBBERS_SHIP_1 + bundleCount); - } else if (position[1] < 1770 && position[1] > 1765) { - randoCheckId = - (RandoCheckId)((int32_t)RC_TTC_HONEYCOMB_BEEHIVE_NEAR_THE_BACK_STAIRS_1 + bundleCount); - } else if (position[1] < 1910 && position[1] > 1905) { - randoCheckId = - (RandoCheckId)((int32_t)RC_TTC_HONEYCOMB_BEEHIVE_IN_THE_CLIFFSIDE_POOL_1 + bundleCount); - } else if (position[1] < 875 && position[1] > 870) { - randoCheckId = - (RandoCheckId)((int32_t)RC_TTC_HONEYCOMB_BEEHIVE_ON_THE_BEACH_1 + bundleCount); - } - break; - } - break; - case LEVEL_3_CLANKERS_CAVERN: - switch (bundleId) { - case BUNDLE_10__JIGGY: - switch (spawnPosition[1]) { - case 1536: - randoCheckId = RC_CC_JIGGY_TOOTH; - break; - default: - randoCheckId = RC_CC_JIGGY_RINGS; - break; - } - break; - case BUNDLE_18__HONEYCOMB: - if (position[1] < 1405 && position[1] > 1395) { - randoCheckId = - (RandoCheckId)((int32_t)RC_CC_HONEYCOMB_BEEHIVE_INSIDE_CLANKER_1 + bundleCount); - } else if (position[1] < 5495 && position[1] > 5490) { - randoCheckId = - (RandoCheckId)((int32_t)RC_CC_HONEYCOMB_BEEHIVE_NEAR_THE_ENTRANCE_1 + bundleCount); - } else if (position[1] < 3820 && position[1] > 3810) { - randoCheckId = - (RandoCheckId)((int32_t)RC_CC_HONEYCOMB_BEEHIVE_NEAR_THE_YELLOW_GRATES_1 + bundleCount); - } - break; - default: - break; - } - break; - case LEVEL_4_BUBBLEGLOOP_SWAMP: - switch (bundleId) { - case BUNDLE_6_MM_HUT_EXTRA_LIFE: - randoCheckId = (RandoCheckId)((int32_t)RC_BGS_EXTRA_LIFE_MR_VILE_1 + vileCount); - vileCount++; - applyCustomPhysics = true; - if (vileCount >= 3) { - vileCount = 0; - } - break; - case BUNDLE_7__JIGGY: - randoCheckId = RC_BGS_JIGGY_CROCTUS; - break; - case BUNDLE_8__JIGGY: - randoCheckId = RC_BGS_JIGGY_MR_VILE; - break; - case BUNDLE_9__JIGGY: - randoCheckId = RC_BGS_JIGGY_TANKTUP; - break; - case BUNDLE_B_BGS_HUT_MUSIC_NOTE: - randoCheckId = (RandoCheckId)((int32_t)RC_BGS_NOTE_HUT_BUNDLE_1 + bundleCount); - break; - case BUNDLE_C_BGS_HUT_JIGGY: - randoCheckId = RC_BGS_JIGGY_HUTS; - break; - case BUNDLE_10__JIGGY: - switch (spawnPosition[2]) { - case 49: - randoCheckId = RC_BGS_JIGGY_ELEVATED_WALKWAY; - break; - case -1386: - randoCheckId = RC_BGS_JIGGY_FLIBBITS; - break; - case 2799: - randoCheckId = RC_BGS_JIGGY_PINKEGG; - break; - case -1020: - randoCheckId = RC_BGS_JIGGY_TIPTUP; - break; - case -6148: - randoCheckId = RC_BGS_JIGGY_MAZE; - break; - default: - break; - } - break; - case BUNDLE_18__HONEYCOMB: - if (position[1] < 1260 && position[1] > 1250) { - randoCheckId = - (RandoCheckId)((int32_t)RC_BGS_HONEYCOMB_BEEHIVE_ELEVATED_WALKWAY_1 + bundleCount); - } else if (position[1] < 1160 && position[1] > 1150) { - randoCheckId = - (RandoCheckId)((int32_t)RC_BGS_HONEYCOMB_BEEHIVE_NEAR_MAZE_ENTRANCE_1 + bundleCount); - } else if (position[0] < 4390 && position[0] > 4385) { - randoCheckId = - (RandoCheckId)((int32_t)RC_BGS_HONEYCOMB_BEEHIVE_NEAR_TANKTUP_1 + bundleCount); - } else if (position[0] < 2565 && position[0] > 2560) { - randoCheckId = - (RandoCheckId)((int32_t)RC_BGS_HONEYCOMB_BEEHIVE_NEAR_WARP_PAD_1 + bundleCount); - } - break; - default: - break; - } - break; - case LEVEL_5_FREEZEEZY_PEAK: - switch (bundleId) { - case BUNDLE_9__JIGGY: - randoCheckId = RC_FP_JIGGY_SLED_TO_BOGGY; - break; - case BUNDLE_10__JIGGY: - if (spawnPosition[1] > 1900) { - randoCheckId = RC_FP_JIGGY_BOGGY_RACE_1; - } else if (spawnPosition[1] < 850) { - randoCheckId = RC_FP_JIGGY_WOZZA; - } - break; - case BUNDLE_7__JIGGY: - randoCheckId = RC_FP_JIGGY_BOGGY_RACE_2; - break; - case BUNDLE_18__HONEYCOMB: - if (position[1] < 820 && position[1] > 810) { - randoCheckId = - (RandoCheckId)((int32_t)RC_FP_HONEYCOMB_BEEHIVE_NEAR_RACE_START_1 + bundleCount); - } else if (position[1] < 590 && position[1] > 580) { - randoCheckId = - (RandoCheckId)((int32_t)RC_FP_HONEYCOMB_BEEHIVE_PRESENT_STACK_1 + bundleCount); - } else if (position[1] < 1755 && position[1] > 1745) { - randoCheckId = - (RandoCheckId)((int32_t)RC_FP_HONEYCOMB_BEEHIVE_SCARF_END_1 + bundleCount); - } else if (position[1] < 5760 && position[1] > 5750) { - randoCheckId = - (RandoCheckId)((int32_t)RC_FP_HONEYCOMB_BEEHIVE_SCARF_START_1 + bundleCount); - } - break; - default: - break; - } - break; - case LEVEL_6_LAIR: - switch (bundleId) { - case BUNDLE_C_BGS_HUT_JIGGY: - if (spawnPosition[1] == - Rando::StaticData::Checks[RC_GL_JIGGY_WITCH_SWITCH_MUMBOS_MOUNTAIN].posY) { - randoCheckId = RC_GL_JIGGY_WITCH_SWITCH_MUMBOS_MOUNTAIN; - break; - } - if (spawnPosition[1] == - Rando::StaticData::Checks[RC_GL_JIGGY_WITCH_SWITCH_RUSTY_BUCKET_BAY].posY) { - randoCheckId = RC_GL_JIGGY_WITCH_SWITCH_RUSTY_BUCKET_BAY; - break; - } - if (spawnPosition[1] == - Rando::StaticData::Checks[RC_GL_JIGGY_WITCH_SWITCH_CLICK_CLOCK_WOOD].posY) { - randoCheckId = RC_GL_JIGGY_WITCH_SWITCH_CLICK_CLOCK_WOOD; - break; - } - if (spawnPosition[1] == - Rando::StaticData::Checks[RC_GL_JIGGY_WITCH_SWITCH_CLANKERS_CAVERN].posY) { - randoCheckId = RC_GL_JIGGY_WITCH_SWITCH_CLANKERS_CAVERN; - break; - } - break; - case BUNDLE_10__JIGGY: - if (fileProgressFlag_get(FILEPROG_1A_TTC_WITCH_SWITCH_JIGGY_PRESSED) && - gsworld_getMap() == MAP_6D_GL_TTC_LOBBY) { - randoCheckId = RC_GL_JIGGY_WITCH_SWITCH_TREASURE_TROVE_COVE; - auto spawnTuple = Rando::StaticData::multiSpawnCheckMap.at(randoCheckId); - spawnPosition[0] = std::get<0>(spawnTuple); - spawnPosition[1] = std::get<1>(spawnTuple); - spawnPosition[2] = std::get<2>(spawnTuple); - } else { - applyCustomPhysics = true; - randoCheckId = Rando::StaticData::GetCheckByPosition(spawnPosition[0], spawnPosition[1], - spawnPosition[2]); - } - break; - case BUNDLE_18__HONEYCOMB: - switch (currentMap) { - case MAP_69_GL_MM_LOBBY: - randoCheckId = - (RandoCheckId)((int32_t)RC_GL_HONEYCOMB_BEEHIVE_NEAR_50_NOTE_DOOR_1 + bundleCount); - break; - case MAP_6D_GL_TTC_LOBBY: - randoCheckId = - (RandoCheckId)((int32_t)RC_GL_HONEYCOMB_BEEHIVE_NEAR_TTC_ENTRANCE_1 + bundleCount); - break; - case MAP_6F_GL_FP_LOBBY: - if (position[1] < 295 && position[1] > 285) { - randoCheckId = - (RandoCheckId)((int32_t)RC_GL_HONEYCOMB_BEEHIVE_BIG_GRUNTY_STATUE_LEFT_1 + bundleCount); - } else if (position[1] < 255 && position[1] > 245) { - randoCheckId = - (RandoCheckId)((int32_t)RC_GL_HONEYCOMB_BEEHIVE_BIG_GRUNTY_STATUE_RIGHT_1 + bundleCount); - } - break; - case MAP_70_GL_CC_LOBBY: - randoCheckId = - (RandoCheckId)((int32_t)RC_GL_HONEYCOMB_BEEHIVE_NEAR_CC_ENTRANCE_1 + bundleCount); - break; - case MAP_71_GL_STATUE_ROOM: - randoCheckId = - (RandoCheckId)((int32_t)RC_GL_HONEYCOMB_BEEHIVE_NEAR_FIRST_GRUNTY_STATUE_1 + bundleCount); - break; - case MAP_72_GL_BGS_LOBBY: - randoCheckId = - (RandoCheckId)((int32_t)RC_GL_HONEYCOMB_BEEHIVE_BEHIND_BGS_ENTRANCE_1 + bundleCount); - break; - case MAP_75_GL_MMM_LOBBY: - randoCheckId = - (RandoCheckId)((int32_t)RC_GL_HONEYCOMB_BEEHIVE_BEHIND_MMM_ENTRANCE_1 + bundleCount); - break; - case MAP_78_GL_RBB_AND_MMM_PUZZLE: - randoCheckId = - (RandoCheckId)((int32_t)RC_GL_HONEYCOMB_BEEHIVE_NEAR_RBB_PUZZLE_1 + bundleCount); - break; - case MAP_79_GL_CCW_LOBBY: - randoCheckId = - (RandoCheckId)((int32_t)RC_GL_HONEYCOMB_BEEHIVE_NEAR_CCW_PUZZLE_SWITCH_1 + bundleCount); - break; - } - break; - default: - break; - } - break; - case LEVEL_7_GOBIS_VALLEY: - switch (bundleId) { - case BUNDLE_10__JIGGY: - randoCheckId = - Rando::StaticData::GetCheckByPosition(spawnPosition[0], spawnPosition[1], spawnPosition[2]); - break; - case BUNDLE_D__EMPTY_HONEYCOMB: - randoCheckId = RC_GV_EMPTY_HONEYCOMB_GOBI; - break; - case BUNDLE_18__HONEYCOMB: - if (position[1] < 2990 && position[1] > 2980) { - randoCheckId = - (RandoCheckId)((int32_t)RC_GV_HONEYCOMB_BEEHIVE_BEHIND_WATER_PYRAMID_1 + bundleCount); - } else if (position[1] < 1990 && position[1] > 1980) { - randoCheckId = - (RandoCheckId)((int32_t)RC_GV_HONEYCOMB_BEEHIVE_NEAR_PUZZLE_PYRAMID_1 + bundleCount); - } else if (position[1] < 610 && position[1] > 600) { - randoCheckId = - (RandoCheckId)((int32_t)RC_GV_HONEYCOMB_BEEHIVE_NEAR_WARP_PAD_1 + bundleCount); - } - break; - default: - break; - } - break; - case LEVEL_8_CLICK_CLOCK_WOOD: - switch (bundleId) { - case BUNDLE_18__HONEYCOMB: - switch (currentMap) { - case MAP_40_CCW_HUB: - if (position[1] < 150 && position[1] > 140) { - randoCheckId = - (RandoCheckId)((int32_t)RC_CCW_HONEYCOMB_BEEHIVE_ENTRANCE_LEFT_OF_SUMMER_DOOR_1 + - bundleCount); - } else if (position[1] < 160 && position[1] > 150) { - randoCheckId = - (RandoCheckId)((int32_t)RC_CCW_HONEYCOMB_BEEHIVE_ENTRANCE_RIGHT_OF_SUMMER_DOOR_1 + - bundleCount); - } - break; - case MAP_43_CCW_SPRING: - if (position[0] < 5 && position[0] > -5) { - randoCheckId = - (RandoCheckId)((int32_t)RC_CCW_HONEYCOMB_BEEHIVE_SPRING_BY_THE_BIG_FLOWER_1 + - bundleCount); - } else if (position[0] < -1545 && position[0] > -1555) { - randoCheckId = - (RandoCheckId)((int32_t)RC_CCW_HONEYCOMB_BEEHIVE_SPRING_GRASS_NEAR_THE_ENTRANCE_1 + - bundleCount); - } else if (position[0] < 4345 && position[0] > 4340) { - randoCheckId = - (RandoCheckId)((int32_t)RC_CCW_HONEYCOMB_BEEHIVE_SPRING_UNDER_THE_TREEHOUSE_1 + - bundleCount); - } - break; - case MAP_44_CCW_SUMMER: - if (position[1] < -440 && position[1] > -450) { - randoCheckId = - (RandoCheckId)((int32_t)RC_CCW_HONEYCOMB_BEEHIVE_SUMMER_DRIED_UP_LAKE_1 + - bundleCount); - } else if (position[1] < 160 && position[1] > 150) { - randoCheckId = - (RandoCheckId)((int32_t)RC_CCW_HONEYCOMB_BEEHIVE_SUMMER_GRASS_NEAR_THE_ENTRANCE_1 + - bundleCount); - } else if (position[1] < 4580 && position[1] > 4570) { - randoCheckId = - (RandoCheckId)((int32_t)RC_CCW_HONEYCOMB_BEEHIVE_SUMMER_OUTSIDE_NABNUTS_1 + - bundleCount); - } - break; - case MAP_45_CCW_AUTUMN: - if (position[1] < 1435 && position[1] > 1425) { - randoCheckId = - (RandoCheckId)((int32_t)RC_CCW_HONEYCOMB_BEEHIVE_AUTUMN_ABOVE_THE_LAKE_1 + - bundleCount); - } else if (position[1] < 160 && position[1] > 150) { - randoCheckId = - (RandoCheckId)((int32_t)RC_CCW_HONEYCOMB_BEEHIVE_AUTUMN_GRASS_NEAR_THE_ENTRANCE_1 + - bundleCount); - } else if (position[1] < 4405 && position[1] > 4395) { - randoCheckId = - (RandoCheckId)((int32_t)RC_CCW_HONEYCOMB_BEEHIVE_AUTUMN_IN_THE_TREEHOUSE_1 + - bundleCount); - } - break; - case MAP_46_CCW_WINTER: - if (position[1] < 1060 && position[1] > 1050) { - randoCheckId = - (RandoCheckId)((int32_t)RC_CCW_HONEYCOMB_BEEHIVE_WINTER_AROUND_THE_TREE_BASE_1 + - bundleCount); - } else if (position[1] < 4405 && position[1] > 4395) { - randoCheckId = - (RandoCheckId)((int32_t)RC_CCW_HONEYCOMB_BEEHIVE_WINTER_OUTSIDE_THE_TREEHOUSE_1 + - bundleCount); - } - break; - case MAP_4D_CCW_WINTER_MUMBOS_SKULL: - randoCheckId = - (RandoCheckId)((int32_t)RC_CCW_HONEYCOMB_BEEHIVE_WINTER_INSIDE_MUMBOS_SKULL_1 + - bundleCount); - break; - } - default: - break; - } - break; - case LEVEL_9_RUSTY_BUCKET_BAY: - switch (bundleId) { - case BUNDLE_6_MM_HUT_EXTRA_LIFE: - randoCheckId = RC_RBB_EXTRA_LIFE_BOOM_BOXES; - applyCustomPhysics = true; - break; - case BUNDLE_18__HONEYCOMB: - if (position[0] == 0 && position[1] == 156 && position[2] == 4800) { - randoCheckId = - (RandoCheckId)((int32_t)RC_RBB_HONEYCOMB_BEEHIVE_ENGINE_ROOM_ENTRANCE_1 + bundleCount); - } else if (position[0] == 0 && position[1] == 156 && position[2] == -178) { - randoCheckId = - (RandoCheckId)((int32_t)RC_RBB_HONEYCOMB_BEEHIVE_FIRST_SHIPPING_CONTAINER_1 + bundleCount); - } else if (position[0] == 7850 && position[1] == -1019 && position[2] == 3550) { - randoCheckId = - (RandoCheckId)((int32_t)RC_RBB_HONEYCOMB_BEEHIVE_GRATE_ABOVE_PINK_JINJO_1 + bundleCount); - } - break; - default: - break; - } - case LEVEL_A_MAD_MONSTER_MANSION: - switch (bundleId) { - case BUNDLE_18__HONEYCOMB: - switch (currentMap) { - case MAP_1C_MMM_CHURCH: - if (position[0] < 1880 && position[0] > 1870) { - randoCheckId = - (RandoCheckId)((int32_t)RC_MMM_HONEYCOMB_BEEHIVE_CHURCH_ORGAN_RIGHT_1 + bundleCount); - } else if (position[0] < -1870 && position[0] > -1880) { - randoCheckId = - (RandoCheckId)((int32_t)RC_MMM_HONEYCOMB_BEEHIVE_CHURCH_ORGAN_LEFT_1 + bundleCount); - } - break; - case MAP_1B_MMM_MAD_MONSTER_MANSION: - if (position[1] < 160 && position[1] > 150) { - randoCheckId = - (RandoCheckId)((int32_t)RC_MMM_HONEYCOMB_BEEHIVE_IN_THE_MAZE_1 + bundleCount); - } else if (position[1] < 335 && position[1] > 325) { - randoCheckId = - (RandoCheckId)((int32_t)RC_MMM_HONEYCOMB_BEEHIVE_IN_THE_TALL_GRASS_1 + - bundleCount); - } - break; - default: - break; - } - break; - default: - break; - } - break; - case LEVEL_B_SPIRAL_MOUNTAIN: - switch (bundleId) { - case BUNDLE_1F_SM_EMPTY_HONEYCOMB: - if (spawnPosition[1] >= 500 && spawnPosition[1] <= 800) { - randoCheckId = RC_SM_EMPTY_HONEYCOMB_COLLIWOBBLE; - } else { - randoCheckId = RC_SM_EMPTY_HONEYCOMB_QUARRIES; - } - break; - case BUNDLE_18__HONEYCOMB: - break; - default: - break; - } - break; - default: - return; - } + RandoBundleInfo randoBundleInfo = IdentifyBundle(bundleId, bundleInfo, bundleCount, spawnPosition); - if (randoCheckId == RC_UNKNOWN) { - return; - } + if (randoBundleInfo.randoCheckId == RC_UNKNOWN || !Rando::Logic::IsCheckShuffled(randoBundleInfo.randoCheckId)) { + return false; + } - if (!Rando::Logic::IsCheckShuffled(randoCheckId)) { - return; - } + if (Rando::Logic::IsCheckObtained(randoBundleInfo.randoCheckId)) { + bool isConsumable = bundleInfo->actor_id == ACTOR_52_BLUE_EGG || bundleInfo->actor_id == ACTOR_50_HONEYCOMB; + return !isConsumable; + } - RandoSaveCheck randoSaveCheck = RANDO_SAVE_CHECKS[randoCheckId]; - if (randoSaveCheck.eligible) { - actor_e actorId = (actor_e)Rando::StaticData::Items[randoSaveCheck.randoItemId].actorId; - *actor = - CustomObject::SpawnCustomActorEX(randoCheckId, spawnPosition, &actorInfoMap.at((actor_e)actorId).first, - actorInfoMap.at((actor_e)actorId).second); + Actor* actor = CustomCollectible::Spawn(position, randoBundleInfo.randoCheckId); + if (randoBundleInfo.customPhysics) { + ApplyCustomActorPhysics(randoBundleInfo.randoCheckId, actor, false); + } else { + ApplyBundleActorPhysics(actor, bundleId, (BundleInfo*)bundleInfo, gBundle_yaw); + } - bundleDespawnQueue.push_back((*actor)->marker); - } else { - *actor = CustomObject::ShouldCreateCustomActorEX(randoCheckId, spawnPosition, false); + return true; +} - if (*actor == NULL) { - *should = true; - return; - } +void RegisterRandoBundles() { + COND_VB_SHOULD(VB_OVERRIDE_BUNDLE_SPAWN, EVENT_PRIORITY_NORMAL, IS_RANDO, { + bundle_e bundleId = (bundle_e)va_arg(args, int); + BundleInfo* bundleInfo = va_arg(args, BundleInfo*); + s32 bundleCount = va_arg(args, s32); + f32* position = va_arg(args, f32*); - if (applyCustomPhysics) { - ApplyCustomActorPhysics(randoCheckId, *actor, false); - } else { - ApplyBundleActorPhysics(*actor, bundleId, (BundleInfo*)bundleInfo, gBundle_yaw); - } + bool replaceBundle = OverrideBundleSpawn(bundleId, bundleInfo, bundleCount, position); + if (replaceBundle) { + *should = true; } - - *should = true; - }) + }); } + +static RegisterShipInitFunc initFunc(RegisterRandoBundles, { "IS_RANDO" }); diff --git a/src/port/Rando/ObjectBehavior/Jinjo.cpp b/src/port/Rando/ObjectBehavior/Jinjo.cpp index af6f4134d..f3c440bd5 100644 --- a/src/port/Rando/ObjectBehavior/Jinjo.cpp +++ b/src/port/Rando/ObjectBehavior/Jinjo.cpp @@ -24,11 +24,10 @@ bool OverrideJinjoSpawn(OnActorSpawn* ev) { return false; } - if (Rando::Logic::IsCheckObtained(randoCheckId)) { - return true; + if (!Rando::Logic::IsCheckObtained(randoCheckId)) { + CustomCollectible::Spawn(spawnPosition, randoCheckId); } - - CustomCollectible::Spawn(spawnPosition, randoCheckId); + return true; } diff --git a/src/port/Rando/ObjectBehavior/MumboToken.cpp b/src/port/Rando/ObjectBehavior/MumboToken.cpp new file mode 100644 index 000000000..1ecbc7a12 --- /dev/null +++ b/src/port/Rando/ObjectBehavior/MumboToken.cpp @@ -0,0 +1,38 @@ +#include "port/ShipInit.hpp" +#include "port/Enhancements/Events/Hooks/Events.h" +#include "port/Rando/Logic/Logic.h" +#include "port/Rando/CustomCollectible/CustomCollectible.h" + +#define OPTION_ENABLED RANDO_SAVE_OPTIONS[RO_SHUFFLE_MUMBO_TOKENS].optionValue + +bool OverrideMumboTokenSpawn(OnActorSpawn* ev) { + if (ev->actorId != ACTOR_2D_MUMBO_TOKEN) { + return false; + } + + int32_t spawnPosition[3] = { ev->posX, ev->posY, ev->posZ }; + RandoCheckId randoCheckId = Rando::StaticData::GetCheckByPosition(ev->posX, ev->posY, ev->posZ); + + if (randoCheckId == RC_UNKNOWN || !Rando::Logic::IsCheckShuffled(randoCheckId)) { + return false; + } + + if (!Rando::Logic::IsCheckObtained(randoCheckId)) { + CustomCollectible::Spawn(spawnPosition, randoCheckId); + } + + return true; +} + +void RegisterRandoMumboTokens() { + COND_HOOK(OnActorSpawn, EVENT_PRIORITY_NORMAL, IS_RANDO && OPTION_ENABLED, [](IEvent* event) { + OnActorSpawn* ev = (OnActorSpawn*)event; + + bool replaceMumboToken = OverrideMumboTokenSpawn(ev); + if (replaceMumboToken) { + event->Cancelled = true; + } + }); +} + +static RegisterShipInitFunc initFunc(RegisterRandoMumboTokens, { "IS_RANDO" }); diff --git a/src/port/Rando/ObjectBehavior/ObjectBehavior.cpp b/src/port/Rando/ObjectBehavior/ObjectBehavior.cpp index 744a71fe2..0dafcc30e 100644 --- a/src/port/Rando/ObjectBehavior/ObjectBehavior.cpp +++ b/src/port/Rando/ObjectBehavior/ObjectBehavior.cpp @@ -241,7 +241,6 @@ static void FireClearBundleDespawnQueue() { // Entry point for the module, run once on game boot void Rando::ObjectBehavior::Init() { - InitBundleBehavior(); InitStopNSwopBehavior(); UpdateJunkList(); @@ -251,7 +250,6 @@ void Rando::ObjectBehavior::Init() { map_e currentMap = gsworld_getMap(); CustomObject::FlushRandoSpawnQueue(); - DespawnCollectedBundles(); if (ev->actorId == ACTOR_12_BEEHIVE) { SPDLOG_INFO("Actor ID: {} {}, {}, {}", ev->actorId, ev->posX, ev->posY, ev->posZ); diff --git a/src/port/Rando/ObjectBehavior/ObjectBehavior.h b/src/port/Rando/ObjectBehavior/ObjectBehavior.h index a0ecfff3e..c620a504c 100644 --- a/src/port/Rando/ObjectBehavior/ObjectBehavior.h +++ b/src/port/Rando/ObjectBehavior/ObjectBehavior.h @@ -13,7 +13,6 @@ namespace Rando { namespace ObjectBehavior { void Init(); -void InitBundleBehavior(); void InitStopNSwopBehavior(); void ModifySwitchBehavior(int32_t switchActorId); @@ -21,7 +20,6 @@ void ModifyGobiBehavior(void* gobiActor); void ModifyBoggyBehavior(void* boggyActor); void ModifyPresentBehavior(void* presentActor); void ModifyStopNSwopWorldBehavior(void* snsActor); -void DespawnCollectedBundles(); } // namespace ObjectBehavior From 817861d916b6f3938ee496c07d68eaf80732ea28 Mon Sep 17 00:00:00 2001 From: aMannus Date: Fri, 7 Aug 2026 15:37:36 +0200 Subject: [PATCH 125/131] Handle honeycombs and extra lives --- .../Rando/ObjectBehavior/EmptyHoneyComb.cpp | 38 +++++++++++++++++++ src/port/Rando/ObjectBehavior/ExtraLife.cpp | 38 +++++++++++++++++++ .../Rando/ObjectBehavior/ObjectBehavior.cpp | 4 +- 3 files changed, 78 insertions(+), 2 deletions(-) create mode 100644 src/port/Rando/ObjectBehavior/EmptyHoneyComb.cpp create mode 100644 src/port/Rando/ObjectBehavior/ExtraLife.cpp diff --git a/src/port/Rando/ObjectBehavior/EmptyHoneyComb.cpp b/src/port/Rando/ObjectBehavior/EmptyHoneyComb.cpp new file mode 100644 index 000000000..90a744a80 --- /dev/null +++ b/src/port/Rando/ObjectBehavior/EmptyHoneyComb.cpp @@ -0,0 +1,38 @@ +#include "port/ShipInit.hpp" +#include "port/Enhancements/Events/Hooks/Events.h" +#include "port/Rando/Logic/Logic.h" +#include "port/Rando/CustomCollectible/CustomCollectible.h" + +#define OPTION_ENABLED RANDO_SAVE_OPTIONS[RO_SHUFFLE_EMPTY_HONEYCOMBS].optionValue + +bool OverrideEmptyHoneyCombSpawn(OnActorSpawn* ev) { + if (ev->actorId != ACTOR_47_EMPTY_HONEYCOMB) { + return false; + } + + int32_t spawnPosition[3] = { ev->posX, ev->posY, ev->posZ }; + RandoCheckId randoCheckId = Rando::StaticData::GetCheckByPosition(ev->posX, ev->posY, ev->posZ); + + if (randoCheckId == RC_UNKNOWN || !Rando::Logic::IsCheckShuffled(randoCheckId)) { + return false; + } + + if (!Rando::Logic::IsCheckObtained(randoCheckId)) { + CustomCollectible::Spawn(spawnPosition, randoCheckId); + } + + return true; +} + +void RegisterRandoEmptyHoneyCombs() { + COND_HOOK(OnActorSpawn, EVENT_PRIORITY_NORMAL, IS_RANDO && OPTION_ENABLED, [](IEvent* event) { + OnActorSpawn* ev = (OnActorSpawn*)event; + + bool replaceEmptyHoneyComb = OverrideEmptyHoneyCombSpawn(ev); + if (replaceEmptyHoneyComb) { + event->Cancelled = true; + } + }); +} + +static RegisterShipInitFunc initFunc(RegisterRandoEmptyHoneyCombs, { "IS_RANDO" }); diff --git a/src/port/Rando/ObjectBehavior/ExtraLife.cpp b/src/port/Rando/ObjectBehavior/ExtraLife.cpp new file mode 100644 index 000000000..875e68355 --- /dev/null +++ b/src/port/Rando/ObjectBehavior/ExtraLife.cpp @@ -0,0 +1,38 @@ +#include "port/ShipInit.hpp" +#include "port/Enhancements/Events/Hooks/Events.h" +#include "port/Rando/Logic/Logic.h" +#include "port/Rando/CustomCollectible/CustomCollectible.h" + +#define OPTION_ENABLED RANDO_SAVE_OPTIONS[RO_SHUFFLE_MUMBO_TOKENS].optionValue + +bool OverrideExtraLifeSpawn(OnActorSpawn* ev) { + if (ev->actorId != ACTOR_49_EXTRA_LIFE) { + return false; + } + + int32_t spawnPosition[3] = { ev->posX, ev->posY, ev->posZ }; + RandoCheckId randoCheckId = Rando::StaticData::GetCheckByPosition(ev->posX, ev->posY, ev->posZ); + + if (randoCheckId == RC_UNKNOWN || !Rando::Logic::IsCheckShuffled(randoCheckId)) { + return false; + } + + if (!Rando::Logic::IsCheckObtained(randoCheckId)) { + CustomCollectible::Spawn(spawnPosition, randoCheckId); + } + + return true; +} + +void RegisterRandoExtraLifes() { + COND_HOOK(OnActorSpawn, EVENT_PRIORITY_NORMAL, IS_RANDO && OPTION_ENABLED, [](IEvent* event) { + OnActorSpawn* ev = (OnActorSpawn*)event; + + bool replaceExtraLife = OverrideExtraLifeSpawn(ev); + if (replaceExtraLife) { + event->Cancelled = true; + } + }); +} + +static RegisterShipInitFunc initFunc(RegisterRandoExtraLifes, { "IS_RANDO" }); diff --git a/src/port/Rando/ObjectBehavior/ObjectBehavior.cpp b/src/port/Rando/ObjectBehavior/ObjectBehavior.cpp index 0dafcc30e..2fbb1d0d7 100644 --- a/src/port/Rando/ObjectBehavior/ObjectBehavior.cpp +++ b/src/port/Rando/ObjectBehavior/ObjectBehavior.cpp @@ -79,7 +79,7 @@ std::vector enemyKillOverlapList = { bool nextActorSaveState = false; bool IsActorWhitelisted(int32_t actorId) { - for (auto& entry : actorSpawnWhitelist) { + /*for (auto& entry : actorSpawnWhitelist) { if (entry == actorId) { return true; } @@ -91,7 +91,7 @@ bool IsActorWhitelisted(int32_t actorId) { return true; } } - } + }*/ return false; } From 40d37bbb4ac6c9ead4fc8e63072b4e93c4d25ee1 Mon Sep 17 00:00:00 2001 From: aMannus Date: Fri, 7 Aug 2026 15:42:01 +0200 Subject: [PATCH 126/131] Remove rando junk options --- src/port/Rando/LighthouseMenuRando.cpp | 30 -------------------------- 1 file changed, 30 deletions(-) diff --git a/src/port/Rando/LighthouseMenuRando.cpp b/src/port/Rando/LighthouseMenuRando.cpp index 11f2b2520..8c654a44d 100644 --- a/src/port/Rando/LighthouseMenuRando.cpp +++ b/src/port/Rando/LighthouseMenuRando.cpp @@ -268,36 +268,6 @@ void LighthouseMenu::AddMenuRando() { } }); - // Rando - Junk Options - AddSidebarEntry("Rando", "Junk Options", 1); - path = { "Rando", "Junk Options", SECTION_COLUMN_1 }; - - AddWidget(path, "Enable Junk", WIDGET_SEPARATOR_TEXT); - - AddWidget(path, "Spawn Junk For Obtained Checks", WIDGET_CVAR_CHECKBOX) - .CVar(Rando::StaticData::Options[RO_SPAWN_JUNK].cvar) - .Options(CheckboxOptions().Tooltip("Spawns a junk item in place of an object that has already been collected.")) - .Callback([](WidgetInfo& info) { UpdateJunkList(); }); - - AddWidget(path, "Junk Selection", WIDGET_SEPARATOR_TEXT); - - AddWidget(path, "Honeycomb Refills", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_RANDOMIZER_SETTING("Junk.HealthRefill")) - .Options(CheckboxOptions().Tooltip("Adds Health Refills to the Junk List.")) - .Callback([](WidgetInfo& info) { UpdateJunkList(); }); - AddWidget(path, "Blue Eggs", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_RANDOMIZER_SETTING("Junk.BlueEggs")) - .Options(CheckboxOptions().Tooltip("Adds Blue Eggs to the Junk List.")) - .Callback([](WidgetInfo& info) { UpdateJunkList(); }); - AddWidget(path, "Red Feathers", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_RANDOMIZER_SETTING("Junk.RedFeathers")) - .Options(CheckboxOptions().Tooltip("Adds Red Feathers to the Junk List.")) - .Callback([](WidgetInfo& info) { UpdateJunkList(); }); - AddWidget(path, "Gold Feathers", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_RANDOMIZER_SETTING("Junk.GoldFeathers")) - .Options(CheckboxOptions().Tooltip("Adds Gold Feathers to the Junk List.")) - .Callback([](WidgetInfo& info) { UpdateJunkList(); }); - // Rando - Check Tracker path.sidebarName = "Check Tracker"; AddSidebarEntry("Rando", path.sidebarName, 1); From 050591f69c4d4f1ae975913ce5c27ea51bd79ee7 Mon Sep 17 00:00:00 2001 From: aMannus Date: Fri, 7 Aug 2026 16:47:01 +0200 Subject: [PATCH 127/131] Fix jiggie totals and bundle crash --- src/port/Rando/ItemQueue.cpp | 1 + src/port/Rando/ObjectBehavior/Bundle.cpp | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/src/port/Rando/ItemQueue.cpp b/src/port/Rando/ItemQueue.cpp index 44b2a4a39..6bb5303d8 100644 --- a/src/port/Rando/ItemQueue.cpp +++ b/src/port/Rando/ItemQueue.cpp @@ -139,6 +139,7 @@ void ItemQueue::GiveItem(RandoItemId randoItemId) { } } coMusicPlayer_playMusic(COMUSIC_D_JINGLE_JIGGY_COLLECTED, -1); + item_adjustByDiffWithoutHud(ITEM_26_JIGGY_TOTAL, 1); item_inc(ITEM_E_JIGGY); spawnOrbit(); break; diff --git a/src/port/Rando/ObjectBehavior/Bundle.cpp b/src/port/Rando/ObjectBehavior/Bundle.cpp index ce2576879..791ff660f 100644 --- a/src/port/Rando/ObjectBehavior/Bundle.cpp +++ b/src/port/Rando/ObjectBehavior/Bundle.cpp @@ -517,6 +517,13 @@ bool OverrideBundleSpawn(bundle_e bundleId, BundleInfo* bundleInfo, s32 bundleCo } void RegisterRandoBundles() { + COND_VB_SHOULD(VB_BUNDLE_SPAWN_SET_ACTOR_DATA, EVENT_PRIORITY_NORMAL, IS_RANDO, { + Actor* refActor = va_arg(args, Actor*); + if (refActor == NULL) { + *should = true; + } + }); + COND_VB_SHOULD(VB_OVERRIDE_BUNDLE_SPAWN, EVENT_PRIORITY_NORMAL, IS_RANDO, { bundle_e bundleId = (bundle_e)va_arg(args, int); BundleInfo* bundleInfo = va_arg(args, BundleInfo*); From 71b41907feda1651336c9e864d0b3514a21b780e Mon Sep 17 00:00:00 2001 From: aMannus Date: Fri, 7 Aug 2026 17:05:57 +0200 Subject: [PATCH 128/131] Clang --- .../CustomCollectible/CustomCollectible.cpp | 4 +- .../CustomCollectible/CustomCollectible.h | 6 +-- .../CustomCollectibleDrawCustom.cpp | 4 +- src/port/Rando/ItemQueue.cpp | 19 ++++---- src/port/Rando/MiscBehavior/OnFileLoad.cpp | 1 - src/port/Rando/ObjectBehavior/Bundle.cpp | 45 ++++++++++++------- src/port/Rando/ObjectBehavior/Jinjo.cpp | 2 +- src/port/Rando/ObjectBehavior/Molehill.cpp | 2 +- src/port/Rando/StaticData/Items.cpp | 6 +-- 9 files changed, 48 insertions(+), 41 deletions(-) diff --git a/src/port/Rando/CustomCollectible/CustomCollectible.cpp b/src/port/Rando/CustomCollectible/CustomCollectible.cpp index 6975abb6e..d1e31cb0d 100644 --- a/src/port/Rando/CustomCollectible/CustomCollectible.cpp +++ b/src/port/Rando/CustomCollectible/CustomCollectible.cpp @@ -90,7 +90,7 @@ void CustomCollectible_Update(Actor* actor) { } f32 CustomCollectible::GetScale(RandoItemType itemType) { - switch (itemType) { + switch (itemType) { case RITYPE_MUSIC_NOTE: case RITYPE_SNS_EGG: return 0.42857143f; @@ -228,7 +228,7 @@ void CustomCollectible::QueueProp(int32_t position[3], RandoCheckId randoCheckId } void CustomCollectible::ProcessPropQueue() { - while (propQueue.size() > 0) { + while (propQueue.size() > 0) { QueuedProp prop = propQueue.front(); Actor* actor = CustomCollectible::Spawn(prop.position, prop.randoCheckId); propQueue.pop(); diff --git a/src/port/Rando/CustomCollectible/CustomCollectible.h b/src/port/Rando/CustomCollectible/CustomCollectible.h index 6e351bf4f..8b2f06bdb 100644 --- a/src/port/Rando/CustomCollectible/CustomCollectible.h +++ b/src/port/Rando/CustomCollectible/CustomCollectible.h @@ -10,11 +10,11 @@ typedef struct { } ActorLocal_CustomCollectible; enum CustomCollectibleDrawTypes { - CCT_GENERIC_MODEL, + CCT_GENERIC_MODEL, CCT_GENERIC_SPRITE, CCT_JINJO, - CCT_MOLEHILL, - CCT_VANILLA_SNS_EGG, + CCT_MOLEHILL, + CCT_VANILLA_SNS_EGG, CCT_CUSTOM_MODEL, }; diff --git a/src/port/Rando/CustomCollectible/CustomCollectibleDrawCustom.cpp b/src/port/Rando/CustomCollectible/CustomCollectibleDrawCustom.cpp index cf9cd4d9e..ea1e9f886 100644 --- a/src/port/Rando/CustomCollectible/CustomCollectibleDrawCustom.cpp +++ b/src/port/Rando/CustomCollectible/CustomCollectibleDrawCustom.cpp @@ -69,8 +69,8 @@ Actor* CustomCollectible_DrawCustomModel(ActorMarker* marker, Gfx** gfx, Mtx** m Actor* actor = marker_getActor(marker); ActorLocal_CustomCollectible* customLocal = (ActorLocal_CustomCollectible*)&actor->local; CustomItemModel model; - - switch (customLocal->randoItemId) { + + switch (customLocal->randoItemId) { case RI_AP_ITEM_PROGRESSION: model = ARCHIPELAGO_MODEL_PROGRESSIVE; break; diff --git a/src/port/Rando/ItemQueue.cpp b/src/port/Rando/ItemQueue.cpp index 6bb5303d8..109976035 100644 --- a/src/port/Rando/ItemQueue.cpp +++ b/src/port/Rando/ItemQueue.cpp @@ -72,7 +72,7 @@ void ItemQueue::Process() { if (itemQueue.size() < 1) { return; } - + RandoCheckId randoCheckId = itemQueue.front(); // Grant item @@ -81,7 +81,7 @@ void ItemQueue::Process() { ItemQueue::GiveItem(randoSaveCheck.randoItemId); ItemQueue::SendNotification(randoSaveCheck.randoItemId); Rando::StaticData::ModifyRandoInfFlagState(randoCheckId); - //RANDO_SAVE_CHECKS[randoCheckId].received = true; + // RANDO_SAVE_CHECKS[randoCheckId].received = true; } itemQueue.pop(); @@ -154,8 +154,9 @@ void ItemQueue::GiveItem(RandoItemId randoItemId) { } setCollectedBits(worldId, collectedJinjos); // Spawn vanilla jinjo on top of the player because the animation is too complex to handle without doing - // this. Collection behaviour is canceled in Jinjo.cpp so that part can all be handled here in the ItemQueue. - switch (actorId) { + // this. Collection behaviour is canceled in Jinjo.cpp so that part can all be handled here in the + // ItemQueue. + switch (actorId) { case ACTOR_5E_JINJO_YELLOW: actorInfo = &chJinjoYellow; break; @@ -237,7 +238,7 @@ void ItemQueue::GiveItem(RandoItemId randoItemId) { case RITYPE_MUMBO_TOKEN: func_8030E760((sfx_e)0x401, 1.0f, 0x7fff); for (uint32_t i = MUMBOTOKEN_01_MM_STUMP_NEAR_CONGA; - i <= MUMBOTOKEN_73_CCW_WINTER_SIR_SLUSH_BETWEEN_BIG_FLOWER_AND_MUMBOS_SKULL; i++) { + i <= MUMBOTOKEN_73_CCW_WINTER_SIR_SLUSH_BETWEEN_BIG_FLOWER_AND_MUMBOS_SKULL; i++) { if ((sMumboTokenScore[(i - 1) / 8] & (1 << (i & 7))) == 0) { mumboscore_set((mumbotoken_e)i, true); break; @@ -335,13 +336,9 @@ void ItemQueue::AddCheck(RandoCheckId randoCheckId) { } void RegisterItemQueue() { - COND_HOOK(GameFrameUpdate, EVENT_PRIORITY_NORMAL, IS_RANDO, [](IEvent* event) { - ItemQueue::Process(); - }); + COND_HOOK(GameFrameUpdate, EVENT_PRIORITY_NORMAL, IS_RANDO, [](IEvent* event) { ItemQueue::Process(); }); - COND_HOOK(OnSaveFileLoad, EVENT_PRIORITY_NORMAL, IS_RANDO, [](IEvent* event) { - ItemQueue::Clear(); - }); + COND_HOOK(OnSaveFileLoad, EVENT_PRIORITY_NORMAL, IS_RANDO, [](IEvent* event) { ItemQueue::Clear(); }); } static RegisterShipInitFunc initFunc(RegisterItemQueue, { "IS_RANDO" }); diff --git a/src/port/Rando/MiscBehavior/OnFileLoad.cpp b/src/port/Rando/MiscBehavior/OnFileLoad.cpp index cc77637aa..12100a6d0 100644 --- a/src/port/Rando/MiscBehavior/OnFileLoad.cpp +++ b/src/port/Rando/MiscBehavior/OnFileLoad.cpp @@ -16,7 +16,6 @@ extern "C" { enum map_e gsworld_getMap(void); } - void Rando::MiscBehavior::OnFileLoad() { REGISTER_LISTENER(OnGameLoad, EVENT_PRIORITY_NORMAL, [](IEvent* event) { OnGameLoad* ev = (OnGameLoad*)event; diff --git a/src/port/Rando/ObjectBehavior/Bundle.cpp b/src/port/Rando/ObjectBehavior/Bundle.cpp index 791ff660f..739359c51 100644 --- a/src/port/Rando/ObjectBehavior/Bundle.cpp +++ b/src/port/Rando/ObjectBehavior/Bundle.cpp @@ -18,8 +18,7 @@ typedef struct { int32_t vileCount = 0; -RandoBundleInfo - IdentifyBundle(bundle_e bundleId, BundleInfo* bundleInfo, s32 bundleCount, f32 spawnPosition[3]) { +RandoBundleInfo IdentifyBundle(bundle_e bundleId, BundleInfo* bundleInfo, s32 bundleCount, f32 spawnPosition[3]) { map_e currentMap = gsworld_getMap(); level_e currentLevel = map_getLevel(currentMap); s32 position[3] = { (int32_t)spawnPosition[0], (int32_t)spawnPosition[1], (int32_t)spawnPosition[2] }; @@ -97,7 +96,8 @@ RandoBundleInfo randoBundleInfo.randoCheckId = (RandoCheckId)((int32_t)RC_TTC_HONEYCOMB_BEEHIVE_IN_THE_CLIFFSIDE_POOL_1 + bundleCount); } else if (position[1] < 875 && position[1] > 870) { - randoBundleInfo.randoCheckId = (RandoCheckId)((int32_t)RC_TTC_HONEYCOMB_BEEHIVE_ON_THE_BEACH_1 + bundleCount); + randoBundleInfo.randoCheckId = + (RandoCheckId)((int32_t)RC_TTC_HONEYCOMB_BEEHIVE_ON_THE_BEACH_1 + bundleCount); } break; } @@ -116,7 +116,8 @@ RandoBundleInfo break; case BUNDLE_18__HONEYCOMB: if (position[1] < 1405 && position[1] > 1395) { - randoBundleInfo.randoCheckId = (RandoCheckId)((int32_t)RC_CC_HONEYCOMB_BEEHIVE_INSIDE_CLANKER_1 + bundleCount); + randoBundleInfo.randoCheckId = + (RandoCheckId)((int32_t)RC_CC_HONEYCOMB_BEEHIVE_INSIDE_CLANKER_1 + bundleCount); } else if (position[1] < 5495 && position[1] > 5490) { randoBundleInfo.randoCheckId = (RandoCheckId)((int32_t)RC_CC_HONEYCOMB_BEEHIVE_NEAR_THE_ENTRANCE_1 + bundleCount); @@ -183,9 +184,11 @@ RandoBundleInfo randoBundleInfo.randoCheckId = (RandoCheckId)((int32_t)RC_BGS_HONEYCOMB_BEEHIVE_NEAR_MAZE_ENTRANCE_1 + bundleCount); } else if (position[0] < 4390 && position[0] > 4385) { - randoBundleInfo.randoCheckId = (RandoCheckId)((int32_t)RC_BGS_HONEYCOMB_BEEHIVE_NEAR_TANKTUP_1 + bundleCount); + randoBundleInfo.randoCheckId = + (RandoCheckId)((int32_t)RC_BGS_HONEYCOMB_BEEHIVE_NEAR_TANKTUP_1 + bundleCount); } else if (position[0] < 2565 && position[0] > 2560) { - randoBundleInfo.randoCheckId = (RandoCheckId)((int32_t)RC_BGS_HONEYCOMB_BEEHIVE_NEAR_WARP_PAD_1 + bundleCount); + randoBundleInfo.randoCheckId = + (RandoCheckId)((int32_t)RC_BGS_HONEYCOMB_BEEHIVE_NEAR_WARP_PAD_1 + bundleCount); } break; default: @@ -209,13 +212,17 @@ RandoBundleInfo break; case BUNDLE_18__HONEYCOMB: if (position[1] < 820 && position[1] > 810) { - randoBundleInfo.randoCheckId = (RandoCheckId)((int32_t)RC_FP_HONEYCOMB_BEEHIVE_NEAR_RACE_START_1 + bundleCount); + randoBundleInfo.randoCheckId = + (RandoCheckId)((int32_t)RC_FP_HONEYCOMB_BEEHIVE_NEAR_RACE_START_1 + bundleCount); } else if (position[1] < 590 && position[1] > 580) { - randoBundleInfo.randoCheckId = (RandoCheckId)((int32_t)RC_FP_HONEYCOMB_BEEHIVE_PRESENT_STACK_1 + bundleCount); + randoBundleInfo.randoCheckId = + (RandoCheckId)((int32_t)RC_FP_HONEYCOMB_BEEHIVE_PRESENT_STACK_1 + bundleCount); } else if (position[1] < 1755 && position[1] > 1745) { - randoBundleInfo.randoCheckId = (RandoCheckId)((int32_t)RC_FP_HONEYCOMB_BEEHIVE_SCARF_END_1 + bundleCount); + randoBundleInfo.randoCheckId = + (RandoCheckId)((int32_t)RC_FP_HONEYCOMB_BEEHIVE_SCARF_END_1 + bundleCount); } else if (position[1] < 5760 && position[1] > 5750) { - randoBundleInfo.randoCheckId = (RandoCheckId)((int32_t)RC_FP_HONEYCOMB_BEEHIVE_SCARF_START_1 + bundleCount); + randoBundleInfo.randoCheckId = + (RandoCheckId)((int32_t)RC_FP_HONEYCOMB_BEEHIVE_SCARF_START_1 + bundleCount); } break; default: @@ -282,8 +289,9 @@ RandoBundleInfo (RandoCheckId)((int32_t)RC_GL_HONEYCOMB_BEEHIVE_NEAR_CC_ENTRANCE_1 + bundleCount); break; case MAP_71_GL_STATUE_ROOM: - randoBundleInfo.randoCheckId = (RandoCheckId)((int32_t)RC_GL_HONEYCOMB_BEEHIVE_NEAR_FIRST_GRUNTY_STATUE_1 + - bundleCount); + randoBundleInfo.randoCheckId = + (RandoCheckId)((int32_t)RC_GL_HONEYCOMB_BEEHIVE_NEAR_FIRST_GRUNTY_STATUE_1 + + bundleCount); break; case MAP_72_GL_BGS_LOBBY: randoBundleInfo.randoCheckId = @@ -324,7 +332,8 @@ RandoBundleInfo randoBundleInfo.randoCheckId = (RandoCheckId)((int32_t)RC_GV_HONEYCOMB_BEEHIVE_NEAR_PUZZLE_PYRAMID_1 + bundleCount); } else if (position[1] < 610 && position[1] > 600) { - randoBundleInfo.randoCheckId = (RandoCheckId)((int32_t)RC_GV_HONEYCOMB_BEEHIVE_NEAR_WARP_PAD_1 + bundleCount); + randoBundleInfo.randoCheckId = + (RandoCheckId)((int32_t)RC_GV_HONEYCOMB_BEEHIVE_NEAR_WARP_PAD_1 + bundleCount); } break; default: @@ -363,8 +372,9 @@ RandoBundleInfo break; case MAP_44_CCW_SUMMER: if (position[1] < -440 && position[1] > -450) { - randoBundleInfo.randoCheckId = (RandoCheckId)((int32_t)RC_CCW_HONEYCOMB_BEEHIVE_SUMMER_DRIED_UP_LAKE_1 + - bundleCount); + randoBundleInfo.randoCheckId = + (RandoCheckId)((int32_t)RC_CCW_HONEYCOMB_BEEHIVE_SUMMER_DRIED_UP_LAKE_1 + + bundleCount); } else if (position[1] < 160 && position[1] > 150) { randoBundleInfo.randoCheckId = (RandoCheckId)((int32_t)RC_CCW_HONEYCOMB_BEEHIVE_SUMMER_GRASS_NEAR_THE_ENTRANCE_1 + @@ -438,8 +448,9 @@ RandoBundleInfo switch (currentMap) { case MAP_1C_MMM_CHURCH: if (position[0] < 1880 && position[0] > 1870) { - randoBundleInfo.randoCheckId = (RandoCheckId)((int32_t)RC_MMM_HONEYCOMB_BEEHIVE_CHURCH_ORGAN_RIGHT_1 + - bundleCount); + randoBundleInfo.randoCheckId = + (RandoCheckId)((int32_t)RC_MMM_HONEYCOMB_BEEHIVE_CHURCH_ORGAN_RIGHT_1 + + bundleCount); } else if (position[0] < -1870 && position[0] > -1880) { randoBundleInfo.randoCheckId = (RandoCheckId)((int32_t)RC_MMM_HONEYCOMB_BEEHIVE_CHURCH_ORGAN_LEFT_1 + bundleCount); diff --git a/src/port/Rando/ObjectBehavior/Jinjo.cpp b/src/port/Rando/ObjectBehavior/Jinjo.cpp index f3c440bd5..3df071888 100644 --- a/src/port/Rando/ObjectBehavior/Jinjo.cpp +++ b/src/port/Rando/ObjectBehavior/Jinjo.cpp @@ -27,7 +27,7 @@ bool OverrideJinjoSpawn(OnActorSpawn* ev) { if (!Rando::Logic::IsCheckObtained(randoCheckId)) { CustomCollectible::Spawn(spawnPosition, randoCheckId); } - + return true; } diff --git a/src/port/Rando/ObjectBehavior/Molehill.cpp b/src/port/Rando/ObjectBehavior/Molehill.cpp index 477d44505..cdcea42f4 100644 --- a/src/port/Rando/ObjectBehavior/Molehill.cpp +++ b/src/port/Rando/ObjectBehavior/Molehill.cpp @@ -74,7 +74,7 @@ void RegisterRandoMolehills() { COND_HOOK(OnActorSpawn, EVENT_PRIORITY_NORMAL, IS_RANDO && OPTION_ENABLED, [](IEvent* event) { OnActorSpawn* ev = (OnActorSpawn*)event; - + bool replaceMole = OverrideMoleSpawn(ev); if (replaceMole) { event->Cancelled = true; diff --git a/src/port/Rando/StaticData/Items.cpp b/src/port/Rando/StaticData/Items.cpp index 9c61ecc40..65591bdeb 100644 --- a/src/port/Rando/StaticData/Items.cpp +++ b/src/port/Rando/StaticData/Items.cpp @@ -11,10 +11,10 @@ namespace Rando { namespace StaticData { #define RI(id, article, name, type, actorId, worldId) \ - { \ - id, { \ + { \ + id, { \ id, #id, article, name, type, actorId, worldId \ - } \ + } \ } // clang-format off From b4b648eca1784f75502d0f226b1b6db5060513f3 Mon Sep 17 00:00:00 2001 From: aMannus Date: Fri, 7 Aug 2026 20:01:20 +0200 Subject: [PATCH 129/131] Fix includes --- .../Rando/CustomCollectible/CustomCollectibleDrawCustom.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/port/Rando/CustomCollectible/CustomCollectibleDrawCustom.cpp b/src/port/Rando/CustomCollectible/CustomCollectibleDrawCustom.cpp index ea1e9f886..80ae1ed27 100644 --- a/src/port/Rando/CustomCollectible/CustomCollectibleDrawCustom.cpp +++ b/src/port/Rando/CustomCollectible/CustomCollectibleDrawCustom.cpp @@ -15,8 +15,8 @@ // extern "C" block below. #include #include "port/ResourceHelpers.h" -#include "port/enhancements/events/hooks/Events.h" -#include "port/interpolation/FrameInterpolation.h" +#include "port/Enhancements/Events/Hooks/Events.h" +#include "port/Interpolation/FrameInterpolation.h" #include "CustomCollectibleDrawCustom.h" #include "CustomCollectible.h" From 953a6be068a7a69263e0788b5dd47df8adc870c0 Mon Sep 17 00:00:00 2001 From: aMannus Date: Fri, 7 Aug 2026 20:17:51 +0200 Subject: [PATCH 130/131] Fix animations --- src/port/Rando/CustomCollectible/CustomCollectible.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/port/Rando/CustomCollectible/CustomCollectible.cpp b/src/port/Rando/CustomCollectible/CustomCollectible.cpp index d1e31cb0d..5178333cc 100644 --- a/src/port/Rando/CustomCollectible/CustomCollectible.cpp +++ b/src/port/Rando/CustomCollectible/CustomCollectible.cpp @@ -35,11 +35,11 @@ std::unordered_map customCollectibleDrawInfo { ACTOR_3CD_CUSTOM_COLLECTIBLE, { ASSET_35F_MODEL_JIGGY, CCT_CUSTOM_MODEL } }, }; -ActorAnimationInfo moleAnimations[] = { +ActorAnimationInfo moleAnimation[] = { { ASSET_13B_ANIM_BOTTLES_IDLE, 7.0f }, }; -ActorAnimationInfo chJinjoAnimations[] = { +ActorAnimationInfo chJinjoAnimation[] = { { ASSET_2F_ANIM_JINJO_HELP, 1.5f }, }; @@ -190,11 +190,11 @@ ActorInfo CustomCollectible::GetActorAndDrawInfo(RandoItemId randoItemId) { break; case CCT_JINJO: collectibleInfo.draw_func = actor_draw; - collectibleInfo.animations = chJinjoAnimations; + collectibleInfo.animations = chJinjoAnimation; break; case CCT_MOLEHILL: collectibleInfo.draw_func = func_802D94B4; - collectibleInfo.animations = moleAnimations; + collectibleInfo.animations = moleAnimation; break; case CCT_VANILLA_SNS_EGG: collectibleInfo.draw_func = chSnsEgg_draw; From a8bc4a0646f15997b145b14ea1ac9bf88363f551 Mon Sep 17 00:00:00 2001 From: aMannus Date: Fri, 7 Aug 2026 21:04:52 +0200 Subject: [PATCH 131/131] Fix build hopefully --- src/port/Rando/ItemQueue.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/port/Rando/ItemQueue.cpp b/src/port/Rando/ItemQueue.cpp index 109976035..8b2571fe7 100644 --- a/src/port/Rando/ItemQueue.cpp +++ b/src/port/Rando/ItemQueue.cpp @@ -21,7 +21,7 @@ extern struct { } jiggyscore; #define MUMBO_TOKEN_COUNT 126 #define MUMBOSCORE_SIZE (((MUMBO_TOKEN_COUNT - 1 + 7) & ~7) / 8) -u8 sMumboTokenScore[MUMBOSCORE_SIZE]; +extern u8 sMumboTokenScore[MUMBOSCORE_SIZE]; extern u8 D_80385FF0[0xE]; extern ActorInfo chJinjoBlue;