entrance shuffle: sign hints (#5335)

* entrance shuffle: sign hints

* update entrance tracker with hint

* show sign hints when any entrances shuffled

* only hint when entrance shuffled

* avoid crash when loading rando file

* fix kf exit

* correct hint from sign outside kokiri forest

* 3 signs on DMT

* improve naming
This commit is contained in:
Philip Dubé
2025-09-17 00:52:47 +00:00
committed by GitHub
parent 524ba26034
commit e6663a1c49
7 changed files with 184 additions and 7 deletions

View File

@@ -79,8 +79,41 @@ typedef enum {
TEXT_SARIAS_SONG_CHANNELING_POWER = 0x016D,
TEXT_LAKE_HYLIA_WATER_SWITCH_NAVI = 0x01B3, // 0x1yy for Navi msg range
TEXT_MASK_SHOP_SIGN = 0x0207,
TEXT_WATERFALL = 0x022D,
TEXT_FROGS_UNDERWATER = 0x022E,
TEXT_OUTSIDE_FISHING_POND = 0x023A,
TEXT_HF_SIGN = 0x0301,
TEXT_HC_GREAT_FAIRY_SIGN = 0x0304,
TEXT_DMT_KAK_SIGN = 0x0305,
TEXT_KAK_TO_GY_SIGN = 0x0306,
TEXT_KAK_WELL_SIGN = 0x0307,
TEXT_KAK_DMT_SIGN = 0x0308,
TEXT_DMT_SIGN = 0x309,
TEXT_DMT_DC_SIGN = 0x030A,
TEXT_GC_SIGN = 0x030B,
TEXT_HF_ZR_SIGN = 0x030C,
TEXT_ZD_SIGN = 0x030E,
TEXT_ZF_JABU_SIGN = 0x030F,
TEXT_KF_LW_SIGN = 0x0314,
TEXT_HF_LON_LON_SIGN = 0x0315,
TEXT_LA_SIGN = 0x0317,
TEXT_LA_LAB_SIGN = 0x0318,
TEXT_GV_SIGN = 0x0319,
TEXT_GF_HBA_SIGN = 0x031A,
TEXT_KF_SHOP_SIGN = 0x031E,
TEXT_LINKS_HOUSE_SIGN = 0x031F,
TEXT_KOKIRI_EXIT_SIGN = 0x0320,
TEXT_DMT_GC_SIGN = 0x0321,
TEXT_DMT_DMC_SIGN = 0x0323,
TEXT_DMT_SUMMIT_SIGN = 0x032D,
TEXT_ZD_SHOP_SIGN = 0x0333,
TEXT_OUTSIDE_KOKIRI_SIGN = 0x0339,
TEXT_OUTSIDE_MARKET_SIGN = 0x033A,
TEXT_MIDO_HOUSE_SIGN = 0x033C,
TEXT_KNOW_IT_ALL_HOUSE_SIGN = 0x033D,
TEXT_TWINS_HOUSE_SIGN = 0x033E,
TEXT_SARIAS_HOUSE_SIGN = 0x033F,
TEXT_NO_DIVING_SIGN = 0x0342,
TEXT_LAKE_HYLIA_WATER_SWITCH_SIGN = 0x0346, // 0x3yy for cuttable sign range
TEXT_WARP_MINUET_OF_FOREST = 0x088D,
TEXT_WARP_BOLERO_OF_FIRE = 0x088E,

View File

@@ -9,7 +9,6 @@
#include "hints.hpp"
#include "shops.hpp"
#include "pool_functions.hpp"
//#include "debug.hpp"
#include "soh/Enhancements/randomizer/static_data.h"
#include "soh/Enhancements/debugger/performanceTimer.h"

View File

@@ -2017,6 +2017,7 @@ void RecalculateAvailableChecks(RandomizerRegion startingRegion /* = RR_ROOT */)
StartPerformanceTimer(PT_RECALCULATE_AVAILABLE_CHECKS);
const auto& ctx = Rando::Context::GetInstance();
logic = ctx->GetLogic();
std::vector<RandomizerCheck> targetLocations;
targetLocations.reserve(RC_MAX);

View File

@@ -739,7 +739,7 @@ void EntranceTrackerSettingsWindow::DrawElement() {
ImGui::BeginDisabled(CVarGetInteger(CVAR_SETTING("DisableChanges"), 0));
UIWidgets::CVarCheckbox(
"Show Source", CVAR_TRACKER_ENTRANCE("ShowFrom"),
UIWidgets::CheckboxOptions().Tooltip("Reveal the sourcefor undiscovered entrances").Color(THEME_COLOR));
UIWidgets::CheckboxOptions().Tooltip("Reveal the source for undiscovered entrances").Color(THEME_COLOR));
UIWidgets::CVarCheckbox("Show Destination", CVAR_TRACKER_ENTRANCE("ShowTo"),
UIWidgets::CheckboxOptions()
.Tooltip("Reveal the destination for undiscovered entrances")
@@ -836,7 +836,7 @@ void EntranceTrackerWindow::DrawElement() {
ImGui::BeginChild("ChildEntranceTrackerLocations", ImVec2(0, -8));
bool showTo = CVarGetInteger(CVAR_TRACKER_ENTRANCE("ShowTo"), 0);
bool showFrom = CVarGetInteger(CVAR_TRACKER_ENTRANCE("ShowFrom"), 0);
bool collapsUndiscovered = CVarGetInteger(CVAR_TRACKER_ENTRANCE("CollapseUndiscovered"), 0);
bool collapseUndiscovered = CVarGetInteger(CVAR_TRACKER_ENTRANCE("CollapseUndiscovered"), 0);
bool highlightPrevious = CVarGetInteger(CVAR_TRACKER_ENTRANCE("HighlightPrevious"), 0);
bool highlightAvailable = CVarGetInteger(CVAR_TRACKER_ENTRANCE("HighlightAvailable"), 0);
bool hideReverse = CVarGetInteger(CVAR_TRACKER_ENTRANCE("HideReverseEntrances"), 1);
@@ -892,7 +892,7 @@ void EntranceTrackerWindow::DrawElement() {
const char* rplcDstName = showOverride ? override->destination.c_str() : "";
// Filter for entrances by group name, type, source/destination names, and meta tags
if ((!locationSearch.IsActive() && (showOriginal || showOverride || !collapsUndiscovered)) ||
if ((!locationSearch.IsActive() && (showOriginal || showOverride || !collapseUndiscovered)) ||
((showOriginal &&
(locationSearch.PassFilter(origSrcName) || locationSearch.PassFilter(origSrcAreaName) ||
locationSearch.PassFilter(origTypeName) || locationSearch.PassFilter(original->metaTag.c_str()))) ||

View File

@@ -184,7 +184,7 @@ s16 Grotto_GetEntranceValueHandlingGrottoRando(s16 nextEntranceIndex) {
}
// Translates and overrides the passed in entrance index if it corresponds to a
// special grotto entrance (grotto load or returnpoint) and updates player respawn data correctly.
// special grotto entrance (grotto load or return point) and updates player respawn data correctly.
s16 Grotto_OverrideSpecialEntrance(s16 nextEntranceIndex) {
// Don't change anything unless grotto shuffle has been enabled

View File

@@ -26,6 +26,8 @@
#include "Enhancements/audio/AudioCollection.h"
#include "Enhancements/enhancementTypes.h"
#include "Enhancements/debugconsole.h"
#include "Enhancements/randomizer/entrance.h"
#include "Enhancements/randomizer/location_access.h"
#include "Enhancements/randomizer/randomizer.h"
#include "Enhancements/randomizer/randomizer_entrance_tracker.h"
#include "Enhancements/randomizer/randomizer_item_tracker.h"
@@ -2257,6 +2259,149 @@ extern "C" int CustomMessage_RetrieveIfExists(PlayState* play) {
s16 actorParams = 0;
if (IS_RANDO) {
auto ctx = Rando::Context::GetInstance();
if (ctx->GetOption(RSK_SHUFFLE_ENTRANCES)) {
s16 entrance = -1;
switch (textId) {
case TEXT_WATERFALL:
entrance = ENTR_ZORAS_DOMAIN_ENTRANCE;
break;
case TEXT_OUTSIDE_FISHING_POND:
entrance = ENTR_FISHING_POND_0;
break;
case TEXT_HF_SIGN:
if (gPlayState->sceneNum == SCENE_KAKARIKO_VILLAGE) {
entrance = ENTR_HYRULE_FIELD_STAIRS_EXIT;
} else if (gPlayState->sceneNum == SCENE_GERUDO_VALLEY) {
entrance = ENTR_HYRULE_FIELD_ROCKY_PATH;
} else if (gPlayState->sceneNum == SCENE_LAKE_HYLIA) {
entrance = ENTR_HYRULE_FIELD_FENCE_EXIT;
}
break;
case TEXT_HC_GREAT_FAIRY_SIGN:
entrance = ENTR_GREAT_FAIRYS_FOUNTAIN_SPELLS_DINS_HC;
break;
case TEXT_DMT_KAK_SIGN:
if (gPlayState->sceneNum == SCENE_HYRULE_FIELD) {
entrance = ENTR_KAKARIKO_VILLAGE_FRONT_GATE;
} else {
entrance = ENTR_KAKARIKO_VILLAGE_GUARD_GATE;
}
break;
case TEXT_KAK_TO_GY_SIGN:
entrance = ENTR_GRAVEYARD_ENTRANCE;
break;
case TEXT_KAK_WELL_SIGN:
entrance = ENTR_BOTTOM_OF_THE_WELL_ENTRANCE;
break;
case TEXT_KAK_DMT_SIGN:
entrance = ENTR_DEATH_MOUNTAIN_TRAIL_BOTTOM_EXIT;
break;
case TEXT_DMT_SIGN:
entrance = ENTR_GROTTOS_13;
break;
case TEXT_DMT_DC_SIGN:
entrance = ENTR_DEATH_MOUNTAIN_TRAIL_OUTSIDE_DODONGOS_CAVERN;
break;
case TEXT_DMT_GC_SIGN:
entrance = ENTR_GORON_CITY_UPPER_EXIT;
break;
case TEXT_GC_SIGN:
if (gPlayState->sceneNum == SCENE_DEATH_MOUNTAIN_TRAIL) {
entrance = ENTR_GORON_CITY_UPPER_EXIT;
} else {
entrance = ENTR_GORON_CITY_DARUNIA_ROOM_EXIT;
}
break;
case TEXT_DMT_DMC_SIGN:
entrance = ENTR_DEATH_MOUNTAIN_CRATER_UPPER_EXIT;
break;
case TEXT_DMT_SUMMIT_SIGN:
entrance = ENTR_GREAT_FAIRYS_FOUNTAIN_MAGIC_DMT;
break;
case TEXT_HF_ZR_SIGN:
entrance = ENTR_ZORAS_RIVER_WEST_EXIT;
break;
case TEXT_KF_SHOP_SIGN:
entrance = ENTR_KOKIRI_SHOP_0;
break;
case TEXT_LINKS_HOUSE_SIGN:
entrance = ENTR_LINKS_HOUSE_1;
break;
case TEXT_KOKIRI_EXIT_SIGN:
entrance = ENTR_LOST_WOODS_BRIDGE_EAST_EXIT;
break;
case TEXT_ZD_SIGN:
if (gPlayState->sceneNum == SCENE_ZORAS_DOMAIN) {
entrance = ENTR_ZORAS_RIVER_WATERFALL_EXIT;
} else {
entrance = ENTR_ZORAS_DOMAIN_KING_ZORA_EXIT;
}
break;
case TEXT_ZF_JABU_SIGN:
entrance = ENTR_JABU_JABU_ENTRANCE;
break;
case TEXT_KF_LW_SIGN:
entrance = ENTR_LOST_WOODS_SOUTH_EXIT;
break;
case TEXT_HF_LON_LON_SIGN:
entrance = ENTR_LON_LON_RANCH_ENTRANCE;
break;
case TEXT_LA_SIGN:
entrance = ENTR_LAKE_HYLIA_NORTH_EXIT;
break;
case TEXT_LA_LAB_SIGN:
entrance = ENTR_LAKESIDE_LABORATORY_0;
break;
case TEXT_GV_SIGN:
if (gPlayState->sceneNum == SCENE_HYRULE_FIELD) {
entrance = ENTR_GERUDO_VALLEY_EAST_EXIT;
} else {
entrance = ENTR_GERUDO_VALLEY_WEST_EXIT;
}
break;
case TEXT_ZD_SHOP_SIGN:
entrance = ENTR_ZORA_SHOP_0;
break;
case TEXT_OUTSIDE_KOKIRI_SIGN:
entrance = ENTR_MARKET_ENTRANCE_NEAR_GUARD_EXIT;
break;
case TEXT_OUTSIDE_MARKET_SIGN:
entrance = ENTR_LON_LON_RANCH_ENTRANCE;
break;
case TEXT_MIDO_HOUSE_SIGN:
entrance = ENTR_MIDOS_HOUSE_0;
break;
case TEXT_KNOW_IT_ALL_HOUSE_SIGN:
entrance = ENTR_KNOW_IT_ALL_BROS_HOUSE_0;
break;
case TEXT_TWINS_HOUSE_SIGN:
entrance = ENTR_TWINS_HOUSE_0;
break;
case TEXT_SARIAS_HOUSE_SIGN:
entrance = ENTR_SARIAS_HOUSE_0;
break;
case TEXT_NO_DIVING_SIGN:
entrance = ENTR_LAKE_HYLIA_RIVER_EXIT;
break;
}
if (entrance != -1) {
auto entranceCtx = ctx->GetEntranceShuffler();
for (size_t i = 0; i < ENTRANCE_OVERRIDES_MAX_COUNT; i++) {
if (Entrance_EntranceIsNull(&entranceCtx->entranceOverrides[i])) {
break;
}
if (entranceCtx->entranceOverrides[i].index == entrance) {
s16 overrideIndex = entranceCtx->entranceOverrides[i].override;
Entrance_SetEntranceDiscovered(entrance, false);
auto data = GetEntranceData(overrideIndex);
font->charTexBuf[0] = (TEXTBOX_TYPE_WOODEN << 4) | TEXTBOX_POS_BOTTOM;
return msgCtx->msgLength = font->msgLength = SohUtils::CopyStringToCharBuffer(
buffer, data->source + CustomMessage::MESSAGE_END(), maxBufferSize);
}
}
}
}
bool nonBeanMerchants = ctx->GetOption(RSK_SHUFFLE_MERCHANTS).Is(RO_SHUFFLE_MERCHANTS_ALL_BUT_BEANS) ||
ctx->GetOption(RSK_SHUFFLE_MERCHANTS).Is(RO_SHUFFLE_MERCHANTS_ALL);
Player* player = GET_PLAYER(play);
@@ -2332,7 +2477,7 @@ extern "C" int CustomMessage_RetrieveIfExists(PlayState* play) {
} else {
messageEntry = ctx->GetHint(stoneHint)->GetHintMessage(MF_AUTO_FORMAT);
}
} else if ((textId == TEXT_ALTAR_CHILD || textId == TEXT_ALTAR_ADULT)) {
} else if (textId == TEXT_ALTAR_CHILD || textId == TEXT_ALTAR_ADULT) {
// rando hints at altar
messageEntry = (LINK_IS_ADULT) ? ctx->GetHint(RH_ALTAR_ADULT)->GetHintMessage(MF_AUTO_FORMAT)
: ctx->GetHint(RH_ALTAR_CHILD)->GetHintMessage(MF_AUTO_FORMAT);

View File

@@ -2782,7 +2782,6 @@ void Message_OpenText(PlayState* play, u16 textId) {
gSaveContext.eventInf[0] = gSaveContext.eventInf[1] = gSaveContext.eventInf[2] = gSaveContext.eventInf[3] = 0;
}
// RANDOTODO: Use this for ice trap messages
if (CustomMessage_RetrieveIfExists(play)) {
osSyncPrintf("Found custom message");
if (gSaveContext.language == LANGUAGE_JPN) {