diff --git a/mm/2s2h/BenGui/BenMenuBar.cpp b/mm/2s2h/BenGui/BenMenuBar.cpp index 5e3ace0ce..89bb3e009 100644 --- a/mm/2s2h/BenGui/BenMenuBar.cpp +++ b/mm/2s2h/BenGui/BenMenuBar.cpp @@ -683,8 +683,32 @@ const char* logLevels[] = { void DrawDeveloperToolsMenu() { if (UIWidgets::BeginMenu("Developer Tools", UIWidgets::Colors::Yellow)) { - UIWidgets::CVarCheckbox("Debug Mode", "gDeveloperTools.DebugEnabled", - { .tooltip = "Enables Debug Mode, allowing you to select maps with L + R + Z." }); + if (UIWidgets::CVarCheckbox("Debug Mode", "gDeveloperTools.DebugEnabled", + { .tooltip = "Enables Debug Mode, revealing some developer options and allows you " + "to enter Map Select with L + R + Z" })) { + // If disabling debug mode, disable all debug features + if (!CVarGetInteger("gDeveloperTools.DebugEnabled", 0)) { + CVarClear("gDeveloperTools.DebugSaveFileMode"); + CVarClear("gDeveloperTools.PreventActorUpdate"); + CVarClear("gDeveloperTools.PreventActorDraw"); + CVarClear("gDeveloperTools.PreventActorInit"); + CVarClear("gDeveloperTools.DisableObjectDependency"); + if (gPlayState != NULL) { + gPlayState->frameAdvCtx.enabled = false; + } + RegisterDebugSaveCreate(); + RegisterPreventActorUpdateHooks(); + RegisterPreventActorDrawHooks(); + RegisterPreventActorInitHooks(); + } + } + if (ImGui::IsItemHovered()) { + ImGui::BeginTooltip(); + ImGui::TextColored(ImVec4(1.0f, 1.0f, 0.0f, 1.0f), + "Warning: Some of these features can break your game,\nor cause unexpected behavior, " + "please ensure you disable them\nbefore reporting any bugs."); + ImGui::EndTooltip(); + } if (CVarGetInteger("gDeveloperTools.DebugEnabled", 0)) { UIWidgets::CVarCheckbox( @@ -697,45 +721,48 @@ void DrawDeveloperToolsMenu() { "Change the behavior of creating saves while debug mode is enabled:\n\n" "- Empty Save: The default 3 heart save file in first cycle\n" "- Vanilla Debug Save: Uses the title screen save info (8 hearts, all items and masks)\n" - "- 100\% Save: All items, equipment, mask, quast status and bombers notebook complete" })) { + "- 100\% Save: All items, equipment, mask, quast status and bombers notebook complete", + .defaultIndex = DEBUG_SAVE_INFO_NONE })) { RegisterDebugSaveCreate(); } - } - if (UIWidgets::CVarCheckbox("Prevent Actor Update", "gDeveloperTools.PreventActorUpdate")) { - RegisterPreventActorUpdateHooks(); - } - if (UIWidgets::CVarCheckbox("Prevent Actor Draw", "gDeveloperTools.PreventActorDraw")) { - RegisterPreventActorDrawHooks(); - } - if (UIWidgets::CVarCheckbox("Prevent Actor Init", "gDeveloperTools.PreventActorInit")) { - RegisterPreventActorInitHooks(); - } - if (UIWidgets::CVarCombobox("Log Level", "gDeveloperTools.LogLevel", logLevels, - { - .tooltip = "The log level determines which messages are printed to the " - "console. This does not affect the log file output", - .defaultIndex = 1, - })) { - Ship::Context::GetInstance()->GetLogger()->set_level( - (spdlog::level::level_enum)CVarGetInteger("gDeveloperTools.LogLevel", 1)); - } + if (UIWidgets::CVarCheckbox("Prevent Actor Update", "gDeveloperTools.PreventActorUpdate")) { + RegisterPreventActorUpdateHooks(); + } + if (UIWidgets::CVarCheckbox("Prevent Actor Draw", "gDeveloperTools.PreventActorDraw")) { + RegisterPreventActorDrawHooks(); + } + if (UIWidgets::CVarCheckbox("Prevent Actor Init", "gDeveloperTools.PreventActorInit")) { + RegisterPreventActorInitHooks(); + } + UIWidgets::CVarCheckbox("Disable Object Dependency", "gDeveloperTools.DisableObjectDependency"); - if (gPlayState != NULL) { - ImGui::Separator(); - UIWidgets::Checkbox( - "Frame Advance", (bool*)&gPlayState->frameAdvCtx.enabled, - { .tooltip = "This allows you to advance through the game one frame at a time on command. " - "To advance a frame, hold Z and tap R on the second controller. Holding Z " - "and R will advance a frame every half second. You can also use the buttons below." }); - if (gPlayState->frameAdvCtx.enabled) { - if (UIWidgets::Button("Advance 1", { .size = UIWidgets::Sizes::Inline })) { - CVarSetInteger("gDeveloperTools.FrameAdvanceTick", 1); - } - ImGui::SameLine(); - UIWidgets::Button("Advance (Hold)", { .size = UIWidgets::Sizes::Inline }); - if (ImGui::IsItemActive()) { - CVarSetInteger("gDeveloperTools.FrameAdvanceTick", 1); + if (UIWidgets::CVarCombobox("Log Level", "gDeveloperTools.LogLevel", logLevels, + { + .tooltip = "The log level determines which messages are printed to the " + "console. This does not affect the log file output", + .defaultIndex = 1, + })) { + Ship::Context::GetInstance()->GetLogger()->set_level( + (spdlog::level::level_enum)CVarGetInteger("gDeveloperTools.LogLevel", 1)); + } + + if (gPlayState != NULL) { + ImGui::Separator(); + UIWidgets::Checkbox( + "Frame Advance", (bool*)&gPlayState->frameAdvCtx.enabled, + { .tooltip = "This allows you to advance through the game one frame at a time on command. " + "To advance a frame, hold Z and tap R on the second controller. Holding Z " + "and R will advance a frame every half second. You can also use the buttons below." }); + if (gPlayState->frameAdvCtx.enabled) { + if (UIWidgets::Button("Advance 1", { .size = UIWidgets::Sizes::Inline })) { + CVarSetInteger("gDeveloperTools.FrameAdvanceTick", 1); + } + ImGui::SameLine(); + UIWidgets::Button("Advance (Hold)", { .size = UIWidgets::Sizes::Inline }); + if (ImGui::IsItemActive()) { + CVarSetInteger("gDeveloperTools.FrameAdvanceTick", 1); + } } } } diff --git a/mm/2s2h/DeveloperTools/ActorViewer.cpp b/mm/2s2h/DeveloperTools/ActorViewer.cpp index e87b920e5..5d87962a2 100644 --- a/mm/2s2h/DeveloperTools/ActorViewer.cpp +++ b/mm/2s2h/DeveloperTools/ActorViewer.cpp @@ -277,8 +277,15 @@ void ActorViewerWindow::DrawElement() { ImGui::InputScalar("rZ", ImGuiDataType_S16, &newActor.rot.z); ImGui::EndGroup(); - UIWidgets::CVarCheckbox("Remove Obj Dep?", "gObjDep", - { .tooltip = "Allows actors to spawn where/when they normally wouldn't." }); + UIWidgets::CVarCheckbox("Disable Object Dependency", "gDeveloperTools.DisableObjectDependency"); + if (ImGui::IsItemHovered()) { + ImGui::BeginTooltip(); + ImGui::TextColored( + ImVec4(1.0f, 1.0f, 0.0f, 1.0f), + "Warning: This will cause some actors to spawn in places they normally wouldn't,\nplease ensure " + "this is disabled before reporting any actor related issues"); + ImGui::EndTooltip(); + } if (UIWidgets::Button("Fetch from Link")) { Player* player = GET_PLAYER(gPlayState); diff --git a/mm/2s2h/DeveloperTools/WarpPoint.cpp b/mm/2s2h/DeveloperTools/WarpPoint.cpp index 1bf27dee7..cde2fb3e6 100644 --- a/mm/2s2h/DeveloperTools/WarpPoint.cpp +++ b/mm/2s2h/DeveloperTools/WarpPoint.cpp @@ -67,6 +67,7 @@ void RenderWarpPointSection() { CVarGetInteger(CV "Room", 0), PLAYER_PARAMS(0xFF, PLAYER_INITMODE_D), &pos, CVarGetFloat(CV "Rotation", 0.0f)); func_80169EFC(&gPlayState->state); + gSaveContext.respawnFlag = -8; } } } diff --git a/mm/src/code/z_map_disp.c b/mm/src/code/z_map_disp.c index e601e00a2..e7a0197ae 100644 --- a/mm/src/code/z_map_disp.c +++ b/mm/src/code/z_map_disp.c @@ -1509,6 +1509,9 @@ s32 MapDisp_ConvertBossSceneToDungeonScene(s32 sceneId) { } } +// 2S2H [Port] Split u16 values into two u8 values for the custom palette below +#define SPLIT(val) (val >> 8) & 0xFF, val & 0xFF + /** * @brief Draws the dungeon room sprites for the pause menu dungeon map * @@ -1534,6 +1537,25 @@ void MapDisp_DrawRooms(PlayState* play, s32 viewX, s32 viewY, s32 viewWidth, s32 0x0000, 0x0623, 0xFFC1, 0x07C1, 0x07FF, 0x003F, 0xFB3F, 0xF305, 0x0453, 0x0577, 0x0095, 0x82E5, 0xFD27, 0x7A49, 0x94A5, 0x0001, }; // palette 2 + + // 2S2H [Port] Merge the 3 map palettes into 1 memory address so that we can load it once + // at index 0, but when the map textures below use index 1 or 2, Fast3D will correctly + // offset in this address to get the expected values. + // Palette stored as u8 to avoid endianeness issues in Fast3D + // clang-format off + static u8 sMergedPal[0x10 * 2 * 3] = { + // sUnvisitedRoomPal - palette 0 + SPLIT(0x0000), SPLIT(0x0000), SPLIT(0xFFC1), SPLIT(0x07C1), SPLIT(0x07FF), SPLIT(0x003F), SPLIT(0xFB3F), SPLIT(0xF305), + SPLIT(0x0453), SPLIT(0x0577), SPLIT(0x0095), SPLIT(0x82E5), SPLIT(0xFD27), SPLIT(0x7A49), SPLIT(0x94A5), SPLIT(0x0001), + // sVisitedRoomPal - palette 1 + SPLIT(0x0000), SPLIT(0x027F), SPLIT(0xFFC1), SPLIT(0x07C1), SPLIT(0x07FF), SPLIT(0x003F), SPLIT(0xFB3F), SPLIT(0xF305), + SPLIT(0x0453), SPLIT(0x0577), SPLIT(0x0095), SPLIT(0x82E5), SPLIT(0xFD27), SPLIT(0x7A49), SPLIT(0x94A5), SPLIT(0x0001), + // sCurrentRoomPal - palette 2 + SPLIT(0x0000), SPLIT(0x0623), SPLIT(0xFFC1), SPLIT(0x07C1), SPLIT(0x07FF), SPLIT(0x003F), SPLIT(0xFB3F), SPLIT(0xF305), + SPLIT(0x0453), SPLIT(0x0577), SPLIT(0x0095), SPLIT(0x82E5), SPLIT(0xFD27), SPLIT(0x7A49), SPLIT(0x94A5), SPLIT(0x0001), + }; + // clang-format on + PauseContext* pauseCtx = &play->pauseCtx; s32 pad[4]; s32 i; @@ -1542,23 +1564,40 @@ void MapDisp_DrawRooms(PlayState* play, s32 viewX, s32 viewY, s32 viewWidth, s32 sCurrentRoomPal[1] = (green << 6) | (blue << 1) | 1; + // 2S2H [Port] Apply runtime palette updates by splitting the color across the low and high index + u16 pulseColor = (green << 6) | (blue << 1) | 1; + sMergedPal[(0x10 * 2 * 2) + (1 * 2) + 0] = (pulseColor >> 8) & 0xFF; + sMergedPal[(0x10 * 2 * 2) + (1 * 2) + 1] = pulseColor & 0xFF; + if (CHECK_DUNGEON_ITEM(DUNGEON_MAP, dungeonIndex)) { s32 requiredScopeTemp; sUnvisitedRoomPal[0xF] = 0xAD5F; sVisitedRoomPal[0xF] = 0xAD5F; sCurrentRoomPal[0xF] = 0xAD5F; + + for (i = 0; i <= 2; i++) { + sMergedPal[(0x10 * 2 * i) + (0xF * 2) + 0] = (0xAD5F >> 8) & 0xFF; + sMergedPal[(0x10 * 2 * i) + (0xF * 2) + 1] = 0xAD5F & 0xFF; + } } else { sCurrentRoomPal[0xF] = sVisitedRoomPal[0xF] = sUnvisitedRoomPal[0xF] = 0; + + for (i = 0; i <= 2; i++) { + sMergedPal[(0x10 * 2 * i) + (0xF * 2) + 0] = sMergedPal[(0x10 * 2 * i) + (0xF * 2) + 1] = 0; + } } OPEN_DISPS(play->state.gfxCtx); Gfx_SetupDL39_Opa(play->state.gfxCtx); gDPSetPrimColor(POLY_OPA_DISP++, 0, 0, 255, 255, 255, pauseCtx->alpha); - gDPLoadTLUT_pal16(POLY_OPA_DISP++, 0, sUnvisitedRoomPal); - gDPLoadTLUT_pal16(POLY_OPA_DISP++, 1, sVisitedRoomPal); - gDPLoadTLUT_pal16(POLY_OPA_DISP++, 2, sCurrentRoomPal); + // #region 2S2H [Port] Load our merged palette at index 0, the other indexes do not need to be loaded + gDPLoadTLUT_pal16(POLY_OPA_DISP++, 0, sMergedPal); + // gDPLoadTLUT_pal16(POLY_OPA_DISP++, 0, sUnvisitedRoomPal); + // gDPLoadTLUT_pal16(POLY_OPA_DISP++, 1, sVisitedRoomPal); + // gDPLoadTLUT_pal16(POLY_OPA_DISP++, 2, sCurrentRoomPal); + // #endregion gDPSetTextureLUT(POLY_OPA_DISP++, G_TT_RGBA16); for (i = 0; i < sSceneNumRooms; i++) { @@ -1648,6 +1687,9 @@ void MapDisp_DrawRooms(PlayState* play, s32 viewX, s32 viewY, s32 viewWidth, s32 } else { continue; } + + // 2S2H [Port] Invalidate the map textures so that the palette updates apply + gSPInvalidateTexCache(POLY_OPA_DISP++, roomTexture); gSPTextureRectangle(POLY_OPA_DISP++, (texPosX << 2), (texPosY << 2), (texPosX + texWidth) << 2, (texPosY + texHeight) << 2, 0, s, t, dsdx, dtdy); gDPPipeSync(POLY_OPA_DISP++); diff --git a/mm/src/code/z_scene.c b/mm/src/code/z_scene.c index e74852dc2..da086e074 100644 --- a/mm/src/code/z_scene.c +++ b/mm/src/code/z_scene.c @@ -110,7 +110,7 @@ s32 Object_GetSlot(ObjectContext* objectCtx, s16 objectId) { } } - return CVarGetInteger("gObjDep", 0) ? 0 : -1; + return CVarGetInteger("gDeveloperTools.DisableObjectDependency", 0) ? 0 : -1; } s32 Object_IsLoaded(ObjectContext* objectCtx, s32 slot) { diff --git a/mm/src/overlays/gamestates/ovl_title/z_title.c b/mm/src/overlays/gamestates/ovl_title/z_title.c index d94842021..ed622dee7 100644 --- a/mm/src/overlays/gamestates/ovl_title/z_title.c +++ b/mm/src/overlays/gamestates/ovl_title/z_title.c @@ -201,6 +201,9 @@ void ConsoleLogo_Main(GameState* thisx) { STOP_GAMESTATE(&this->state); if (CVarGetInteger("gEnhancements.Cutscenes.SkipToFileSelect", 0)) { + // Normally the PRNG seed is set at least once from the title opening running Play_Init + // We need to call it manually before file select creates RNG values for new saves + Rand_Seed(osGetTime()); SET_NEXT_GAMESTATE(&this->state, FileSelect_Init, sizeof(FileSelectState)); } else { SET_NEXT_GAMESTATE(&this->state, TitleSetup_Init, sizeof(TitleSetupState));