From 2117d98178af72e6abdcd2aec66a26d5d8711411 Mon Sep 17 00:00:00 2001 From: Adam Bird Date: Wed, 8 Mar 2023 10:18:02 -0500 Subject: [PATCH 1/9] fix skulltula token count message on vanilla (#2597) --- soh/soh/OTRGlobals.cpp | 2 +- soh/src/overlays/actors/ovl_En_Si/z_en_si.c | 30 ++++++++++----------- 2 files changed, 15 insertions(+), 17 deletions(-) diff --git a/soh/soh/OTRGlobals.cpp b/soh/soh/OTRGlobals.cpp index 5528bfba1..f6e5bc5d8 100644 --- a/soh/soh/OTRGlobals.cpp +++ b/soh/soh/OTRGlobals.cpp @@ -1678,7 +1678,7 @@ extern "C" int CustomMessage_RetrieveIfExists(PlayState* play) { textId = TEXT_GS_FREEZE; } messageEntry = CustomMessageManager::Instance->RetrieveMessage(customMessageTableID, textId); - CustomMessageManager::ReplaceStringInMessage(messageEntry, "{{gsCount}}", std::to_string(gSaveContext.inventory.gsTokens + 1)); + CustomMessageManager::ReplaceStringInMessage(messageEntry, "{{gsCount}}", std::to_string(gSaveContext.inventory.gsTokens)); } } if (textId == TEXT_HEART_CONTAINER && CVarGetInteger("gInjectItemCounts", 0)) { diff --git a/soh/src/overlays/actors/ovl_En_Si/z_en_si.c b/soh/src/overlays/actors/ovl_En_Si/z_en_si.c index 344173805..d9eb19ebe 100644 --- a/soh/src/overlays/actors/ovl_En_Si/z_en_si.c +++ b/soh/src/overlays/actors/ovl_En_Si/z_en_si.c @@ -103,6 +103,11 @@ void func_80AFB768(EnSi* this, PlayState* play) { if (gSaveContext.n64ddFlag) { Randomizer_UpdateSkullReward(this, play); + if (getItemId != RG_ICE_TRAP) { + Randomizer_GiveSkullReward(this, play); + } else { + gSaveContext.pendingIceTrapCount++; + } } else { Item_Give(play, giveItemId); } @@ -117,14 +122,8 @@ void func_80AFB768(EnSi* this, PlayState* play) { Message_StartTextbox(play, textId, NULL); - if (gSaveContext.n64ddFlag) { - if (getItemId != RG_ICE_TRAP) { - Randomizer_GiveSkullReward(this, play); - Audio_PlayFanfare_Rando(getItem); - } else { - gSaveContext.pendingIceTrapCount++; - Audio_PlayFanfare(NA_BGM_SMALL_ITEM_GET); - } + if (gSaveContext.n64ddFlag && getItemId != RG_ICE_TRAP) { + Audio_PlayFanfare_Rando(getItem); } else { Audio_PlayFanfare(NA_BGM_SMALL_ITEM_GET); } @@ -149,20 +148,19 @@ void func_80AFB89C(EnSi* this, PlayState* play) { if (!CHECK_FLAG_ALL(this->actor.flags, ACTOR_FLAG_13)) { if (gSaveContext.n64ddFlag) { Randomizer_UpdateSkullReward(this, play); + if (getItemId != RG_ICE_TRAP) { + Randomizer_GiveSkullReward(this, play); + } else { + gSaveContext.pendingIceTrapCount++; + } } else { Item_Give(play, giveItemId); } Message_StartTextbox(play, textId, NULL); - if (gSaveContext.n64ddFlag) { - if (getItemId != RG_ICE_TRAP) { - Randomizer_GiveSkullReward(this, play); - Audio_PlayFanfare_Rando(getItem); - } else { - gSaveContext.pendingIceTrapCount++; - Audio_PlayFanfare(NA_BGM_SMALL_ITEM_GET); - } + if (gSaveContext.n64ddFlag && getItemId != RG_ICE_TRAP) { + Audio_PlayFanfare_Rando(getItem); } else { Audio_PlayFanfare(NA_BGM_SMALL_ITEM_GET); } From 60f4f71495a03deae30204f2a03c028bd03f161f Mon Sep 17 00:00:00 2001 From: Adam Bird Date: Wed, 8 Mar 2023 13:08:54 -0500 Subject: [PATCH 2/9] fix flag wind speed to use correct uint type (#2600) --- .../resource/importer/scenecommand/SetWindSettingsFactory.cpp | 2 +- soh/soh/resource/type/scenecommand/SetWindSettings.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/soh/soh/resource/importer/scenecommand/SetWindSettingsFactory.cpp b/soh/soh/resource/importer/scenecommand/SetWindSettingsFactory.cpp index f22a9c2d8..f4d3be08b 100644 --- a/soh/soh/resource/importer/scenecommand/SetWindSettingsFactory.cpp +++ b/soh/soh/resource/importer/scenecommand/SetWindSettingsFactory.cpp @@ -37,7 +37,7 @@ void Ship::SetWindSettingsFactoryV0::ParseFileBinary(std::shared_ptrsettings.windWest = reader->ReadInt8(); setWind->settings.windVertical = reader->ReadInt8(); setWind->settings.windSouth = reader->ReadInt8(); - setWind->settings.windSpeed = reader->ReadInt8(); + setWind->settings.windSpeed = reader->ReadUByte(); } } // namespace Ship diff --git a/soh/soh/resource/type/scenecommand/SetWindSettings.h b/soh/soh/resource/type/scenecommand/SetWindSettings.h index b51bdf839..2a8825fc7 100644 --- a/soh/soh/resource/type/scenecommand/SetWindSettings.h +++ b/soh/soh/resource/type/scenecommand/SetWindSettings.h @@ -12,7 +12,7 @@ typedef struct { int8_t windWest; int8_t windVertical; int8_t windSouth; - int8_t windSpeed; + uint8_t windSpeed; } WindSettings; class SetWindSettings : public SceneCommand { From 7c558ae089d17259c41dafff12ef21b1a99d63fa Mon Sep 17 00:00:00 2001 From: Adam Bird Date: Wed, 8 Mar 2023 13:09:22 -0500 Subject: [PATCH 3/9] fix rando quest selection falling back to vanilla saves (#2599) --- soh/soh/SaveManager.cpp | 2 ++ soh/src/code/z_sram.c | 4 +--- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/soh/soh/SaveManager.cpp b/soh/soh/SaveManager.cpp index 270bca60c..6cea7024b 100644 --- a/soh/soh/SaveManager.cpp +++ b/soh/soh/SaveManager.cpp @@ -1726,6 +1726,8 @@ void SaveManager::DeleteZeldaFile(int fileNum) { } fileMetaInfo[fileNum].valid = false; fileMetaInfo[fileNum].randoSave = false; + fileMetaInfo[fileNum].requiresMasterQuest = false; + fileMetaInfo[fileNum].requiresOriginal = false; GameInteractor::Instance->ExecuteHooks(fileNum); } diff --git a/soh/src/code/z_sram.c b/soh/src/code/z_sram.c index 7e6486734..31cc8b5e2 100644 --- a/soh/src/code/z_sram.c +++ b/soh/src/code/z_sram.c @@ -298,9 +298,7 @@ void Sram_InitSave(FileChooseContext* fileChooseCtx) { gSaveContext.playerName[offset] = Save_GetSaveMetaInfo(fileChooseCtx->buttonIndex)->playerName[offset]; } - if (fileChooseCtx->questType[fileChooseCtx->buttonIndex] == 2 && strnlen(CVarGetString("gSpoilerLog", ""), 1) != 0 && - !((Save_GetSaveMetaInfo(fileChooseCtx->buttonIndex)->requiresMasterQuest && !ResourceMgr_GameHasMasterQuest()) || - (Save_GetSaveMetaInfo(fileChooseCtx->buttonIndex)->requiresMasterQuest && !ResourceMgr_GameHasOriginal()))) { + if (fileChooseCtx->questType[fileChooseCtx->buttonIndex] == 2 && strnlen(CVarGetString("gSpoilerLog", ""), 1) != 0) { // Set N64DD Flags for save file fileChooseCtx->n64ddFlags[fileChooseCtx->buttonIndex] = 1; fileChooseCtx->n64ddFlag = 1; From 1c00d56053199814551cf37daff3e5359a783b70 Mon Sep 17 00:00:00 2001 From: aMannus Date: Wed, 8 Mar 2023 19:10:14 +0100 Subject: [PATCH 4/9] Exclude club moblins in clear rooms (#2593) --- soh/soh/Enhancements/enemyrandomizer.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/soh/soh/Enhancements/enemyrandomizer.cpp b/soh/soh/Enhancements/enemyrandomizer.cpp index 36bff0e37..0e9d9fcdf 100644 --- a/soh/soh/Enhancements/enemyrandomizer.cpp +++ b/soh/soh/Enhancements/enemyrandomizer.cpp @@ -319,9 +319,11 @@ bool IsEnemyAllowedToSpawn(int16_t sceneNum, int8_t roomNum, EnemyEntry enemy) { // Shell Blade & Spike - Child link can't kill these with sword or deku stick. // Arwing & Dark Link - Both go out of bounds way too easily, softlocking the player. // Wallmaster - Not easily visible, often makes players think they're softlocked and that there's no enemies left. + // Club Moblin - Many issues with them falling or placing out of bounds. Maybe fixable in the future? bool enemiesToExcludeClearRooms = enemy.id == ACTOR_EN_FZ || enemy.id == ACTOR_EN_VM || enemy.id == ACTOR_EN_SB || enemy.id == ACTOR_EN_NY || enemy.id == ACTOR_EN_CLEAR_TAG || - enemy.id == ACTOR_EN_WALLMAS || enemy.id == ACTOR_EN_TORCH2; + enemy.id == ACTOR_EN_WALLMAS || enemy.id == ACTOR_EN_TORCH2 || + enemy.id == ACTOR_EN_MB; // Bari - Spawns 3 more enemies, potentially extremely difficult in timed rooms. bool enemiesToExcludeTimedRooms = enemiesToExcludeClearRooms || enemy.id == ACTOR_EN_VALI; From 095066ffcddab40bee2c4f77cc9cd7a5104cfdc7 Mon Sep 17 00:00:00 2001 From: aMannus Date: Sat, 11 Mar 2023 18:47:56 +0100 Subject: [PATCH 5/9] Enemy Rando - Arwing range check (Khan Edition) (#2613) * Arwing range check * Small code cleanup --- soh/src/overlays/actors/ovl_En_Clear_Tag/z_en_clear_tag.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/soh/src/overlays/actors/ovl_En_Clear_Tag/z_en_clear_tag.c b/soh/src/overlays/actors/ovl_En_Clear_Tag/z_en_clear_tag.c index a095ae500..62e991d38 100644 --- a/soh/src/overlays/actors/ovl_En_Clear_Tag/z_en_clear_tag.c +++ b/soh/src/overlays/actors/ovl_En_Clear_Tag/z_en_clear_tag.c @@ -475,9 +475,13 @@ void EnClearTag_Update(Actor* thisx, PlayState* play2) { Math_ApproachS(&this->actor.world.rot.z, 0, 15, this->targetDirection.z); Math_ApproachF(&this->targetDirection.z, 0x500, 1.0f, 0x100); + // Introduce a range requirement in Enemy Rando so Arwings don't shoot the player from + // across the map. Especially noticeable in big maps like Lake Hylia and Hyrule Field. + uint8_t enemyRandoShootLaser = !CVarGetInteger("gRandomizedEnemies", 0) || this->actor.xzDistToPlayer < 1000.0f; + // Check if the Arwing should fire its laser. if ((this->frameCounter % 4) == 0 && (Rand_ZeroOne() < 0.75f) && - (this->state == CLEAR_TAG_STATE_TARGET_LOCKED)) { + (this->state == CLEAR_TAG_STATE_TARGET_LOCKED) && enemyRandoShootLaser) { this->shouldShootLaser = true; } } else { From 39acd71fc4a1591b31b1563a8e8573bbf26fa1d6 Mon Sep 17 00:00:00 2001 From: Adam Bird Date: Sun, 12 Mar 2023 03:01:18 -0400 Subject: [PATCH 6/9] remove left over boss location logic from mq logic (#2619) --- .../3drando/location_access/locacc_deku_tree.cpp | 11 ++--------- .../location_access/locacc_dodongos_cavern.cpp | 4 ---- 2 files changed, 2 insertions(+), 13 deletions(-) diff --git a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_deku_tree.cpp b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_deku_tree.cpp index 9f22eea63..eb6793225 100644 --- a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_deku_tree.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_deku_tree.cpp @@ -233,16 +233,9 @@ void AreaTable_Init_DekuTree() { Entrance(DEKU_TREE_MQ_BASEMENT_WATER_ROOM_BACK, {[]{return (IsChild && CanUse(KOKIRI_SWORD)) || CanUseProjectile || (Nuts && (IsChild && CanUse(STICKS)));}}), }); - areaTable[DEKU_TREE_MQ_BASEMENT_LEDGE] = Area("Deku Tree MQ Basement Ledge", "Deku Tree", DEKU_TREE, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&DekuTreeClear, {[]{return DekuTreeClear || (Here(DEKU_TREE_MQ_BASEMENT_LEDGE, []{return HasFireSourceWithTorch;}) && - Here(DEKU_TREE_MQ_BASEMENT_LEDGE, []{return HasShield;}) && - (IsAdult || KokiriSword || Sticks) && (Nuts || CanUse(SLINGSHOT) || CanUse(BOW) || HookshotOrBoomerang));}}), - }, { + areaTable[DEKU_TREE_MQ_BASEMENT_LEDGE] = Area("Deku Tree MQ Basement Ledge", "Deku Tree", DEKU_TREE, NO_DAY_NIGHT_CYCLE, {}, { //Locations - LocationAccess(DEKU_TREE_MQ_DEKU_SCRUB, {[]{return CanStunDeku;}}), - LocationAccess(DEKU_TREE_QUEEN_GOHMA_HEART, {[]{return HasFireSourceWithTorch && HasShield && (IsAdult || KokiriSword || Sticks) && (Nuts || CanUse(SLINGSHOT) || CanUse(BOW) || HookshotOrBoomerang);}}), - LocationAccess(QUEEN_GOHMA, {[]{return HasFireSourceWithTorch && HasShield && (IsAdult || KokiriSword || Sticks) && (Nuts || CanUse(SLINGSHOT) || CanUse(BOW) || HookshotOrBoomerang);}}), + LocationAccess(DEKU_TREE_MQ_DEKU_SCRUB, {[]{return CanStunDeku;}}), }, { //Exits Entrance(DEKU_TREE_MQ_BASEMENT_BACK_ROOM, {[]{return IsChild;}}), diff --git a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_dodongos_cavern.cpp b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_dodongos_cavern.cpp index fa6985077..ac32354c5 100644 --- a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_dodongos_cavern.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_dodongos_cavern.cpp @@ -291,13 +291,9 @@ void AreaTable_Init_DodongosCavern() { areaTable[DODONGOS_CAVERN_MQ_BOSS_AREA] = Area("Dodongos Cavern MQ BossArea", "Dodongos Cavern", DODONGOS_CAVERN, NO_DAY_NIGHT_CYCLE, { //Events EventAccess(&FairyPot, {[]{return true;}}), - EventAccess(&DodongosCavernClear, {[]{return DodongosCavernClear || (CanBlastOrSmash && (Bombs || GoronBracelet) && (IsAdult || Sticks || KokiriSword));}}), }, { //Locations LocationAccess(DODONGOS_CAVERN_MQ_UNDER_GRAVE_CHEST, {[]{return true;}}), - LocationAccess(DODONGOS_CAVERN_BOSS_ROOM_CHEST, {[]{return true;}}), - LocationAccess(DODONGOS_CAVERN_KING_DODONGO_HEART, {[]{return CanBlastOrSmash && (Bombs || GoronBracelet) && (IsAdult || Sticks || KokiriSword);}}), - LocationAccess(KING_DODONGO, {[]{return CanBlastOrSmash && (Bombs || GoronBracelet) && (IsAdult || Sticks || KokiriSword);}}), LocationAccess(DODONGOS_CAVERN_MQ_GS_BACK_AREA, {[]{return true;}}), }, { //Exits From 1ce9634f65c8ce1913cb3279cdfaae7eae1d9473 Mon Sep 17 00:00:00 2001 From: Adam Bird Date: Sun, 12 Mar 2023 03:06:52 -0400 Subject: [PATCH 7/9] clear bongo bongo static effect on actor reset (#2603) --- soh/src/overlays/actors/ovl_Boss_Sst/z_boss_sst.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/soh/src/overlays/actors/ovl_Boss_Sst/z_boss_sst.c b/soh/src/overlays/actors/ovl_Boss_Sst/z_boss_sst.c index b621dfadb..9c36952ab 100644 --- a/soh/src/overlays/actors/ovl_Boss_Sst/z_boss_sst.c +++ b/soh/src/overlays/actors/ovl_Boss_Sst/z_boss_sst.c @@ -247,7 +247,7 @@ const ActorInit Boss_Sst_InitVars = { (ActorFunc)BossSst_Destroy, (ActorFunc)BossSst_UpdateHand, (ActorFunc)BossSst_DrawHand, - NULL, + (ActorResetFunc)BossSst_Reset, }; #include "z_boss_sst_colchk.c" @@ -3268,4 +3268,13 @@ void BossSst_Reset(void) { sCutsceneCamera= 0; sBodyStatic = false; + // Reset death colors + sBodyColor.a = 255; + sBodyColor.r = 255; + sBodyColor.g = 255; + sBodyColor.b = 255; + sStaticColor.a = 255; + sStaticColor.r = 0; + sStaticColor.g = 0; + sStaticColor.b = 0; } From d9008938f8518de31bce394615b0db19287e0805 Mon Sep 17 00:00:00 2001 From: Christopher Leggett Date: Sun, 12 Mar 2023 15:55:25 -0400 Subject: [PATCH 8/9] Makes sequenceMap and seqLoadStatus a dynamic size (#2610) Refactors to allow the above two arrays to be a dynamic size when the game launches, size is set during the AudioLoad_Init function. --- soh/include/z64audio.h | 5 +++-- soh/src/code/audio_heap.c | 2 +- soh/src/code/audio_load.c | 12 ++++++++---- soh/src/code/audio_seqplayer.c | 2 +- 4 files changed, 13 insertions(+), 8 deletions(-) diff --git a/soh/include/z64audio.h b/soh/include/z64audio.h index 0942772c4..a7587ea2c 100644 --- a/soh/include/z64audio.h +++ b/soh/include/z64audio.h @@ -22,7 +22,8 @@ #define CALC_RESAMPLE_FREQ(sampleRate) ((float)sampleRate / (s32)gAudioContext.audioBufferParameters.frequency) -#define MAX_SEQUENCES 0x400 +//#define MAX_SEQUENCES 0x800 +extern size_t sequenceMapSize; extern char* fontMap[256]; @@ -917,7 +918,7 @@ typedef struct { /* 0x342C */ AudioPoolSplit3 temporaryCommonPoolSplit; /* 0x3438 */ u8 sampleFontLoadStatus[0x30]; /* 0x3468 */ u8 fontLoadStatus[0x30]; - /* 0x3498 */ u8 seqLoadStatus[MAX_SEQUENCES]; + /* 0x3498 */ u8* seqLoadStatus; /* 0x3518 */ volatile u8 resetStatus; /* 0x3519 */ u8 audioResetSpecIdToLoad; /* 0x351C */ s32 audioResetFadeOutFramesLeft; diff --git a/soh/src/code/audio_heap.c b/soh/src/code/audio_heap.c index 72c1c8870..8d0e97fa3 100644 --- a/soh/src/code/audio_heap.c +++ b/soh/src/code/audio_heap.c @@ -53,7 +53,7 @@ void AudioHeap_ResetLoadStatus(void) { } } - for (i = 0; i < MAX_SEQUENCES; i++) { + for (i = 0; i < sequenceMapSize; i++) { if (gAudioContext.seqLoadStatus[i] != 5) { gAudioContext.seqLoadStatus[i] = 0; } diff --git a/soh/src/code/audio_load.c b/soh/src/code/audio_load.c index 81d395a81..eb788fd0c 100644 --- a/soh/src/code/audio_load.c +++ b/soh/src/code/audio_load.c @@ -77,7 +77,8 @@ void* sUnusedHandler = NULL; s32 gAudioContextInitalized = false; -char* sequenceMap[MAX_SEQUENCES]; +char** sequenceMap; +size_t sequenceMapSize; // A map of authentic sequence IDs to their cache policies, for use with sequence swapping. u8 seqCachePolicyMap[MAX_AUTHENTIC_SEQID]; char* fontMap[256]; @@ -488,7 +489,7 @@ u8* AudioLoad_GetFontsForSequence(s32 seqId, u32* outNumFonts) { return NULL; u16 newSeqId = AudioEditor_GetReplacementSeq(seqId); - if (newSeqId > MAX_SEQUENCES || !sequenceMap[newSeqId]) { + if (newSeqId > sequenceMapSize || !sequenceMap[newSeqId]) { return NULL; } SequenceData sDat = ResourceMgr_LoadSeqByName(sequenceMap[newSeqId]); @@ -1342,7 +1343,12 @@ void AudioLoad_Init(void* heap, size_t heapSize) { AudioHeap_ResetStep(); int seqListSize = 0; + int customSeqListSize = 0; char** seqList = ResourceMgr_ListFiles("audio/sequences*", &seqListSize); + char** customSeqList = ResourceMgr_ListFiles("custom/music/*", &customSeqListSize); + sequenceMapSize = (size_t)(seqListSize + customSeqListSize); + sequenceMap = malloc(sequenceMapSize * sizeof(char*)); + gAudioContext.seqLoadStatus = malloc(sequenceMapSize * sizeof(char*)); for (size_t i = 0; i < seqListSize; i++) { @@ -1357,9 +1363,7 @@ void AudioLoad_Init(void* heap, size_t heapSize) { free(seqList); - int customSeqListSize = 0; int startingSeqNum = MAX_AUTHENTIC_SEQID; // 109 is the highest vanilla sequence - char** customSeqList = ResourceMgr_ListFiles("custom/music/*", &customSeqListSize); qsort(customSeqList, customSeqListSize, sizeof(char*), strcmp_sort); for (size_t i = startingSeqNum; i < startingSeqNum + customSeqListSize; i++) { diff --git a/soh/src/code/audio_seqplayer.c b/soh/src/code/audio_seqplayer.c index 0b5192b0b..9e9ee645c 100644 --- a/soh/src/code/audio_seqplayer.c +++ b/soh/src/code/audio_seqplayer.c @@ -3,7 +3,7 @@ #include #include "global.h" -extern char* sequenceMap[MAX_SEQUENCES]; +extern char** sequenceMap; #define PORTAMENTO_IS_SPECIAL(x) ((x).mode & 0x80) #define PORTAMENTO_MODE(x) ((x).mode & ~0x80) From 264623f40ac2a79fe7afd7818266a8f0f55ec2c2 Mon Sep 17 00:00:00 2001 From: Malkierian Date: Mon, 13 Mar 2023 14:24:51 -0700 Subject: [PATCH 9/9] Shopsanity Affordable Logic Update (#2617) * Modified Affordable logic to select randomly from 10, 105, 205, and 505 depending on the selected wallet tier. Updated the tooltip to reflect. * Clarified logic in comments and variable names. * Streamlined affordable check for starter wallet. One more function comment. * More streamlining of affordable price generation, comment clarification. --- .../Enhancements/randomizer/3drando/shops.cpp | 44 +++++++++++-------- .../Enhancements/randomizer/randomizer.cpp | 6 +-- 2 files changed, 29 insertions(+), 21 deletions(-) diff --git a/soh/soh/Enhancements/randomizer/3drando/shops.cpp b/soh/soh/Enhancements/randomizer/3drando/shops.cpp index 1b4dbb28d..3cfaa01ad 100644 --- a/soh/soh/Enhancements/randomizer/3drando/shops.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/shops.cpp @@ -128,31 +128,39 @@ static constexpr std::array ShopPriceProbability= { 0.959992180, 0.968187000, 0.975495390, 0.981884488, 0.987344345, 0.991851853, 0.995389113, 0.997937921, 0.999481947, 1.000000000, }; -std::map affordableCaps = { - {RO_SHOPSANITY_PRICE_STARTER, 10}, - {RO_SHOPSANITY_PRICE_ADULT, 105}, - {RO_SHOPSANITY_PRICE_GIANT, 205}, - {RO_SHOPSANITY_PRICE_TYCOON, 505}, -}; - -// If affordable option is on, cap items at affordable price just above the max of the previous wallet tier -int CapPriceAffordable(int value, int cap) { - if (Settings::ShopsanityPricesAffordable.Is(true) && value > cap) - return cap; - return value; -} - // Generate random number from 5 to wallet max int GetPriceFromMax(int max) { - int temp = Random(1, max) * 5; // random range of 1 - wallet max / 5, where wallet max is the highest it goes as a multiple of 5 - return CapPriceAffordable(temp, affordableCaps.find(Settings::ShopsanityPrices.Value())->second); + return Random(1, max) * 5; // random range of 1 - wallet max / 5, where wallet max is the highest it goes as a multiple of 5 +} + +// Get random price out of available "affordable prices", or just return 10 if Starter wallet is selected (no need to randomly select +// from a single element) +int GetPriceAffordable() { + if (Settings::ShopsanityPrices.Is(RO_SHOPSANITY_PRICE_STARTER)) { + return 10; + } + + static const std::vector affordablePrices = { 10, 105, 205, 505 }; + std::vector priceList; + uint8_t maxElements = Settings::ShopsanityPrices.Value(); + for (int i = 0; i < maxElements; i++) { + priceList.push_back(affordablePrices.at(i)); + } + return RandomElement(priceList); } int GetRandomShopPrice() { + // If Affordable is enabled, no need to set randomizer max price + if (Settings::ShopsanityPricesAffordable.Is(true)) { + return GetPriceAffordable(); + } + + // max 0 means Balanced is selected, and thus shouldn't trigger GetPriceFromMax int max = 0; - if(Settings::ShopsanityPrices.Is(RO_SHOPSANITY_PRICE_STARTER)) {// check for xx wallet setting and set max amount as method for - max = 19; // 95/5 // setting true randomization + // check settings for a wallet tier selection and set max amount as method for setting true randomization + if(Settings::ShopsanityPrices.Is(RO_SHOPSANITY_PRICE_STARTER)) { + max = 19; // 95/5 } else if (Settings::ShopsanityPrices.Is(RO_SHOPSANITY_PRICE_ADULT)) { max = 40; // 200/5 diff --git a/soh/soh/Enhancements/randomizer/randomizer.cpp b/soh/soh/Enhancements/randomizer/randomizer.cpp index f3664c719..3e2cd3e60 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer.cpp @@ -3094,7 +3094,7 @@ void DrawRandoEditor(bool& open) { static const char* randoLinksPocket[4] = { "Dungeon Reward", "Advancement", "Anything", "Nothing" }; static const char* randoShuffleSongs[3] = { "Song Locations", "Dungeon Rewards", "Anywhere" }; static const char* randoShopsanity[7] = { "Off", "0 Items", "1 Item", "2 Items", "3 Items", "4 Items", "Random" }; - static const char* randoShopsanityPrices[6] = { "Balanced", "Starter Wallet", "Adult Wallet", "Giant's Wallet", "Tycoon's Wallet", "Affordable" }; + static const char* randoShopsanityPrices[5] = { "Balanced", "Starter Wallet", "Adult Wallet", "Giant's Wallet", "Tycoon's Wallet" }; static const char* randoTokensanity[4] = { "Off", "Dungeons", "Overworld", "All Tokens" }; static const char* randoShuffleScrubs[4] = { "Off", "Affordable", "Expensive", "Random Prices" }; static const char* randoShuffleMerchants[3] = { "Off", "On (no hints)", "On (with hints)" }; @@ -3729,8 +3729,8 @@ void DrawRandoEditor(bool& open) { UIWidgets::EnhancementCheckbox(Settings::ShopsanityPricesAffordable.GetName().c_str(), "gRandomizeShopsanityPricesAffordable", CVarGetInteger("gRandomizeShopsanityPrices", RO_SHOPSANITY_PRICE_BALANCED) == RO_SHOPSANITY_PRICE_BALANCED, "This can only apply to a wallet range."); - UIWidgets::InsertHelpHoverText("Cap item prices to a value just above the previous tier wallet's max value.\n" - "Affordable caps: starter = 10, adult = 105, giant = 205, tycoon = 505\n" + UIWidgets::InsertHelpHoverText("Random selection between the selected wallet tier's affordable price and the affordable prices of the preceding wallet tiers.\n\n" + "Affordable prices per tier: starter = 10, adult = 105, giant = 205, tycoon = 505\n\n" "Use this to enable wallet tier locking, but make shop items not as expensive as they could be."); }