Merge branch 'develop' of garrettjoecox.github.com:HarbourMasters/Shipwright into let-it-snow

This commit is contained in:
Garrett Cox 2024-12-09 21:01:45 -06:00
commit c47f1d6d92
30 changed files with 790 additions and 1408 deletions

View file

@ -537,7 +537,7 @@ void func_80034BA0(PlayState* play, SkelAnime* skelAnime, OverrideLimbDraw overr
PostLimbDraw postLimbDraw, Actor* actor, s16 alpha); PostLimbDraw postLimbDraw, Actor* actor, s16 alpha);
void func_80034CC4(PlayState* play, SkelAnime* skelAnime, OverrideLimbDraw overrideLimbDraw, void func_80034CC4(PlayState* play, SkelAnime* skelAnime, OverrideLimbDraw overrideLimbDraw,
PostLimbDraw postLimbDraw, Actor* actor, s16 alpha); PostLimbDraw postLimbDraw, Actor* actor, s16 alpha);
s16 func_80034DD4(Actor* actor, PlayState* play, s16 arg2, f32 arg3); s16 Actor_UpdateAlphaByDistance(Actor* actor, PlayState* play, s16 arg2, f32 arg3);
void Animation_ChangeByInfo(SkelAnime* skelAnime, AnimationInfo* animationInfo, s32 index); void Animation_ChangeByInfo(SkelAnime* skelAnime, AnimationInfo* animationInfo, s32 index);
void func_80034F54(PlayState* play, s16* arg1, s16* arg2, s32 arg3); void func_80034F54(PlayState* play, s16* arg1, s16* arg2, s32 arg3);
void Actor_Noop(Actor* actor, PlayState* play); void Actor_Noop(Actor* actor, PlayState* play);

View file

@ -281,6 +281,9 @@ typedef enum {
VB_SPAWN_BLUE_WARP, VB_SPAWN_BLUE_WARP,
// Vanilla condition: this->warpTimer > sWarpTimerTarget && gSaveContext.nextCutsceneIndex == 0xFFEF // Vanilla condition: this->warpTimer > sWarpTimerTarget && gSaveContext.nextCutsceneIndex == 0xFFEF
VB_BLUE_WARP_APPLY_ENTRANCE_AND_CUTSCENE, VB_BLUE_WARP_APPLY_ENTRANCE_AND_CUTSCENE,
// Vanilla condition: SurfaceType_GetSlope(&play->colCtx, poly, bgId) == 2
// Opt: int (original next entrance index)
VB_SET_VOIDOUT_FROM_SURFACE,
// Vanilla condition: this->collider.base.acFlags & 2 // Vanilla condition: this->collider.base.acFlags & 2
VB_BG_BREAKWALL_BREAK, VB_BG_BREAKWALL_BREAK,
// Vanilla condition: true // Vanilla condition: true

View file

@ -2493,86 +2493,91 @@ void StaticData::HintTable_Init() {
/*-------------------------- /*--------------------------
| BOSS HINT TEXT | | BOSS HINT TEXT |
---------------------------*/ ---------------------------*/
//RANDOTODO check the beginning and end on the french and german translations
hintTextTable[RHT_QUEEN_GOHMA] = HintText(CustomMessage("#Queen Gohma# holds", hintTextTable[RHT_QUEEN_GOHMA] = HintText(CustomMessage("They say that #Queen Gohma# holds #[[1]]#.",
/*german*/ "#Königin Gohma# hält", /*german*/ "Man erzählt sich, daß #Königin Gohma# hält #[[1]]# lehre.",
/*french*/ "la #Reine Gohma# possède"), /*french*/ "Selon moi, la #Reine Gohma# possède #[[1]]#.", {QM_RED, QM_GREEN}),
// /*spanish*/la #Reina Goma# porta // /*spanish*/la #Reina Goma# porta #[[1]]#.
{}, {},
{CustomMessage("the #Parasitic Armored Arachnid# holds", {CustomMessage("They say that the #Parasitic Armored Arachnid# holds #[[1]]#.",
/*german*/ "die #gepanzerte parasitäre Spinne# hält", /*german*/ "Man erzählt sich, daß die #gepanzerte parasitäre Spinne# hält #[[1]]# lehre.",
/*french*/ "le #monstre insectoïde géant# possède")}); /*french*/ "Selon moi, le #monstre insectoïde géant# possède #[[1]]#.", {QM_RED, QM_GREEN})});
// /*spanish*/el #arácnido parasitario acorazado# porta // /*spanish*/el #arácnido parasitario acorazado# porta #[[1]]#.
hintTextTable[RHT_KING_DODONGO] = HintText(CustomMessage("#King Dodongo# holds", hintTextTable[RHT_KING_DODONGO] = HintText(CustomMessage("They say that #King Dodongo# holds #[[1]]#.",
/*german*/ "#König Dodongo# hält", /*german*/ "Man erzählt sich, daß #König Dodongo# hält #[[1]]# lehre.",
/*french*/ "le #Roi Dodongo# possède"), /*french*/ "Selon moi, le #Roi Dodongo# possède #[[1]]#.", {QM_RED, QM_GREEN}),
// /*spanish*/el #Rey Dodongo# porta // /*spanish*/el #Rey Dodongo# porta #[[1]]#.
{}, {},
{CustomMessage("the #Infernal Dinosaur# holds", {CustomMessage("They say that the #Infernal Dinosaur# holds #[[1]]#.",
/*german*/ "der #infernalische Dinosaurier# hält", /*german*/ "Man erzählt sich, daß der #infernalische Dinosaurier# hält #[[1]]# lehre.",
/*french*/ "le #dinosaure infernal# possède")}); /*french*/ "Selon moi, le #dinosaure infernal# possède #[[1]]#.", {QM_RED, QM_GREEN})});
// /*spanish*/el #dinosaurio infernal# porta // /*spanish*/el #dinosaurio infernal# porta #[[1]]#.
hintTextTable[RHT_BARINADE] = HintText(CustomMessage("#Barinade# holds", hintTextTable[RHT_BARINADE] = HintText(CustomMessage("They say that #Barinade# holds #[[1]]#.",
/*german*/ "#Barinade# hält", /*german*/ "Man erzählt sich, daß #Barinade# hält #[[1]]# lehre.",
/*french*/ "#Barinade# possède"), /*french*/ "Selon moi, #Barinade# possède #[[1]]#.", {QM_RED, QM_GREEN}),
// /*spanish*/#Barinade# porta // /*spanish*/#Barinade# porta #[[1]]#.
{}, {},
{CustomMessage("the #Bio-Electric Anemone# holds", {CustomMessage("They say that the #Bio-Electric Anemone# holds #[[1]]#.",
/*german*/ "die #bioelektrische Anemone# hält", /*german*/ "Man erzählt sich, daß die #bioelektrische Anemone# hält #[[1]]# lehre.",
/*french*/ "l'#anémone bioélectrique# possède")}); /*french*/ "Selon moi, l'#anémone bioélectrique# possède #[[1]]#.", {QM_RED, QM_GREEN})});
// /*spanish*/la #anémona bioeléctrica# porta // /*spanish*/la #anémona bioeléctrica# porta #[[1]]#.
hintTextTable[RHT_PHANTOM_GANON] = HintText(CustomMessage("#Phantom Ganon# holds", hintTextTable[RHT_PHANTOM_GANON] = HintText(CustomMessage("They say that #Phantom Ganon# holds #[[1]]#.",
/*german*/ "#Phantom-Ganon# hält", /*german*/ "Man erzählt sich, daß #Phantom-Ganon# hält #[[1]]# lehre.",
/*french*/ "#Ganon Spectral# possède"), /*french*/ "Selon moi, #Ganon Spectral# possède #[[1]]#.", {QM_RED, QM_GREEN}),
// /*spanish*/#Ganon Fantasma# porta // /*spanish*/#Ganon Fantasma# porta #[[1]]#.
{}, {},
{CustomMessage("the #Evil Spirit from Beyond# holds", {CustomMessage("They say that the #Evil Spirit from Beyond# holds #[[1]]#.",
/*german*/ "der #böse Geist aus dem Jenseits# hält", /*german*/ "Man erzählt sich, daß der #böse Geist aus dem Jenseits# hält #[[1]]# lehre.",
/*french*/ "l'#esprit maléfique de l'au-delà# possède")}); /*french*/ "Selon moi, l'#esprit maléfique de l'au-delà# possède #[[1]]#.", {QM_RED, QM_GREEN})});
// /*spanish*/el #espíritu maligno de ultratumba# porta // /*spanish*/el #espíritu maligno de ultratumba# porta #[[1]]#.
hintTextTable[RHT_VOLVAGIA] = HintText(CustomMessage("#Volvagia# holds", hintTextTable[RHT_VOLVAGIA] = HintText(CustomMessage("They say that #Volvagia# holds #[[1]]#.",
/*german*/ "#Volvagia# hält", /*german*/ "Man erzählt sich, daß #Volvagia# hält #[[1]]# lehre.",
/*french*/ "#Volvagia# possède"), /*french*/ "Selon moi, #Volvagia# possède #[[1]]#.", {QM_RED, QM_GREEN}),
// /*spanish*/#Volvagia# porta // /*spanish*/#Volvagia# porta #[[1]]#.
{}, {},
{CustomMessage("the #Subterranean Lava Dragon# holds", {CustomMessage("They say that the #Subterranean Lava Dragon# holds #[[1]]#.",
/*german*/ "der #subterrane Lavadrache# hält", /*german*/ "Man erzählt sich, daß der #subterrane Lavadrache# hält #[[1]]# lehre.",
/*french*/ "le #dragon des profondeurs# possède")}); /*french*/ "Selon moi, le #dragon des profondeurs# possède #[[1]]#.", {QM_RED, QM_GREEN})});
// /*spanish*/el #dragón de lava subterráneo# porta // /*spanish*/el #dragón de lava subterráneo# porta #[[1]]#.
hintTextTable[RHT_MORPHA] = HintText(CustomMessage("#Morpha# holds", hintTextTable[RHT_MORPHA] = HintText(CustomMessage("They say that #Morpha# holds #[[1]]#.",
/*german*/ "#Morpha# hält", /*german*/ "Man erzählt sich, daß #Morpha# hält #[[1]]# lehre.",
/*french*/ "#Morpha# possède"), /*french*/ "Selon moi, #Morpha# possède #[[1]]#.", {QM_RED, QM_GREEN}),
// /*spanish*/#Morpha# porta // /*spanish*/#Morpha# porta #[[1]]#.
{}, {},
{CustomMessage("the #Giant Aquatic Amoeba# holds", {CustomMessage("They say that the #Giant Aquatic Amoeba# holds #[[1]]#.",
/*german*/ "die #gigantische aquatische Amöbe# hält", /*german*/ "Man erzählt sich, daß die #gigantische aquatische Amöbe# hält #[[1]]# lehre.",
/*french*/ "l'#amibe aquatique géante# possède")}); /*french*/ "Selon moi, l'#amibe aquatique géante# possède #[[1]]#.", {QM_RED, QM_GREEN})});
// /*spanish*/la #ameba acuática gigante# porta // /*spanish*/la #ameba acuática gigante# porta #[[1]]#.
hintTextTable[RHT_BONGO_BONGO] = HintText(CustomMessage("#Bongo Bongo# holds", hintTextTable[RHT_BONGO_BONGO] = HintText(CustomMessage("They say that #Bongo Bongo# holds #[[1]]#.",
/*german*/ "#Bongo Bongo# hält", /*german*/ "Man erzählt sich, daß #Bongo Bongo# hält #[[1]]# lehre.",
/*french*/ "#Bongo Bongo# possède"), /*french*/ "Selon moi, #Bongo Bongo# possède #[[1]]#.", {QM_RED, QM_GREEN}),
// /*spanish*/#Bongo Bongo# porta // /*spanish*/#Bongo Bongo# porta #[[1]]#.
{}, {},
{CustomMessage("the #Phantom Shadow Beast# holds", {CustomMessage("They say that the #Phantom Shadow Beast# holds #[[1]]#.",
/*german*/ "das #Phantomschattenbiest# hält", /*german*/ "Man erzählt sich, daß das #Phantomschattenbiest# hält #[[1]]# lehre.",
/*french*/ "le #monstre de l'ombre# possède")}); /*french*/ "Selon moi, le #monstre de l'ombre# possède #[[1]]#.", {QM_RED, QM_GREEN})});
// /*spanish*/la #alimaña oscura espectral# porta // /*spanish*/la #alimaña oscura espectral# porta #[[1]]#.
hintTextTable[RHT_TWINROVA] = HintText(CustomMessage("#Twinrova# holds", hintTextTable[RHT_TWINROVA] = HintText(CustomMessage("They say that #Twinrova# holds #[[1]]#.",
/*german*/ "#Twinrova# hält", /*german*/ "Man erzählt sich, daß #Twinrova# hält #[[1]]# lehre.",
/*french*/ "#Twinrova# possède"), /*french*/ "Selon moi, #Twinrova# possède #[[1]]#.", {QM_RED, QM_GREEN}),
// /*spanish*/#Birova# porta // /*spanish*/#Birova# porta #[[1]]#.
{}, {},
{CustomMessage("the #Sorceress Sisters# hold", {CustomMessage("They say that the #Sorceress Sisters# hold #[[1]]#.",
/*german*/ "die #Hexenschwestern# halten", /*german*/ "Man erzählt sich, daß die #Hexenschwestern# halten #[[1]]# lehre.",
/*french*/ "#les sorcières jumelles# possède")}); /*french*/ "Selon moi, #les sorcières jumelles# possède #[[1]]#.", {QM_RED, QM_GREEN})});
// /*spanish*/las #hermanas hechiceras# portan // /*spanish*/las #hermanas hechiceras# portan #[[1]]#.
hintTextTable[RHT_GIFT_FROM_SAGES] = HintText(CustomMessage("They say that the #Sage of Light# gifts @ #[[1]]#.", {QM_RED, QM_GREEN}),
{},
{CustomMessage("They say that #a former owl# gifts @ #[[1]]#.", {QM_RED, QM_GREEN})});
/*-------------------------- /*--------------------------
| BRIDGE HINT TEXT | | BRIDGE HINT TEXT |
---------------------------*/ ---------------------------*/

View file

@ -1026,7 +1026,7 @@ void GenerateItemPool() {
} }
//Gerudo Fortress //Gerudo Fortress
if (ctx->GetOption(RSK_GERUDO_FORTRESS).Is(RO_GF_OPEN)) { if (ctx->GetOption(RSK_GERUDO_FORTRESS).Is(RO_GF_FREE)) {
ctx->PlaceItemInLocation(RC_GF_NORTH_F1_CARPENTER, RG_RECOVERY_HEART, false, true); ctx->PlaceItemInLocation(RC_GF_NORTH_F1_CARPENTER, RG_RECOVERY_HEART, false, true);
ctx->PlaceItemInLocation(RC_GF_NORTH_F2_CARPENTER, RG_RECOVERY_HEART, false, true); ctx->PlaceItemInLocation(RC_GF_NORTH_F2_CARPENTER, RG_RECOVERY_HEART, false, true);
ctx->PlaceItemInLocation(RC_GF_SOUTH_F1_CARPENTER, RG_RECOVERY_HEART, false, true); ctx->PlaceItemInLocation(RC_GF_SOUTH_F1_CARPENTER, RG_RECOVERY_HEART, false, true);
@ -1071,7 +1071,7 @@ void GenerateItemPool() {
} }
//Gerudo Membership Card //Gerudo Membership Card
if (ctx->GetOption(RSK_SHUFFLE_GERUDO_MEMBERSHIP_CARD) && ctx->GetOption(RSK_GERUDO_FORTRESS).IsNot(RO_GF_OPEN)) { if (ctx->GetOption(RSK_SHUFFLE_GERUDO_MEMBERSHIP_CARD) && ctx->GetOption(RSK_GERUDO_FORTRESS).IsNot(RO_GF_FREE)) {
AddItemToMainPool(RG_GERUDO_MEMBERSHIP_CARD); AddItemToMainPool(RG_GERUDO_MEMBERSHIP_CARD);
ctx->possibleIceTrapModels.push_back(RG_GERUDO_MEMBERSHIP_CARD); ctx->possibleIceTrapModels.push_back(RG_GERUDO_MEMBERSHIP_CARD);
} else if (ctx->GetOption(RSK_SHUFFLE_GERUDO_MEMBERSHIP_CARD)) { } else if (ctx->GetOption(RSK_SHUFFLE_GERUDO_MEMBERSHIP_CARD)) {

View file

@ -16,7 +16,7 @@ void RegionTable_Init_GerudoValley() {
Entrance(RR_GV_UPPER_STREAM, {[]{return true;}}), Entrance(RR_GV_UPPER_STREAM, {[]{return true;}}),
Entrance(RR_GV_CRATE_LEDGE, {[]{return logic->IsChild || logic->CanUse(RG_LONGSHOT);}}), Entrance(RR_GV_CRATE_LEDGE, {[]{return logic->IsChild || logic->CanUse(RG_LONGSHOT);}}),
Entrance(RR_GV_GROTTO_LEDGE, {[]{return true;}}), Entrance(RR_GV_GROTTO_LEDGE, {[]{return true;}}),
Entrance(RR_GV_FORTRESS_SIDE, {[]{return (logic->IsAdult && (logic->CanUse(RG_EPONA) || logic->CanUse(RG_LONGSHOT) || ctx->GetOption(RSK_GERUDO_FORTRESS).Is(RO_GF_OPEN) || logic->CarpenterRescue)) || (logic->IsChild && logic->CanUse(RG_HOOKSHOT));}}), Entrance(RR_GV_FORTRESS_SIDE, {[]{return (logic->IsAdult && (logic->CanUse(RG_EPONA) || logic->CanUse(RG_LONGSHOT) || ctx->GetOption(RSK_GERUDO_FORTRESS).Is(RO_GF_FREE) || logic->CarpenterRescue)) || (logic->IsChild && logic->CanUse(RG_HOOKSHOT));}}),
}); });
areaTable[RR_GV_UPPER_STREAM] = Region("GV Upper Stream", "Gerudo Valley", {RA_GERUDO_VALLEY}, DAY_NIGHT_CYCLE, { areaTable[RR_GV_UPPER_STREAM] = Region("GV Upper Stream", "Gerudo Valley", {RA_GERUDO_VALLEY}, DAY_NIGHT_CYCLE, {
@ -64,7 +64,7 @@ void RegionTable_Init_GerudoValley() {
//Exits //Exits
Entrance(RR_GERUDO_FORTRESS, {[]{return true;}}), Entrance(RR_GERUDO_FORTRESS, {[]{return true;}}),
Entrance(RR_GV_UPPER_STREAM, {[]{return true;}}), Entrance(RR_GV_UPPER_STREAM, {[]{return true;}}),
Entrance(RR_GERUDO_VALLEY, {[]{return logic->IsChild || logic->CanUse(RG_EPONA) || logic->CanUse(RG_LONGSHOT) || ctx->GetOption(RSK_GERUDO_FORTRESS).Is(RO_GF_OPEN) || logic->CarpenterRescue;}}), Entrance(RR_GERUDO_VALLEY, {[]{return logic->IsChild || logic->CanUse(RG_EPONA) || logic->CanUse(RG_LONGSHOT) || ctx->GetOption(RSK_GERUDO_FORTRESS).Is(RO_GF_FREE) || logic->CarpenterRescue;}}),
Entrance(RR_GV_CARPENTER_TENT, {[]{return logic->IsAdult;}}), Entrance(RR_GV_CARPENTER_TENT, {[]{return logic->IsAdult;}}),
Entrance(RR_GV_STORMS_GROTTO, {[]{return logic->IsAdult && logic->CanOpenStormsGrotto();}}), Entrance(RR_GV_STORMS_GROTTO, {[]{return logic->IsAdult && logic->CanOpenStormsGrotto();}}),
Entrance(RR_GV_CRATE_LEDGE, {[]{return false;}}), Entrance(RR_GV_CRATE_LEDGE, {[]{return false;}}),

View file

@ -139,14 +139,11 @@ static void WriteShuffledEntrance(std::string sphereString, Entrance* entrance)
// Writes the settings (without excluded locations, starting inventory and tricks) to the spoilerLog document. // Writes the settings (without excluded locations, starting inventory and tricks) to the spoilerLog document.
static void WriteSettings() { static void WriteSettings() {
auto ctx = Rando::Context::GetInstance(); auto ctx = Rando::Context::GetInstance();
auto allOptionGroups = ctx->GetSettings()->GetOptionGroups(); std::array<Rando::Option, RSK_MAX> options = ctx->GetSettings()->GetAllOptions();
for (const Rando::OptionGroup& optionGroup : allOptionGroups) { for (const Rando::Option& option : options) {
if (optionGroup.GetContainsType() == Rando::OptionGroupType::DEFAULT && optionGroup.PrintInSpoiler()) { if (option.GetName() != ""){
for (Rando::Option* option : optionGroup.GetOptions()) { jsonData["settings"][option.GetName()] = option.GetSelectedOptionText();
std::string settingName = optionGroup.GetName() + ":" + option->GetName(); }
jsonData["settings"][settingName] = option->GetSelectedOptionText();
}
}
} }
} }

View file

@ -61,7 +61,7 @@ void GenerateStartingInventory() {
AddItemToInventory(RG_GANONS_CASTLE_BOSS_KEY); AddItemToInventory(RG_GANONS_CASTLE_BOSS_KEY);
} }
if (ctx->GetOption(RSK_GERUDO_FORTRESS).Is(RO_GF_OPEN) && !ctx->GetOption(RSK_SHUFFLE_GERUDO_MEMBERSHIP_CARD)) { if (ctx->GetOption(RSK_GERUDO_FORTRESS).Is(RO_GF_FREE) && !ctx->GetOption(RSK_SHUFFLE_GERUDO_MEMBERSHIP_CARD)) {
AddItemToInventory(RG_GERUDO_MEMBERSHIP_CARD); AddItemToInventory(RG_GERUDO_MEMBERSHIP_CARD);
} }

View file

@ -1558,6 +1558,40 @@ void RandomizerOnVanillaBehaviorHandler(GIVanillaBehavior id, bool* should, va_l
*should = !Flags_GetInfTable(INFTABLE_145) || Flags_GetInfTable(INFTABLE_146); *should = !Flags_GetInfTable(INFTABLE_145) || Flags_GetInfTable(INFTABLE_146);
break; break;
} }
case VB_SET_VOIDOUT_FROM_SURFACE: {
// ENTRTODO: Move all entrance rando handling to a dedicated file
std::vector<s16> entrPersistTempFlags = {
ENTR_DEKU_TREE_BOSS_ENTRANCE, ENTR_DEKU_TREE_BOSS_DOOR, ENTR_DODONGOS_CAVERN_BOSS_ENTRANCE,
ENTR_DODONGOS_CAVERN_BOSS_DOOR, ENTR_JABU_JABU_BOSS_ENTRANCE, ENTR_JABU_JABU_BOSS_DOOR,
ENTR_FOREST_TEMPLE_BOSS_ENTRANCE, ENTR_FOREST_TEMPLE_BOSS_DOOR, ENTR_FIRE_TEMPLE_BOSS_ENTRANCE,
ENTR_FIRE_TEMPLE_BOSS_DOOR, ENTR_WATER_TEMPLE_BOSS_ENTRANCE, ENTR_WATER_TEMPLE_BOSS_DOOR,
ENTR_SPIRIT_TEMPLE_BOSS_ENTRANCE, ENTR_SPIRIT_TEMPLE_BOSS_DOOR, ENTR_SHADOW_TEMPLE_BOSS_ENTRANCE,
ENTR_SHADOW_TEMPLE_BOSS_DOOR, ENTR_SPIRIT_TEMPLE_ENTRANCE,
};
s16 originalEntrance = (s16)va_arg(args, int);
// In Entrance rando, if our respawnFlag is set for a grotto return, we don't want the void out to happen
if (*should == true && RAND_GET_OPTION(RSK_SHUFFLE_ENTRANCES)) {
// Check for dungeon special entrances that are randomized to a new location
if (std::find(entrPersistTempFlags.begin(), entrPersistTempFlags.end(), originalEntrance) !=
entrPersistTempFlags.end() && originalEntrance != gPlayState->nextEntranceIndex) {
// Normally dungeons use a special voidout between scenes so that entering/exiting a boss room,
// or leaving via Spirit Hands and going back in persist temp flags across scenes.
// For ER, the temp flags should be wiped out so that they aren't transferred to the new location.
gPlayState->actorCtx.flags.tempSwch = 0;
gPlayState->actorCtx.flags.tempCollect = 0;
// If the respawnFlag is set for a grotto return, we don't want the void out to happen.
// Set the data flag to one to prevent the respawn point from being overriden by dungeon doors.
if (gSaveContext.respawnFlag == 2) {
gSaveContext.respawn[RESPAWN_MODE_DOWN].data = 1;
*should = false;
}
}
}
break;
}
case VB_FREEZE_ON_SKULL_TOKEN: case VB_FREEZE_ON_SKULL_TOKEN:
case VB_TRADE_TIMER_ODD_MUSHROOM: case VB_TRADE_TIMER_ODD_MUSHROOM:
case VB_TRADE_TIMER_FROG: case VB_TRADE_TIMER_FROG:
@ -1623,6 +1657,7 @@ void RandomizerOnSceneInitHandler(int16_t sceneNum) {
CheckTracker::RecalculateAllAreaTotals(); CheckTracker::RecalculateAllAreaTotals();
} }
// ENTRTODO: Move all entrance rando handling to a dedicated file
if (RAND_GET_OPTION(RSK_SHUFFLE_ENTRANCES)) { if (RAND_GET_OPTION(RSK_SHUFFLE_ENTRANCES)) {
// In ER, override roomNum to load based on scene and spawn during scene init // In ER, override roomNum to load based on scene and spawn during scene init
if (gSaveContext.respawnFlag <= 0) { if (gSaveContext.respawnFlag <= 0) {
@ -2336,6 +2371,7 @@ void RandomizerRegisterHooks() {
if (!IS_RANDO) return; if (!IS_RANDO) return;
// ENTRTODO: Move all entrance rando handling to a dedicated file
// Setup the modified entrance table and entrance shuffle table for rando // Setup the modified entrance table and entrance shuffle table for rando
Entrance_Init(); Entrance_Init();

View file

@ -818,7 +818,7 @@ void Rando::StaticData::InitLocationTable() { //
locationTable[RC_TWINROVA] = Location::Base(RC_TWINROVA, RCQUEST_BOTH, RCTYPE_DUNGEON_REWARD, ACTOR_DOOR_WARP1, SCENE_SPIRIT_TEMPLE_BOSS, 0x00, "Twinrova", "Twinrova", RHT_TWINROVA, RG_SPIRIT_MEDALLION, SpoilerCollectionCheck::RandomizerInf(RAND_INF_DUNGEONS_DONE_SPIRIT_TEMPLE), true); locationTable[RC_TWINROVA] = Location::Base(RC_TWINROVA, RCQUEST_BOTH, RCTYPE_DUNGEON_REWARD, ACTOR_DOOR_WARP1, SCENE_SPIRIT_TEMPLE_BOSS, 0x00, "Twinrova", "Twinrova", RHT_TWINROVA, RG_SPIRIT_MEDALLION, SpoilerCollectionCheck::RandomizerInf(RAND_INF_DUNGEONS_DONE_SPIRIT_TEMPLE), true);
locationTable[RC_BONGO_BONGO] = Location::Base(RC_BONGO_BONGO, RCQUEST_BOTH, RCTYPE_DUNGEON_REWARD, ACTOR_DOOR_WARP1, SCENE_SHADOW_TEMPLE_BOSS, 0x00, "Bongo Bongo", "Bongo Bongo", RHT_BONGO_BONGO, RG_SHADOW_MEDALLION, SpoilerCollectionCheck::RandomizerInf(RAND_INF_DUNGEONS_DONE_SHADOW_TEMPLE), true); locationTable[RC_BONGO_BONGO] = Location::Base(RC_BONGO_BONGO, RCQUEST_BOTH, RCTYPE_DUNGEON_REWARD, ACTOR_DOOR_WARP1, SCENE_SHADOW_TEMPLE_BOSS, 0x00, "Bongo Bongo", "Bongo Bongo", RHT_BONGO_BONGO, RG_SHADOW_MEDALLION, SpoilerCollectionCheck::RandomizerInf(RAND_INF_DUNGEONS_DONE_SHADOW_TEMPLE), true);
locationTable[RC_GANON] = Location::Base(RC_GANON, RCQUEST_BOTH, RCTYPE_DUNGEON_REWARD, ACTOR_DOOR_WARP1, SCENE_GANON_BOSS, 0x00, "Ganon", "Ganon", RHT_NONE, RG_TRIFORCE); locationTable[RC_GANON] = Location::Base(RC_GANON, RCQUEST_BOTH, RCTYPE_DUNGEON_REWARD, ACTOR_DOOR_WARP1, SCENE_GANON_BOSS, 0x00, "Ganon", "Ganon", RHT_NONE, RG_TRIFORCE);
locationTable[RC_GIFT_FROM_SAGES] = Location::Base(RC_GIFT_FROM_SAGES, RCQUEST_BOTH, RCTYPE_DUNGEON_REWARD, RCAREA_MARKET, ACTOR_ID_MAX, SCENE_ID_MAX, 0x00, "Gift from Raoru", "Gift from Raoru", RHT_NONE, RG_LIGHT_MEDALLION, SpoilerCollectionCheck::EventChkInf(0xC9), true); locationTable[RC_GIFT_FROM_SAGES] = Location::Base(RC_GIFT_FROM_SAGES, RCQUEST_BOTH, RCTYPE_DUNGEON_REWARD, RCAREA_MARKET, ACTOR_ID_MAX, SCENE_ID_MAX, 0x00, "Gift from Raoru", "Gift from Raoru", RHT_GIFT_FROM_SAGES, RG_LIGHT_MEDALLION, SpoilerCollectionCheck::EventChkInf(0xC9), true);
// Heart Containers // Heart Containers
locationTable[RC_DEKU_TREE_QUEEN_GOHMA_HEART] = Location::Base(RC_DEKU_TREE_QUEEN_GOHMA_HEART, RCQUEST_BOTH, RCTYPE_BOSS_HEART_OR_OTHER_REWARD, ACTOR_ITEM_B_HEART, SCENE_DEKU_TREE_BOSS, 0x00, "Queen Gohma Heart Container", RHT_DEKU_TREE_QUEEN_GOHMA_HEART, RG_HEART_CONTAINER, SpoilerCollectionCheck::Collectable(0x11, 0x1F), true); locationTable[RC_DEKU_TREE_QUEEN_GOHMA_HEART] = Location::Base(RC_DEKU_TREE_QUEEN_GOHMA_HEART, RCQUEST_BOTH, RCTYPE_BOSS_HEART_OR_OTHER_REWARD, ACTOR_ITEM_B_HEART, SCENE_DEKU_TREE_BOSS, 0x00, "Queen Gohma Heart Container", RHT_DEKU_TREE_QUEEN_GOHMA_HEART, RG_HEART_CONTAINER, SpoilerCollectionCheck::Collectable(0x11, 0x1F), true);

View file

@ -1124,7 +1124,7 @@ namespace Rando {
bool Logic::CanFinishGerudoFortress(){ bool Logic::CanFinishGerudoFortress(){
return (ctx->GetOption(RSK_GERUDO_FORTRESS).Is(RO_GF_NORMAL) && SmallKeys(RR_GERUDO_FORTRESS, 4) && (CanUse(RG_KOKIRI_SWORD) || CanUse(RG_MASTER_SWORD) || CanUse(RG_BIGGORON_SWORD)) && (HasItem(RG_GERUDO_MEMBERSHIP_CARD) || CanUse(RG_FAIRY_BOW) || CanUse(RG_HOOKSHOT) || CanUse(RG_HOVER_BOOTS) || ctx->GetTrickOption(RT_GF_KITCHEN))) || return (ctx->GetOption(RSK_GERUDO_FORTRESS).Is(RO_GF_NORMAL) && SmallKeys(RR_GERUDO_FORTRESS, 4) && (CanUse(RG_KOKIRI_SWORD) || CanUse(RG_MASTER_SWORD) || CanUse(RG_BIGGORON_SWORD)) && (HasItem(RG_GERUDO_MEMBERSHIP_CARD) || CanUse(RG_FAIRY_BOW) || CanUse(RG_HOOKSHOT) || CanUse(RG_HOVER_BOOTS) || ctx->GetTrickOption(RT_GF_KITCHEN))) ||
(ctx->GetOption(RSK_GERUDO_FORTRESS).Is(RO_GF_FAST) && SmallKeys(RR_GERUDO_FORTRESS, 1) && (CanUse(RG_KOKIRI_SWORD) || CanUse(RG_MASTER_SWORD) || CanUse(RG_BIGGORON_SWORD))) || (ctx->GetOption(RSK_GERUDO_FORTRESS).Is(RO_GF_FAST) && SmallKeys(RR_GERUDO_FORTRESS, 1) && (CanUse(RG_KOKIRI_SWORD) || CanUse(RG_MASTER_SWORD) || CanUse(RG_BIGGORON_SWORD))) ||
ctx->GetOption(RSK_GERUDO_FORTRESS).Is(RO_GF_OPEN); ctx->GetOption(RSK_GERUDO_FORTRESS).Is(RO_GF_FREE);
} }
bool Logic::CanStandingShield(){ bool Logic::CanStandingShield(){

View file

@ -178,6 +178,15 @@ void Option::RemoveFlag(const int imFlag_) {
imFlags &= ~imFlag_; imFlags &= ~imFlag_;
} }
void Option::SetContextIndexFromText(const std::string text) {
if (optionsTextToVar.contains(text)){
SetContextIndex(optionsTextToVar[text]);
} else {
SPDLOG_ERROR("Option {} does not have a var named {}.", name, text);
assert(false);
}
}
Option::Option(uint8_t var_, std::string name_, std::vector<std::string> options_, OptionCategory category_, Option::Option(uint8_t var_, std::string name_, std::vector<std::string> options_, OptionCategory category_,
std::string cvarName_, std::string description_, WidgetType widgetType_, uint8_t defaultOption_, std::string cvarName_, std::string description_, WidgetType widgetType_, uint8_t defaultOption_,
bool defaultHidden_, int imFlags_) bool defaultHidden_, int imFlags_)
@ -186,6 +195,7 @@ Option::Option(uint8_t var_, std::string name_, std::vector<std::string> options
defaultOption(defaultOption_), defaultHidden(defaultHidden_), imFlags(imFlags_) { defaultOption(defaultOption_), defaultHidden(defaultHidden_), imFlags(imFlags_) {
menuSelection = contextSelection = defaultOption; menuSelection = contextSelection = defaultOption;
hidden = defaultHidden; hidden = defaultHidden;
PopulateTextToNum();
SetFromCVar(); SetFromCVar();
} }
Option::Option(bool var_, std::string name_, std::vector<std::string> options_, const OptionCategory category_, Option::Option(bool var_, std::string name_, std::vector<std::string> options_, const OptionCategory category_,
@ -196,6 +206,7 @@ Option::Option(bool var_, std::string name_, std::vector<std::string> options_,
defaultOption(defaultOption_), defaultHidden(defaultHidden_), imFlags(imFlags_) { defaultOption(defaultOption_), defaultHidden(defaultHidden_), imFlags(imFlags_) {
menuSelection = contextSelection = defaultOption; menuSelection = contextSelection = defaultOption;
hidden = defaultHidden; hidden = defaultHidden;
PopulateTextToNum();
SetFromCVar(); SetFromCVar();
} }
@ -333,6 +344,12 @@ bool Option::RenderSlider() {
return changed; return changed;
} }
void Option::PopulateTextToNum(){
for (uint8_t count = 0; count < options.size(); count++){
optionsTextToVar[options[count]] = count;
}
}
TrickOption::TrickOption(const RandomizerCheckQuest quest_, const RandomizerArea area_, std::set<Tricks::Tag> tags_, const bool glitch_, const std::string& name_, std::string description_) : TrickOption::TrickOption(const RandomizerCheckQuest quest_, const RandomizerArea area_, std::set<Tricks::Tag> tags_, const bool glitch_, const std::string& name_, std::string description_) :
Option(false, name_, {"Disabled", "Enabled"}, OptionCategory::Setting, "", Option(false, name_, {"Disabled", "Enabled"}, OptionCategory::Setting, "",
std::move(description_), WidgetType::Checkbox, 0, false, IMFLAG_NONE), std::move(description_), WidgetType::Checkbox, 0, false, IMFLAG_NONE),
@ -363,26 +380,26 @@ const std::set<Tricks::Tag>& TrickOption::GetTags() const {
} }
OptionGroup::OptionGroup(std::string name, std::vector<Option*> options, const OptionGroupType groupType, OptionGroup::OptionGroup(std::string name, std::vector<Option*> options, const OptionGroupType groupType,
const bool printInSpoiler, const WidgetContainerType containerType, std::string description) const WidgetContainerType containerType, std::string description)
: mName(std::move(name)), mOptions(std::move(options)), mGroupType(groupType), mPrintInSpoiler(printInSpoiler), : mName(std::move(name)), mOptions(std::move(options)), mGroupType(groupType),
mContainerType(containerType), mDescription(std::move(description)) { mContainerType(containerType), mDescription(std::move(description)) {
} }
OptionGroup::OptionGroup(std::string name, std::vector<OptionGroup*> subGroups, const OptionGroupType groupType, OptionGroup::OptionGroup(std::string name, std::vector<OptionGroup*> subGroups, const OptionGroupType groupType,
const bool printInSpoiler, const WidgetContainerType containerType, std::string description) const WidgetContainerType containerType, std::string description)
: mName(std::move(name)), mSubGroups(std::move(subGroups)), mGroupType(groupType), mPrintInSpoiler(printInSpoiler), : mName(std::move(name)), mSubGroups(std::move(subGroups)), mGroupType(groupType),
mContainsType(OptionGroupType::SUBGROUP), mContainerType(containerType), mDescription(std::move(description)) { mContainsType(OptionGroupType::SUBGROUP), mContainerType(containerType), mDescription(std::move(description)) {
} }
OptionGroup OptionGroup::SubGroup(std::string name, std::vector<Option*> options, const bool printInSpoiler, OptionGroup OptionGroup::SubGroup(std::string name, std::vector<Option*> options,
const WidgetContainerType containerType, std::string description) { const WidgetContainerType containerType, std::string description) {
return {std::move(name), std::move(options), OptionGroupType::SUBGROUP, printInSpoiler, containerType, return {std::move(name), std::move(options), OptionGroupType::SUBGROUP, containerType,
std::move(description)}; std::move(description)};
} }
OptionGroup OptionGroup::SubGroup(std::string name, std::vector<OptionGroup*> subGroups, const bool printInSpoiler, OptionGroup OptionGroup::SubGroup(std::string name, std::vector<OptionGroup*> subGroups,
const WidgetContainerType containerType, std::string description) { const WidgetContainerType containerType, std::string description) {
return {std::move(name), std::move(subGroups), OptionGroupType::SUBGROUP, printInSpoiler, containerType, return {std::move(name), std::move(subGroups), OptionGroupType::SUBGROUP, containerType,
std::move(description)}; std::move(description)};
} }
@ -398,10 +415,6 @@ const std::vector<OptionGroup*>& OptionGroup::GetSubGroups() const {
return mSubGroups; return mSubGroups;
} }
bool OptionGroup::PrintInSpoiler() const {
return mPrintInSpoiler;
}
OptionGroupType OptionGroup::GetGroupType() const { OptionGroupType OptionGroup::GetGroupType() const {
return mGroupType; return mGroupType;
} }

View file

@ -56,9 +56,9 @@ class Option {
* @param options_ A vector of value names for this Option. This vector should have a size of 2. * @param options_ A vector of value names for this Option. This vector should have a size of 2.
* The name corresponding to the selected index for this option will be printed to the spoiler/patch file. * The name corresponding to the selected index for this option will be printed to the spoiler/patch file.
* @param category_ The desired `OptionCategory` for this option. * @param category_ The desired `OptionCategory` for this option.
* @param cvarName_ The name ofthe CVar this option should correspond with. Set as an empty string to not * @param cvarName_ The name of the CVar this option should correspond with. Set as an empty string to not
* link to any Cvar. * link to any Cvar.
* @param description_ A description of what this option affects. Will be rendered in a toolip in ImGui. * @param description_ A description of what this option affects. Will be rendered in a tooltip in ImGui.
* Can be left as an empty string if desired, no tooltip will be rendered. * Can be left as an empty string if desired, no tooltip will be rendered.
* @param widgetType_ What type of widget should be rendered. Should probably be `Checkbox` but technically * @param widgetType_ What type of widget should be rendered. Should probably be `Checkbox` but technically
* `Combobox` or `Slider` would render and function correctly. * `Combobox` or `Slider` would render and function correctly.
@ -305,6 +305,8 @@ class Option {
void SetFlag(int imFlag_); void SetFlag(int imFlag_);
void RemoveFlag(int imFlag_); void RemoveFlag(int imFlag_);
void SetContextIndexFromText(std::string text);
protected: protected:
Option(uint8_t var_, std::string name_, std::vector<std::string> options_, OptionCategory category_, Option(uint8_t var_, std::string name_, std::vector<std::string> options_, OptionCategory category_,
std::string cvarName_, std::string description_, WidgetType widgetType_, uint8_t defaultOption_, std::string cvarName_, std::string description_, WidgetType widgetType_, uint8_t defaultOption_,
@ -318,6 +320,7 @@ protected:
bool RenderTristateCheckbox(); bool RenderTristateCheckbox();
bool RenderCombobox(); bool RenderCombobox();
bool RenderSlider(); bool RenderSlider();
void PopulateTextToNum();
std::variant<bool, uint8_t> var; std::variant<bool, uint8_t> var;
std::string name; std::string name;
std::vector<std::string> options; std::vector<std::string> options;
@ -335,6 +338,7 @@ protected:
bool disabled = false; bool disabled = false;
UIWidgets::CheckboxGraphics disabledGraphic = UIWidgets::CheckboxGraphics::Cross; UIWidgets::CheckboxGraphics disabledGraphic = UIWidgets::CheckboxGraphics::Cross;
std::string disabledText; std::string disabledText;
std::unordered_map<std::string, uint8_t> optionsTextToVar = {};
}; };
class TrickOption : public Option { class TrickOption : public Option {
@ -416,13 +420,11 @@ class OptionGroup {
* @param options A vector of Option pointers * @param options A vector of Option pointers
* @param groupType `DEFAULT` if this group is not contained within any other groups, `SUBGROUP` if it is a * @param groupType `DEFAULT` if this group is not contained within any other groups, `SUBGROUP` if it is a
* subgroup of another group. * subgroup of another group.
* @param printInSpoiler Whether or not to print the contents of this group to the spoiler/patch file.
* @param containerType Specifies the type of container this widget should render as in ImGui. * @param containerType Specifies the type of container this widget should render as in ImGui.
* @param description A description that can appear in a tooltip in ImGui. * @param description A description that can appear in a tooltip in ImGui.
*/ */
OptionGroup(std::string name, std::vector<Option*> options, OptionGroupType groupType = OptionGroupType::DEFAULT, OptionGroup(std::string name, std::vector<Option*> options, OptionGroupType groupType = OptionGroupType::DEFAULT,
bool printInSpoiler = true, WidgetContainerType containerType = WidgetContainerType::BASIC, WidgetContainerType containerType = WidgetContainerType::BASIC, std::string description = "");
std::string description = "");
/** /**
* @brief Construct a new Option Group containing a list of `OptionGroup` pointers. * @brief Construct a new Option Group containing a list of `OptionGroup` pointers.
@ -431,13 +433,11 @@ class OptionGroup {
* @param subGroups A vector of OptionGroup pointers that will be subgroups of this group. * @param subGroups A vector of OptionGroup pointers that will be subgroups of this group.
* @param groupType `DEFAULT` if this group is not contained within any other groups, `SUBGROUP` if it is a * @param groupType `DEFAULT` if this group is not contained within any other groups, `SUBGROUP` if it is a
* subgroup of another group. * subgroup of another group.
* @param printInSpoiler Whether or not to print the contents of this group to spoiler/patch file.
* @param containerType Specifies the type of container this widget should render as in ImGui. * @param containerType Specifies the type of container this widget should render as in ImGui.
* @param description A description that can appear in a tooltip in ImGui. * @param description A description that can appear in a tooltip in ImGui.
*/ */
OptionGroup(std::string name, std::vector<OptionGroup*> subGroups, OptionGroupType groupType = OptionGroupType::DEFAULT, OptionGroup(std::string name, std::vector<OptionGroup*> subGroups, OptionGroupType groupType = OptionGroupType::DEFAULT,
bool printInSpoiler = true, WidgetContainerType containerType = WidgetContainerType::BASIC, WidgetContainerType containerType = WidgetContainerType::BASIC, std::string description = "");
std::string description = "");
/** /**
* @brief Convenience function for constructing an OptionGroup of groupType `SUBGROUP` with * @brief Convenience function for constructing an OptionGroup of groupType `SUBGROUP` with
@ -445,13 +445,11 @@ class OptionGroup {
* *
* @param name The name of this option group. Appears in the spoiler/patch file. * @param name The name of this option group. Appears in the spoiler/patch file.
* @param options A vector of Option pointers. * @param options A vector of Option pointers.
* @param printInSpoiler Whether or not to print the options of this group to the spoiler/patch file.
* @param containerType Specifies the type of container this widget should render as in ImGui. * @param containerType Specifies the type of container this widget should render as in ImGui.
* @param description A description that can appear in a tooltip in ImGui. * @param description A description that can appear in a tooltip in ImGui.
* @return OptionGroup * @return OptionGroup
*/ */
static OptionGroup SubGroup(std::string name, std::vector<Option*> options, bool printInSpoiler = true, static OptionGroup SubGroup(std::string name, std::vector<Option*> options, WidgetContainerType containerType = WidgetContainerType::BASIC,
WidgetContainerType containerType = WidgetContainerType::BASIC,
std::string description = ""); std::string description = "");
/** /**
@ -460,13 +458,11 @@ class OptionGroup {
* *
* @param name The name of this option group. Appears in the spoiler/patch file. * @param name The name of this option group. Appears in the spoiler/patch file.
* @param subGroups A vector of OptionGroup pointers. * @param subGroups A vector of OptionGroup pointers.
* @param printInSpoiler Whether or not to print the options of this group to the spoiler/patch file.
* @param containerType Specifies the type of container this widget should render as in ImGui. * @param containerType Specifies the type of container this widget should render as in ImGui.
* @param description A description that can appear in a tooltip in ImGui. * @param description A description that can appear in a tooltip in ImGui.
* @return OptionGroup * @return OptionGroup
*/ */
static OptionGroup SubGroup(std::string name, std::vector<OptionGroup*> subGroups, bool printInSpoiler = true, static OptionGroup SubGroup(std::string name, std::vector<OptionGroup*> subGroups, WidgetContainerType containerType = WidgetContainerType::BASIC,
WidgetContainerType containerType = WidgetContainerType::BASIC,
std::string description = ""); std::string description = "");
/** /**
@ -490,15 +486,6 @@ class OptionGroup {
*/ */
const std::vector<OptionGroup*>& GetSubGroups() const; const std::vector<OptionGroup*>& GetSubGroups() const;
/**
* @brief Returns whether or not this `OptionGroup`'s contents should be printed to the
* spoiler/patch file.
*
* @return true
* @return false
*/
bool PrintInSpoiler() const;
/** /**
* @brief Get the Group Type of this `OptionGroup`. `DEFAULT` means this group is not contained * @brief Get the Group Type of this `OptionGroup`. `DEFAULT` means this group is not contained
* within any other groups, while `SUBGROUP` means that it is contained within at least one other. * within any other groups, while `SUBGROUP` means that it is contained within at least one other.
@ -532,7 +519,6 @@ class OptionGroup {
std::vector<Option*> mOptions; std::vector<Option*> mOptions;
std::vector<OptionGroup*> mSubGroups; std::vector<OptionGroup*> mSubGroups;
OptionGroupType mGroupType = OptionGroupType::DEFAULT; OptionGroupType mGroupType = OptionGroupType::DEFAULT;
bool mPrintInSpoiler = true;
OptionGroupType mContainsType = OptionGroupType::DEFAULT; OptionGroupType mContainsType = OptionGroupType::DEFAULT;
WidgetContainerType mContainerType = WidgetContainerType::BASIC; WidgetContainerType mContainerType = WidgetContainerType::BASIC;
std::string mDescription; std::string mDescription;

View file

@ -43,14 +43,15 @@ void Settings::CreateOptionDescriptions() {
"Choose which age Link will start as.\n\n" "Choose which age Link will start as.\n\n"
"Starting as adult means you start with the Master Sword in your inventory.\n" "Starting as adult means you start with the Master Sword in your inventory.\n"
"The child option is forcefully set if it would conflict with other options."; "The child option is forcefully set if it would conflict with other options.";
mOptionDescriptions[RSK_GERUDO_FORTRESS] = "Sets the amount of carpenters required to repair the bridge " mOptionDescriptions[RSK_GERUDO_FORTRESS] = "Sets the state of the carpenters captured by Gerudo "
"in Gerudo Valley.\n" "in Gerudo Fortress, and with it the number of guards that spawn.\n"
"\n" "\n"
"Normal - All 4 carpenters are required to be saved.\n" "Normal - All 4 carpenters are required to be saved.\n"
"\n" "\n"
"Fast - Only the bottom left carpenter requires rescuing.\n" "Fast - Only the bottom left carpenter requires rescuing.\n"
"\n" "\n"
"Open - The bridge is repaired from the start.\n" "Free - The bridge is repaired from the start, and Nabooru cannot spawn.\n"
"If the Gerudo Membership Card isn't shuffled, you start with it.\n"
"\n" "\n"
"Only \"Normal\" is compatible with Gerudo Fortress Key Rings."; "Only \"Normal\" is compatible with Gerudo Fortress Key Rings.";
mOptionDescriptions[RSK_RAINBOW_BRIDGE] = mOptionDescriptions[RSK_RAINBOW_BRIDGE] =

View file

@ -2661,6 +2661,7 @@ typedef enum {
RHT_MORPHA, RHT_MORPHA,
RHT_BONGO_BONGO, RHT_BONGO_BONGO,
RHT_TWINROVA, RHT_TWINROVA,
RHT_GIFT_FROM_SAGES,
RHT_SONG_FROM_IMPA, RHT_SONG_FROM_IMPA,
RHT_SONG_FROM_MALON, RHT_SONG_FROM_MALON,
RHT_SONG_FROM_SARIA, RHT_SONG_FROM_SARIA,
@ -4198,7 +4199,7 @@ typedef enum {
typedef enum { typedef enum {
RO_GF_NORMAL, RO_GF_NORMAL,
RO_GF_FAST, RO_GF_FAST,
RO_GF_OPEN, RO_GF_FREE,
} RandoOptionGerudoFortress; } RandoOptionGerudoFortress;
//Kakariko Gate settings (closed/open) //Kakariko Gate settings (closed/open)

View file

@ -206,7 +206,7 @@ void RandomizerCheckObjects::UpdateImGuiVisibility() {
CVarGetInteger(CVAR_RANDOMIZER_SETTING("ShuffleGanonBossKey"), RO_GANON_BOSS_KEY_VANILLA) != CVarGetInteger(CVAR_RANDOMIZER_SETTING("ShuffleGanonBossKey"), RO_GANON_BOSS_KEY_VANILLA) !=
RO_GANON_BOSS_KEY_KAK_TOKENS) && // 100 skull reward ganon boss key RO_GANON_BOSS_KEY_KAK_TOKENS) && // 100 skull reward ganon boss key
(location.GetRCType() != RCTYPE_GF_KEY && location.GetRandomizerCheck() != RC_GF_GERUDO_MEMBERSHIP_CARD || (location.GetRCType() != RCTYPE_GF_KEY && location.GetRandomizerCheck() != RC_GF_GERUDO_MEMBERSHIP_CARD ||
(CVarGetInteger(CVAR_RANDOMIZER_SETTING("GerudoFortress"), RO_GF_NORMAL) == RO_GF_OPEN && (CVarGetInteger(CVAR_RANDOMIZER_SETTING("GerudoFortress"), RO_GF_NORMAL) == RO_GF_FREE &&
location.GetRCType() != RCTYPE_GF_KEY && location.GetRandomizerCheck() != RC_GF_GERUDO_MEMBERSHIP_CARD) || location.GetRCType() != RCTYPE_GF_KEY && location.GetRandomizerCheck() != RC_GF_GERUDO_MEMBERSHIP_CARD) ||
(CVarGetInteger(CVAR_RANDOMIZER_SETTING("GerudoFortress"), RO_GF_NORMAL) == RO_GF_FAST && (CVarGetInteger(CVAR_RANDOMIZER_SETTING("GerudoFortress"), RO_GF_NORMAL) == RO_GF_FAST &&
((location.GetRandomizerCheck() == RC_GF_GERUDO_MEMBERSHIP_CARD && ((location.GetRandomizerCheck() == RC_GF_GERUDO_MEMBERSHIP_CARD &&

View file

@ -1185,7 +1185,7 @@ void LoadSettings() {
fortressFast = false; fortressFast = false;
fortressNormal = false; fortressNormal = false;
switch (OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_GERUDO_FORTRESS)) { switch (OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_GERUDO_FORTRESS)) {
case RO_GF_OPEN: case RO_GF_FREE:
showGerudoFortressKeys = false; showGerudoFortressKeys = false;
showGerudoCard = false; showGerudoCard = false;
break; break;

View file

@ -267,13 +267,6 @@ s16 Entrance_PeekNextIndexOverride(int16_t nextEntranceIndex) {
} }
s16 Entrance_OverrideNextIndex(s16 nextEntranceIndex) { s16 Entrance_OverrideNextIndex(s16 nextEntranceIndex) {
// When entering Spirit Temple, clear temp flags so they don't carry over to the randomized dungeon
if (nextEntranceIndex == ENTR_SPIRIT_TEMPLE_ENTRANCE && Entrance_GetOverride(nextEntranceIndex) != nextEntranceIndex &&
gPlayState != NULL) {
gPlayState->actorCtx.flags.tempSwch = 0;
gPlayState->actorCtx.flags.tempCollect = 0;
}
// Exiting through the crawl space from Hyrule Castle courtyard is the same exit as leaving Ganon's castle // Exiting through the crawl space from Hyrule Castle courtyard is the same exit as leaving Ganon's castle
// Don't override the entrance if we came from the Castle courtyard (day and night scenes) // Don't override the entrance if we came from the Castle courtyard (day and night scenes)
if (gPlayState != NULL && (gPlayState->sceneNum == SCENE_CASTLE_COURTYARD_GUARDS_DAY || gPlayState->sceneNum == SCENE_CASTLE_COURTYARD_GUARDS_NIGHT) && if (gPlayState != NULL && (gPlayState->sceneNum == SCENE_CASTLE_COURTYARD_GUARDS_DAY || gPlayState->sceneNum == SCENE_CASTLE_COURTYARD_GUARDS_NIGHT) &&

View file

@ -453,7 +453,7 @@ extern "C" void Randomizer_InitSaveFile() {
} }
if (Randomizer_GetSettingValue(RSK_GERUDO_FORTRESS) == RO_GF_FAST || if (Randomizer_GetSettingValue(RSK_GERUDO_FORTRESS) == RO_GF_FAST ||
Randomizer_GetSettingValue(RSK_GERUDO_FORTRESS) == RO_GF_OPEN) { Randomizer_GetSettingValue(RSK_GERUDO_FORTRESS) == RO_GF_FREE) {
Flags_SetEventChkInf(EVENTCHKINF_CARPENTERS_FREE(1)); Flags_SetEventChkInf(EVENTCHKINF_CARPENTERS_FREE(1));
Flags_SetEventChkInf(EVENTCHKINF_CARPENTERS_FREE(2)); Flags_SetEventChkInf(EVENTCHKINF_CARPENTERS_FREE(2));
Flags_SetEventChkInf(EVENTCHKINF_CARPENTERS_FREE(3)); Flags_SetEventChkInf(EVENTCHKINF_CARPENTERS_FREE(3));
@ -471,7 +471,7 @@ extern "C" void Randomizer_InitSaveFile() {
gSaveContext.sceneFlags[SCENE_THIEVES_HIDEOUT].collect |= (1 << 0x0F); gSaveContext.sceneFlags[SCENE_THIEVES_HIDEOUT].collect |= (1 << 0x0F);
} }
if (Randomizer_GetSettingValue(RSK_GERUDO_FORTRESS) == RO_GF_OPEN) { if (Randomizer_GetSettingValue(RSK_GERUDO_FORTRESS) == RO_GF_FREE) {
Flags_SetEventChkInf(EVENTCHKINF_CARPENTERS_FREE(0)); Flags_SetEventChkInf(EVENTCHKINF_CARPENTERS_FREE(0));
gSaveContext.sceneFlags[SCENE_THIEVES_HIDEOUT].swch |= (1 << 0x01); // heard yell and unlocked door gSaveContext.sceneFlags[SCENE_THIEVES_HIDEOUT].swch |= (1 << 0x01); // heard yell and unlocked door
gSaveContext.sceneFlags[SCENE_THIEVES_HIDEOUT].swch |= (1 << 0x05); gSaveContext.sceneFlags[SCENE_THIEVES_HIDEOUT].swch |= (1 << 0x05);

File diff suppressed because it is too large Load diff

View file

@ -25,6 +25,14 @@ class Settings {
*/ */
void CreateOptions(); void CreateOptions();
/**
* @brief Populates the map used to translate strings into RandomiserSettingKeys
*
* @return std::unordered_map<std::string, RandomizerSettingKey>
*/
std::unordered_map<std::string, RandomizerSettingKey> PopulateOptionNameToEnum();
/** /**
* @brief Get a reference to the `Option` corresponding to the provided RandomizerSettingKey. * @brief Get a reference to the `Option` corresponding to the provided RandomizerSettingKey.
* *
@ -192,7 +200,6 @@ class Settings {
std::array<OptionGroup, RSG_MAX> mOptionGroups = {}; std::array<OptionGroup, RSG_MAX> mOptionGroups = {};
std::array<TrickOption, RT_MAX> mTrickOptions = {}; std::array<TrickOption, RT_MAX> mTrickOptions = {};
std::vector<std::vector<Option*>> mExcludeLocationsOptionsAreas = {}; std::vector<std::vector<Option*>> mExcludeLocationsOptionsAreas = {};
std::unordered_map<std::string, RandomizerSettingKey> mSpoilerfileSettingNameToEnum;
RandoOptionStartingAge mResolvedStartingAge = RO_AGE_CHILD; RandoOptionStartingAge mResolvedStartingAge = RO_AGE_CHILD;
RandoOptionLACSCondition mLACSCondition = RO_LACS_VANILLA; RandoOptionLACSCondition mLACSCondition = RO_LACS_VANILLA;
std::string mHash; std::string mHash;

View file

@ -251,7 +251,8 @@ std::unordered_map<std::string, uint32_t> StaticData::hintNameToEnum = {};
std::unordered_map<std::string, uint32_t> StaticData::hintTypeNameToEnum = {}; std::unordered_map<std::string, uint32_t> StaticData::hintTypeNameToEnum = {};
std::unordered_map<std::string, uint32_t> StaticData::areaNameToEnum = {}; std::unordered_map<std::string, uint32_t> StaticData::areaNameToEnum = {};
std::unordered_map<std::string, uint32_t> StaticData::trialNameToEnum = {}; std::unordered_map<std::string, uint32_t> StaticData::trialNameToEnum = {};
std::unordered_map<std::string, RandomizerCheck> StaticData::locationNameToEnum = {}; //is filled in context based on location table, not touching that because of VB std::unordered_map<std::string, RandomizerSettingKey> StaticData::optionNameToEnum = {};
std::unordered_map<std::string, RandomizerCheck> StaticData::locationNameToEnum = {}; //is filled in context based on location table
std::unordered_map<u32, RandomizerHint> StaticData::stoneParamsToHint{ std::unordered_map<u32, RandomizerHint> StaticData::stoneParamsToHint{
{0x1, RH_ZF_FAIRY_GOSSIP_STONE}, {0x1, RH_ZF_FAIRY_GOSSIP_STONE},

View file

@ -61,6 +61,7 @@ class StaticData {
static std::unordered_map<std::string, uint32_t> areaNameToEnum; static std::unordered_map<std::string, uint32_t> areaNameToEnum;
static std::unordered_map<uint32_t, RandomizerHintTextKey> trialData; static std::unordered_map<uint32_t, RandomizerHintTextKey> trialData;
static std::unordered_map<std::string, uint32_t> trialNameToEnum; static std::unordered_map<std::string, uint32_t> trialNameToEnum;
static std::unordered_map<std::string, RandomizerSettingKey> optionNameToEnum;
static std::unordered_map<RandomizerHint, StaticHintInfo> staticHintInfoMap; static std::unordered_map<RandomizerHint, StaticHintInfo> staticHintInfoMap;
static std::unordered_map<u32, RandomizerHint> stoneParamsToHint; static std::unordered_map<u32, RandomizerHint> stoneParamsToHint;
static std::unordered_map<u32, RandomizerHint> grottoChestParamsToHint; static std::unordered_map<u32, RandomizerHint> grottoChestParamsToHint;

View file

@ -38,7 +38,7 @@ extern int32_t D_8011D3AC;
extern void BgSpot03Taki_HandleWaterfallState(BgSpot03Taki* bgSpot03Taki, PlayState* play); extern void BgSpot03Taki_HandleWaterfallState(BgSpot03Taki* bgSpot03Taki, PlayState* play);
extern void BgSpot03Taki_ApplyOpeningAlpha(BgSpot03Taki* bgSpot03Taki, s32 bufferIndex); extern void BgSpot03Taki_ApplyOpeningAlpha(BgSpot03Taki* bgSpot03Taki, s32 bufferIndex);
extern void func_80AF36EC(EnRu2* enRu2, PlayState* play); extern void EnRu2_SetEncounterSwitchFlag(EnRu2* enRu2, PlayState* play);
} }
#define RAND_GET_OPTION(option) Rando::Context::GetInstance()->GetOption(option).GetContextOptionIndex() #define RAND_GET_OPTION(option) Rando::Context::GetInstance()->GetOption(option).GetContextOptionIndex()
@ -340,11 +340,14 @@ void TimeSaverOnVanillaBehaviorHandler(GIVanillaBehavior id, bool* should, va_li
if (ForcedDialogIsDisabled(FORCED_DIALOG_SKIP_NAVI)) { if (ForcedDialogIsDisabled(FORCED_DIALOG_SKIP_NAVI)) {
ElfMsg* naviTalk = va_arg(args, ElfMsg*); ElfMsg* naviTalk = va_arg(args, ElfMsg*);
int32_t paramsHighByte = naviTalk->actor.params >> 8; int32_t paramsHighByte = naviTalk->actor.params >> 8;
if ((paramsHighByte & 0x80) == 0 && (paramsHighByte & 0x3F) != 0x3F) { if ((paramsHighByte & 0x80) != 0) {
Flags_SetSwitch(gPlayState, paramsHighByte & 0x3F); break;
Actor_Kill(&naviTalk->actor);
*should = false;
} }
if ((paramsHighByte & 0x3F) != 0x3F) {
Flags_SetSwitch(gPlayState, paramsHighByte & 0x3F);
}
Actor_Kill(&naviTalk->actor);
*should = false;
} }
break; break;
} }
@ -893,7 +896,7 @@ void TimeSaverOnActorInitHandler(void* actorRef) {
if (actor->id == ACTOR_EN_RU2 && gPlayState->sceneNum == SCENE_WATER_TEMPLE) { if (actor->id == ACTOR_EN_RU2 && gPlayState->sceneNum == SCENE_WATER_TEMPLE) {
if (CVarGetInteger(CVAR_ENHANCEMENT("TimeSavers.SkipCutscene.Story"), IS_RANDO)) { if (CVarGetInteger(CVAR_ENHANCEMENT("TimeSavers.SkipCutscene.Story"), IS_RANDO)) {
EnRu2* enRu2 = (EnRu2*)actor; EnRu2* enRu2 = (EnRu2*)actor;
func_80AF36EC(enRu2, gPlayState); EnRu2_SetEncounterSwitchFlag(enRu2, gPlayState);
Actor_Kill(actor); Actor_Kill(actor);
} }
} }

View file

@ -4558,25 +4558,25 @@ void func_80034CC4(PlayState* play, SkelAnime* skelAnime, OverrideLimbDraw overr
CLOSE_DISPS(play->state.gfxCtx); CLOSE_DISPS(play->state.gfxCtx);
} }
s16 func_80034DD4(Actor* actor, PlayState* play, s16 arg2, f32 arg3) { s16 Actor_UpdateAlphaByDistance(Actor* actor, PlayState* play, s16 alpha, f32 radius) {
Player* player = GET_PLAYER(play); Player* player = GET_PLAYER(play);
f32 var; f32 distance;
if ((play->csCtx.state != CS_STATE_IDLE) || (gDbgCamEnabled)) { if ((play->csCtx.state != CS_STATE_IDLE) || (gDbgCamEnabled)) {
var = Math_Vec3f_DistXYZ(&actor->world.pos, &play->view.eye) * 0.25f; distance = Math_Vec3f_DistXYZ(&actor->world.pos, &play->view.eye) * 0.25f;
} else { } else {
var = Math_Vec3f_DistXYZ(&actor->world.pos, &player->actor.world.pos); distance = Math_Vec3f_DistXYZ(&actor->world.pos, &player->actor.world.pos);
} }
if (arg3 < var) { if (radius < distance) {
actor->flags &= ~ACTOR_FLAG_TARGETABLE; actor->flags &= ~ACTOR_FLAG_TARGETABLE;
Math_SmoothStepToS(&arg2, 0, 6, 0x14, 1); Math_SmoothStepToS(&alpha, 0, 6, 0x14, 1);
} else { } else {
actor->flags |= ACTOR_FLAG_TARGETABLE; actor->flags |= ACTOR_FLAG_TARGETABLE;
Math_SmoothStepToS(&arg2, 0xFF, 6, 0x14, 1); Math_SmoothStepToS(&alpha, 0xFF, 6, 0x14, 1);
} }
return arg2; return alpha;
} }
void Animation_ChangeByInfo(SkelAnime* skelAnime, AnimationInfo* animationInfo, s32 index) { void Animation_ChangeByInfo(SkelAnime* skelAnime, AnimationInfo* animationInfo, s32 index) {

View file

@ -629,7 +629,7 @@ void func_80AAB5A4(EnMd* this, PlayState* play) {
: 400.0f; : 400.0f;
} }
this->alpha = func_80034DD4(&this->actor, play, this->alpha, temp); this->alpha = Actor_UpdateAlphaByDistance(&this->actor, play, this->alpha, temp);
this->actor.shape.shadowAlpha = this->alpha; this->actor.shape.shadowAlpha = this->alpha;
} else { } else {
this->alpha = 255; this->alpha = 255;

File diff suppressed because it is too large Load diff

View file

@ -14,18 +14,18 @@ typedef struct EnRu2 {
/* 0x014C */ SkelAnime skelAnime; /* 0x014C */ SkelAnime skelAnime;
/* 0x0190 */ Vec3s jointTable[23]; /* 0x0190 */ Vec3s jointTable[23];
/* 0x021A */ Vec3s morphTable[23]; /* 0x021A */ Vec3s morphTable[23];
/* 0x02A4 */ s16 unk_2A4; /* 0x02A4 */ s16 eyeIndex;
/* 0x02A6 */ s16 unk_2A6; /* 0x02A6 */ s16 blinkTimer;
/* 0x02A8 */ s32 action; /* 0x02A8 */ s32 action;
/* 0x02AC */ s32 drawConfig; /* 0x02AC */ s32 drawConfig;
/* 0x02B0 */ f32 unk_2B0; /* 0x02B0 */ f32 fadeTimer;
/* 0x02B4 */ u32 alpha; /* 0x02B4 */ u32 alpha;
/* 0x02B8 */ s32 unk_2B8; /* 0x02B8 */ s32 isLightBall;
/* 0x02BC */ s32 unk_2BC; /* 0x02BC */ s32 cueId;
/* 0x02C0 */ u16 unk_2C0; /* 0x02C0 */ u16 swimmingUpFrame;
/* 0x02C2 */ u8 unk_2C2; /* 0x02C2 */ u8 textboxCount;
/* 0x02C3 */ u8 unk_2C3; /* 0x02C3 */ u8 lastDialogState;
/* 0x02C4 */ f32 unk_2C4; /* 0x02C4 */ f32 encounterTimer;
/* 0x02C8 */ ColliderCylinder collider; /* 0x02C8 */ ColliderCylinder collider;
/* 0x02C8 */ s16 subCamId; /* 0x02C8 */ s16 subCamId;
} EnRu2; // size = 0x0314 } EnRu2; // size = 0x0314

View file

@ -2,7 +2,7 @@
#include "z64cutscene_commands.h" #include "z64cutscene_commands.h"
// clang-format off // clang-format off
static CutsceneData D_80AF411C[] = { static CutsceneData gWaterMedallionCs[] = {
CS_BEGIN_CUTSCENE(35, 3338), CS_BEGIN_CUTSCENE(35, 3338),
CS_UNK_DATA_LIST(0x00000020, 1), CS_UNK_DATA_LIST(0x00000020, 1),
CS_UNK_DATA(0x00010000, 0x0BB80000, 0x00000000, 0x00000000, 0xFFFFFFFC, 0x00000002, 0x00000000, 0xFFFFFFFC, 0x00000002, 0x00000000, 0x00000000, 0x00000000), CS_UNK_DATA(0x00010000, 0x0BB80000, 0x00000000, 0x00000000, 0xFFFFFFFC, 0x00000002, 0x00000000, 0xFFFFFFFC, 0x00000002, 0x00000000, 0x00000000, 0x00000000),

View file

@ -742,10 +742,10 @@ void EnSa_Update(Actor* thisx, PlayState* play) {
if (this->actionFunc != func_80AF68E4) { if (this->actionFunc != func_80AF68E4) {
if (CVarGetInteger(CVAR_ENHANCEMENT("DisableKokiriDrawDistance"), 0) != 0) { if (CVarGetInteger(CVAR_ENHANCEMENT("DisableKokiriDrawDistance"), 0) != 0) {
this->alpha = func_80034DD4(&this->actor, play, this->alpha, 32767); this->alpha = Actor_UpdateAlphaByDistance(&this->actor, play, this->alpha, 32767);
} }
else { else {
this->alpha = func_80034DD4(&this->actor, play, this->alpha, 400.0f); this->alpha = Actor_UpdateAlphaByDistance(&this->actor, play, this->alpha, 400.0f);
} }
} else { } else {
this->alpha = 255; this->alpha = 255;

View file

@ -5147,9 +5147,9 @@ s32 Player_HandleExitsAndVoids(PlayState* play, Player* this, CollisionPoly* pol
Scene_SetTransitionForNextEntrance(play); Scene_SetTransitionForNextEntrance(play);
} else { } else {
// In Entrance rando, if our respawnFlag is set for a grotto return, we don't want the void out to happen if (GameInteractor_Should(VB_SET_VOIDOUT_FROM_SURFACE,
if (SurfaceType_GetSlope(&play->colCtx, poly, bgId) == 2 && SurfaceType_GetSlope(&play->colCtx, poly, bgId) == 2,
(!IS_RANDO || (Randomizer_GetSettingValue(RSK_SHUFFLE_ENTRANCES) && gSaveContext.respawnFlag != 2))) { play->setupExitList[exitIndex - 1])) {
gSaveContext.respawn[RESPAWN_MODE_DOWN].entranceIndex = play->nextEntranceIndex; gSaveContext.respawn[RESPAWN_MODE_DOWN].entranceIndex = play->nextEntranceIndex;
Play_TriggerVoidOut(play); Play_TriggerVoidOut(play);
gSaveContext.respawnFlag = -2; gSaveContext.respawnFlag = -2;