You've already forked Shipwright
mirror of
https://github.com/CraftyBoss/Shipwright.git
synced 2026-07-14 05:07:46 -07:00
Decouple GBK from LACS (#5838)
Triforce Pieces can now be tokens for bridge or ganon's soul. & can be tokens for multiple rewards Wincon can now be arbitrary conditions Ganon's Soul (removed from existing boss soul options) can now be arbitrary conditions Co-authored-by: Pepper0ni <93387759+Pepper0ni@users.noreply.github.com>
This commit is contained in:
@@ -24,7 +24,7 @@
|
||||
"IncludeTycoonWallet": 1,
|
||||
"KakarikoGate": 1,
|
||||
"Keysanity": 5,
|
||||
"LacsRewardCount": 8,
|
||||
"GbkRewardCount": 8,
|
||||
"MalonHint": 1,
|
||||
"MerchantText": 1,
|
||||
"RainbowBridge": 7,
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
"IncludeTycoonWallet": 1,
|
||||
"KakarikoGate": 1,
|
||||
"Keysanity": 2,
|
||||
"LacsRewardCount": 6,
|
||||
"GbkRewardCount": 6,
|
||||
"MalonHint": 1,
|
||||
"MerchantText": 1,
|
||||
"RainbowBridge": 7,
|
||||
|
||||
@@ -18,8 +18,8 @@
|
||||
"IncludeTycoonWallet": 1,
|
||||
"KakarikoGate": 1,
|
||||
"Keysanity": 5,
|
||||
"LacsRewardCount": 10,
|
||||
"LacsRewardOptions": 1,
|
||||
"GbkRewardCount": 10,
|
||||
"GbkRewardOptions": 1,
|
||||
"LockOverworldDoors": 1,
|
||||
"MedallionLockedTrials": 1,
|
||||
"MixBosses": 1,
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
"IncludeTycoonWallet": 1,
|
||||
"KakarikoGate": 1,
|
||||
"Keysanity": 5,
|
||||
"LacsRewardCount": 7,
|
||||
"GbkRewardCount": 7,
|
||||
"MalonHint": 1,
|
||||
"MerchantText": 1,
|
||||
"RainbowBridge": 7,
|
||||
|
||||
@@ -1540,7 +1540,6 @@ u8 CheckStoneCount();
|
||||
u8 CheckMedallionCount();
|
||||
u8 CheckDungeonCount();
|
||||
u8 CheckBridgeRewardCount();
|
||||
u8 CheckLACSRewardCount();
|
||||
s32 Play_InCsMode(PlayState* play);
|
||||
f32 func_800BFCB8(PlayState* play, MtxF* mf, Vec3f* vec);
|
||||
void* Play_LoadFile(PlayState* play, RomFile* file);
|
||||
|
||||
@@ -175,12 +175,9 @@ void TimeSaverOnVanillaBehaviorHandler(GIVanillaBehavior id, bool* should, va_li
|
||||
|
||||
if (CVarGetInteger(CVAR_ENHANCEMENT("TimeSavers.SkipCutscene.Story"), IS_RANDO)) {
|
||||
// LACS
|
||||
bool meetsLACSRequirements =
|
||||
LINK_IS_ADULT &&
|
||||
(gEntranceTable[((void)0, gSaveContext.entranceIndex)].scene == SCENE_TEMPLE_OF_TIME) &&
|
||||
if (LINK_IS_ADULT && (gEntranceTable[gSaveContext.entranceIndex].scene == SCENE_TEMPLE_OF_TIME) &&
|
||||
CHECK_QUEST_ITEM(QUEST_MEDALLION_SPIRIT) && CHECK_QUEST_ITEM(QUEST_MEDALLION_SHADOW) &&
|
||||
!Flags_GetEventChkInf(EVENTCHKINF_RETURNED_TO_TEMPLE_OF_TIME_WITH_ALL_MEDALLIONS);
|
||||
if (GameInteractor_Should(VB_BE_ELIGIBLE_FOR_LIGHT_ARROWS, meetsLACSRequirements)) {
|
||||
!Flags_GetEventChkInf(EVENTCHKINF_RETURNED_TO_TEMPLE_OF_TIME_WITH_ALL_MEDALLIONS)) {
|
||||
Flags_SetEventChkInf(EVENTCHKINF_RETURNED_TO_TEMPLE_OF_TIME_WITH_ALL_MEDALLIONS);
|
||||
if (GameInteractor_Should(VB_GIVE_ITEM_LIGHT_ARROW, true)) {
|
||||
Item_Give(gPlayState, ITEM_ARROW_LIGHT);
|
||||
|
||||
@@ -35,7 +35,7 @@ static const std::unordered_map<std::string, ItemID> altarIcons = {
|
||||
{ "l", ITEM_ARROW_LIGHT }, { "b", ITEM_KEY_BOSS }, { "o", ITEM_SWORD_MASTER },
|
||||
{ "c", ITEM_OCARINA_FAIRY }, { "i", ITEM_OCARINA_TIME }, { "L", ITEM_BOW_ARROW_LIGHT },
|
||||
{ "k", ITEM_TUNIC_KOKIRI }, { "m", ITEM_DUNGEON_MAP }, { "C", ITEM_COMPASS },
|
||||
{ "s", ITEM_SKULL_TOKEN }, { "g", ITEM_MASK_GORON },
|
||||
{ "s", ITEM_SKULL_TOKEN }, { "g", ITEM_MASK_GORON }, { "w", ITEM_CUSTOM },
|
||||
};
|
||||
|
||||
static std::map<std::string, int> pixelWidthTable = {
|
||||
|
||||
@@ -406,8 +406,7 @@ void DrawInfoTab() {
|
||||
Combobox("Z Target Mode", &gSaveContext.zTargetSetting, zTargetMap,
|
||||
comboboxOptionsBase.Tooltip("Z-Targeting behavior"));
|
||||
|
||||
if (IS_RANDO &&
|
||||
(OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_TRIFORCE_HUNT) != RO_TRIFORCE_HUNT_OFF)) {
|
||||
if (IS_RANDO && (OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_TRIFORCE_HUNT_PIECES_TOTAL) > 0)) {
|
||||
PushStyleInput(THEME_COLOR);
|
||||
ImGui::InputScalar("Triforce Pieces", ImGuiDataType_U8,
|
||||
&gSaveContext.ship.quest.data.randomizer.triforcePiecesCollected);
|
||||
|
||||
@@ -74,8 +74,8 @@ uint8_t GameInteractor_GetRandomWindActive();
|
||||
uint8_t GameInteractor_GetRandomBonksActive();
|
||||
uint8_t GameInteractor_GetSlipperyFloorActive();
|
||||
uint8_t GameInteractor_SecondCollisionUpdate();
|
||||
void GameInteractor_SetTriforceHuntPieceGiven(uint8_t state);
|
||||
void GameInteractor_SetTriforceHuntCreditsWarpActive(uint8_t state);
|
||||
void GameInteractor_SetTriforceHuntPieceGiven(bool state);
|
||||
void GameInteractor_SetTriforceHuntCreditsWarpActive(bool state);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -203,8 +203,8 @@ class GameInteractor {
|
||||
static uint8_t RandomBonksActive;
|
||||
static uint8_t SlipperyFloorActive;
|
||||
static uint8_t SecondCollisionUpdate;
|
||||
static uint8_t TriforceHuntPieceGiven;
|
||||
static uint8_t TriforceHuntCreditsWarpActive;
|
||||
static bool TriforceHuntPieceGiven;
|
||||
static bool TriforceHuntCreditsWarpActive;
|
||||
|
||||
static void SetPacifistMode(bool active);
|
||||
};
|
||||
|
||||
@@ -20,8 +20,8 @@ uint8_t GameInteractor::State::RandomWindSecondsSinceLastDirectionChange = 0;
|
||||
uint8_t GameInteractor::State::RandomBonksActive = 0;
|
||||
uint8_t GameInteractor::State::SlipperyFloorActive = 0;
|
||||
uint8_t GameInteractor::State::SecondCollisionUpdate = 0;
|
||||
uint8_t GameInteractor::State::TriforceHuntPieceGiven = 0;
|
||||
uint8_t GameInteractor::State::TriforceHuntCreditsWarpActive = 0;
|
||||
bool GameInteractor::State::TriforceHuntPieceGiven = false;
|
||||
bool GameInteractor::State::TriforceHuntCreditsWarpActive = false;
|
||||
|
||||
void GameInteractor::State::SetPacifistMode(bool active) {
|
||||
PacifistModeActive = active;
|
||||
@@ -131,11 +131,11 @@ uint8_t GameInteractor_SecondCollisionUpdate() {
|
||||
}
|
||||
|
||||
// MARK: - GameInteractor::State::TriforceHuntPieceGiven
|
||||
void GameInteractor_SetTriforceHuntPieceGiven(uint8_t state) {
|
||||
void GameInteractor_SetTriforceHuntPieceGiven(bool state) {
|
||||
GameInteractor::State::TriforceHuntPieceGiven = state;
|
||||
}
|
||||
|
||||
// MARK: - GameInteractor::State::TriforceHuntCreditsWarpActive
|
||||
void GameInteractor_SetTriforceHuntCreditsWarpActive(uint8_t state) {
|
||||
void GameInteractor_SetTriforceHuntCreditsWarpActive(bool state) {
|
||||
GameInteractor::State::TriforceHuntCreditsWarpActive = state;
|
||||
}
|
||||
|
||||
@@ -2411,6 +2411,14 @@ typedef enum {
|
||||
// - None
|
||||
VB_SKIP_TALKING,
|
||||
|
||||
// #### `result`
|
||||
// ```c
|
||||
// true
|
||||
// ```
|
||||
// #### `args`
|
||||
// - None
|
||||
VB_SLAY_GANON,
|
||||
|
||||
// #### `result`
|
||||
// ```c
|
||||
// (collectible >= 0) && (collectible <= 0x19
|
||||
|
||||
@@ -144,12 +144,11 @@ Kaleido::Kaleido() {
|
||||
gItemIconFishingPoleTex, G_IM_FMT_RGBA, G_IM_SIZ_32b, 32, 32, Color_RGBA8{ 255, 255, 255, 255 },
|
||||
FlagType::FLAG_RANDOMIZER_INF, static_cast<int>(RAND_INF_FISHING_POLE_FOUND), "Fishing Pole"));
|
||||
}
|
||||
if (ctx->GetOption(RSK_TRIFORCE_HUNT).IsNot(RO_TRIFORCE_HUNT_OFF)) {
|
||||
if (ctx->GetOption(RSK_TRIFORCE_HUNT_PIECES_TOTAL).Get() > 0) {
|
||||
mEntries.push_back(std::make_shared<KaleidoEntryIconCountRequired>(
|
||||
gTriforcePieceTex, G_IM_FMT_RGBA, G_IM_SIZ_32b, 32, 32, Color_RGBA8{ 255, 255, 255, 255 },
|
||||
reinterpret_cast<int*>(&gSaveContext.ship.quest.data.randomizer.triforcePiecesCollected),
|
||||
ctx->GetOption(RSK_TRIFORCE_HUNT_PIECES_REQUIRED).Get() + 1,
|
||||
ctx->GetOption(RSK_TRIFORCE_HUNT_PIECES_TOTAL).Get() + 1));
|
||||
ctx->GetOption(RSK_WINCON_TRIFORCE_COUNT).Get(), ctx->GetOption(RSK_TRIFORCE_HUNT_PIECES_TOTAL).Get()));
|
||||
}
|
||||
if (ctx->GetOption(RSK_SKELETON_KEY)) {
|
||||
mEntries.push_back(std::make_shared<KaleidoEntryIconFlag>(
|
||||
@@ -170,7 +169,7 @@ Kaleido::Kaleido() {
|
||||
FlagType::FLAG_RANDOMIZER_INF, i, bossSoulNames[i - RAND_INF_GOHMA_SOUL]));
|
||||
}
|
||||
}
|
||||
if (ctx->GetOption(RSK_SHUFFLE_BOSS_SOULS).Is(RO_BOSS_SOULS_ON_PLUS_GANON)) {
|
||||
if (ctx->GetOption(RSK_GANONS_SOUL).IsNot(RO_GANONS_SOUL_STARTWITH)) {
|
||||
mEntries.push_back(std::make_shared<KaleidoEntryIconFlag>(
|
||||
gBossSoulTex, G_IM_FMT_RGBA, G_IM_SIZ_32b, 32, 32, Color_RGBA8{ 255, 255, 255, 255 },
|
||||
FlagType::FLAG_RANDOMIZER_INF, RAND_INF_GANON_SOUL, "Ganon's Soul"));
|
||||
|
||||
@@ -230,16 +230,6 @@ void ProcessExits(Region* region, GetAccessibleLocationsStruct& gals, Randomizer
|
||||
// Get the max number of tokens that can possibly be useful
|
||||
static int GetMaxGSCount() {
|
||||
auto ctx = Rando::Context::GetInstance();
|
||||
// If bridge or LACS is set to tokens, get how many are required
|
||||
int maxBridge = 0;
|
||||
int maxLACS = 0;
|
||||
if (ctx->GetOption(RSK_RAINBOW_BRIDGE).Is(RO_BRIDGE_TOKENS)) {
|
||||
maxBridge = ctx->GetOption(RSK_RAINBOW_BRIDGE_TOKEN_COUNT).Get();
|
||||
}
|
||||
if (ctx->GetOption(RSK_GANONS_BOSS_KEY).Is(RO_GANON_BOSS_KEY_LACS_TOKENS)) {
|
||||
maxLACS = ctx->GetOption(RSK_LACS_TOKEN_COUNT).Get();
|
||||
}
|
||||
maxBridge = std::max(maxBridge, maxLACS);
|
||||
// Get the max amount of GS which could be useful from token reward locations
|
||||
int maxUseful = 0;
|
||||
// If the highest advancement item is a token, we know it is useless since it won't lead to an otherwise useful item
|
||||
@@ -262,8 +252,21 @@ static int GetMaxGSCount() {
|
||||
ctx->GetItemLocation(RC_KAK_10_GOLD_SKULLTULA_REWARD)->GetPlacedItem().GetItemType() != ITEMTYPE_TOKEN) {
|
||||
maxUseful = 10;
|
||||
}
|
||||
// If bridge, GBK, Ganon's Soul, or win condition is set to tokens, get how many are required
|
||||
if (ctx->GetOption(RSK_RAINBOW_BRIDGE).Is(RO_BRIDGE_TOKENS)) {
|
||||
maxUseful = std::max(maxUseful, (int)ctx->GetOption(RSK_RAINBOW_BRIDGE_TOKEN_COUNT).Get());
|
||||
}
|
||||
if (ctx->GetOption(RSK_GANONS_BOSS_KEY).Is(RO_GANON_BOSS_KEY_TOKENS)) {
|
||||
maxUseful = std::max(maxUseful, (int)ctx->GetOption(RSK_GBK_TOKEN_COUNT).Get());
|
||||
}
|
||||
if (ctx->GetOption(RSK_GANONS_SOUL).Is(RO_GANONS_SOUL_TOKENS)) {
|
||||
maxUseful = std::max(maxUseful, (int)ctx->GetOption(RSK_GANONS_SOUL_TOKEN_COUNT).Get());
|
||||
}
|
||||
if (ctx->GetOption(RSK_WINCON).Is(RO_WINCON_TOKENS)) {
|
||||
maxUseful = std::max(maxUseful, (int)ctx->GetOption(RSK_WINCON_TOKEN_COUNT).Get());
|
||||
}
|
||||
// Return max of the two possible reasons tokens could be important, minus the tokens in the starting inventory
|
||||
return std::max(maxUseful, maxBridge) - ctx->GetOption(RSK_STARTING_SKULLTULA_TOKEN).Get();
|
||||
return maxUseful - ctx->GetOption(RSK_STARTING_SKULLTULA_TOKEN).Get();
|
||||
}
|
||||
|
||||
std::string GetShopItemBaseName(std::string itemName) {
|
||||
@@ -369,12 +372,12 @@ void AddToPlaythrough(LocationAccess& locPair, GetAccessibleLocationsStruct& gal
|
||||
if (!exclude) {
|
||||
gals.itemSphere.push_back(loc);
|
||||
}
|
||||
}
|
||||
// Triforce has been found, seed is beatable, nothing else in this or future spheres matters
|
||||
else if (location->GetPlacedRandomizerGet() == RG_TRIFORCE) {
|
||||
gals.itemSphere.clear();
|
||||
gals.itemSphere.push_back(loc);
|
||||
ctx->playthroughBeatable = true;
|
||||
// Triforce has been found, seed is beatable, nothing else in this or future spheres matters
|
||||
if (location->GetPlacedRandomizerGet() == RG_TRIFORCE) {
|
||||
gals.itemSphere.clear();
|
||||
gals.itemSphere.push_back(loc);
|
||||
ctx->playthroughBeatable = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1159,6 +1162,14 @@ static void RandomizeDungeonItems() {
|
||||
}
|
||||
}
|
||||
|
||||
if (ctx->GetOption(RSK_GANONS_SOUL).Is(RO_GANONS_SOUL_ANY_DUNGEON)) {
|
||||
auto ganonSoul = FilterAndEraseFromPool(itemPool, [](const auto i) { return i == RG_GANON_SOUL; });
|
||||
AddElementsToPool(anyDungeonItems, ganonSoul);
|
||||
} else if (ctx->GetOption(RSK_GANONS_SOUL).Is(RO_GANONS_SOUL_OVERWORLD)) {
|
||||
auto ganonSoul = FilterAndEraseFromPool(itemPool, [](const auto i) { return i == RG_GANON_SOUL; });
|
||||
AddElementsToPool(overworldItems, ganonSoul);
|
||||
}
|
||||
|
||||
if (ctx->GetOption(RSK_GERUDO_KEYS).Is(RO_GERUDO_KEYS_ANY_DUNGEON)) {
|
||||
auto gerudoKeys = FilterAndEraseFromPool(itemPool, [](const auto i) {
|
||||
return i == RG_GERUDO_FORTRESS_SMALL_KEY || i == RG_GERUDO_FORTRESS_KEY_RING;
|
||||
|
||||
@@ -2013,8 +2013,13 @@ void StaticData::HintTable_Init() {
|
||||
{QM_YELLOW}, {}, TEXTBOX_TYPE_BLUE));
|
||||
// /*spanish*/$sLos sabios aguardarán a que el héroe obtenga #[[d]] símbolo||s| de skulltula dorada#.^
|
||||
|
||||
hintTextTable[RHT_BRIDGE_TRIFORCE_PIECES_HINT] = HintText(CustomMessage("$wThe awakened ones will await for the Hero to collect #[[d]] Triforce Piece||s|#.^",
|
||||
/*german*/ "$wDie Weisen werden darauf&warten, daß der Held&#[[d]] Triforce-Fragment||e|# sammelt.^",
|
||||
/*french*/ "$wLes êtres de sagesse attendront le héros muni de #[[d]] Morceau||x| de Triforce#.^",
|
||||
{QM_YELLOW}, {}, TEXTBOX_TYPE_BLUE));
|
||||
|
||||
hintTextTable[RHT_BRIDGE_GREG_HINT] = HintText(CustomMessage("$gThe awakened ones will await for the Hero to find #Greg#.^",
|
||||
/*german*/ "$gDie Weisen werden darauf&warten, daß der Held&#Greg# findet.^",
|
||||
/*german*/ "$gDie Weisen werden darauf&warten, daß der Held&#Greg# findet.^",
|
||||
/*french*/ "$gLes êtres de sagesse attendront le héros muni de #Greg#.^",
|
||||
{QM_GREEN}, {}, TEXTBOX_TYPE_BLUE));
|
||||
|
||||
@@ -2059,56 +2064,118 @@ void StaticData::HintTable_Init() {
|
||||
{QM_PINK, QM_BLUE}));
|
||||
// /*spanish*/$bY la llave del #señor del mal# aguardará en #cualquier lugar de Hyrule#.^
|
||||
|
||||
hintTextTable[RHT_GANON_BK_TRIFORCE_HINT] = HintText(CustomMessage("$bAnd the #evil one#'s key will be given to the Hero once the #Triforce## is completed.^",
|
||||
/*german*/ "$bUnd der #Schlüssel des Bösen# wird verliehen, sobald das #Triforce# vervollständigt wurde.^",
|
||||
/*french*/ "$bAussi, la #clé du Malin# se&révèlera une fois la #Triforce#&assemblée.^",
|
||||
{QM_PINK, QM_YELLOW}));
|
||||
// /*spanish*/$bY el héroe recibirá la llave del #señor del mal# cuando haya completado la #Trifuerza#.^
|
||||
|
||||
hintTextTable[RHT_GANON_BK_SKULLTULA_HINT] = HintText(CustomMessage("$bAnd the #evil one#'s key will be provided by the cursed rich man once #100 Gold Skulltula Tokens# are retrieved.^",
|
||||
/*german*/ "$bUnd der #Schlüssel des Bösen# wird von einem verfluchten reichen Mann verliehen, sobald #100 Skulltula-Symbole# gesammelt wurden.^",
|
||||
/*french*/ "$bAussi, la #clé du Malin# sera&donnée par l'homme maudit une fois que #100 Symboles de Skulltula d'or# auront été trouvés.^",
|
||||
{QM_PINK, QM_YELLOW}));
|
||||
// /*spanish*/$bY el rico maldito entregará la llave&del #señor de mal# tras obtener&100 símbolos de skulltula dorada#.^
|
||||
|
||||
hintTextTable[RHT_LACS_VANILLA_HINT] = HintText(CustomMessage("$bAnd the #evil one#'s key will be provided by #Zelda# once the #Shadow and Spirit Medallions# are retrieved.^",
|
||||
/*german*/ "$bUnd der #Schlüssel des Bösen# wird von #Zelda# verliehen, sobald #die Amulette des Schattens und der Geister# geborgen wurden.^",
|
||||
/*french*/ "$bAussi, la #clé du Malin# sera fournie par #Zelda# une fois que les #Médaillons de l'Ombre et de l'Esprit# seront récupérés.^",
|
||||
{QM_PINK, QM_YELLOW, QM_RED}));
|
||||
// /*spanish*/$bY #Zelda# entregará la llave del #señor del mal# tras obtener #el medallón de las sombras y del espíritu#.^
|
||||
|
||||
hintTextTable[RHT_LACS_MEDALLIONS_HINT] = HintText(CustomMessage("$bAnd the #evil one#'s key will be provided by #Zelda# once #[[d]] Medallion|# is|s# are| retrieved.^",
|
||||
/*german*/ "$bUnd der #Schlüssel des Bösen# wird von #Zelda# verliehen, sobald #[[d]] Amulett|# geborgen wurde|e# geborgen wurden|.^",
|
||||
/*french*/ "$bAussi, la #clé du Malin# sera fournie par #Zelda# une fois |qu' #[[d]] Médaillon# aura été récupéré|que #[[d]] Médaillons# auront été récupérés|.^",
|
||||
hintTextTable[RHT_GBK_MEDALLIONS_HINT] = HintText(CustomMessage("$bAnd the #evil one#'s key will be provided once #[[d]] Medallion|# is|s# are| retrieved.^",
|
||||
/*german*/ "$bUnd der #Schlüssel des Bösen# wird verliehen, sobald #[[d]] Amulett|# geborgen wurde|e# geborgen wurden|.^",
|
||||
/*french*/ "$bAussi, la #clé du Malin# sera fournie une fois |qu' #[[d]] Médaillon# aura été récupéré|que #[[d]] Médaillons# auront été récupérés|.^",
|
||||
{QM_PINK, QM_YELLOW, QM_RED}));
|
||||
// /*spanish*/$bY #Zelda# entregará la llave&del #señor del mal# tras obtener #[[d]] |medallón|medallones|#.^
|
||||
|
||||
hintTextTable[RHT_LACS_STONES_HINT] = HintText(CustomMessage("$bAnd the #evil one#'s key will be provided by #Zelda# once #[[d]] Spiritual Stone|# is|s# are| retrieved.^",
|
||||
/*german*/ "$bUnd der #Schlüssel des Bösen# wird von #Zelda# verliehen, sobald #[[d]] Heilige|r Stein# geborgen wurde| Steine# geborgen wurden|.^",
|
||||
/*french*/ "$bAussi, la #clé du Malin# sera fournie par #Zelda# une fois |qu' #[[d]] Pierre Ancestrale# aura été&récupérée|que #[[d]] Pierres Ancestrales# auront été récupérées|.^",
|
||||
hintTextTable[RHT_GBK_STONES_HINT] = HintText(CustomMessage("$bAnd the #evil one#'s key will be provided once #[[d]] Spiritual Stone|# is|s# are| retrieved.^",
|
||||
/*german*/ "$bUnd der #Schlüssel des Bösen# wird verliehen, sobald #[[d]] Heilige|r Stein# geborgen wurde| Steine# geborgen wurden|.^",
|
||||
/*french*/ "$bAussi, la #clé du Malin# sera fournie une fois |qu' #[[d]] Pierre Ancestrale# aura été&récupérée|que #[[d]] Pierres Ancestrales# auront été récupérées|.^",
|
||||
{QM_PINK, QM_YELLOW, QM_BLUE}));
|
||||
// /*spanish*/$bY #Zelda# entregará la llave del #señor del mal# tras obtener #[[d]] piedra| espiritual|s espirituales|#.^
|
||||
|
||||
hintTextTable[RHT_LACS_REWARDS_HINT] = HintText(CustomMessage("$bAnd the #evil one#'s key will be provided by #Zelda# once #[[d]]# #Spiritual Stone|# or #Medallion# is|s# and #Medallions# are| retrieved.^",
|
||||
/*german*/ "$bUnd der #Schlüssel des Bösen# wird von #Zelda# verliehen, sobald #[[d]]# #Heilige|r Stein# oder #Amulett#&geborgen wurde| Steine# oder #Amulette#&geborgen wurden|.^",
|
||||
/*french*/ "$bAussi, la #clé du Malin# sera fournie par #Zelda# une fois qu|' #[[d]]# #Pierre Ancestrale# ou #[[d]] Médaillon# sera récupéré|e&#[[d]]# #Pierres Ancestrales# et&#Médaillons# seront récupérés|.^",
|
||||
hintTextTable[RHT_GBK_REWARDS_HINT] = HintText(CustomMessage("$bAnd the #evil one#'s key will be provided once #[[d]]# #Spiritual Stone|# or #Medallion# is|s# and #Medallions# are| retrieved.^",
|
||||
/*german*/ "$bUnd der #Schlüssel des Bösen# wird verliehen, sobald #[[d]]# #Heilige|r Stein# oder #Amulett#&geborgen wurde| Steine# oder #Amulette#&geborgen wurden|.^",
|
||||
/*french*/ "$bAussi, la #clé du Malin# sera fournie une fois qu|' #[[d]]# #Pierre Ancestrale# ou #[[d]] Médaillon# sera récupéré|e&#[[d]]# #Pierres Ancestrales# et&#Médaillons# seront récupérés|.^",
|
||||
{QM_PINK, QM_YELLOW, QM_YELLOW, QM_BLUE, QM_RED}));
|
||||
// /*spanish*/$bY #Zelda# entregará la llave del #señor del mal# tras obtener #[[d]]# piedra| espiritual o medallón|s espirituales o medallones|#.^
|
||||
|
||||
hintTextTable[RHT_LACS_DUNGEONS_HINT] = HintText(CustomMessage("$bAnd the #evil one#'s key will be provided by #Zelda# once #[[d]] Dungeon|# is|s# are| conquered.^",
|
||||
/*german*/ "$bUnd der #Schlüssel des Bösen# wird von #Zelda# verliehen, sobald #[[d]] Labyrinth|# abgeschloßen wurde|e# abgeschloßen wurden|.^",
|
||||
/*french*/ "$bAussi, la #clé du Malin# sera fournie par #Zelda# une fois qu|' #[[d]] donjon #sera conquis|e #[[d]] donjons# seront conquis|.^",
|
||||
hintTextTable[RHT_GBK_DUNGEONS_HINT] = HintText(CustomMessage("$bAnd the #evil one#'s key will be provided once #[[d]] Dungeon|# is|s# are| conquered.^",
|
||||
/*german*/ "$bUnd der #Schlüssel des Bösen# wird verliehen, sobald #[[d]] Labyrinth|# abgeschloßen wurde|e# abgeschloßen wurden|.^",
|
||||
/*french*/ "$bAussi, la #clé du Malin# sera fournie une fois qu|' #[[d]] donjon #sera conquis|e #[[d]] donjons# seront conquis|.^",
|
||||
{QM_PINK, QM_YELLOW, QM_PINK}));
|
||||
// /*spanish*/$bY #Zelda# entregará la llave del #señor del mal# tras completar #[[d]] mazmorra||s|#.^
|
||||
|
||||
hintTextTable[RHT_LACS_TOKENS_HINT] = HintText(CustomMessage("$bAnd the #evil one#'s key will be provided by #Zelda# once #[[d]] Gold Skulltula Token|# is|s# are| retrieved.^",
|
||||
/*german*/ "$bUnd der #Schlüssel des Bösen# wird von #Zelda# verliehen, sobald #[[d]] Skulltula-Symbol|# gesammelt wurde|e# gesammelt wurden|.^",
|
||||
/*french*/ "$bAussi, la #clé du Malin# sera fournie par #Zelda# une fois |qu' #[[d]] symbole de Skulltula d'or #sera récupuéré"
|
||||
hintTextTable[RHT_GBK_TOKENS_HINT] = HintText(CustomMessage("$bAnd the #evil one#'s key will be provided once #[[d]] Gold Skulltula Token|# is|s# are| retrieved.^",
|
||||
/*german*/ "$bUnd der #Schlüssel des Bösen# wird verliehen, sobald #[[d]] Skulltula-Symbol|# gesammelt wurde|e# gesammelt wurden|.^",
|
||||
/*french*/ "$bAussi, la #clé du Malin# sera fournie une fois |qu' #[[d]] symbole de Skulltula d'or #sera récupuéré"
|
||||
"|que &#[[d]] symboles de Skulltula d'or&#seront recupérés|.^",
|
||||
{QM_PINK, QM_YELLOW, QM_YELLOW}));
|
||||
// /*spanish*/$bY #Zelda# entregará la llave del #señor del mal# tras obtener #[[d]] símbolo
|
||||
// ||s| de skulltula dorada#.^
|
||||
|
||||
hintTextTable[RHT_GBK_TRIFORCE_PIECES_HINT] = HintText(CustomMessage("$bAnd the #evil one#'s key will be provided once #[[d]] Triforce Piece|# is|s# are| retrieved.^",
|
||||
/*german*/ "$bUnd der #Schlüssel des Bösen# wird verliehen, sobald #[[d]] Triforce-Fragment|# gesammelt wurde|e# gesammelt wurden|.^",
|
||||
/*french*/ "$bAussi, la #clé du Malin# sera fournie une fois |qu' #[[d]] Morceau de Triforce# aura été récupéré|que #[[d]] Morceaux de Triforce# auront été récupérés|.^",
|
||||
{QM_PINK, QM_YELLOW, QM_YELLOW}));
|
||||
|
||||
/*--------------------------
|
||||
| GANON'S SOUL HINT TEXT |
|
||||
---------------------------*/
|
||||
|
||||
hintTextTable[RHT_GANONS_SOUL_MEDALLIONS_HINT] = HintText(CustomMessage("$bAnd the #evil one#'s soul will be provided once #[[d]] Medallion|# is|s# are| retrieved.^",
|
||||
/*german*/ "$bUnd die #Seele des Bösen# wird verliehen, sobald #[[d]] Amulett|# geborgen wurde|e# geborgen wurden|.^",
|
||||
/*french*/ "$bAussi, l'#âme du Malin# sera fournie une fois |qu' #[[d]] Médaillon# aura été récupéré|que #[[d]] Médaillons# auront été récupérés|.^",
|
||||
{QM_PINK, QM_YELLOW, QM_RED}));
|
||||
|
||||
hintTextTable[RHT_GANONS_SOUL_STONES_HINT] = HintText(CustomMessage("$bAnd the #evil one#'s soul will be provided once #[[d]] Spiritual Stone|# is|s# are| retrieved.^",
|
||||
/*german*/ "$bUnd die #Seele des Bösen# wird verliehen, sobald #[[d]] Heilige|r Stein# geborgen wurde| Steine# geborgen wurden|.^",
|
||||
/*french*/ "$bAussi, l'#âme du Malin# sera fournie une fois |qu' #[[d]] Pierre Ancestrale# aura été&récupérée|que #[[d]] Pierres Ancestrales# auront été récupérées|.^",
|
||||
{QM_PINK, QM_YELLOW, QM_BLUE}));
|
||||
|
||||
hintTextTable[RHT_GANONS_SOUL_REWARDS_HINT] = HintText(CustomMessage("$bAnd the #evil one#'s soul will be provided once #[[d]]# #Spiritual Stone|# or #Medallion# is|s# and #Medallions# are| retrieved.^",
|
||||
/*german*/ "$bUnd die #Seele des Bösen# wird verliehen, sobald #[[d]]# #Heilige|r Stein# oder #Amulett#&geborgen wurde| Steine# oder #Amulette#&geborgen wurden|.^",
|
||||
/*french*/ "$bAussi, l'#âme du Malin# sera fournie une fois qu|' #[[d]]# #Pierre Ancestrale# ou #[[d]] Médaillon# sera récupéré|e&#[[d]]# #Pierres Ancestrales# et&#Médaillons# seront récupérés|.^",
|
||||
{QM_PINK, QM_YELLOW, QM_YELLOW, QM_BLUE, QM_RED}));
|
||||
|
||||
hintTextTable[RHT_GANONS_SOUL_DUNGEONS_HINT] = HintText(CustomMessage("$bAnd the #evil one#'s soul will be provided once #[[d]] Dungeon|# is|s# are| conquered.^",
|
||||
/*german*/ "$bUnd die #Seele des Bösen# wird verliehen, sobald #[[d]] Labyrinth|# abgeschloßen wurde|e# abgeschloßen wurden|.^",
|
||||
/*french*/ "$bAussi, l'#âme du Malin# sera fournie une fois qu|' #[[d]] donjon #sera conquis|e #[[d]] donjons# seront conquis|.^",
|
||||
{QM_PINK, QM_YELLOW, QM_PINK}));
|
||||
|
||||
hintTextTable[RHT_GANONS_SOUL_TOKENS_HINT] = HintText(CustomMessage("$bAnd the #evil one#'s soul will be provided once #[[d]] Gold Skulltula Token|# is|s# are| retrieved.^",
|
||||
/*german*/ "$bUnd die #Seele des Bösen# wird verliehen, sobald #[[d]] Skulltula-Symbol|# gesammelt wurde|e# gesammelt wurden|.^",
|
||||
/*french*/ "$bAussi, l'#âme du Malin# sera fournie une fois |qu' #[[d]] symbole de Skulltula d'or #sera récupuéré"
|
||||
"|que &#[[d]] symboles de Skulltula d'or&#seront recupérés|.^",
|
||||
{QM_PINK, QM_YELLOW, QM_YELLOW}));
|
||||
|
||||
hintTextTable[RHT_GANONS_SOUL_TRIFORCE_PIECES_HINT] = HintText(CustomMessage("$bAnd the #evil one#'s soul will be provided once #[[d]] Triforce Piece|# is|s# are| retrieved.^",
|
||||
/*german*/ "$bUnd die #Seele des Bösen# wird verliehen, sobald #[[d]] Triforce-Fragment|# gesammelt wurde|e# gesammelt wurden|.^",
|
||||
/*french*/ "$bAussi, l'#âme du Malin# sera fournie une fois |qu' #[[d]] Morceau de Triforce# aura été récupéré|que #[[d]] Morceaux de Triforce# auront été récupérés|.^",
|
||||
{QM_PINK, QM_YELLOW, QM_YELLOW}));
|
||||
|
||||
/*--------------------------
|
||||
| WINCON HINT TEXT |
|
||||
---------------------------*/
|
||||
|
||||
hintTextTable[RHT_WINCON_ANYWHERE_HINT] = HintText(CustomMessage("$wAnd the #Triforce# will be hidden somewhere&#in Hyrule#.^",
|
||||
/*german*/ "$wUnd das #Triforce# wird irgendwo #in Hyrule# zu finden sein.^",
|
||||
/*french*/ "$wAussi, la #Triforce# se trouve quelque part #dans Hyrule#.^",
|
||||
{QM_YELLOW, QM_BLUE}));
|
||||
|
||||
hintTextTable[RHT_WINCON_MEDALLIONS_HINT] = HintText(CustomMessage("$wAnd the #Triforce# will be granted once #[[d]] Medallion|# is|s# are| retrieved.^",
|
||||
/*german*/ "$wUnd das #Triforce# wird gewährt, sobald #[[d]] Amulett|# geborgen wurde|e# geborgen wurden|.^",
|
||||
/*french*/ "$wAussi, la #Triforce# sera accordée une fois |qu' #[[d]] Médaillon# aura été récupéré|que #[[d]] Médaillons# auront été récupérés|.^",
|
||||
{QM_YELLOW, QM_YELLOW, QM_RED}));
|
||||
|
||||
hintTextTable[RHT_WINCON_STONES_HINT] = HintText(CustomMessage("$wAnd the #Triforce# will be granted once #[[d]] Spiritual Stone|# is|s# are| retrieved.^",
|
||||
/*german*/ "$wUnd das #Triforce# wird gewährt, sobald #[[d]] Heilige|r Stein# geborgen wurde| Steine# geborgen wurden|.^",
|
||||
/*french*/ "$wAussi, la #Triforce# sera accordée une fois |qu' #[[d]] Pierre Ancestrale# aura été&récupérée|que #[[d]] Pierres Ancestrales# auront été récupérées|.^",
|
||||
{QM_YELLOW, QM_YELLOW, QM_BLUE}));
|
||||
|
||||
hintTextTable[RHT_WINCON_REWARDS_HINT] = HintText(CustomMessage("$wAnd the #Triforce# will be granted once #[[d]]# #Spiritual Stone|# or #Medallion# is|s# and #Medallions# are| retrieved.^",
|
||||
/*german*/ "$wUnd das #Triforce# wird gewährt, sobald #[[d]]# #Heilige|r Stein# oder #Amulett#&geborgen wurde| Steine# oder #Amulette#&geborgen wurden|.^",
|
||||
/*french*/ "$wAussi, la #Triforce# sera accordée une fois qu|' #[[d]]# #Pierre Ancestrale# ou #[[d]] Médaillon# sera récupéré|e&#[[d]]# #Pierres Ancestrales# et&#Médaillons# seront récupérés|.^",
|
||||
{QM_YELLOW, QM_YELLOW, QM_YELLOW, QM_BLUE, QM_RED}));
|
||||
|
||||
hintTextTable[RHT_WINCON_DUNGEONS_HINT] = HintText(CustomMessage("$wAnd the #Triforce# will be granted once #[[d]] Dungeon|# is|s# are| conquered.^",
|
||||
/*german*/ "$wUnd das #Triforce# wird gewährt, sobald #[[d]] Labyrinth|# abgeschloßen wurde|e# abgeschloßen wurden|.^",
|
||||
/*french*/ "$wAussi, la #Triforce# sera accordée une fois qu|' #[[d]] donjon #sera conquis|e #[[d]] donjons# seront conquis|.^",
|
||||
{QM_YELLOW, QM_YELLOW, QM_PINK}));
|
||||
|
||||
hintTextTable[RHT_WINCON_TOKENS_HINT] = HintText(CustomMessage("$wAnd the #Triforce# will be granted once #[[d]] Gold Skulltula Token|# is|s# are| retrieved.^",
|
||||
/*german*/ "$wUnd das #Triforce# wird gewährt, sobald #[[d]] Skulltula-Symbol|# gesammelt wurde|e# gesammelt wurden|.^",
|
||||
/*french*/ "$wAussi, la #Triforce# sera accordée une fois |qu' #[[d]] symbole de Skulltula d'or #sera récupuéré"
|
||||
"|que &#[[d]] symboles de Skulltula d'or&#seront recupérés|.^",
|
||||
{QM_YELLOW, QM_YELLOW, QM_YELLOW}));
|
||||
|
||||
hintTextTable[RHT_WINCON_TRIFORCE_PIECES_HINT] = HintText(CustomMessage("$wAnd the #Triforce# will be granted once #[[d]] Triforce Piece|# is|s# are| retrieved.^",
|
||||
/*german*/ "$wUnd das #Triforce# wird gewährt, sobald #[[d]] Triforce-Fragment|# gesammelt wurde|e# gesammelt wurden|.^",
|
||||
/*french*/ "$wAussi, la #Triforce# sera accordée une fois |qu' #[[d]] Morceau de Triforce# aura été récupéré|que #[[d]] Morceaux de Triforce# auront été récupérés|.^",
|
||||
{QM_YELLOW, QM_YELLOW, QM_YELLOW}));
|
||||
|
||||
/*--------------------------
|
||||
| TRIAL HINT TEXT |
|
||||
---------------------------*/
|
||||
|
||||
@@ -211,39 +211,72 @@ const std::array<HintSetting, 4> hintSettingTable{{
|
||||
}};
|
||||
|
||||
struct BridgeReqConfig {
|
||||
RandomizerSettingKey bridgeDirectKey;
|
||||
RandomizerSettingKey lacsDirectKey;
|
||||
RandomizerSettingKey bridgeKey;
|
||||
RandomizerSettingKey gbkKey;
|
||||
RandomizerSettingKey soulKey;
|
||||
RandomizerSettingKey winKey;
|
||||
RandoOptionRainbowBridge bridgeEnum;
|
||||
RandoOptionGanonsBossKey lacsEnum;
|
||||
RandoOptionGanonsBossKey gbkEnum;
|
||||
RandoOptionGanonsSoul soulEnum;
|
||||
RandoOptionWincon winEnum;
|
||||
uint8_t offset;
|
||||
};
|
||||
|
||||
static constexpr BridgeReqConfig StonesConfig{ RSK_RAINBOW_BRIDGE_STONE_COUNT, RSK_LACS_STONE_COUNT, RO_BRIDGE_STONES,
|
||||
RO_GANON_BOSS_KEY_LACS_STONES, 6 };
|
||||
static constexpr BridgeReqConfig MedallionsConfig{ RSK_RAINBOW_BRIDGE_MEDALLION_COUNT, RSK_LACS_MEDALLION_COUNT,
|
||||
RO_BRIDGE_MEDALLIONS, RO_GANON_BOSS_KEY_LACS_MEDALLIONS, 3 };
|
||||
static constexpr BridgeReqConfig TokensConfig{ RSK_RAINBOW_BRIDGE_TOKEN_COUNT, RSK_LACS_TOKEN_COUNT, RO_BRIDGE_TOKENS,
|
||||
RO_GANON_BOSS_KEY_LACS_TOKENS, 0 };
|
||||
static constexpr BridgeReqConfig StonesConfig{
|
||||
RSK_RAINBOW_BRIDGE_STONE_COUNT, RSK_GBK_STONE_COUNT, RSK_GANONS_SOUL_STONE_COUNT,
|
||||
RSK_WINCON_STONE_COUNT, RO_BRIDGE_STONES, RO_GANON_BOSS_KEY_STONES,
|
||||
RO_GANONS_SOUL_STONES, RO_WINCON_STONES, 6
|
||||
};
|
||||
static constexpr BridgeReqConfig MedallionsConfig{
|
||||
RSK_RAINBOW_BRIDGE_MEDALLION_COUNT, RSK_GBK_MEDALLION_COUNT, RSK_GANONS_SOUL_MEDALLION_COUNT,
|
||||
RSK_WINCON_MEDALLION_COUNT, RO_BRIDGE_MEDALLIONS, RO_GANON_BOSS_KEY_MEDALLIONS,
|
||||
RO_GANONS_SOUL_MEDALLIONS, RO_WINCON_MEDALLIONS, 3
|
||||
};
|
||||
static constexpr BridgeReqConfig TokensConfig{
|
||||
RSK_RAINBOW_BRIDGE_TOKEN_COUNT, RSK_GBK_TOKEN_COUNT, RSK_GANONS_SOUL_TOKEN_COUNT,
|
||||
RSK_WINCON_TOKEN_COUNT, RO_BRIDGE_TOKENS, RO_GANON_BOSS_KEY_TOKENS,
|
||||
RO_GANONS_SOUL_TOKENS, RO_WINCON_TOKENS, 0
|
||||
};
|
||||
|
||||
static uint8_t RequiredBySettings(const BridgeReqConfig& cfg) {
|
||||
auto ctx = Rando::Context::GetInstance();
|
||||
uint8_t count = 0;
|
||||
|
||||
if (ctx->GetOption(RSK_RAINBOW_BRIDGE).Is(cfg.bridgeEnum)) {
|
||||
count = ctx->GetOption(cfg.bridgeDirectKey).Get();
|
||||
count = ctx->GetOption(cfg.bridgeKey).Get();
|
||||
} else if (ctx->GetOption(RSK_RAINBOW_BRIDGE).Is(RO_BRIDGE_DUNGEON_REWARDS)) {
|
||||
count = ctx->GetOption(RSK_RAINBOW_BRIDGE_REWARD_COUNT).Get() - cfg.offset;
|
||||
} else if (ctx->GetOption(RSK_RAINBOW_BRIDGE).Is(RO_BRIDGE_DUNGEONS) &&
|
||||
ctx->GetOption(RSK_SHUFFLE_DUNGEON_REWARDS).Is(RO_DUNGEON_REWARDS_END_OF_DUNGEON)) {
|
||||
count = ctx->GetOption(RSK_RAINBOW_BRIDGE_DUNGEON_COUNT).Get() - cfg.offset;
|
||||
}
|
||||
if (ctx->GetOption(RSK_GANONS_BOSS_KEY).Is(cfg.lacsEnum)) {
|
||||
count = std::max<uint8_t>(count, ctx->GetOption(cfg.lacsDirectKey).Get());
|
||||
} else if (ctx->GetOption(RSK_GANONS_BOSS_KEY).Is(RO_GANON_BOSS_KEY_LACS_REWARDS)) {
|
||||
count = std::max<uint8_t>(count, (uint8_t)(ctx->GetOption(RSK_LACS_REWARD_COUNT).Get() - cfg.offset));
|
||||
} else if (ctx->GetOption(RSK_GANONS_BOSS_KEY).Is(RO_GANON_BOSS_KEY_LACS_DUNGEONS) &&
|
||||
if (ctx->GetOption(RSK_GANONS_BOSS_KEY).Is(cfg.gbkEnum)) {
|
||||
count = std::max<uint8_t>(count, ctx->GetOption(cfg.gbkKey).Get());
|
||||
} else if (ctx->GetOption(RSK_GANONS_BOSS_KEY).Is(RO_GANON_BOSS_KEY_REWARDS)) {
|
||||
count = std::max<uint8_t>(count, (uint8_t)(ctx->GetOption(RSK_GBK_REWARD_COUNT).Get() - cfg.offset));
|
||||
} else if (ctx->GetOption(RSK_GANONS_BOSS_KEY).Is(RO_GANON_BOSS_KEY_DUNGEONS) &&
|
||||
ctx->GetOption(RSK_SHUFFLE_DUNGEON_REWARDS).Is(RO_DUNGEON_REWARDS_END_OF_DUNGEON)) {
|
||||
count = std::max<uint8_t>(count, (uint8_t)(ctx->GetOption(RSK_LACS_DUNGEON_COUNT).Get() - cfg.offset));
|
||||
count = std::max<uint8_t>(count, (uint8_t)(ctx->GetOption(RSK_GBK_DUNGEON_COUNT).Get() - cfg.offset));
|
||||
}
|
||||
|
||||
if (ctx->GetOption(RSK_GANONS_SOUL).Is(cfg.soulEnum)) {
|
||||
count = std::max<uint8_t>(count, ctx->GetOption(cfg.soulKey).Get());
|
||||
} else if (ctx->GetOption(RSK_GANONS_SOUL).Is(RO_GANONS_SOUL_REWARDS)) {
|
||||
count = std::max<uint8_t>(count, (uint8_t)(ctx->GetOption(RSK_GANONS_SOUL_REWARD_COUNT).Get() - cfg.offset));
|
||||
} else if (ctx->GetOption(RSK_GANONS_SOUL).Is(RO_GANONS_SOUL_DUNGEONS) &&
|
||||
ctx->GetOption(RSK_SHUFFLE_DUNGEON_REWARDS).Is(RO_DUNGEON_REWARDS_END_OF_DUNGEON)) {
|
||||
count = std::max<uint8_t>(count, (uint8_t)(ctx->GetOption(RSK_GANONS_SOUL_DUNGEON_COUNT).Get() - cfg.offset));
|
||||
}
|
||||
|
||||
if (ctx->GetOption(RSK_WINCON).Is(cfg.winEnum)) {
|
||||
count = std::max<uint8_t>(count, ctx->GetOption(cfg.winKey).Get());
|
||||
} else if (ctx->GetOption(RSK_WINCON).Is(RO_WINCON_REWARDS)) {
|
||||
count = std::max<uint8_t>(count, (uint8_t)(ctx->GetOption(RSK_WINCON_REWARD_COUNT).Get() - cfg.offset));
|
||||
} else if (ctx->GetOption(RSK_WINCON).Is(RO_WINCON_DUNGEONS) &&
|
||||
ctx->GetOption(RSK_SHUFFLE_DUNGEON_REWARDS).Is(RO_DUNGEON_REWARDS_END_OF_DUNGEON)) {
|
||||
count = std::max<uint8_t>(count, (uint8_t)(ctx->GetOption(RSK_WINCON_DUNGEON_COUNT).Get() - cfg.offset));
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
@@ -326,27 +326,27 @@ void GenerateItemPool() {
|
||||
AddFixedItemToPool(RG_SHADOW_MEDALLION, 1, rewardIceTraps);
|
||||
AddFixedItemToPool(RG_LIGHT_MEDALLION, 1, rewardIceTraps);
|
||||
|
||||
if (ctx->GetOption(RSK_TRIFORCE_HUNT).IsNot(RO_TRIFORCE_HUNT_OFF)) {
|
||||
AddFixedItemToPool(RG_TRIFORCE_PIECE, ctx->GetOption(RSK_TRIFORCE_HUNT_PIECES_TOTAL).Get() + 1, false);
|
||||
|
||||
switch (ctx->GetOption(RSK_TRIFORCE_HUNT).Get()) {
|
||||
case RO_TRIFORCE_HUNT_OFF:
|
||||
break;
|
||||
case RO_TRIFORCE_HUNT_WIN:
|
||||
ctx->PlaceItemInLocation(RC_TRIFORCE_COMPLETED, RG_TRIFORCE); // Win condition
|
||||
ctx->PlaceItemInLocation(RC_GANON, RG_BLUE_RUPEE, false, true);
|
||||
break;
|
||||
case RO_TRIFORCE_HUNT_GBK:
|
||||
ctx->PlaceItemInLocation(RC_TRIFORCE_COMPLETED, RG_GANONS_CASTLE_BOSS_KEY);
|
||||
ctx->PlaceItemInLocation(RC_GANON, RG_TRIFORCE); // Win condition
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
ctx->PlaceItemInLocation(RC_GANON, RG_TRIFORCE); // Win condition
|
||||
if (ctx->GetOption(RSK_TRIFORCE_HUNT_PIECES_TOTAL).Get() > 0) {
|
||||
AddFixedItemToPool(RG_TRIFORCE_PIECE, ctx->GetOption(RSK_TRIFORCE_HUNT_PIECES_TOTAL).Get(), false);
|
||||
}
|
||||
|
||||
// Fixed item locations
|
||||
ctx->PlaceItemInLocation(RC_HC_ZELDAS_LETTER, RG_ZELDAS_LETTER);
|
||||
ctx->PlaceItemInLocation(RC_GANONS_BOSS_KEY, RG_BLUE_RUPEE); // placeholder, filled by setting
|
||||
ctx->PlaceItemInLocation(RC_GANON_SOUL, RG_BLUE_RUPEE); // placeholder, filled by setting
|
||||
ctx->PlaceItemInLocation(RC_WINCON, RG_BLUE_RUPEE); // placeholder, filled by setting
|
||||
|
||||
if (ctx->GetOption(RSK_WINCON).Is(RO_WINCON_DEFEAT_GANON)) {
|
||||
ctx->PlaceItemInLocation(RC_GANON, RG_TRIFORCE); // Win condition
|
||||
} else {
|
||||
// Ganon isn't the win condition, so slaying him is optional and just hands out a junk reward.
|
||||
ctx->PlaceItemInLocation(RC_GANON, RG_BLUE_RUPEE, false, true);
|
||||
if (ctx->GetOption(RSK_WINCON).Is(RO_WINCON_ANYWHERE)) {
|
||||
AddFixedItemToPool(RG_TRIFORCE, 1);
|
||||
} else {
|
||||
ctx->PlaceItemInLocation(RC_WINCON, RG_TRIFORCE);
|
||||
}
|
||||
}
|
||||
|
||||
if (!ctx->GetOption(RSK_STARTING_KOKIRI_SWORD)) {
|
||||
if (ctx->GetOption(RSK_SHUFFLE_KOKIRI_SWORD)) {
|
||||
@@ -625,9 +625,6 @@ void GenerateItemPool() {
|
||||
AddItemToPool(RG_MORPHA_SOUL, 2, 1, 1, 1);
|
||||
AddItemToPool(RG_BONGO_BONGO_SOUL, 2, 1, 1, 1);
|
||||
AddItemToPool(RG_TWINROVA_SOUL, 2, 1, 1, 1);
|
||||
if (ctx->GetOption(RSK_SHUFFLE_BOSS_SOULS).Is(RO_BOSS_SOULS_ON_PLUS_GANON)) {
|
||||
AddItemToPool(RG_GANON_SOUL, 2, 1, 1, 1);
|
||||
}
|
||||
}
|
||||
|
||||
// Gerudo Fortress
|
||||
@@ -727,12 +724,9 @@ void GenerateItemPool() {
|
||||
AddItemToPool(RG_SHADOW_TEMPLE_BOSS_KEY, 2, 1, 1, 1);
|
||||
}
|
||||
|
||||
// Don't add GBK to the pool at all for Triforce Hunt or if we start with it.
|
||||
if (!(ctx->GetOption(RSK_GANONS_BOSS_KEY).Is(RO_GANON_BOSS_KEY_STARTWITH) || ctx->GetOption(RSK_TRIFORCE_HUNT))) {
|
||||
if (ctx->GetOption(RSK_GANONS_BOSS_KEY).Is(RO_GANON_BOSS_KEY_KAK_TOKENS)) {
|
||||
ctx->PlaceItemInLocation(RC_KAK_100_GOLD_SKULLTULA_REWARD, RG_GANONS_CASTLE_BOSS_KEY);
|
||||
} else if (ctx->GetOption(RSK_GANONS_BOSS_KEY).Get() >= RO_GANON_BOSS_KEY_LACS_VANILLA) {
|
||||
ctx->PlaceItemInLocation(RC_TOT_LIGHT_ARROWS_CUTSCENE, RG_GANONS_CASTLE_BOSS_KEY);
|
||||
if (!(ctx->GetOption(RSK_GANONS_BOSS_KEY).Is(RO_GANON_BOSS_KEY_STARTWITH))) {
|
||||
if (ctx->GetOption(RSK_GANONS_BOSS_KEY).Get() >= RO_GANON_BOSS_KEY_STONES) {
|
||||
ctx->PlaceItemInLocation(RC_GANONS_BOSS_KEY, RG_GANONS_CASTLE_BOSS_KEY);
|
||||
} else if (ctx->GetOption(RSK_GANONS_BOSS_KEY).Is(RO_GANON_BOSS_KEY_VANILLA)) {
|
||||
ctx->PlaceItemInLocation(RC_GANONS_TOWER_BOSS_KEY_CHEST, RG_GANONS_CASTLE_BOSS_KEY);
|
||||
} else {
|
||||
@@ -740,6 +734,14 @@ void GenerateItemPool() {
|
||||
}
|
||||
}
|
||||
|
||||
if (!(ctx->GetOption(RSK_GANONS_SOUL).Is(RO_GANONS_SOUL_STARTWITH))) {
|
||||
if (ctx->GetOption(RSK_GANONS_SOUL).Get() >= RO_GANONS_SOUL_STONES) {
|
||||
ctx->PlaceItemInLocation(RC_GANON_SOUL, RG_GANON_SOUL);
|
||||
} else {
|
||||
AddItemToPool(RG_GANON_SOUL, 2, 1, 1, 1);
|
||||
}
|
||||
}
|
||||
|
||||
// Shopsanity
|
||||
if (ctx->GetOption(RSK_SHOPSANITY).Is(RO_SHOPSANITY_OFF) ||
|
||||
(ctx->GetOption(RSK_SHOPSANITY).Is(RO_SHOPSANITY_SPECIFIC_COUNT) &&
|
||||
|
||||
@@ -43,7 +43,7 @@ bool GenerateRandomizer(std::set<RandomizerCheck> excludedLocations, std::set<Ra
|
||||
ctx->ClearItemLocations();
|
||||
int ret = Playthrough::Playthrough_Init(ctx->GetSeed(), excludedLocations, enabledTricks);
|
||||
if (ret < 0) {
|
||||
if (ret == -1) { // Failed to generate after 5 tries
|
||||
if (ret == -1) {
|
||||
SPDLOG_ERROR("Failed to generate after 5 tries.");
|
||||
return false;
|
||||
} else {
|
||||
|
||||
@@ -53,10 +53,7 @@ void GenerateStartingInventory() {
|
||||
AddItemToInventory(RG_SHADOW_TEMPLE_BOSS_KEY);
|
||||
}
|
||||
|
||||
// Add Ganon's Boss key with Triforce Hunt's Win setting so the game thinks it's obtainable from the start.
|
||||
// During save init, the boss key isn't actually given and it's instead given when completing the triforce.
|
||||
if (ctx->GetOption(RSK_GANONS_BOSS_KEY).Is(RO_GANON_BOSS_KEY_STARTWITH) ||
|
||||
ctx->GetOption(RSK_TRIFORCE_HUNT).Is(RO_TRIFORCE_HUNT_WIN)) {
|
||||
if (ctx->GetOption(RSK_GANONS_BOSS_KEY).Is(RO_GANON_BOSS_KEY_STARTWITH)) {
|
||||
AddItemToInventory(RG_GANONS_CASTLE_BOSS_KEY);
|
||||
}
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include <soh/ResourceManagerHelpers.h>
|
||||
|
||||
#include <cstdarg>
|
||||
#include <algorithm>
|
||||
|
||||
extern "C" {
|
||||
#include <variables.h>
|
||||
@@ -24,47 +25,111 @@ extern PlayState* gPlayState;
|
||||
}
|
||||
|
||||
void BuildTriforcePieceMessage(CustomMessage& msg) {
|
||||
auto rando = OTRGlobals::Instance->gRandomizer;
|
||||
uint8_t current = gSaveContext.ship.quest.data.randomizer.triforcePiecesCollected + 1;
|
||||
uint8_t required = OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_TRIFORCE_HUNT_PIECES_REQUIRED) + 1;
|
||||
uint8_t remaining = required - current;
|
||||
float percentageCollected = (float)current / (float)required;
|
||||
// if any settings are off, 0 them out here as a precaution
|
||||
uint8_t bridge = rando->GetRandoSettingValue(RSK_RAINBOW_BRIDGE) == RO_BRIDGE_TRIFORCE_PIECES
|
||||
? rando->GetRandoSettingValue(RSK_RAINBOW_BRIDGE_TRIFORCE_COUNT)
|
||||
: 0;
|
||||
uint8_t wincon = rando->GetRandoSettingValue(RSK_WINCON) == RO_WINCON_TRIFORCE_PIECES
|
||||
? rando->GetRandoSettingValue(RSK_WINCON_TRIFORCE_COUNT)
|
||||
: 0;
|
||||
uint8_t GBK = rando->GetRandoSettingValue(RSK_GANONS_BOSS_KEY) == RO_GANON_BOSS_KEY_TRIFORCE_PIECES
|
||||
? rando->GetRandoSettingValue(RSK_GBK_TRIFORCE_COUNT)
|
||||
: 0;
|
||||
uint8_t soul = rando->GetRandoSettingValue(RSK_GANONS_SOUL) == RO_GANONS_SOUL_TRIFORCE_PIECES
|
||||
? rando->GetRandoSettingValue(RSK_GANONS_SOUL_TRIFORCE_COUNT)
|
||||
: 0;
|
||||
|
||||
if (percentageCollected <= 0.25) {
|
||||
msg = { "You found a %yTriforce Piece%w!&%g[[current]]%w down, %c[[remaining]]%w to go. It's a start!",
|
||||
"Ein %yTriforce-Splitter%w! Du hast&%g[[current]]%w von %c[[required]]%w gefunden. Es ist ein&Anfang!",
|
||||
"Vous trouvez un %yFragment de la&Triforce%w! Vous en avez %g[[current]]%w, il en&reste "
|
||||
"%c[[remaining]]%w à trouver. C'est un début!" };
|
||||
} else if (percentageCollected <= 0.5) {
|
||||
msg = { "You found a %yTriforce Piece%w!&%g[[current]]%w down, %c[[remaining]]%w to go. Progress!",
|
||||
"Ein %yTriforce-Splitter%w! Du hast&%g[[current]]%w von %c[[required]]%w gefunden. Es geht voran!",
|
||||
"Vous trouvez un %yFragment de la&Triforce%w! Vous en avez %g[[current]]%w, il en&reste "
|
||||
"%c[[remaining]]%w à trouver. Ça avance!" };
|
||||
} else if (percentageCollected <= 0.75) {
|
||||
msg = { "You found a %yTriforce Piece%w!&%g[[current]]%w down, %c[[remaining]]%w to go. Over half-way&there!",
|
||||
"Ein %yTriforce-Splitter%w! Du hast&schon %g[[current]]%w von %c[[required]]%w gefunden. Schon&über "
|
||||
"die Hälfte!",
|
||||
"Vous trouvez un %yFragment de la&Triforce%w! Vous en avez %g[[current]]%w, il en&reste "
|
||||
"%c[[remaining]]%w à trouver. Il en reste un&peu moins que la moitié!" };
|
||||
} else if (percentageCollected < 1.0) {
|
||||
msg = {
|
||||
"You found a %yTriforce Piece%w!&%g[[current]]%w down, %c[[remaining]]%w to go. Almost done!",
|
||||
"Ein %yTriforce-Splitter%w! Du hast&schon %g[[current]]%w von %c[[required]]%w gefunden. Fast&geschafft!",
|
||||
"Vous trouvez un %yFragment de la&Triforce%w! Vous en avez %g[[current]]%w, il en&reste %c[[remaining]]%w "
|
||||
"à trouver. C'est presque&terminé!"
|
||||
};
|
||||
} else if (current == required) {
|
||||
msg = { "You completed the %yTriforce of&Courage%w! %gGG%w!",
|
||||
"Das %yTriforce des Mutes%w! Du hast&alle Splitter gefunden. %gGut gemacht%w!",
|
||||
"Vous avez complété la %yTriforce&du Courage%w! %gFélicitations%w!" };
|
||||
// If we reach wincon, we win!
|
||||
if (current == wincon) {
|
||||
msg = { "You completed the %yTriforce of Courage%w! %gGG%w!",
|
||||
"Das %yTriforce des Mutes%w! Du hast alle Splitter gefunden. %gGut gemacht%w!",
|
||||
"Vous avez complété la %yTriforce du Courage%w! %gFélicitations%w!" };
|
||||
// otherwise prioritise the different triggers
|
||||
} else if (current == bridge) {
|
||||
msg = { "You made your wish to the %yTriforce%w! %rTh%ye R%gai%cnb%bow %pBr%rid%yge %gha%cs r%bai%psed%w!",
|
||||
TODO_TRANSLATE, TODO_TRANSLATE };
|
||||
} else if (current == GBK) {
|
||||
msg = { "You completed the %yTriforce of Power%w! %rThe Key to Evil is yours%w!", TODO_TRANSLATE,
|
||||
TODO_TRANSLATE };
|
||||
} else if (current == soul) {
|
||||
msg = { "You completed the %yTriforce of Wisdom%w! %bGanon's soul is reclaimed%w!", TODO_TRANSLATE,
|
||||
TODO_TRANSLATE };
|
||||
// if everything is zero, then there's no goal...
|
||||
} else if (bridge + wincon + GBK + soul == 0) {
|
||||
msg = { "You found a %yTriforce Piece%w! But it's %puseless%w...", TODO_TRANSLATE, TODO_TRANSLATE };
|
||||
} else {
|
||||
msg = { "You found a spare %yTriforce Piece%w!&You only needed %c[[required]]%w, but you have %g[[current]]%w!",
|
||||
"Ein übriger %yTriforce-Splitter%w! Du&hast nun %g[[current]]%w von %c[[required]]%w nötigen gefunden.",
|
||||
"Vous avez trouvé un %yFragment de&Triforce%w en plus! Vous n'aviez besoin&que de %c[[required]]%w, "
|
||||
"mais vous en avez %g[[current]]%w en&tout!" };
|
||||
// if nothing is complete, we need to check is we have more than we need
|
||||
uint8_t highest = std::max({ current, bridge, wincon, GBK, soul });
|
||||
if (highest == current) {
|
||||
// RANDOTODO TODO_TRANSLATE you could maybe make this sound cleaner because InsertNumber allows for dynamic
|
||||
// plurals
|
||||
msg = { "You found a spare %yTriforce Piece%w! You only needed %c[[d]]%w, but you have %g[[current]]%w!",
|
||||
"Ein übriger %yTriforce-Splitter%w! Du hast nun %g[[current]]%w von %c[[d]]%w nötigen gefunden.",
|
||||
"Vous avez trouvé un %yFragment de Triforce%w en plus! Vous n'aviez besoin que de %c[[d]]%w, "
|
||||
"mais vous en avez %g[[current]]%w en tout!" };
|
||||
msg.InsertNumber(std::max({ bridge, wincon, GBK, soul }));
|
||||
} else {
|
||||
// find the next goal by setting everything below current (including failed conditions set to 0 before)
|
||||
// to a high number, then looking for the lowest.
|
||||
// if we have the exact amount, it will be caught by the first check, so no worries there
|
||||
if (bridge < current) {
|
||||
bridge = 255;
|
||||
}
|
||||
if (GBK < current) {
|
||||
GBK = 255;
|
||||
}
|
||||
if (soul < current) {
|
||||
soul = 255;
|
||||
}
|
||||
if (wincon < current) {
|
||||
wincon = 255;
|
||||
}
|
||||
uint8_t next = std::min({ bridge, GBK, soul, wincon });
|
||||
|
||||
uint8_t remaining = next - current;
|
||||
float percentageCollected = (float)current / (float)next;
|
||||
|
||||
if (percentageCollected <= 0.25) {
|
||||
msg = { "You found a %yTriforce Piece%w! %g[[current]]%w down, %c[[d]]%w more and you [[condition]]! "
|
||||
"It's a start!",
|
||||
TODO_TRANSLATE, TODO_TRANSLATE };
|
||||
} else if (percentageCollected <= 0.5) {
|
||||
msg = { "You found a %yTriforce Piece%w! that makes %g[[current]]%w, %c[[d]]%w to go until you "
|
||||
"[[condition]]! Progress!",
|
||||
TODO_TRANSLATE, TODO_TRANSLATE };
|
||||
} else if (percentageCollected <= 0.75) {
|
||||
msg = { "You found a %yTriforce Piece%w! You have %g[[current]]%w and need %c[[d]]%w more and you "
|
||||
"[[condition]]! Over half-way there!",
|
||||
TODO_TRANSLATE, TODO_TRANSLATE };
|
||||
} else if (percentageCollected < 1.0) {
|
||||
msg = { "You found a %yTriforce Piece%w! %g[[current]]%w down, %c[[d]]%w left until you [[condition]]! "
|
||||
"Almost done!",
|
||||
TODO_TRANSLATE, TODO_TRANSLATE };
|
||||
}
|
||||
|
||||
// default condition is soul
|
||||
CustomMessage condition = { "%brelease Ganons Soul%w", TODO_TRANSLATE, TODO_TRANSLATE };
|
||||
if (next == wincon) {
|
||||
condition = { "%gWin the game%w", TODO_TRANSLATE, TODO_TRANSLATE };
|
||||
} else if (next == bridge) {
|
||||
condition = { "%csummon the Rainbow Bridge%w", TODO_TRANSLATE, TODO_TRANSLATE };
|
||||
} else if (next == GBK) {
|
||||
condition = { "%rfind the key to Ganondorf's Lair%w", TODO_TRANSLATE, TODO_TRANSLATE };
|
||||
}
|
||||
msg.Replace("[[condition]]", condition);
|
||||
msg.InsertNumber(remaining);
|
||||
}
|
||||
}
|
||||
msg.Replace("[[current]]", std::to_string(current));
|
||||
msg.Replace("[[remaining]]", std::to_string(remaining));
|
||||
msg.Replace("[[required]]", std::to_string(required));
|
||||
msg.AutoFormat(ITEM_CUSTOM);
|
||||
}
|
||||
|
||||
void BuildTriforceMessage(CustomMessage& msg) {
|
||||
msg = { "You completed the %yTriforce of&Courage%w! %gGG%w!",
|
||||
"Das %yTriforce des Mutes%w! Du hast&alle Splitter gefunden. %gGut gemacht%w!",
|
||||
"Vous avez complété la %yTriforce&du Courage%w! %gFélicitations%w!" };
|
||||
msg.Format(ITEM_CUSTOM);
|
||||
}
|
||||
|
||||
@@ -100,12 +165,16 @@ void LoadCustomItemIcon(bool displayAsEnglish) {
|
||||
RandomizerGet rgid = static_cast<RandomizerGet>(player->getItemEntry.getItemId);
|
||||
customIcon = Rando::StaticData::RetrieveItem(rgid).GetCustomIcon();
|
||||
iconSize = Rando::StaticData::RetrieveItem(rgid).GetCustomIconSize();
|
||||
} else {
|
||||
// if we're seeing an icon and we don't have a GI, assume we're in the alter text showing a triforce piece
|
||||
customIcon = Rando::StaticData::RetrieveItem(RG_TRIFORCE_PIECE).GetCustomIcon();
|
||||
iconSize = Rando::StaticData::RetrieveItem(RG_TRIFORCE_PIECE).GetCustomIconSize();
|
||||
}
|
||||
if (customIcon != nullptr) {
|
||||
static int16_t sIconItem32XOffsets[] = { 74, 74, 74, 54 };
|
||||
static int16_t sIconItem24XOffsets[] = { 72, 72, 72, 50 };
|
||||
MessageContext* msgCtx = &gPlayState->msgCtx;
|
||||
uint8_t language = displayAsEnglish ? LANGUAGE_ENG : gSaveContext.language;
|
||||
uint8_t language = displayAsEnglish ? LANGUAGE_ENG : (Language)gSaveContext.language;
|
||||
if (iconSize == ICON_SIZE_32) {
|
||||
R_TEXTBOX_ICON_XPOS = R_TEXT_INIT_XPOS - sIconItem32XOffsets[language];
|
||||
R_TEXTBOX_ICON_YPOS = (R_TEXTBOX_Y + 10) + 6;
|
||||
@@ -150,6 +219,8 @@ void BuildItemMessage(u16* textId, bool* loadFromMessageTable) {
|
||||
Rando::Traps::BuildIceTrapMessage(msg, player->getItemEntry);
|
||||
} else if (player->getItemEntry.getItemId == RG_TRIFORCE_PIECE) {
|
||||
BuildTriforcePieceMessage(msg);
|
||||
} else if (player->getItemEntry.getItemId == RG_TRIFORCE) {
|
||||
BuildTriforceMessage(msg);
|
||||
} else {
|
||||
BuildCustomItemMessage(player, msg);
|
||||
}
|
||||
|
||||
@@ -255,6 +255,7 @@ std::unordered_map<RandomizerGet, std::string> itemImageMap = {
|
||||
{ RG_FISHING_POLE, "ITEM_FISHING_POLE" },
|
||||
{ RG_SOLD_OUT, "ITEM_SOLD_OUT" },
|
||||
{ RG_TRIFORCE_PIECE, "TRIFORCE_PIECE" },
|
||||
{ RG_TRIFORCE, "TRIFORCE" },
|
||||
{ RG_SKELETON_KEY, "ITEM_KEY_SMALL" }
|
||||
};
|
||||
|
||||
@@ -1207,4 +1208,6 @@ void PlandomizerWindow::InitElement() {
|
||||
->LoadGuiTexture("BOSS_SOUL", gBossSoulTex, ImVec4(1, 1, 1, 1));
|
||||
std::dynamic_pointer_cast<Fast::Fast3dGui>(Ship::Context::GetRawInstance()->GetWindow()->GetGui())
|
||||
->LoadGuiTexture("TRIFORCE_PIECE", gTriforcePieceTex, ImVec4(1, 1, 1, 1));
|
||||
std::dynamic_pointer_cast<Fast::Fast3dGui>(Ship::Context::GetRawInstance()->GetWindow()->GetGui())
|
||||
->LoadGuiTexture("TRIFORCE", gTriforcePieceTex, ImVec4(1, 1, 1, 1));
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user