Skip to content
Open
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 59 additions & 0 deletions soh/soh/Enhancements/custom-message/text.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include "text.h"
#include "soh/ShipUtils.h"
#include <functional>

Text::Text() = default;
Expand Down Expand Up @@ -96,3 +97,61 @@ void Text::Replace(const std::string& oldStr, const Text& newText) {
replaceAll(german, oldStr, newText.GetGerman());
replaceAll(spanish, oldStr, newText.GetSpanish());
}

static void replaceRandomVowel(std::string& target, uint64_t* randState) {
std::vector<size_t> vowelPositions;

for (size_t i = 0; i < target.size(); ++i) {
char c = std::tolower(target[i]);
if (c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u') {
vowelPositions.push_back(i);
}
}

if (vowelPositions.empty()) {
return;
}

size_t pos = ShipUtils::RandomElement(vowelPositions, randState);

const std::vector<char> vowels = { 'a', 'e', 'i', 'o', 'u' };
Comment thread
Pepe20129 marked this conversation as resolved.
Outdated
char newVowel = ShipUtils::RandomElement(vowels, randState);

if (std::isupper(target[pos])) {
newVowel = std::toupper(newVowel);
}

target[pos] = newVowel;
}

void Text::ReplaceRandomVowel(uint64_t* randState) {
for (std::string& str : { std::ref(english), std::ref(french), std::ref(german), std::ref(spanish) }) {
replaceRandomVowel(str, randState);
}
}

static void duplicateRandomLetter(std::string& target, uint64_t* randState) {
std::vector<size_t> letterPositions;
Comment thread
serprex marked this conversation as resolved.

for (size_t i = 0; i < target.size(); ++i) {
if (std::isalpha(target[i])) {
letterPositions.push_back(i);
}
}

if (letterPositions.empty()) {
return;
}

size_t pos = ShipUtils::RandomElement(letterPositions, randState);

char c = target[pos];

target.insert(target.begin() + pos + 1, c);
}

void Text::DuplicateRandomLetter(uint64_t* randState) {
for (std::string& str : { std::ref(english), std::ref(french), std::ref(german), std::ref(spanish) }) {
duplicateRandomLetter(str, randState);
}
}
4 changes: 4 additions & 0 deletions soh/soh/Enhancements/custom-message/text.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ class Text {
void Replace(const std::string& oldStr, const std::string& newStr);
void Replace(const std::string& oldStr, const Text& newText);

void ReplaceRandomVowel(uint64_t* randState = nullptr);

void DuplicateRandomLetter(uint64_t* randState = nullptr);

std::string english = "";
std::string french = "";
std::string german = "";
Expand Down
3 changes: 2 additions & 1 deletion soh/soh/Enhancements/randomizer/Plandomizer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -878,7 +878,8 @@ void PlandomizerDrawIceTrapSetup(uint32_t index) {
.Size(UIWidgets::Sizes::Inline)
.Padding(ImVec2(10.f, 6.f)))) {
plandoLogData[index].iceTrapName =
Rando::Traps::GetTrapName(plandoLogData[index].iceTrapModel.GetRandomizerGet())
Rando::Traps::GetTrapName(plandoLogData[index].iceTrapModel.GetRandomizerGet(),
RO_ICE_TRAP_NAMES_SIMILAR)
.name.GetForLanguage(CVarGetInteger(CVAR_SETTING("Languages"), 0))
.c_str();
}
Expand Down
3 changes: 2 additions & 1 deletion soh/soh/Enhancements/randomizer/SeedContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -342,7 +342,8 @@ void Context::CreateItemOverrides() {
if (itemLoc->GetPlacedRandomizerGet() == RG_ICE_TRAP) {
ItemOverride val(locKey, Traps::GetTrapTrickModel(&rando_state));
iceTrapModels[locKey] = val.LooksLike();
Traps::TrickName trickName = Traps::GetTrapName(val.LooksLike(), &rando_state);
Traps::TrickName trickName = Traps::GetTrapName(
val.LooksLike(), static_cast<RandoIceTrapNames>(mOptions[RSK_ICE_TRAP_NAMES].Get()), &rando_state);
val.SetTrickName(trickName.name);
val.SetTrickArticle(trickName.article);
// If this is ice trap is in a shop, change the name based on what the model will look like
Expand Down
66 changes: 53 additions & 13 deletions soh/soh/Enhancements/randomizer/Traps.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@

#include "soh/Enhancements/randomizer/rng.h"

#define NOGDI // avoid various windows defines that conflict with things in z64.h
#include <spdlog/spdlog.h>

#include <vector>

// Table of trick names for ice traps
Expand Down Expand Up @@ -1859,21 +1862,58 @@ static void InitTrickNames() {
*/
}

// Generate a fake name for the ice trap based on the item it's displayed as
Rando::Traps::TrickName Rando::Traps::GetTrapName(uint16_t id, uint64_t* state) {
// If the trick names table has not been initialized, do so
if (!initTrickNames) {
InitTrickNames();
initTrickNames = true;
}
/// @brief Gets the "trick name" for an Ice Trap
/// @param id The RandomizerGet of the item the Ice Trap is disguised as
/// @param iceTrapNamesOption The current value of the RSK_ICE_TRAP_NAMES setting
/// @param state The rng state
/// @return A Text object with the selected trick name
Rando::Traps::TrickName Rando::Traps::GetTrapName(RandomizerGet id, RandoIceTrapNames iceTrapNamesOption,
uint64_t* state) {
switch (iceTrapNamesOption) {
case RO_ICE_TRAP_NAMES_IDENTICAL: {
auto item = Rando::StaticData::RetrieveItem(id);
return { item.GetName(), item.GetArticle() };
}
case RO_ICE_TRAP_NAMES_SIMILAR: {
// If the trick names table has not been initialized, do so
if (!initTrickNames) {
InitTrickNames();
initTrickNames = true;
}

if (trickNameTable[id].empty()) {
assert(false);
return { Text{ "not an Ice Trap" }, Text{ "", "", "" } };
}
if (trickNameTable[id].empty()) {
SPDLOG_ERROR("[Rando::Traps::GetTrapName] Couldn't find entry for RG %d in trickNameTable",
static_cast<u8>(id));
assert(false);
return { Text{ "Error: Couldn't get Ice Trap name" }, Text{ "Error: Couldn't get Ice Trap name" } };
}

// Randomly get the easy, medium, or hard name for the given item id
return ShipUtils::RandomElement(trickNameTable[id], state);
// Randomly get the easy, medium, or hard name for the given item id
return ShipUtils::RandomElement(trickNameTable[id], state);
}
case RO_ICE_TRAP_NAMES_MISSPELLED_CHANGED_VOWEL: {
auto item = Rando::StaticData::RetrieveItem(id);
Text name = item.GetName();
name.ReplaceRandomVowel(state);
return { name, item.GetArticle() };
}
case RO_ICE_TRAP_NAMES_MISSPELLED_DUPLICATED_LETTER: {
auto item = Rando::StaticData::RetrieveItem(id);
Text name = item.GetName();
name.DuplicateRandomLetter(state);
return { name, item.GetArticle() };
}
case RO_ICE_TRAP_NAMES_REVEALED: {
auto item = Rando::StaticData::RetrieveItem(RG_ICE_TRAP);
return { item.GetName(), item.GetArticle() };
}
default: {
SPDLOG_ERROR("[Rando::Traps::GetTrapName] Invalid value for RSK_ICE_TRAP_NAMES (%d)",
static_cast<u8>(iceTrapNamesOption));
assert(false);
return { Text{ "Error: Couldn't get Ice Trap name" }, Text{ "Error: Couldn't get Ice Trap name" } };
}
}
}

RandomizerGet Rando::Traps::GetTrapTrickModel(uint64_t* state) {
Expand Down
7 changes: 5 additions & 2 deletions soh/soh/Enhancements/randomizer/Traps.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,11 @@
#error This header should not be used in C files
#endif

#include "soh/Enhancements/custom-message/CustomMessageManager.h"
#include "soh/Enhancements/custom-message/text.h"
#include "soh/Enhancements/item-tables/ItemTableTypes.h"
#include "soh/Enhancements/randomizer/randomizerTypes.h"

class CustomMessage;

namespace Rando {
namespace Traps {
Expand All @@ -14,7 +17,7 @@ struct TrickName {
Text name;
Text article;
};
TrickName GetTrapName(uint16_t id, uint64_t* state = nullptr);
TrickName GetTrapName(RandomizerGet id, RandoIceTrapNames iceTrapNamesOption, uint64_t* state = nullptr);
RandomizerGet GetTrapTrickModel(uint64_t* state = nullptr);
bool ShouldJunkItemBeTrap();
void BuildIceTrapMessage(CustomMessage& msg, GetItemEntry getItemEntry);
Expand Down
13 changes: 13 additions & 0 deletions soh/soh/Enhancements/randomizer/option_descriptions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -743,6 +743,19 @@ void Settings::CreateOptionDescriptions() {
"You do not need to have base ice traps on for this setting to work.";
mOptionDescriptions[RSK_ICE_TRAP_PERCENT] =
"If set above 0, each Junk item has that chance of being replaced with an extra Ice Trap.";
mOptionDescriptions[RSK_ICE_TRAP_NAMES] =
"Sets how Ice Traps disguise themselves in text.\n"
"\n"
"Identical - There's no tell for an item being an Ice Trap.\n"
"\n"
"Similar - The name will be similar to the item's real name (for example, \"Korok Sword\" instead of \"Kokiri "
"Sword\").\n"
"\n"
"Misspelled (Vowel) - The name is misspelled by changing a random vowel with another random vowel.\n"
"\n"
"Misspelled (Duplicate) - The name is misspelled by duplicating a random letter.\n"
"\n"
"Revealed - Ice Traps will not disguide themselves in text.";
mOptionDescriptions[RSK_GOSSIP_STONE_HINTS] =
"Allows Gossip Stones to provide hints on item locations. Hints mentioning "
"\"Way of the Hero\" indicate a location that holds an item required to beat "
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,14 @@ RANDO_ENUM_ITEM(RO_ICE_TRAPS_COUNT)
RANDO_ENUM_ITEM(RO_ICE_TRAPS_PERCENT)
RANDO_ENUM_END(RandoOptionIceTraps)

RANDO_ENUM_BEGIN(RandoIceTrapNames)
RANDO_ENUM_ITEM(RO_ICE_TRAP_NAMES_IDENTICAL)
RANDO_ENUM_ITEM(RO_ICE_TRAP_NAMES_SIMILAR)
RANDO_ENUM_ITEM(RO_ICE_TRAP_NAMES_MISSPELLED_CHANGED_VOWEL)
RANDO_ENUM_ITEM(RO_ICE_TRAP_NAMES_MISSPELLED_DUPLICATED_LETTER)
RANDO_ENUM_ITEM(RO_ICE_TRAP_NAMES_REVEALED)
RANDO_ENUM_END(RandoIceTrapNames)

// Gossip Stone Hint Settings (no hints, needs nothing,
// needs mask of truth, needs stone of agony)
RANDO_ENUM_BEGIN(RandoOptionGossipStones)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ RANDO_ENUM_ITEM(RSK_ITEM_POOL)
RANDO_ENUM_ITEM(RSK_BASE_ICE_TRAPS)
RANDO_ENUM_ITEM(RSK_ADDITIONAL_ICE_TRAPS)
RANDO_ENUM_ITEM(RSK_ICE_TRAP_PERCENT)
RANDO_ENUM_ITEM(RSK_ICE_TRAP_NAMES)
RANDO_ENUM_ITEM(RSK_GOSSIP_STONE_HINTS)
RANDO_ENUM_ITEM(RSK_TOT_ALTAR_HINT)
RANDO_ENUM_ITEM(RSK_GANONDORF_HINT)
Expand Down
2 changes: 2 additions & 0 deletions soh/soh/Enhancements/randomizer/settings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1407,6 +1407,7 @@ void Settings::CreateOptions() {
OPT_BOOL(RSK_BASE_ICE_TRAPS, "Base Ice Traps", CVAR_RANDOMIZER_SETTING("BaseIceTraps"), mOptionDescriptions[RSK_BASE_ICE_TRAPS], IMFLAG_NONE, WIDGET_CVAR_COMBOBOX, RO_GENERIC_ON);
OPT_U8(RSK_ADDITIONAL_ICE_TRAPS, "Additional Ice Traps", {NumOpts(0, 100)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("AdditionalIceTraps"), mOptionDescriptions[RSK_ADDITIONAL_ICE_TRAPS], WIDGET_CVAR_SLIDER_INT, 0);
OPT_U8(RSK_ICE_TRAP_PERCENT, "Ice Trap Percent", {NumOpts(0, 100)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("IceTrapPercent"), mOptionDescriptions[RSK_ICE_TRAP_PERCENT], WIDGET_CVAR_SLIDER_INT, 0);
OPT_U8(RSK_ICE_TRAP_NAMES, "Ice Trap Trick Names", {"Identical", "Similar", "Misspelled (Vowel)", "Misspelled (Duplicate)", "Revealed"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("IceTrapNames"), mOptionDescriptions[RSK_ICE_TRAP_NAMES], WIDGET_CVAR_COMBOBOX, RO_ICE_TRAP_NAMES_SIMILAR);
// TODO: Remove Double Defense
OPT_U8(RSK_STARTING_OCARINA, "Start with Ocarina", {"Off", "Fairy Ocarina", "Ocarina of Time"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("StartingOcarina"), "", WIDGET_CVAR_COMBOBOX, RO_STARTING_OCARINA_OFF);
OPT_BOOL(RSK_STARTING_DEKU_SHIELD, "Start with Deku Shield", CVAR_RANDOMIZER_SETTING("StartingDekuShield"));
Expand Down Expand Up @@ -2143,6 +2144,7 @@ void Settings::CreateOptions() {
&mOptions[RSK_BASE_ICE_TRAPS],
&mOptions[RSK_ADDITIONAL_ICE_TRAPS],
&mOptions[RSK_ICE_TRAP_PERCENT],
&mOptions[RSK_ICE_TRAP_NAMES],
},
WidgetContainerType::SECTION);
mOptionGroups[RSG_MENU_COLUMN_HINTS_TRAPS] =
Expand Down
Loading