mirror of
https://github.com/HarbourMasters/Shipwright.git
synced 2024-11-29 12:52:18 -05:00
Improvement: Additional Spoiler Hint Info (#2727)
* First attempt at tracking hinted locations. Not looking promising for more than a hint tracker. * Spoiler log now generates with human-readable hinted area, type, and item for gossip stone hints. * Hints now only output location if their hint text specifically states the check. Any overworld or dungeon region hint no longer does. * Expanded gossip stone hints to include item, hinted location and area, and `RandomizerGet` names. Currently only English names. Part of this required changing `HintType` into a `typedef enum` instead of an `enum class` to allow usage in a .c filespace, and consolidating types from `randomizer_check_objects.h` to `randomizerTypes.h`. * Beginning of alter rewards information. * Step 2 of altar reward info. * Altar reward info (location and area) now writes to and reads from the spoiler log. Added a few entries to `SpoilerfileAreaNameToEnum` to accommodate area name variants from region hint names. * Streamlined altar data (only needed location name for `RandomizerCheck` translation. `RandomizerCheck` provides access to `RandomizerCheckArea` via `RandomizerCheckObject`). Added Light Arrows, Greg, and Dampe's Hookshot hint locations to write and read of the spoiler. * Fix attempts to lookup values in `hintTypeNames` as array, now uses map's `find()`.
This commit is contained in:
parent
f976003563
commit
c9bcd64beb
@ -155,6 +155,10 @@ typedef struct {
|
||||
|
||||
typedef struct {
|
||||
RandomizerCheck check;
|
||||
RandomizerCheck hintedCheck;
|
||||
RandomizerGet rGet;
|
||||
RandomizerCheckArea area;
|
||||
HintType type;
|
||||
char hintText[200];
|
||||
} HintLocationRando;
|
||||
|
||||
@ -298,6 +302,7 @@ typedef struct {
|
||||
/* */ EntranceOverride entranceOverrides[ENTRANCE_OVERRIDES_MAX_COUNT];
|
||||
/* */ char childAltarText[250];
|
||||
/* */ char adultAltarText[750];
|
||||
/* */ RandomizerCheck rewardCheck[9];
|
||||
/* */ char ganonHintText[150];
|
||||
/* */ char gregHintText[250];
|
||||
/* */ char ganonText[250];
|
||||
@ -308,6 +313,9 @@ typedef struct {
|
||||
/* */ char warpRequiemText[100];
|
||||
/* */ char warpNocturneText[100];
|
||||
/* */ char warpPreludeText[100];
|
||||
/* */ RandomizerCheck ganonHintCheck;
|
||||
/* */ RandomizerCheck gregCheck;
|
||||
/* */ RandomizerCheck dampeCheck;
|
||||
/* */ u8 seedIcons[5];
|
||||
/* */ u16 randomizerInf[9];
|
||||
/* */ u16 adultTradeItems;
|
||||
|
@ -20,6 +20,22 @@ using namespace Logic;
|
||||
using namespace Settings;
|
||||
using namespace Trial;
|
||||
|
||||
std::unordered_map<HintType, std::string> hintTypeNames = {
|
||||
{ HINT_TYPE_TRIAL, "Trial" },
|
||||
{ HINT_TYPE_ALWAYS, "Always" },
|
||||
{ HINT_TYPE_WOTH, "WotH" },
|
||||
{ HINT_TYPE_BARREN, "Barren" },
|
||||
{ HINT_TYPE_ENTRANCE, "Entrance" },
|
||||
{ HINT_TYPE_SOMETIMES, "Sometimes" },
|
||||
{ HINT_TYPE_RANDOM, "Random"},
|
||||
{ HINT_TYPE_ITEM, "Item" },
|
||||
{ HINT_TYPE_SONG, "Song" },
|
||||
{ HINT_TYPE_OVERWORLD, "Overworld" },
|
||||
{ HINT_TYPE_DUNGEON, "Dungeon" },
|
||||
{ HINT_TYPE_JUNK, "Junk" },
|
||||
{ HINT_TYPE_NAMED_ITEM, "NamedItem" },
|
||||
};
|
||||
|
||||
constexpr std::array<HintSetting, 4> hintSettingTable{{
|
||||
// Useless hints
|
||||
{
|
||||
@ -27,19 +43,19 @@ constexpr std::array<HintSetting, 4> hintSettingTable{{
|
||||
.dungeonsBarrenLimit = 1,
|
||||
.namedItemsRequired = false,
|
||||
.distTable = {{
|
||||
{.type = HintType::Trial, .order = 1, .weight = 0, .fixed = 0, .copies = 0},
|
||||
{.type = HintType::Always, .order = 2, .weight = 0, .fixed = 0, .copies = 0},
|
||||
{.type = HintType::Woth, .order = 3, .weight = 0, .fixed = 0, .copies = 0},
|
||||
{.type = HintType::Barren, .order = 4, .weight = 0, .fixed = 0, .copies = 0},
|
||||
{.type = HintType::Entrance, .order = 5, .weight = 0, .fixed = 0, .copies = 0},
|
||||
{.type = HintType::Sometimes, .order = 6, .weight = 0, .fixed = 0, .copies = 0},
|
||||
{.type = HintType::Random, .order = 7, .weight = 0, .fixed = 0, .copies = 0},
|
||||
{.type = HintType::Item, .order = 8, .weight = 0, .fixed = 0, .copies = 0},
|
||||
{.type = HintType::Song, .order = 9, .weight = 0, .fixed = 0, .copies = 0},
|
||||
{.type = HintType::Overworld, .order = 10, .weight = 0, .fixed = 0, .copies = 0},
|
||||
{.type = HintType::Dungeon, .order = 11, .weight = 0, .fixed = 0, .copies = 0},
|
||||
{.type = HintType::Junk, .order = 12, .weight = 99, .fixed = 0, .copies = 0},
|
||||
{.type = HintType::NamedItem, .order = 13, .weight = 0, .fixed = 0, .copies = 0},
|
||||
{.type = HINT_TYPE_TRIAL, .order = 1, .weight = 0, .fixed = 0, .copies = 0},
|
||||
{.type = HINT_TYPE_ALWAYS, .order = 2, .weight = 0, .fixed = 0, .copies = 0},
|
||||
{.type = HINT_TYPE_WOTH, .order = 3, .weight = 0, .fixed = 0, .copies = 0},
|
||||
{.type = HINT_TYPE_BARREN, .order = 4, .weight = 0, .fixed = 0, .copies = 0},
|
||||
{.type = HINT_TYPE_ENTRANCE, .order = 5, .weight = 0, .fixed = 0, .copies = 0},
|
||||
{.type = HINT_TYPE_SOMETIMES, .order = 6, .weight = 0, .fixed = 0, .copies = 0},
|
||||
{.type = HINT_TYPE_RANDOM, .order = 7, .weight = 0, .fixed = 0, .copies = 0},
|
||||
{.type = HINT_TYPE_ITEM, .order = 8, .weight = 0, .fixed = 0, .copies = 0},
|
||||
{.type = HINT_TYPE_SONG, .order = 9, .weight = 0, .fixed = 0, .copies = 0},
|
||||
{.type = HINT_TYPE_OVERWORLD, .order = 10, .weight = 0, .fixed = 0, .copies = 0},
|
||||
{.type = HINT_TYPE_DUNGEON, .order = 11, .weight = 0, .fixed = 0, .copies = 0},
|
||||
{.type = HINT_TYPE_JUNK, .order = 12, .weight = 99, .fixed = 0, .copies = 0},
|
||||
{.type = HINT_TYPE_NAMED_ITEM, .order = 13, .weight = 0, .fixed = 0, .copies = 0},
|
||||
}},
|
||||
},
|
||||
|
||||
@ -49,19 +65,19 @@ constexpr std::array<HintSetting, 4> hintSettingTable{{
|
||||
.dungeonsBarrenLimit = 1,
|
||||
.namedItemsRequired = true,
|
||||
.distTable = {{
|
||||
{.type = HintType::Trial, .order = 1, .weight = 0, .fixed = 0, .copies = 1},
|
||||
{.type = HintType::Always, .order = 2, .weight = 0, .fixed = 0, .copies = 1},
|
||||
{.type = HintType::Woth, .order = 3, .weight = 7, .fixed = 0, .copies = 1},
|
||||
{.type = HintType::Barren, .order = 4, .weight = 4, .fixed = 0, .copies = 1},
|
||||
{.type = HintType::Entrance, .order = 5, .weight = 6, .fixed = 0, .copies = 1},
|
||||
{.type = HintType::Sometimes, .order = 6, .weight = 0, .fixed = 0, .copies = 1},
|
||||
{.type = HintType::Random, .order = 7, .weight = 12, .fixed = 0, .copies = 1},
|
||||
{.type = HintType::Item, .order = 8, .weight = 10, .fixed = 0, .copies = 1},
|
||||
{.type = HintType::Song, .order = 9, .weight = 2, .fixed = 0, .copies = 1},
|
||||
{.type = HintType::Overworld, .order = 10, .weight = 4, .fixed = 0, .copies = 1},
|
||||
{.type = HintType::Dungeon, .order = 11, .weight = 3, .fixed = 0, .copies = 1},
|
||||
{.type = HintType::Junk, .order = 12, .weight = 6, .fixed = 0, .copies = 1},
|
||||
{.type = HintType::NamedItem, .order = 13, .weight = 0, .fixed = 0, .copies = 1},
|
||||
{.type = HINT_TYPE_TRIAL, .order = 1, .weight = 0, .fixed = 0, .copies = 1},
|
||||
{.type = HINT_TYPE_ALWAYS, .order = 2, .weight = 0, .fixed = 0, .copies = 1},
|
||||
{.type = HINT_TYPE_WOTH, .order = 3, .weight = 7, .fixed = 0, .copies = 1},
|
||||
{.type = HINT_TYPE_BARREN, .order = 4, .weight = 4, .fixed = 0, .copies = 1},
|
||||
{.type = HINT_TYPE_ENTRANCE, .order = 5, .weight = 6, .fixed = 0, .copies = 1},
|
||||
{.type = HINT_TYPE_SOMETIMES, .order = 6, .weight = 0, .fixed = 0, .copies = 1},
|
||||
{.type = HINT_TYPE_RANDOM, .order = 7, .weight = 12, .fixed = 0, .copies = 1},
|
||||
{.type = HINT_TYPE_ITEM, .order = 8, .weight = 10, .fixed = 0, .copies = 1},
|
||||
{.type = HINT_TYPE_SONG, .order = 9, .weight = 2, .fixed = 0, .copies = 1},
|
||||
{.type = HINT_TYPE_OVERWORLD, .order = 10, .weight = 4, .fixed = 0, .copies = 1},
|
||||
{.type = HINT_TYPE_DUNGEON, .order = 11, .weight = 3, .fixed = 0, .copies = 1},
|
||||
{.type = HINT_TYPE_JUNK, .order = 12, .weight = 6, .fixed = 0, .copies = 1},
|
||||
{.type = HINT_TYPE_NAMED_ITEM, .order = 13, .weight = 0, .fixed = 0, .copies = 1},
|
||||
}},
|
||||
},
|
||||
|
||||
@ -71,19 +87,19 @@ constexpr std::array<HintSetting, 4> hintSettingTable{{
|
||||
.dungeonsBarrenLimit = 1,
|
||||
.namedItemsRequired = true,
|
||||
.distTable = {{
|
||||
{.type = HintType::Trial, .order = 1, .weight = 0, .fixed = 0, .copies = 1},
|
||||
{.type = HintType::Always, .order = 2, .weight = 0, .fixed = 0, .copies = 2},
|
||||
{.type = HintType::Woth, .order = 3, .weight = 12, .fixed = 0, .copies = 2},
|
||||
{.type = HintType::Barren, .order = 4, .weight = 12, .fixed = 0, .copies = 1},
|
||||
{.type = HintType::Entrance, .order = 5, .weight = 4, .fixed = 0, .copies = 1},
|
||||
{.type = HintType::Sometimes, .order = 6, .weight = 0, .fixed = 0, .copies = 1},
|
||||
{.type = HintType::Random, .order = 7, .weight = 8, .fixed = 0, .copies = 1},
|
||||
{.type = HintType::Item, .order = 8, .weight = 8, .fixed = 0, .copies = 1},
|
||||
{.type = HintType::Song, .order = 9, .weight = 4, .fixed = 0, .copies = 1},
|
||||
{.type = HintType::Overworld, .order = 10, .weight = 6, .fixed = 0, .copies = 1},
|
||||
{.type = HintType::Dungeon, .order = 11, .weight = 6, .fixed = 0, .copies = 1},
|
||||
{.type = HintType::Junk, .order = 12, .weight = 0, .fixed = 0, .copies = 1},
|
||||
{.type = HintType::NamedItem, .order = 13, .weight = 0, .fixed = 0, .copies = 1},
|
||||
{.type = HINT_TYPE_TRIAL, .order = 1, .weight = 0, .fixed = 0, .copies = 1},
|
||||
{.type = HINT_TYPE_ALWAYS, .order = 2, .weight = 0, .fixed = 0, .copies = 2},
|
||||
{.type = HINT_TYPE_WOTH, .order = 3, .weight = 12, .fixed = 0, .copies = 2},
|
||||
{.type = HINT_TYPE_BARREN, .order = 4, .weight = 12, .fixed = 0, .copies = 1},
|
||||
{.type = HINT_TYPE_ENTRANCE, .order = 5, .weight = 4, .fixed = 0, .copies = 1},
|
||||
{.type = HINT_TYPE_SOMETIMES, .order = 6, .weight = 0, .fixed = 0, .copies = 1},
|
||||
{.type = HINT_TYPE_RANDOM, .order = 7, .weight = 8, .fixed = 0, .copies = 1},
|
||||
{.type = HINT_TYPE_ITEM, .order = 8, .weight = 8, .fixed = 0, .copies = 1},
|
||||
{.type = HINT_TYPE_SONG, .order = 9, .weight = 4, .fixed = 0, .copies = 1},
|
||||
{.type = HINT_TYPE_OVERWORLD, .order = 10, .weight = 6, .fixed = 0, .copies = 1},
|
||||
{.type = HINT_TYPE_DUNGEON, .order = 11, .weight = 6, .fixed = 0, .copies = 1},
|
||||
{.type = HINT_TYPE_JUNK, .order = 12, .weight = 0, .fixed = 0, .copies = 1},
|
||||
{.type = HINT_TYPE_NAMED_ITEM, .order = 13, .weight = 0, .fixed = 0, .copies = 1},
|
||||
}},
|
||||
},
|
||||
|
||||
@ -93,19 +109,19 @@ constexpr std::array<HintSetting, 4> hintSettingTable{{
|
||||
.dungeonsBarrenLimit = 40,
|
||||
.namedItemsRequired = true,
|
||||
.distTable = {{
|
||||
{.type = HintType::Trial, .order = 1, .weight = 0, .fixed = 0, .copies = 1},
|
||||
{.type = HintType::Always, .order = 2, .weight = 0, .fixed = 0, .copies = 2},
|
||||
{.type = HintType::Woth, .order = 3, .weight = 15, .fixed = 0, .copies = 2},
|
||||
{.type = HintType::Barren, .order = 4, .weight = 15, .fixed = 0, .copies = 1},
|
||||
{.type = HintType::Entrance, .order = 5, .weight = 10, .fixed = 0, .copies = 1},
|
||||
{.type = HintType::Sometimes, .order = 6, .weight = 0, .fixed = 0, .copies = 1},
|
||||
{.type = HintType::Random, .order = 7, .weight = 0, .fixed = 0, .copies = 1},
|
||||
{.type = HintType::Item, .order = 8, .weight = 5, .fixed = 0, .copies = 1},
|
||||
{.type = HintType::Song, .order = 9, .weight = 2, .fixed = 0, .copies = 1},
|
||||
{.type = HintType::Overworld, .order = 10, .weight = 7, .fixed = 0, .copies = 1},
|
||||
{.type = HintType::Dungeon, .order = 11, .weight = 7, .fixed = 0, .copies = 1},
|
||||
{.type = HintType::Junk, .order = 12, .weight = 0, .fixed = 0, .copies = 1},
|
||||
{.type = HintType::NamedItem, .order = 13, .weight = 0, .fixed = 0, .copies = 1},
|
||||
{.type = HINT_TYPE_TRIAL, .order = 1, .weight = 0, .fixed = 0, .copies = 1},
|
||||
{.type = HINT_TYPE_ALWAYS, .order = 2, .weight = 0, .fixed = 0, .copies = 2},
|
||||
{.type = HINT_TYPE_WOTH, .order = 3, .weight = 15, .fixed = 0, .copies = 2},
|
||||
{.type = HINT_TYPE_BARREN, .order = 4, .weight = 15, .fixed = 0, .copies = 1},
|
||||
{.type = HINT_TYPE_ENTRANCE, .order = 5, .weight = 10, .fixed = 0, .copies = 1},
|
||||
{.type = HINT_TYPE_SOMETIMES, .order = 6, .weight = 0, .fixed = 0, .copies = 1},
|
||||
{.type = HINT_TYPE_RANDOM, .order = 7, .weight = 0, .fixed = 0, .copies = 1},
|
||||
{.type = HINT_TYPE_ITEM, .order = 8, .weight = 5, .fixed = 0, .copies = 1},
|
||||
{.type = HINT_TYPE_SONG, .order = 9, .weight = 2, .fixed = 0, .copies = 1},
|
||||
{.type = HINT_TYPE_OVERWORLD, .order = 10, .weight = 7, .fixed = 0, .copies = 1},
|
||||
{.type = HINT_TYPE_DUNGEON, .order = 11, .weight = 7, .fixed = 0, .copies = 1},
|
||||
{.type = HINT_TYPE_JUNK, .order = 12, .weight = 0, .fixed = 0, .copies = 1},
|
||||
{.type = HINT_TYPE_NAMED_ITEM, .order = 13, .weight = 0, .fixed = 0, .copies = 1},
|
||||
}},
|
||||
},
|
||||
}};
|
||||
@ -125,6 +141,9 @@ Text warpRequiemText;
|
||||
Text warpNocturneText;
|
||||
Text warpPreludeText;
|
||||
|
||||
std::string ganonHintLoc;
|
||||
std::string dampeHintLoc;
|
||||
|
||||
Text& GetChildAltarText() {
|
||||
return childAltarText;
|
||||
}
|
||||
@ -173,7 +192,15 @@ Text& GetWarpPreludeText() {
|
||||
return warpPreludeText;
|
||||
}
|
||||
|
||||
static Area* GetHintRegion(const uint32_t area) {
|
||||
std::string GetGanonHintLoc() {
|
||||
return ganonHintLoc;
|
||||
}
|
||||
|
||||
std::string GetDampeHintLoc() {
|
||||
return dampeHintLoc;
|
||||
}
|
||||
|
||||
Area* GetHintRegion(const uint32_t area) {
|
||||
|
||||
std::vector<uint32_t> alreadyChecked = {};
|
||||
std::vector<uint32_t> spotQueue = {area};
|
||||
@ -232,10 +259,13 @@ static std::vector<uint32_t> GetAccessibleGossipStones(const uint32_t hintedLoca
|
||||
return accessibleGossipStones;
|
||||
}
|
||||
|
||||
static void AddHint(Text hint, const uint32_t gossipStone, const std::vector<uint8_t>& colors = {}) {
|
||||
static void AddHint(Text hint, const uint32_t gossipStone, const std::vector<uint8_t>& colors = {}, HintType hintType = HINT_TYPE_ITEM, const uint32_t hintedLocation = NONE) {
|
||||
//save hints as dummy items for writing to the spoiler log
|
||||
NewItem(gossipStone, Item{RG_HINT, hint, ITEMTYPE_EVENT, GI_RUPEE_BLUE_LOSE, false, &noVariable, NONE});
|
||||
Location(gossipStone)->SetPlacedItem(gossipStone);
|
||||
Location(gossipStone)->SetHintedLocation(hintedLocation);
|
||||
Location(gossipStone)->SetHintType(hintType);
|
||||
Location(gossipStone)->SetHintedRegion(GetHintRegion(Location(hintedLocation)->GetParentRegionKey())->GetHint().GetText().GetEnglish());
|
||||
|
||||
//create the in game message
|
||||
// uint32_t messageId = 0x400 + Location(gossipStone)->GetFlag();
|
||||
@ -280,7 +310,7 @@ static void CreateLocationHint(const std::vector<uint32_t>& possibleHintLocation
|
||||
SPDLOG_DEBUG(finalHint.english);
|
||||
SPDLOG_DEBUG("\n\n");
|
||||
|
||||
AddHint(finalHint, gossipStone, {QM_GREEN, QM_RED});
|
||||
AddHint(finalHint, gossipStone, {QM_GREEN, QM_RED}, HINT_TYPE_ITEM, hintedLocation);
|
||||
}
|
||||
|
||||
static void CreateWothHint(uint8_t* remainingDungeonWothHints) {
|
||||
@ -332,7 +362,7 @@ static void CreateWothHint(uint8_t* remainingDungeonWothHints) {
|
||||
SPDLOG_DEBUG("\tMessage: ");
|
||||
SPDLOG_DEBUG(finalWothHint.english);
|
||||
SPDLOG_DEBUG("\n\n");
|
||||
AddHint(finalWothHint, gossipStone, { QM_LBLUE });
|
||||
AddHint(finalWothHint, gossipStone, { QM_LBLUE }, HINT_TYPE_WOTH, hintedLocation);
|
||||
}
|
||||
|
||||
static void CreateBarrenHint(uint8_t* remainingDungeonBarrenHints, std::vector<uint32_t>& barrenLocations) {
|
||||
@ -376,7 +406,7 @@ static void CreateBarrenHint(uint8_t* remainingDungeonBarrenHints, std::vector<u
|
||||
SPDLOG_DEBUG("\tMessage: ");
|
||||
SPDLOG_DEBUG(finalBarrenHint.english);
|
||||
SPDLOG_DEBUG("\n\n");
|
||||
AddHint(finalBarrenHint, gossipStone, { QM_PINK });
|
||||
AddHint(finalBarrenHint, gossipStone, { QM_PINK }, HINT_TYPE_BARREN, hintedLocation);
|
||||
|
||||
// get rid of all other locations in this same barren region
|
||||
barrenLocations = FilterFromPool(barrenLocations, [hintedLocation](uint32_t loc) {
|
||||
@ -422,13 +452,13 @@ static void CreateRandomLocationHint(const bool goodItem = false) {
|
||||
SPDLOG_DEBUG("\tMessage: ");
|
||||
SPDLOG_DEBUG(finalHint.english);
|
||||
SPDLOG_DEBUG("\n\n");
|
||||
AddHint(finalHint, gossipStone, {QM_GREEN, QM_RED});
|
||||
AddHint(finalHint, gossipStone, {QM_GREEN, QM_RED}, HINT_TYPE_NAMED_ITEM, hintedLocation);
|
||||
} else {
|
||||
Text finalHint = Hint(PREFIX).GetText()+"#"+itemText+"# "+Hint(CAN_BE_FOUND_AT).GetText()+" #"+locationText+"#.";
|
||||
SPDLOG_DEBUG("\tMessage: ");
|
||||
SPDLOG_DEBUG(finalHint.english);
|
||||
SPDLOG_DEBUG("\n\n");
|
||||
AddHint(finalHint, gossipStone, {QM_RED, QM_GREEN});
|
||||
AddHint(finalHint, gossipStone, { QM_RED, QM_GREEN }, HINT_TYPE_NAMED_ITEM, hintedLocation);
|
||||
}
|
||||
}
|
||||
|
||||
@ -452,7 +482,7 @@ static void CreateJunkHint() {
|
||||
SPDLOG_DEBUG(hint.english);
|
||||
SPDLOG_DEBUG("\n\n");
|
||||
|
||||
AddHint(hint, gossipStone, {QM_PINK});
|
||||
AddHint(hint, gossipStone, { QM_PINK }, HINT_TYPE_JUNK);
|
||||
}
|
||||
|
||||
static std::vector<uint32_t> CalculateBarrenRegions() {
|
||||
@ -495,7 +525,7 @@ static void CreateTrialHints() {
|
||||
|
||||
//make hint
|
||||
auto hint = Hint(PREFIX).GetText() + Hint(SIX_TRIALS).GetText();
|
||||
AddHint(hint, gossipStone, {QM_PINK});
|
||||
AddHint(hint, gossipStone, { QM_PINK }, HINT_TYPE_TRIAL);
|
||||
|
||||
//zero trials
|
||||
} else if (RandomGanonsTrials && GanonsTrialsCount.Is(0)) {
|
||||
@ -506,7 +536,7 @@ static void CreateTrialHints() {
|
||||
|
||||
//make hint
|
||||
auto hint = Hint(PREFIX).GetText() + Hint(ZERO_TRIALS).GetText();
|
||||
AddHint(hint, gossipStone, {QM_YELLOW});
|
||||
AddHint(hint, gossipStone, { QM_YELLOW }, HINT_TYPE_TRIAL);
|
||||
|
||||
//4 or 5 required trials
|
||||
} else if (GanonsTrialsCount.Is(5) || GanonsTrialsCount.Is(4)) {
|
||||
@ -524,7 +554,7 @@ static void CreateTrialHints() {
|
||||
|
||||
//make hint
|
||||
auto hint = Hint(PREFIX).GetText()+"#"+trial->GetName()+"#"+Hint(FOUR_TO_FIVE_TRIALS).GetText();
|
||||
AddHint(hint, gossipStone, {QM_YELLOW});
|
||||
AddHint(hint, gossipStone, { QM_YELLOW }, HINT_TYPE_TRIAL);
|
||||
}
|
||||
//1 to 3 trials
|
||||
} else if (GanonsTrialsCount.Value<uint8_t>() >= 1 && GanonsTrialsCount.Value<uint8_t>() <= 3) {
|
||||
@ -541,7 +571,7 @@ static void CreateTrialHints() {
|
||||
|
||||
//make hint
|
||||
auto hint = Hint(PREFIX).GetText()+"#"+trial->GetName()+"#"+Hint(ONE_TO_THREE_TRIALS).GetText();
|
||||
AddHint(hint, gossipStone, {QM_PINK});
|
||||
AddHint(hint, gossipStone, { QM_PINK }, HINT_TYPE_TRIAL);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -556,10 +586,13 @@ void CreateGanonText() {
|
||||
auto lightArrowLocation = FilterFromPool(allLocations, [](const uint32_t loc){return Location(loc)->GetPlaceduint32_t() == LIGHT_ARROWS;});
|
||||
|
||||
//If there is no light arrow location, it was in the player's inventory at the start
|
||||
auto hint = Hint(LIGHT_ARROW_LOCATION_HINT);
|
||||
if (lightArrowLocation.empty()) {
|
||||
ganonHintText = Hint(LIGHT_ARROW_LOCATION_HINT).GetText()+Hint(YOUR_POCKET).GetText();
|
||||
ganonHintText = hint.GetText()+Hint(YOUR_POCKET).GetText();
|
||||
ganonHintLoc = "Link's Pocket";
|
||||
} else {
|
||||
ganonHintText = Hint(LIGHT_ARROW_LOCATION_HINT).GetText()+GetHintRegion(Location(lightArrowLocation[0])->GetParentRegionKey())->GetHint().GetText();
|
||||
ganonHintText = hint.GetText()+GetHintRegion(Location(lightArrowLocation[0])->GetParentRegionKey())->GetHint().GetText();
|
||||
ganonHintLoc = Location(lightArrowLocation[0])->GetName();
|
||||
}
|
||||
ganonHintText = ganonHintText + "!";
|
||||
|
||||
@ -759,6 +792,7 @@ void CreateMerchantsHints() {
|
||||
void CreateDampesDiaryText() {
|
||||
if (!DampeHintText) {
|
||||
dampesText = Text();
|
||||
dampeHintLoc = "";
|
||||
return;
|
||||
}
|
||||
|
||||
@ -778,6 +812,7 @@ void CreateDampesDiaryText() {
|
||||
};
|
||||
|
||||
dampesText = temp1 + area + temp2;
|
||||
dampeHintLoc = Location(location)->GetName();
|
||||
}
|
||||
|
||||
void CreateGregRupeeHint() {
|
||||
@ -861,7 +896,7 @@ void CreateAllHints() {
|
||||
uint8_t remainingDungeonBarrenHints = hintSetting.dungeonsBarrenLimit;
|
||||
|
||||
// Add 'always' location hints
|
||||
if (hintSetting.distTable[static_cast<int>(HintType::Always)].copies > 0) {
|
||||
if (hintSetting.distTable[static_cast<int>(HINT_TYPE_ALWAYS)].copies > 0) {
|
||||
// Only filter locations that had a random item placed at them (e.g. don't get cow locations if shuffle cows is off)
|
||||
auto alwaysHintLocations = FilterFromPool(allLocations, [](const uint32_t loc){
|
||||
return ((Location(loc)->GetHint().GetType() == HintCategory::Always) ||
|
||||
@ -883,7 +918,7 @@ void CreateAllHints() {
|
||||
}
|
||||
|
||||
//Add 'trial' location hints
|
||||
if (hintSetting.distTable[static_cast<int>(HintType::Trial)].copies > 0) {
|
||||
if (hintSetting.distTable[static_cast<int>(HINT_TYPE_TRIAL)].copies > 0) {
|
||||
CreateTrialHints();
|
||||
}
|
||||
|
||||
@ -945,22 +980,6 @@ void CreateAllHints() {
|
||||
}
|
||||
}
|
||||
|
||||
std::array<std::string, 13> hintTypeNames = {
|
||||
"Trial",
|
||||
"Always",
|
||||
"WotH",
|
||||
"Barren",
|
||||
"Entrance",
|
||||
"Sometimes",
|
||||
"Random",
|
||||
"Item",
|
||||
"Song",
|
||||
"Overworld",
|
||||
"Dungeon",
|
||||
"Junk",
|
||||
"NamedItem",
|
||||
};
|
||||
|
||||
//while there are still gossip stones remaining
|
||||
while (FilterFromPool(gossipStoneLocations, [](const uint32_t loc){return Location(loc)->GetPlaceduint32_t() == NONE;}).size() != 0) {
|
||||
//TODO: fixed hint types
|
||||
@ -973,39 +992,39 @@ void CreateAllHints() {
|
||||
HintType type = RandomElement(remainingHintTypes, true);
|
||||
|
||||
SPDLOG_DEBUG("Attempting to make hint of type: ");
|
||||
SPDLOG_DEBUG(hintTypeNames[static_cast<int>(type)]);
|
||||
SPDLOG_DEBUG(hintTypeNames.find(type)->second);
|
||||
SPDLOG_DEBUG("\n");
|
||||
|
||||
//create the appropriate hint for the type
|
||||
if (type == HintType::Woth) {
|
||||
if (type == HINT_TYPE_WOTH) {
|
||||
CreateWothHint(&remainingDungeonWothHints);
|
||||
|
||||
} else if (type == HintType::Barren) {
|
||||
} else if (type == HINT_TYPE_BARREN) {
|
||||
CreateBarrenHint(&remainingDungeonBarrenHints, barrenLocations);
|
||||
|
||||
} else if (type == HintType::Sometimes){
|
||||
} else if (type == HINT_TYPE_SOMETIMES){
|
||||
std::vector<uint32_t> sometimesHintLocations = FilterFromPool(allLocations, [](const uint32_t loc){return Location(loc)->GetHint().GetType() == HintCategory::Sometimes && Location(loc)->IsHintable() && !(Location(loc)->IsHintedAt());});
|
||||
CreateLocationHint(sometimesHintLocations);
|
||||
|
||||
} else if (type == HintType::Random) {
|
||||
} else if (type == HINT_TYPE_RANDOM) {
|
||||
CreateRandomLocationHint();
|
||||
|
||||
} else if (type == HintType::Item) {
|
||||
} else if (type == HINT_TYPE_ITEM) {
|
||||
CreateGoodItemHint();
|
||||
|
||||
} else if (type == HintType::Song){
|
||||
} else if (type == HINT_TYPE_SONG){
|
||||
std::vector<uint32_t> songHintLocations = FilterFromPool(allLocations, [](const uint32_t loc){return Location(loc)->IsCategory(Category::cSong) && Location(loc)->IsHintable() && !(Location(loc)->IsHintedAt());});
|
||||
CreateLocationHint(songHintLocations);
|
||||
|
||||
} else if (type == HintType::Overworld){
|
||||
} else if (type == HINT_TYPE_OVERWORLD){
|
||||
std::vector<uint32_t> overworldHintLocations = FilterFromPool(allLocations, [](const uint32_t loc){return Location(loc)->IsOverworld() && Location(loc)->IsHintable() && !(Location(loc)->IsHintedAt());});
|
||||
CreateLocationHint(overworldHintLocations);
|
||||
|
||||
} else if (type == HintType::Dungeon){
|
||||
} else if (type == HINT_TYPE_DUNGEON){
|
||||
std::vector<uint32_t> dungeonHintLocations = FilterFromPool(allLocations, [](const uint32_t loc){return Location(loc)->IsDungeon() && Location(loc)->IsHintable() && !(Location(loc)->IsHintedAt());});
|
||||
CreateLocationHint(dungeonHintLocations);
|
||||
|
||||
} else if (type == HintType::Junk) {
|
||||
} else if (type == HINT_TYPE_JUNK) {
|
||||
CreateJunkHint();
|
||||
}
|
||||
}
|
||||
|
@ -10,23 +10,6 @@
|
||||
#include "settings.hpp"
|
||||
#include <functional>
|
||||
|
||||
enum class HintType {
|
||||
Trial,
|
||||
Always,
|
||||
Woth, //Way of the Hero
|
||||
Barren,
|
||||
Entrance,
|
||||
Sometimes,
|
||||
Random,
|
||||
Item,
|
||||
Song,
|
||||
Overworld,
|
||||
Dungeon,
|
||||
Junk,
|
||||
NamedItem,
|
||||
MaxCount,
|
||||
};
|
||||
|
||||
struct HintDistributionSetting {
|
||||
HintType type;
|
||||
uint8_t order;
|
||||
@ -36,7 +19,7 @@ struct HintDistributionSetting {
|
||||
};
|
||||
|
||||
struct HintSetting {
|
||||
using DistributionTable = std::array<HintDistributionSetting, static_cast<int>(HintType::MaxCount)>;
|
||||
using DistributionTable = std::array<HintDistributionSetting, static_cast<int>(HINT_TYPE_MAX)>;
|
||||
|
||||
uint8_t dungeonsWothLimit;
|
||||
uint8_t dungeonsBarrenLimit;
|
||||
@ -239,3 +222,6 @@ Text& GetWarpSerenadeText();
|
||||
Text& GetWarpRequiemText();
|
||||
Text& GetWarpNocturneText();
|
||||
Text& GetWarpPreludeText();
|
||||
|
||||
std::string GetDampeHintLoc();
|
||||
std::string GetGanonHintLoc();
|
||||
|
@ -347,6 +347,30 @@ public:
|
||||
return isHintable;
|
||||
}
|
||||
|
||||
void SetHintedLocation(uint32_t location) {
|
||||
hintedLocation = location;
|
||||
}
|
||||
|
||||
uint32_t GetHintedLocation() {
|
||||
return hintedLocation;
|
||||
}
|
||||
|
||||
void SetHintType(HintType type) {
|
||||
hintType = type;
|
||||
}
|
||||
|
||||
HintType GetHintType() {
|
||||
return hintType;
|
||||
}
|
||||
|
||||
void SetHintedRegion (std::string region) {
|
||||
hintedRegion = region;
|
||||
}
|
||||
|
||||
std::string GetHintedRegion() {
|
||||
return hintedRegion;
|
||||
}
|
||||
|
||||
void SetAsHintable() {
|
||||
isHintable = true;
|
||||
}
|
||||
@ -465,6 +489,9 @@ private:
|
||||
std::vector<Category> categories;
|
||||
bool addedToPool = false;
|
||||
uint32_t placedItem = NONE;
|
||||
uint32_t hintedLocation = NONE;
|
||||
HintType hintType;
|
||||
std::string hintedRegion;
|
||||
uint32_t delayedItem = NONE;
|
||||
Option excludedOption = Option::Bool(name, {"Include", "Exclude"}, {"", ""});
|
||||
uint16_t price = 0;
|
||||
|
@ -11,6 +11,8 @@
|
||||
#include "utils.hpp"
|
||||
#include "shops.hpp"
|
||||
#include "hints.hpp"
|
||||
#include "pool_functions.hpp"
|
||||
#include "soh/Enhancements/randomizer/randomizer_check_objects.h"
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
#include <cstdio>
|
||||
@ -32,6 +34,11 @@
|
||||
using json = nlohmann::json;
|
||||
|
||||
json jsonData;
|
||||
std::map<HintKey, ItemLocation*> hintedLocations;
|
||||
|
||||
extern std::unordered_map<HintType, std::string> hintTypeNames;
|
||||
extern std::array<std::string, 17> hintCategoryNames;
|
||||
extern Area* GetHintRegion(uint32_t);
|
||||
|
||||
namespace {
|
||||
std::string placementtxt;
|
||||
@ -645,6 +652,10 @@ std::string AutoFormatHintTextString(std::string unformattedHintTextString) {
|
||||
return textStr;
|
||||
}
|
||||
|
||||
ItemLocation* GetItemLocation(uint32_t item) {
|
||||
return Location(FilterFromPool(allLocations, [item](const uint32_t loc){return Location(loc)->GetPlaceduint32_t() == item;})[0]);
|
||||
}
|
||||
|
||||
// Writes the hints to the spoiler log, if they are enabled.
|
||||
static void WriteHints(int language) {
|
||||
std::string unformattedGanonText;
|
||||
@ -665,8 +676,8 @@ static void WriteHints(int language) {
|
||||
jsonData["warpRequiemText"] = GetWarpRequiemText().GetEnglish();
|
||||
jsonData["warpNocturneText"] = GetWarpNocturneText().GetEnglish();
|
||||
jsonData["warpPreludeText"] = GetWarpPreludeText().GetEnglish();
|
||||
jsonData["childAltarText"] = GetChildAltarText().GetEnglish();
|
||||
jsonData["adultAltarText"] = GetAdultAltarText().GetEnglish();
|
||||
jsonData["childAltar"]["hintText"] = GetChildAltarText().GetEnglish();
|
||||
jsonData["adultAltar"]["hintText"] = GetAdultAltarText().GetEnglish();
|
||||
break;
|
||||
case 2:
|
||||
unformattedGanonText = GetGanonText().GetFrench();
|
||||
@ -679,11 +690,36 @@ static void WriteHints(int language) {
|
||||
jsonData["warpRequiemText"] = GetWarpRequiemText().GetFrench();
|
||||
jsonData["warpNocturneText"] = GetWarpNocturneText().GetFrench();
|
||||
jsonData["warpPreludeText"] = GetWarpPreludeText().GetFrench();
|
||||
jsonData["childAltarText"] = GetChildAltarText().GetFrench();
|
||||
jsonData["adultAltarText"] = GetAdultAltarText().GetFrench();
|
||||
jsonData["childAltar"]["hintText"] = GetChildAltarText().GetFrench();
|
||||
jsonData["adultAltar"]["hintText"] = GetAdultAltarText().GetFrench();
|
||||
break;
|
||||
}
|
||||
|
||||
ItemLocation* emeraldLoc = GetItemLocation(KOKIRI_EMERALD);
|
||||
ItemLocation* rubyLoc = GetItemLocation(GORON_RUBY);
|
||||
ItemLocation* sapphireLoc = GetItemLocation(ZORA_SAPPHIRE);
|
||||
std::string emeraldArea;
|
||||
std::string erubyArea;
|
||||
std::string sapphireArea;
|
||||
|
||||
jsonData["childAltar"]["rewards"]["emeraldLoc"] = emeraldLoc->GetName();
|
||||
jsonData["childAltar"]["rewards"]["rubyLoc"] = rubyLoc->GetName();
|
||||
jsonData["childAltar"]["rewards"]["sapphireLoc"] = sapphireLoc->GetName();
|
||||
|
||||
ItemLocation* forestMedallionLoc = GetItemLocation(FOREST_MEDALLION);
|
||||
ItemLocation* fireMedallionLoc = GetItemLocation(FIRE_MEDALLION);
|
||||
ItemLocation* waterMedallionLoc = GetItemLocation(WATER_MEDALLION);
|
||||
ItemLocation* shadowMedallionLoc = GetItemLocation(SHADOW_MEDALLION);
|
||||
ItemLocation* spiritMedallionLoc = GetItemLocation(SPIRIT_MEDALLION);
|
||||
ItemLocation* lightMedallionLoc = GetItemLocation(LIGHT_MEDALLION);
|
||||
|
||||
jsonData["adultAltar"]["rewards"]["forestMedallionLoc"] = forestMedallionLoc->GetName();
|
||||
jsonData["adultAltar"]["rewards"]["fireMedallionLoc"] = fireMedallionLoc->GetName();
|
||||
jsonData["adultAltar"]["rewards"]["waterMedallionLoc"] = waterMedallionLoc->GetName();
|
||||
jsonData["adultAltar"]["rewards"]["shadowMedallionLoc"] = shadowMedallionLoc->GetName();
|
||||
jsonData["adultAltar"]["rewards"]["spiritMedallionLoc"] = spiritMedallionLoc->GetName();
|
||||
jsonData["adultAltar"]["rewards"]["lightMedallionLoc"] = lightMedallionLoc->GetName();
|
||||
|
||||
std::string ganonText = AutoFormatHintTextString(unformattedGanonText);
|
||||
std::string ganonHintText = AutoFormatHintTextString(unformattedGanonHintText);
|
||||
std::string dampesText = AutoFormatHintTextString(unformattedDampesText);
|
||||
@ -691,8 +727,11 @@ static void WriteHints(int language) {
|
||||
|
||||
jsonData["ganonText"] = ganonText;
|
||||
jsonData["ganonHintText"] = ganonHintText;
|
||||
jsonData["ganonHintLoc"] = GetGanonHintLoc();
|
||||
jsonData["dampeText"] = dampesText;
|
||||
jsonData["dampeHintLoc"] = GetDampeHintLoc();
|
||||
jsonData["gregText"] = gregText;
|
||||
jsonData["gregLoc"] = GetItemLocation(GREG_RUPEE)->GetName();
|
||||
|
||||
if (Settings::GossipStoneHints.Is(HINTS_NO_HINTS)) {
|
||||
return;
|
||||
@ -700,6 +739,7 @@ static void WriteHints(int language) {
|
||||
|
||||
for (const uint32_t key : gossipStoneLocations) {
|
||||
ItemLocation* location = Location(key);
|
||||
ItemLocation* hintedLocation = Location(location->GetHintedLocation());
|
||||
std::string unformattedHintTextString;
|
||||
switch (language) {
|
||||
case 0:
|
||||
@ -711,8 +751,20 @@ static void WriteHints(int language) {
|
||||
break;
|
||||
}
|
||||
|
||||
HintType hintType = location->GetHintType();
|
||||
|
||||
std::string textStr = AutoFormatHintTextString(unformattedHintTextString);
|
||||
jsonData["hints"][location->GetName()] = textStr;
|
||||
jsonData["hints"][location->GetName()]["hint"] = textStr;
|
||||
jsonData["hints"][location->GetName()]["type"] = hintTypeNames.find(hintType)->second;
|
||||
if (hintType == HINT_TYPE_ITEM || hintType == HINT_TYPE_NAMED_ITEM) {
|
||||
jsonData["hints"][location->GetName()]["item"] = hintedLocation->GetPlacedItemName().GetEnglish();
|
||||
if (hintType != HINT_TYPE_NAMED_ITEM) {
|
||||
jsonData["hints"][location->GetName()]["location"] = hintedLocation->GetName();
|
||||
}
|
||||
}
|
||||
if (hintType != HINT_TYPE_TRIAL && hintType != HINT_TYPE_JUNK) {
|
||||
jsonData["hints"][location->GetName()]["area"] = location->GetHintedRegion();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -747,6 +799,9 @@ static void WriteAllLocations(int language) {
|
||||
if (location->HasScrubsanityPrice() || location->HasShopsanityPrice()) {
|
||||
jsonData["locations"][location->GetName()]["price"] = location->GetPrice();
|
||||
}
|
||||
if (location->IsHintedAt()) {
|
||||
hintedLocations.emplace(location->GetHintKey(), location);
|
||||
}
|
||||
|
||||
if (location->GetPlacedItemKey() == ICE_TRAP) {
|
||||
switch (language) {
|
||||
@ -768,6 +823,16 @@ static void WriteAllLocations(int language) {
|
||||
}
|
||||
}
|
||||
|
||||
//static void WriteHintData(int language) {
|
||||
// for (auto [hintKey, item_location] : hintedLocations) {
|
||||
// ItemLocation *hint_location = Location(hintKey);
|
||||
// jsonData["hints"][hint_location->GetName()] = { { "text", hint_location->GetPlacedItemName().GetEnglish() },
|
||||
// { "item", item_location->GetPlacedItemName().GetEnglish() },
|
||||
// { "itemLocation", item_location->GetName() },
|
||||
// { "locationArea", item_location->GetParentRegionKey() } };
|
||||
// }
|
||||
//}
|
||||
|
||||
const char* SpoilerLog_Write(int language) {
|
||||
auto spoilerLog = tinyxml2::XMLDocument(false);
|
||||
spoilerLog.InsertEndChild(spoilerLog.NewDeclaration());
|
||||
@ -806,6 +871,7 @@ const char* SpoilerLog_Write(int language) {
|
||||
WriteHints(language);
|
||||
WriteShuffledEntrances();
|
||||
WriteAllLocations(language);
|
||||
//WriteHintData(language);
|
||||
|
||||
if (!std::filesystem::exists(LUS::Context::GetPathRelativeToAppDirectory("Randomizer"))) {
|
||||
std::filesystem::create_directory(LUS::Context::GetPathRelativeToAppDirectory("Randomizer"));
|
||||
|
@ -31,11 +31,16 @@
|
||||
extern "C" uint32_t ResourceMgr_IsGameMasterQuest();
|
||||
extern "C" uint32_t ResourceMgr_IsSceneMasterQuest(s16 sceneNum);
|
||||
|
||||
extern std::map<RandomizerCheckArea, std::string> rcAreaNames;
|
||||
extern std::unordered_map<HintType, std::string> hintTypeNames;
|
||||
|
||||
using json = nlohmann::json;
|
||||
using namespace std::literals::string_literals;
|
||||
|
||||
std::unordered_map<std::string, RandomizerCheck> SpoilerfileCheckNameToEnum;
|
||||
std::unordered_map<std::string, RandomizerGet> SpoilerfileGetNameToEnum;
|
||||
std::unordered_map<std::string, RandomizerCheckArea> SpoilerfileAreaNameToEnum;
|
||||
std::unordered_map<std::string, HintType> SpoilerfileHintTypeNameToEnum;
|
||||
std::multimap<std::tuple<s16, s16, s32>, RandomizerCheckObject> checkFromActorMultimap;
|
||||
std::set<RandomizerCheck> excludedLocations;
|
||||
|
||||
@ -123,6 +128,18 @@ Randomizer::Randomizer() {
|
||||
item.GetName().french,
|
||||
};
|
||||
}
|
||||
for (auto area : rcAreaNames) {
|
||||
SpoilerfileAreaNameToEnum[area.second] = area.first;
|
||||
}
|
||||
SpoilerfileAreaNameToEnum["Inside Ganon's Castle"] = RCAREA_GANONS_CASTLE;
|
||||
SpoilerfileAreaNameToEnum["the Lost Woods"] = RCAREA_LOST_WOODS;
|
||||
SpoilerfileAreaNameToEnum["the Market"] = RCAREA_MARKET;
|
||||
SpoilerfileAreaNameToEnum["the Graveyard"] = RCAREA_GRAVEYARD;
|
||||
SpoilerfileAreaNameToEnum["Haunted Wasteland"] = RCAREA_WASTELAND;
|
||||
SpoilerfileAreaNameToEnum["outside Ganon's Castle"] = RCAREA_HYRULE_CASTLE;
|
||||
for (auto [type, name] : hintTypeNames) {
|
||||
SpoilerfileHintTypeNameToEnum[name] = type;
|
||||
}
|
||||
}
|
||||
|
||||
Sprite* Randomizer::GetSeedTexture(uint8_t index) {
|
||||
@ -1226,20 +1243,30 @@ void Randomizer::ParseHintLocationsFile(const char* spoilerFileName) {
|
||||
json spoilerFileJson;
|
||||
spoilerFileStream >> spoilerFileJson;
|
||||
|
||||
std::string childAltarJsonText = spoilerFileJson["childAltarText"].get<std::string>();
|
||||
std::string childAltarJsonText = spoilerFileJson["childAltar"]["hintText"].get<std::string>();
|
||||
std::string formattedChildAltarText = FormatJsonHintText(childAltarJsonText);
|
||||
strncpy(gSaveContext.childAltarText, formattedChildAltarText.c_str(), sizeof(gSaveContext.childAltarText) - 1);
|
||||
gSaveContext.childAltarText[sizeof(gSaveContext.childAltarText) - 1] = 0;
|
||||
gSaveContext.rewardCheck[0] = SpoilerfileCheckNameToEnum[spoilerFileJson["childAltar"]["rewards"]["emeraldLoc"]];
|
||||
gSaveContext.rewardCheck[1] = SpoilerfileCheckNameToEnum[spoilerFileJson["childAltar"]["rewards"]["rubyLoc"]];
|
||||
gSaveContext.rewardCheck[2] = SpoilerfileCheckNameToEnum[spoilerFileJson["childAltar"]["rewards"]["sapphireLoc"]];
|
||||
|
||||
std::string adultAltarJsonText = spoilerFileJson["adultAltarText"].get<std::string>();
|
||||
std::string adultAltarJsonText = spoilerFileJson["adultAltar"]["hintText"].get<std::string>();
|
||||
std::string formattedAdultAltarText = FormatJsonHintText(adultAltarJsonText);
|
||||
strncpy(gSaveContext.adultAltarText, formattedAdultAltarText.c_str(), sizeof(gSaveContext.adultAltarText) - 1);
|
||||
gSaveContext.adultAltarText[sizeof(gSaveContext.adultAltarText) - 1] = 0;
|
||||
gSaveContext.rewardCheck[3] = SpoilerfileCheckNameToEnum[spoilerFileJson["adultAltar"]["rewards"]["forestMedallionLoc"]];
|
||||
gSaveContext.rewardCheck[4] = SpoilerfileCheckNameToEnum[spoilerFileJson["adultAltar"]["rewards"]["fireMedallionLoc"]];
|
||||
gSaveContext.rewardCheck[5] = SpoilerfileCheckNameToEnum[spoilerFileJson["adultAltar"]["rewards"]["waterMedallionLoc"]];
|
||||
gSaveContext.rewardCheck[6] = SpoilerfileCheckNameToEnum[spoilerFileJson["adultAltar"]["rewards"]["shadowMedallionLoc"]];
|
||||
gSaveContext.rewardCheck[7] = SpoilerfileCheckNameToEnum[spoilerFileJson["adultAltar"]["rewards"]["spiritMedallionLoc"]];
|
||||
gSaveContext.rewardCheck[8] = SpoilerfileCheckNameToEnum[spoilerFileJson["adultAltar"]["rewards"]["lightMedallionLoc"]];
|
||||
|
||||
std::string ganonHintJsonText = spoilerFileJson["ganonHintText"].get<std::string>();
|
||||
std::string formattedGanonHintJsonText = FormatJsonHintText(ganonHintJsonText);
|
||||
strncpy(gSaveContext.ganonHintText, formattedGanonHintJsonText.c_str(), sizeof(gSaveContext.ganonHintText) - 1);
|
||||
gSaveContext.ganonHintText[sizeof(gSaveContext.ganonHintText) - 1] = 0;
|
||||
gSaveContext.ganonHintCheck = SpoilerfileCheckNameToEnum[spoilerFileJson["ganonHintLoc"]];
|
||||
|
||||
std::string ganonJsonText = spoilerFileJson["ganonText"].get<std::string>();
|
||||
std::string formattedGanonJsonText = FormatJsonHintText(ganonJsonText);
|
||||
@ -1250,11 +1277,13 @@ void Randomizer::ParseHintLocationsFile(const char* spoilerFileName) {
|
||||
std::string formattedDampeJsonText = FormatJsonHintText(dampeJsonText);
|
||||
strncpy(gSaveContext.dampeText, formattedDampeJsonText.c_str(), sizeof(gSaveContext.dampeText) - 1);
|
||||
gSaveContext.dampeText[sizeof(gSaveContext.dampeText) - 1] = 0;
|
||||
gSaveContext.dampeCheck = SpoilerfileCheckNameToEnum[spoilerFileJson["dampeHintLoc"]];
|
||||
|
||||
std::string gregJsonText = spoilerFileJson["gregText"].get<std::string>();
|
||||
std::string formattedGregJsonText = FormatJsonHintText(gregJsonText);
|
||||
strncpy(gSaveContext.gregHintText, formattedGregJsonText.c_str(), sizeof(gSaveContext.gregHintText) - 1);
|
||||
gSaveContext.gregHintText[sizeof(gSaveContext.gregHintText) - 1] = 0;
|
||||
gSaveContext.gregCheck = SpoilerfileCheckNameToEnum[spoilerFileJson["gregLoc"]];
|
||||
|
||||
std::string warpMinuetJsonText = spoilerFileJson["warpMinuetText"].get<std::string>();
|
||||
strncpy(gSaveContext.warpMinuetText, warpMinuetJsonText.c_str(), sizeof(gSaveContext.warpMinuetText) - 1);
|
||||
@ -1284,8 +1313,28 @@ void Randomizer::ParseHintLocationsFile(const char* spoilerFileName) {
|
||||
int index = 0;
|
||||
for (auto it = hintsJson.begin(); it != hintsJson.end(); ++it) {
|
||||
gSaveContext.hintLocations[index].check = SpoilerfileCheckNameToEnum[it.key()];
|
||||
auto hintInfo = it.value();
|
||||
if (hintInfo["location"].is_null()) {
|
||||
gSaveContext.hintLocations[index].hintedCheck = RC_UNKNOWN_CHECK;
|
||||
} else {
|
||||
gSaveContext.hintLocations[index].hintedCheck = SpoilerfileCheckNameToEnum[hintInfo["location"]];
|
||||
}
|
||||
if (hintInfo["item"].is_null()) {
|
||||
gSaveContext.hintLocations[index].rGet = RG_NONE;
|
||||
} else {
|
||||
gSaveContext.hintLocations[index].rGet = SpoilerfileGetNameToEnum[hintInfo["item"]];
|
||||
}
|
||||
gSaveContext.hintLocations[index].type = SpoilerfileHintTypeNameToEnum[hintInfo["type"]];
|
||||
|
||||
std::string hintMessage = FormatJsonHintText(it.value());
|
||||
if (gSaveContext.hintLocations[index].type == HINT_TYPE_TRIAL) {
|
||||
gSaveContext.hintLocations[index].area = RCAREA_GANONS_CASTLE;
|
||||
} else if (gSaveContext.hintLocations[index].type == HINT_TYPE_JUNK) {
|
||||
gSaveContext.hintLocations[index].area = RCAREA_INVALID;
|
||||
} else {
|
||||
gSaveContext.hintLocations[index].area = SpoilerfileAreaNameToEnum[hintInfo["area"]];
|
||||
}
|
||||
|
||||
std::string hintMessage = FormatJsonHintText(hintInfo["hint"]);
|
||||
size_t maxHintTextSize = sizeof(gSaveContext.hintLocations[index].hintText);
|
||||
strncpy(gSaveContext.hintLocations[index].hintText, hintMessage.c_str(), maxHintTextSize - 1);
|
||||
gSaveContext.hintLocations[index].hintText[maxHintTextSize - 1] = 0;
|
||||
|
@ -20,6 +20,86 @@ typedef struct {
|
||||
uint8_t id;
|
||||
} Sprite;
|
||||
|
||||
typedef enum {
|
||||
HINT_TYPE_TRIAL,
|
||||
HINT_TYPE_ALWAYS,
|
||||
HINT_TYPE_WOTH, // Way of the Hero
|
||||
HINT_TYPE_BARREN,
|
||||
HINT_TYPE_ENTRANCE,
|
||||
HINT_TYPE_SOMETIMES,
|
||||
HINT_TYPE_RANDOM,
|
||||
HINT_TYPE_ITEM,
|
||||
HINT_TYPE_SONG,
|
||||
HINT_TYPE_OVERWORLD,
|
||||
HINT_TYPE_DUNGEON,
|
||||
HINT_TYPE_JUNK,
|
||||
HINT_TYPE_NAMED_ITEM,
|
||||
HINT_TYPE_MAX
|
||||
} HintType;
|
||||
|
||||
// Check types based on main settings
|
||||
typedef enum {
|
||||
RCTYPE_STANDARD, // Base set of rando checks
|
||||
RCTYPE_SKULL_TOKEN, // Gold Skulltulas
|
||||
RCTYPE_COW, // Cows
|
||||
RCTYPE_ADULT_TRADE, // Adult trade quest checks
|
||||
RCTYPE_FROG_SONG, // Frog song purple rupee checks
|
||||
RCTYPE_MAP_COMPASS, // Maps/Compasses
|
||||
RCTYPE_SMALL_KEY, // Small Keys
|
||||
RCTYPE_GF_KEY, // Gerudo Fortress Keys
|
||||
RCTYPE_BOSS_KEY, // Boss Keys
|
||||
RCTYPE_GANON_BOSS_KEY, // Ganon's boss key
|
||||
RCTYPE_SHOP, // shops
|
||||
RCTYPE_SCRUB, // scrubs
|
||||
RCTYPE_MERCHANT, // merchants
|
||||
RCTYPE_CHEST_GAME, // todo replace this once we implement it, just using it to exclude for now
|
||||
RCTYPE_LINKS_POCKET, // todo this feels hacky
|
||||
RCTYPE_GOSSIP_STONE,
|
||||
RCTYPE_SONG_LOCATION, // Song locations
|
||||
RCTYPE_BOSS_HEART_OR_OTHER_REWARD, // Boss heart container or lesser dungeon rewards (lens, ice arrow)
|
||||
RCTYPE_DUNGEON_REWARD, // Dungeon rewards (blue warps)
|
||||
RCTYPE_OCARINA, // Ocarina locations
|
||||
} RandomizerCheckType;
|
||||
|
||||
typedef enum { RCVORMQ_VANILLA, RCVORMQ_MQ, RCVORMQ_BOTH } RandomizerCheckVanillaOrMQ;
|
||||
|
||||
typedef enum {
|
||||
RCAREA_KOKIRI_FOREST,
|
||||
RCAREA_LOST_WOODS,
|
||||
RCAREA_SACRED_FOREST_MEADOW,
|
||||
RCAREA_HYRULE_FIELD,
|
||||
RCAREA_LAKE_HYLIA,
|
||||
RCAREA_GERUDO_VALLEY,
|
||||
RCAREA_GERUDO_FORTRESS,
|
||||
RCAREA_WASTELAND,
|
||||
RCAREA_DESERT_COLOSSUS,
|
||||
RCAREA_MARKET,
|
||||
RCAREA_HYRULE_CASTLE,
|
||||
RCAREA_KAKARIKO_VILLAGE,
|
||||
RCAREA_GRAVEYARD,
|
||||
RCAREA_DEATH_MOUNTAIN_TRAIL,
|
||||
RCAREA_GORON_CITY,
|
||||
RCAREA_DEATH_MOUNTAIN_CRATER,
|
||||
RCAREA_ZORAS_RIVER,
|
||||
RCAREA_ZORAS_DOMAIN,
|
||||
RCAREA_ZORAS_FOUNTAIN,
|
||||
RCAREA_LON_LON_RANCH,
|
||||
RCAREA_DEKU_TREE,
|
||||
RCAREA_DODONGOS_CAVERN,
|
||||
RCAREA_JABU_JABUS_BELLY,
|
||||
RCAREA_FOREST_TEMPLE,
|
||||
RCAREA_FIRE_TEMPLE,
|
||||
RCAREA_WATER_TEMPLE,
|
||||
RCAREA_SPIRIT_TEMPLE,
|
||||
RCAREA_SHADOW_TEMPLE,
|
||||
RCAREA_BOTTOM_OF_THE_WELL,
|
||||
RCAREA_ICE_CAVERN,
|
||||
RCAREA_GERUDO_TRAINING_GROUND,
|
||||
RCAREA_GANONS_CASTLE,
|
||||
// If adding any more areas, Check Tracker will need a refactor
|
||||
RCAREA_INVALID
|
||||
} RandomizerCheckArea;
|
||||
|
||||
typedef enum {
|
||||
RC_UNKNOWN_CHECK,
|
||||
RC_LINKS_POCKET,
|
||||
|
@ -7,73 +7,6 @@
|
||||
enum ActorID : int;
|
||||
enum SceneID : int;
|
||||
|
||||
// Check types based on main settings
|
||||
typedef enum {
|
||||
RCTYPE_STANDARD, // Base set of rando checks
|
||||
RCTYPE_SKULL_TOKEN, // Gold Skulltulas
|
||||
RCTYPE_COW, // Cows
|
||||
RCTYPE_ADULT_TRADE, // Adult trade quest checks
|
||||
RCTYPE_FROG_SONG, // Frog song purple rupee checks
|
||||
RCTYPE_MAP_COMPASS, // Maps/Compasses
|
||||
RCTYPE_SMALL_KEY, // Small Keys
|
||||
RCTYPE_GF_KEY, // Gerudo Fortress Keys
|
||||
RCTYPE_BOSS_KEY, // Boss Keys
|
||||
RCTYPE_GANON_BOSS_KEY, // Ganon's boss key
|
||||
RCTYPE_SHOP, // shops
|
||||
RCTYPE_SCRUB, // scrubs
|
||||
RCTYPE_MERCHANT, // merchants
|
||||
RCTYPE_CHEST_GAME, //todo replace this once we implement it, just using it to exclude for now
|
||||
RCTYPE_LINKS_POCKET, //todo this feels hacky
|
||||
RCTYPE_GOSSIP_STONE,
|
||||
RCTYPE_SONG_LOCATION, // Song locations
|
||||
RCTYPE_BOSS_HEART_OR_OTHER_REWARD, // Boss heart container or lesser dungeon rewards (lens, ice arrow)
|
||||
RCTYPE_DUNGEON_REWARD, // Dungeon rewards (blue warps)
|
||||
RCTYPE_OCARINA, // Ocarina locations
|
||||
} RandomizerCheckType;
|
||||
|
||||
typedef enum {
|
||||
RCVORMQ_VANILLA,
|
||||
RCVORMQ_MQ,
|
||||
RCVORMQ_BOTH
|
||||
} RandomizerCheckVanillaOrMQ;
|
||||
|
||||
typedef enum {
|
||||
RCAREA_KOKIRI_FOREST,
|
||||
RCAREA_LOST_WOODS,
|
||||
RCAREA_SACRED_FOREST_MEADOW,
|
||||
RCAREA_HYRULE_FIELD,
|
||||
RCAREA_LAKE_HYLIA,
|
||||
RCAREA_GERUDO_VALLEY,
|
||||
RCAREA_GERUDO_FORTRESS,
|
||||
RCAREA_WASTELAND,
|
||||
RCAREA_DESERT_COLOSSUS,
|
||||
RCAREA_MARKET,
|
||||
RCAREA_HYRULE_CASTLE,
|
||||
RCAREA_KAKARIKO_VILLAGE,
|
||||
RCAREA_GRAVEYARD,
|
||||
RCAREA_DEATH_MOUNTAIN_TRAIL,
|
||||
RCAREA_GORON_CITY,
|
||||
RCAREA_DEATH_MOUNTAIN_CRATER,
|
||||
RCAREA_ZORAS_RIVER,
|
||||
RCAREA_ZORAS_DOMAIN,
|
||||
RCAREA_ZORAS_FOUNTAIN,
|
||||
RCAREA_LON_LON_RANCH,
|
||||
RCAREA_DEKU_TREE,
|
||||
RCAREA_DODONGOS_CAVERN,
|
||||
RCAREA_JABU_JABUS_BELLY,
|
||||
RCAREA_FOREST_TEMPLE,
|
||||
RCAREA_FIRE_TEMPLE,
|
||||
RCAREA_WATER_TEMPLE,
|
||||
RCAREA_SPIRIT_TEMPLE,
|
||||
RCAREA_SHADOW_TEMPLE,
|
||||
RCAREA_BOTTOM_OF_THE_WELL,
|
||||
RCAREA_ICE_CAVERN,
|
||||
RCAREA_GERUDO_TRAINING_GROUND,
|
||||
RCAREA_GANONS_CASTLE,
|
||||
//If adding any more areas, Check Tracker will need a refactor
|
||||
RCAREA_INVALID
|
||||
} RandomizerCheckArea;
|
||||
|
||||
#define TWO_ACTOR_PARAMS(a, b) (abs(a) << 16) | abs(b)
|
||||
|
||||
#define RC_OBJECT(rc, rc_v_or_mq, rc_type, rc_area, actor_id, scene_id, actor_params, og_item_id, rc_shortname, rc_spoilername) \
|
||||
|
Loading…
Reference in New Issue
Block a user