mirror of
https://github.com/TwilitRealm/dusklight
synced 2026-08-30 08:01:13 -04:00
implement agitha hint sign
This commit is contained in:
@@ -267,6 +267,14 @@
|
||||
- 0x9E8
|
||||
- 0x9E8
|
||||
|
||||
# This is just a listing of the flow node for the AGITHA'S CASTLE text so that we
|
||||
# can create new nodes if the text length overflows
|
||||
- only if: Agitha_Hints == On
|
||||
index: 0xA2D
|
||||
type: message
|
||||
message: Agithas Castle Sign Text
|
||||
next: 0xFFFF
|
||||
|
||||
5: # zel_05.bmg
|
||||
# Patch Yeta flow to always give the map check even if the player has obtained the Ordon Cheese
|
||||
- index: 0x8
|
||||
|
||||
@@ -567,6 +567,12 @@
|
||||
- "Off": "All locations will be treated equally for location hints."
|
||||
- "On": "Certain locations which are time-consuming to check will be given priority for location hints."
|
||||
|
||||
- Name: Agitha Hints
|
||||
Default Option: "On"
|
||||
Options:
|
||||
- "Off": "The sign outside Agitha's Castle will not contain any hints."
|
||||
- "On": "The sign outside Agitha's Castle will hint all major items that can be obtained from turning in golden bugs to Agitha."
|
||||
|
||||
#############################
|
||||
## Entrance Randomizer ##
|
||||
#############################
|
||||
@@ -642,7 +648,7 @@
|
||||
- Name: Back Slice as Sword
|
||||
Default Option: "Off"
|
||||
Options:
|
||||
- "Off": "Back Slicing without a sword can be logically required to do damage."
|
||||
- "Off": "Back Slicing without a sword will not be logically required to do damage."
|
||||
- "On": "Back Slicing without a sword can be logically required to do damage."
|
||||
|
||||
- Name: Ball and Chain Webs
|
||||
|
||||
@@ -1200,9 +1200,9 @@ Goron Mines Key Shard:
|
||||
Cryptic:
|
||||
Text: "{one third of a key}"
|
||||
|
||||
Coro Key:
|
||||
Faron Woods Coro Key:
|
||||
Standard:
|
||||
Text: Coro Key
|
||||
Text: Faron Woods Coro Key
|
||||
Pretty:
|
||||
Text: "{Coro's Key}"
|
||||
Cryptic:
|
||||
@@ -1248,6 +1248,10 @@ Lanayru Twilight Tear:
|
||||
Cryptic:
|
||||
Text: a {tear of a lake spirit}
|
||||
|
||||
Progressive Item Prefix:
|
||||
Standard:
|
||||
Text: "Progressive "
|
||||
|
||||
# ITEM NAMES FOR PROGRESSIVE ITEMS
|
||||
Progressive Wallet x0:
|
||||
Standard:
|
||||
@@ -2256,6 +2260,20 @@ Castle Town Goron Hylian Shield Confirmation Later Text Template:
|
||||
Text: |-
|
||||
Would you want <Item Pretty Name> for <purple>210 Rupees<white>?<begin choice>
|
||||
|
||||
Agithas Castle Zero Items Sign Text:
|
||||
Standard:
|
||||
Text: |-
|
||||
<font size 48>Please bring <purple>golden bugs<white> you find to Agitha's Castle.
|
||||
|
||||
And tell them the princess awaits!
|
||||
|
||||
Agithas Castle Some Items Sign Text:
|
||||
Standard:
|
||||
Text: |-
|
||||
<font size 48>Please bring <yellow>golden bugs<white> you find to Agitha's Castle. I'll share <red>GREAT happiness<white> with you:
|
||||
|
||||
<green><Items>
|
||||
|
||||
Coro Bottle Offer 1 Text Template:
|
||||
Standard:
|
||||
Text: |-
|
||||
|
||||
@@ -1200,9 +1200,9 @@ Goron Mines Key Shard:
|
||||
Cryptic:
|
||||
Text: "{one third of a key}"
|
||||
|
||||
Coro Key:
|
||||
Faron Woods Coro Key:
|
||||
Standard:
|
||||
Text: Coro Key
|
||||
Text: Faron Woods Coro Key
|
||||
Pretty:
|
||||
Text: "{Coro's Key}"
|
||||
Cryptic:
|
||||
@@ -1248,6 +1248,10 @@ Lanayru Twilight Tear:
|
||||
Cryptic:
|
||||
Text: a {tear of a lake spirit}
|
||||
|
||||
Progressive Item Prefix:
|
||||
Standard:
|
||||
Text: "Progressive "
|
||||
|
||||
# ITEM NAMES FOR PROGRESSIVE ITEMS
|
||||
Progressive Wallet x0:
|
||||
Standard:
|
||||
@@ -2248,6 +2252,20 @@ Castle Town Goron Hylian Shield Confirmation Later Text Template:
|
||||
Text: |-
|
||||
Would you want <Item Pretty Name> for <purple>210 Rupees<white>?<begin choice>
|
||||
|
||||
Agithas Castle Zero Items Sign Text:
|
||||
Standard:
|
||||
Text: |-
|
||||
<font size 48>Veuillez apporter les <purple>insectes dorés<white> au Château de Machaon.
|
||||
|
||||
Et dites leurs que la princesse attend !
|
||||
|
||||
Agithas Castle Some Items Sign Text:
|
||||
Standard:
|
||||
Text: |-
|
||||
<font size 48>Veuillez apporter les <yellow>insectes dorés<white> au Château de Machaon. Je saurai partager mon <red>bonheur<white> avec vous :
|
||||
|
||||
<green><Items>
|
||||
|
||||
Coro Bottle Offer 1 Text Template:
|
||||
Standard:
|
||||
Text: |-
|
||||
|
||||
@@ -1200,9 +1200,9 @@ Goron Mines Key Shard:
|
||||
Cryptic:
|
||||
Text: "{one third of a key}"
|
||||
|
||||
Coro Key:
|
||||
Faron Woods Coro Key:
|
||||
Standard:
|
||||
Text: Coro Key
|
||||
Text: Faron Woods Coro Key
|
||||
Pretty:
|
||||
Text: "{Coro's Key}"
|
||||
Cryptic:
|
||||
@@ -1248,6 +1248,10 @@ Lanayru Twilight Tear:
|
||||
Cryptic:
|
||||
Text: a {tear of a lake spirit}
|
||||
|
||||
Progressive Item Prefix:
|
||||
Standard:
|
||||
Text: "Progressive "
|
||||
|
||||
# ITEM NAMES FOR PROGRESSIVE ITEMS
|
||||
Progressive Wallet x0:
|
||||
Standard:
|
||||
@@ -2248,6 +2252,20 @@ Castle Town Goron Hylian Shield Confirmation Later Text Template:
|
||||
Text: |-
|
||||
Would you want <Item Pretty Name> for <purple>210 Rupees<white>?<begin choice>
|
||||
|
||||
Agithas Castle Zero Items Sign Text:
|
||||
Standard:
|
||||
Text: |-
|
||||
<font size 48>Please bring <purple>golden bugs<white> you find to Agitha's Castle.
|
||||
|
||||
And tell them the princess awaits!
|
||||
|
||||
Agithas Castle Some Items Sign Text:
|
||||
Standard:
|
||||
Text: |-
|
||||
<font size 48>Please bring <yellow>golden bugs<white> you find to Agitha's Castle. I'll share <red>GREAT happiness<white> with you:
|
||||
|
||||
<green><Items>
|
||||
|
||||
Coro Bottle Offer 1 Text Template:
|
||||
Standard:
|
||||
Text: |-
|
||||
|
||||
@@ -1200,9 +1200,9 @@ Goron Mines Key Shard:
|
||||
Cryptic:
|
||||
Text: "{one third of a key}"
|
||||
|
||||
Coro Key:
|
||||
Faron Woods Coro Key:
|
||||
Standard:
|
||||
Text: Coro Key
|
||||
Text: Faron Woods Coro Key
|
||||
Pretty:
|
||||
Text: "{Coro's Key}"
|
||||
Cryptic:
|
||||
@@ -1248,6 +1248,10 @@ Lanayru Twilight Tear:
|
||||
Cryptic:
|
||||
Text: a {tear of a lake spirit}
|
||||
|
||||
Progressive Item Prefix:
|
||||
Standard:
|
||||
Text: "Progressive "
|
||||
|
||||
# ITEM NAMES FOR PROGRESSIVE ITEMS
|
||||
Progressive Wallet x0:
|
||||
Standard:
|
||||
@@ -2248,6 +2252,20 @@ Castle Town Goron Hylian Shield Confirmation Later Text Template:
|
||||
Text: |-
|
||||
Would you want <Item Pretty Name> for <purple>210 Rupees<white>?<begin choice>
|
||||
|
||||
Agithas Castle Zero Items Sign Text:
|
||||
Standard:
|
||||
Text: |-
|
||||
<font size 48>Please bring <purple>golden bugs<white> you find to Agitha's Castle.
|
||||
|
||||
And tell them the princess awaits!
|
||||
|
||||
Agithas Castle Some Items Sign Text:
|
||||
Standard:
|
||||
Text: |-
|
||||
<font size 48>Please bring <yellow>golden bugs<white> you find to Agitha's Castle. I'll share <red>GREAT happiness<white> with you:
|
||||
|
||||
<green><Items>
|
||||
|
||||
Coro Bottle Offer 1 Text Template:
|
||||
Standard:
|
||||
Text: |-
|
||||
|
||||
@@ -1200,9 +1200,9 @@ Goron Mines Key Shard:
|
||||
Cryptic:
|
||||
Text: "{one third of a key}"
|
||||
|
||||
Coro Key:
|
||||
Faron Woods Coro Key:
|
||||
Standard:
|
||||
Text: Coro Key
|
||||
Text: Faron Woods Coro Key
|
||||
Pretty:
|
||||
Text: "{Coro's Key}"
|
||||
Cryptic:
|
||||
@@ -1248,6 +1248,10 @@ Lanayru Twilight Tear:
|
||||
Cryptic:
|
||||
Text: a {tear of a lake spirit}
|
||||
|
||||
Progressive Item Prefix:
|
||||
Standard:
|
||||
Text: "Progressive "
|
||||
|
||||
# ITEM NAMES FOR PROGRESSIVE ITEMS
|
||||
Progressive Wallet x0:
|
||||
Standard:
|
||||
@@ -2209,6 +2213,20 @@ Castle Town Goron Hylian Shield Confirmation Later Text Template:
|
||||
Text: |-
|
||||
Would you want <Item Pretty Name> for <purple>210 Rupees<white>?<begin choice>
|
||||
|
||||
Agithas Castle Zero Items Sign Text:
|
||||
Standard:
|
||||
Text: |-
|
||||
<font size 48>Please bring <purple>golden bugs<white> you find to Agitha's Castle.
|
||||
|
||||
And tell them the princess awaits!
|
||||
|
||||
Agithas Castle Some Items Sign Text:
|
||||
Standard:
|
||||
Text: |-
|
||||
<font size 48>Please bring <yellow>golden bugs<white> you find to Agitha's Castle. I'll share <red>GREAT happiness<white> with you:
|
||||
|
||||
<green><Items>
|
||||
|
||||
Coro Bottle Offer 1 Text Template:
|
||||
Standard:
|
||||
Text: |-
|
||||
|
||||
@@ -1200,9 +1200,9 @@ Goron Mines Key Shard:
|
||||
Cryptic:
|
||||
Text: "{one third of a key}"
|
||||
|
||||
Coro Key:
|
||||
Faron Woods Coro Key:
|
||||
Standard:
|
||||
Text: Coro Key
|
||||
Text: Faron Woods Coro Key
|
||||
Pretty:
|
||||
Text: "{Coro's Key}"
|
||||
Cryptic:
|
||||
@@ -1248,6 +1248,10 @@ Lanayru Twilight Tear:
|
||||
Cryptic:
|
||||
Text: a {tear of a lake spirit}
|
||||
|
||||
Progressive Item Prefix:
|
||||
Standard:
|
||||
Text: "Progressive "
|
||||
|
||||
# ITEM NAMES FOR PROGRESSIVE ITEMS
|
||||
Progressive Wallet x0:
|
||||
Standard:
|
||||
@@ -2248,6 +2252,20 @@ Castle Town Goron Hylian Shield Confirmation Later Text Template:
|
||||
Text: |-
|
||||
Would you want <Item Pretty Name> for <purple>210 Rupees<white>?<begin choice>
|
||||
|
||||
Agithas Castle Zero Items Sign Text:
|
||||
Standard:
|
||||
Text: |-
|
||||
<font size 48>Please bring <purple>golden bugs<white> you find to Agitha's Castle.
|
||||
|
||||
And tell them the princess awaits!
|
||||
|
||||
Agithas Castle Some Items Sign Text:
|
||||
Standard:
|
||||
Text: |-
|
||||
<font size 48>Please bring <yellow>golden bugs<white> you find to Agitha's Castle. I'll share <red>GREAT happiness<white> with you:
|
||||
|
||||
<green><Items>
|
||||
|
||||
Coro Bottle Offer 1 Text Template:
|
||||
Standard:
|
||||
Text: |-
|
||||
|
||||
@@ -432,6 +432,16 @@
|
||||
Group: 4
|
||||
Message Id: 6664
|
||||
|
||||
- Only If: Agitha_Hints == On
|
||||
Name: Agithas Castle Sign Text
|
||||
Group: 4
|
||||
Message Id: 8005
|
||||
Style:
|
||||
Box Kind: 0x02
|
||||
Draw Type: 2
|
||||
Box Position: 1
|
||||
Trailing Data: 0x0800
|
||||
|
||||
- Name: Coro Bottle Offer 1 Text
|
||||
Group: 6
|
||||
Message Id: 5216
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include "search.hpp"
|
||||
#include "world.hpp"
|
||||
#include "../utility/general.hpp"
|
||||
#include "../utility/platform.hpp"
|
||||
#include "../utility/string.hpp"
|
||||
#include "../utility/text.hpp"
|
||||
@@ -45,6 +46,50 @@ namespace randomizer::logic::hints {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static void GenerateAgithaSignHint(world::WorldPool& worlds) {
|
||||
for (auto& world : worlds) {
|
||||
if (world->Setting("Agitha Hints") == "On") {
|
||||
|
||||
// Gather all the items in Agitha's Castle
|
||||
std::map<item::Item*, int, utility::general::PointerLess> agithaItems{};
|
||||
auto agithasCastleArea = world->GetArea("Castle Town Agithas House");
|
||||
for (auto locAcc : agithasCastleArea->GetLocations()) {
|
||||
auto itemAtLocation = locAcc->GetLocation()->GetCurrentItem();
|
||||
if (!itemAtLocation->IsJunk() && !itemAtLocation->IsGoldenBug()) {
|
||||
agithaItems[itemAtLocation] += 1;
|
||||
}
|
||||
}
|
||||
|
||||
auto& agithaSignText = world->AddNewText("Agithas Castle Sign Text");
|
||||
|
||||
if (agithaItems.empty()) {
|
||||
agithaSignText += getTextObject("Agithas Castle Zero Items Sign Text");
|
||||
} else {
|
||||
agithaSignText += getTextObject("Agithas Castle Some Items Sign Text");
|
||||
|
||||
std::vector<Text> agithaItemTexts{};
|
||||
for (const auto& [item, count] : agithaItems) {
|
||||
auto itemText = getTextObject(item->GetName());
|
||||
if (count > 1) {
|
||||
itemText += " x" + std::to_string(count);
|
||||
}
|
||||
itemText.Replace(getTextObject("Progressive Item Prefix"), "");
|
||||
agithaItemTexts.push_back(itemText);
|
||||
}
|
||||
|
||||
auto agithaItemsListing = makeTextListing(agithaItemTexts);
|
||||
agithaSignText.Replace("<Items>", agithaItemsListing);
|
||||
agithaSignText.BreakLines(22.f);
|
||||
agithaSignText.mLinesPerBox = 7;
|
||||
agithaSignText.mNewLinesPerMessage = 7;
|
||||
|
||||
// Set the font size and color before each separate box
|
||||
agithaSignText.mSplitMessagePrefix = "<font size 48><green>";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void CalculatePossiblePathLocations(world::WorldPool& worlds) {
|
||||
LOG_TO_DEBUG("Calculating Possible Path Locations");
|
||||
// First generate the goal location keys and also remove items from non-
|
||||
@@ -1070,6 +1115,8 @@ namespace randomizer::logic::hints {
|
||||
|
||||
utility::platform::Log("Generating Hints...");
|
||||
|
||||
GenerateAgithaSignHint(worlds);
|
||||
|
||||
CalculatePossiblePathLocations(worlds);
|
||||
CalculatePossibleBarrenRegions(worlds);
|
||||
|
||||
|
||||
@@ -95,7 +95,7 @@ namespace randomizer::logic::item
|
||||
return this->_importance == Importance::MINOR;
|
||||
}
|
||||
|
||||
bool Item::isJunk() const
|
||||
bool Item::IsJunk() const
|
||||
{
|
||||
return this->_importance == Importance::JUNK;
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ namespace randomizer::logic::item
|
||||
Importance GetImportance() const;
|
||||
bool IsMajor() const;
|
||||
bool IsMinor() const;
|
||||
bool isJunk() const;
|
||||
bool IsJunk() const;
|
||||
bool IsGameWinningItem() const;
|
||||
void AddChainLocation(location::Location* location);
|
||||
std::list<location::Location*> GetChainLocations() const;
|
||||
|
||||
@@ -245,7 +245,7 @@ namespace randomizer::logic::spoiler_log
|
||||
}
|
||||
}
|
||||
|
||||
// Print Hints
|
||||
// Print Hints
|
||||
spoilerLog << std::endl << "Hints:" << std::endl;
|
||||
for (const auto& world : worlds) {
|
||||
// Midna hints first
|
||||
@@ -255,6 +255,14 @@ namespace randomizer::logic::spoiler_log
|
||||
midnaText = utility::str::Replace(midnaText, "\n", "\n ");
|
||||
spoilerLog << " " << midnaText << std::endl;
|
||||
|
||||
// Then Agitha's Castle Sign
|
||||
if (world->Setting("Agitha Hints") == "On") {
|
||||
spoilerLog << " Agitha's Castle Sign:" << std::endl;
|
||||
auto agithaSignText = world->GetText("Agithas Castle Sign Text");
|
||||
agithaSignText = utility::str::Replace(agithaSignText, "\n", "\n ");
|
||||
spoilerLog << " " << agithaSignText << std::endl;
|
||||
}
|
||||
|
||||
spoilerLog << std::endl;
|
||||
// Put sign hints into a structure that will automatically sort them
|
||||
const auto& hintSignHints = world->GetHintSignHints();
|
||||
|
||||
@@ -7,4 +7,13 @@ namespace randomizer::utility::general
|
||||
{
|
||||
return ((first == t) || ...);
|
||||
}
|
||||
|
||||
struct PointerLess {
|
||||
bool operator()(const auto* lhs, const auto* rhs) const {
|
||||
if (!lhs || !rhs) {
|
||||
return lhs < rhs;
|
||||
}
|
||||
return *lhs < *rhs;
|
||||
}
|
||||
};
|
||||
} // namespace randomizer::utility::general
|
||||
|
||||
@@ -95,6 +95,9 @@ namespace randomizer::utility::str {
|
||||
const std::string& replacementStr,
|
||||
uint32_t count) {
|
||||
std::string retStr = originalStr;
|
||||
if (oldStr.empty()) {
|
||||
return retStr;
|
||||
}
|
||||
auto startPos = retStr.find(oldStr);
|
||||
for (int i = 0; i < count; ++i) {
|
||||
if (startPos == std::string::npos) {
|
||||
|
||||
@@ -51,6 +51,28 @@ const auto kSilverMessageCode = text_color_code(0xBFBFBFFF);
|
||||
}
|
||||
}
|
||||
|
||||
void Text::Replace(const Text& oldText, const std::string& replacementText, uint32_t count /* = max*/) {
|
||||
for (size_t i = 0; i < mText.size(); ++i) {
|
||||
auto& curString = mText[i];
|
||||
auto& oldString = oldText.mText[i];
|
||||
curString = utility::str::Replace(curString, oldString, replacementText, count);
|
||||
}
|
||||
}
|
||||
|
||||
void Text::PopBack() {
|
||||
for (auto& text : mText) {
|
||||
if (!text.empty()) {
|
||||
text.pop_back();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Text::Clear() {
|
||||
for (auto& text : mText) {
|
||||
text.clear();
|
||||
}
|
||||
}
|
||||
|
||||
void Text::Capitalize() {
|
||||
try {
|
||||
// Determine the platform-specific locale string
|
||||
@@ -90,9 +112,9 @@ const auto kSilverMessageCode = text_color_code(0xBFBFBFFF);
|
||||
BreakLines();
|
||||
for (size_t lang = 0; lang < mText.size(); ++lang) {
|
||||
auto& text = mText[lang];
|
||||
auto linesPerBox = LINES_PER_BOX_LATIN;
|
||||
auto linesPerBox = mLinesPerBox;
|
||||
if (lang == JAPANESE) {
|
||||
linesPerBox = LINES_PER_BOX_JP;
|
||||
linesPerBox = mLinesPerBoxJP;
|
||||
}
|
||||
size_t numNewLines = std::ranges::count_if(text, [](char c){return c == '\n';});
|
||||
while (numNewLines == 0 || text.back() != '\n' || numNewLines % linesPerBox != 0) {
|
||||
@@ -114,7 +136,7 @@ const auto kSilverMessageCode = text_color_code(0xBFBFBFFF);
|
||||
bool Text::IsTooLong() const {
|
||||
for (auto& text : mText) {
|
||||
auto numNewLines = std::ranges::count_if(text, [](char c){return c == '\n';});
|
||||
if (numNewLines > MAX_NEWLINES_PER_MESSAGE) {
|
||||
if (numNewLines > mNewLinesPerMessage) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -130,17 +152,23 @@ const auto kSilverMessageCode = text_color_code(0xBFBFBFFF);
|
||||
size_t numTextObjects{1};
|
||||
for (auto& text : mText) {
|
||||
double numNewLines = std::ranges::count_if(text, [](char c){return c == '\n';});
|
||||
auto curTextSplitAmount = static_cast<size_t>(std::ceil(numNewLines / MAX_NEWLINES_PER_MESSAGE));
|
||||
auto curTextSplitAmount = static_cast<size_t>(std::ceil(numNewLines / mNewLinesPerMessage));
|
||||
numTextObjects = std::max(curTextSplitAmount, numTextObjects);
|
||||
}
|
||||
|
||||
std::vector<Text> splitText{numTextObjects};
|
||||
// Populate the Text vector with copies of this object to copy over the fields
|
||||
auto splitText = std::vector(numTextObjects, *this);
|
||||
// Clear the text
|
||||
for (auto& text : splitText) {
|
||||
text.Clear();
|
||||
}
|
||||
|
||||
// Split each string into the appropriate number of objects
|
||||
for (size_t textIdx = 0; textIdx < mText.size(); ++textIdx) {
|
||||
auto& textStr = mText[textIdx];
|
||||
auto linesPerBox = LINES_PER_BOX_LATIN;
|
||||
auto linesPerBox = mLinesPerBox;
|
||||
if (textIdx == JAPANESE) {
|
||||
linesPerBox = LINES_PER_BOX_JP;
|
||||
linesPerBox = mLinesPerBoxJP;
|
||||
}
|
||||
// Calculate how many newlines we're allowing in this string per message
|
||||
// Different languages may have different amounts of newlines
|
||||
@@ -154,6 +182,9 @@ const auto kSilverMessageCode = text_color_code(0xBFBFBFFF);
|
||||
size_t splitIdx = 0;
|
||||
do {
|
||||
size_t pos = 0;
|
||||
if (newLinesPerMessage == 0) {
|
||||
pos = std::string::npos;
|
||||
}
|
||||
for (int i = 0; i < newLinesPerMessage; ++i) {
|
||||
pos = textStr.find('\n', pos);
|
||||
if (pos == std::string::npos) {
|
||||
@@ -183,6 +214,16 @@ const auto kSilverMessageCode = text_color_code(0xBFBFBFFF);
|
||||
|
||||
// Reassign the vector everything except the first element
|
||||
splitText.assign(splitText.begin() + 1, splitText.end());
|
||||
|
||||
// Add the split message prefix to every box
|
||||
if (!mSplitMessagePrefix.empty()) {
|
||||
for (auto& textObj : splitText) {
|
||||
for (auto& text : textObj.mText) {
|
||||
text = mSplitMessagePrefix + text;
|
||||
applyMessageCodes(text);
|
||||
}
|
||||
}
|
||||
}
|
||||
return splitText;
|
||||
}
|
||||
|
||||
@@ -331,61 +372,61 @@ const auto kSilverMessageCode = text_color_code(0xBFBFBFFF);
|
||||
return latin1Str;
|
||||
}
|
||||
|
||||
std::string UTF8ToShiftJIS(const std::string& utf8Str) {
|
||||
std::string sjisStr;
|
||||
sjisStr.reserve(utf8Str.length());
|
||||
std::string UTF8ToShiftJIS(const std::string& utf8Str) {
|
||||
std::string sjisStr;
|
||||
sjisStr.reserve(utf8Str.length());
|
||||
|
||||
size_t read_pos = 0;
|
||||
size_t len = utf8Str.length();
|
||||
size_t read_pos = 0;
|
||||
size_t len = utf8Str.length();
|
||||
|
||||
while (read_pos < len) {
|
||||
uint32_t codepoint = 0;
|
||||
unsigned char c = utf8Str[read_pos];
|
||||
while (read_pos < len) {
|
||||
uint32_t codepoint = 0;
|
||||
unsigned char c = utf8Str[read_pos];
|
||||
|
||||
// Decode UTF-8 sequence to Unicode codepoint
|
||||
if (c < 0x80) {
|
||||
codepoint = c;
|
||||
read_pos += 1;
|
||||
} else if ((c & 0xE0) == 0xC0 && (read_pos + 1 < len)) {
|
||||
codepoint = ((c & 0x1F) << 6) | (utf8Str[read_pos + 1] & 0x3F);
|
||||
read_pos += 2;
|
||||
} else if ((c & 0xF0) == 0xE0 && (read_pos + 2 < len)) {
|
||||
codepoint = ((c & 0x0F) << 12) |
|
||||
((utf8Str[read_pos + 1] & 0x3F) << 6) |
|
||||
(utf8Str[read_pos + 2] & 0x3F);
|
||||
read_pos += 3;
|
||||
} else if ((c & 0xF8) == 0xF0 && (read_pos + 3 < len)) {
|
||||
codepoint = ((c & 0x07) << 18) |
|
||||
((utf8Str[read_pos + 1] & 0x3F) << 12) |
|
||||
((utf8Str[read_pos + 2] & 0x3F) << 6) |
|
||||
(utf8Str[read_pos + 3] & 0x3F);
|
||||
read_pos += 4;
|
||||
} else {
|
||||
throw std::runtime_error(fmt::format("Invalid UTF-8 byte sequence in \"{}\"", utf8Str));
|
||||
}
|
||||
|
||||
// Convert Codepoint to Shift-JIS
|
||||
if (codepoint < 0x80) {
|
||||
// Standard ASCII maps directly (Note: 0x5C is '\' in ASCII, '¥' in JIS X 0201)
|
||||
sjisStr.push_back(static_cast<char>(codepoint));
|
||||
} else if (codepoint >= 0xFF61 && codepoint <= 0xFF9F) {
|
||||
// Half-width Katakana (U+FF61 - U+FF9F -> 0xA1 - 0xDF)
|
||||
sjisStr.push_back(static_cast<char>(codepoint - 0xFF61 + 0xA1));
|
||||
} else {
|
||||
// Full-width Kana / Kanji lookup
|
||||
auto it = unicodeToShiftJISMap.find(codepoint);
|
||||
if (it == unicodeToShiftJISMap.end()) {
|
||||
throw std::runtime_error(fmt::format("Codepoint U+{:04X} cannot be represented in Shift-JIS", codepoint));
|
||||
// Decode UTF-8 sequence to Unicode codepoint
|
||||
if (c < 0x80) {
|
||||
codepoint = c;
|
||||
read_pos += 1;
|
||||
} else if ((c & 0xE0) == 0xC0 && (read_pos + 1 < len)) {
|
||||
codepoint = ((c & 0x1F) << 6) | (utf8Str[read_pos + 1] & 0x3F);
|
||||
read_pos += 2;
|
||||
} else if ((c & 0xF0) == 0xE0 && (read_pos + 2 < len)) {
|
||||
codepoint = ((c & 0x0F) << 12) |
|
||||
((utf8Str[read_pos + 1] & 0x3F) << 6) |
|
||||
(utf8Str[read_pos + 2] & 0x3F);
|
||||
read_pos += 3;
|
||||
} else if ((c & 0xF8) == 0xF0 && (read_pos + 3 < len)) {
|
||||
codepoint = ((c & 0x07) << 18) |
|
||||
((utf8Str[read_pos + 1] & 0x3F) << 12) |
|
||||
((utf8Str[read_pos + 2] & 0x3F) << 6) |
|
||||
(utf8Str[read_pos + 3] & 0x3F);
|
||||
read_pos += 4;
|
||||
} else {
|
||||
throw std::runtime_error(fmt::format("Invalid UTF-8 byte sequence in \"{}\"", utf8Str));
|
||||
}
|
||||
|
||||
uint16_t sjisVal = it->second;
|
||||
sjisStr.push_back(static_cast<char>((sjisVal >> 8) & 0xFF)); // Lead byte
|
||||
sjisStr.push_back(static_cast<char>(sjisVal & 0xFF)); // Trail byte
|
||||
}
|
||||
}
|
||||
// Convert Codepoint to Shift-JIS
|
||||
if (codepoint < 0x80) {
|
||||
// Standard ASCII maps directly (Note: 0x5C is '\' in ASCII, '¥' in JIS X 0201)
|
||||
sjisStr.push_back(static_cast<char>(codepoint));
|
||||
} else if (codepoint >= 0xFF61 && codepoint <= 0xFF9F) {
|
||||
// Half-width Katakana (U+FF61 - U+FF9F -> 0xA1 - 0xDF)
|
||||
sjisStr.push_back(static_cast<char>(codepoint - 0xFF61 + 0xA1));
|
||||
} else {
|
||||
// Full-width Kana / Kanji lookup
|
||||
auto it = unicodeToShiftJISMap.find(codepoint);
|
||||
if (it == unicodeToShiftJISMap.end()) {
|
||||
throw std::runtime_error(fmt::format("Codepoint U+{:04X} cannot be represented in Shift-JIS", codepoint));
|
||||
}
|
||||
|
||||
return sjisStr;
|
||||
}
|
||||
uint16_t sjisVal = it->second;
|
||||
sjisStr.push_back(static_cast<char>((sjisVal >> 8) & 0xFF)); // Lead byte
|
||||
sjisStr.push_back(static_cast<char>(sjisVal & 0xFF)); // Trail byte
|
||||
}
|
||||
}
|
||||
|
||||
return sjisStr;
|
||||
}
|
||||
|
||||
static void LoadTextData(TextDatabase& tb) {
|
||||
struct LanguageEntry {
|
||||
@@ -527,6 +568,8 @@ std::string UTF8ToShiftJIS(const std::string& utf8Str) {
|
||||
{"<dark green>", kDarkGreenMessageCode},
|
||||
{"<blue>", kBlueMessageCode},
|
||||
{"<silver>", kSilverMessageCode},
|
||||
// TODO: Custom font sizes
|
||||
{"<font size 48>", "\x1A\x07\xFF\x00\x01\x00\x48"sv},
|
||||
};
|
||||
|
||||
void breakLines(std::string& str, float maxStrLength, int lang) {
|
||||
|
||||
@@ -73,6 +73,11 @@ namespace randomizer {
|
||||
std::array<std::string, LANGUAGE_MAX> mText{};
|
||||
std::array<Gender, LANGUAGE_MAX> mGender{};
|
||||
std::array<Plurality, LANGUAGE_MAX> mPlurality{};
|
||||
float mLineWidth = MAX_LINE_WIDTH_NORMAL_TEXTBOX;
|
||||
size_t mNewLinesPerMessage = MAX_NEWLINES_PER_MESSAGE;
|
||||
size_t mLinesPerBox = LINES_PER_BOX_LATIN;
|
||||
size_t mLinesPerBoxJP = LINES_PER_BOX_JP;
|
||||
std::string mSplitMessagePrefix{};
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -82,6 +87,9 @@ namespace randomizer {
|
||||
*/
|
||||
void Replace(const std::string& oldText, const Text& replacementText, uint32_t count = std::numeric_limits<uint32_t>::max());
|
||||
void Replace(const std::string& oldText, const std::string& replacementText, uint32_t count = std::numeric_limits<uint32_t>::max());
|
||||
void Replace(const Text& oldText, const std::string& replacementText, uint32_t count = std::numeric_limits<uint32_t>::max());
|
||||
void PopBack();
|
||||
void Clear();
|
||||
void BreakLines(float maxLineWidth = MAX_LINE_WIDTH_NORMAL_TEXTBOX);
|
||||
|
||||
// Inserts newlines to pad the text to the next box
|
||||
|
||||
@@ -954,6 +954,9 @@ ModResult buildHintsTab(ModContext* ctx, UiWindowHandle, UiElementHandle leftPan
|
||||
add_select_setting(leftPane, "Location Hints on Hint Signs");
|
||||
add_select_setting(leftPane, "Prioritize Remote Location Hints");
|
||||
|
||||
add_section(leftPane, "Miscellaneous Hints");
|
||||
add_select_setting(leftPane, "Agitha Hints");
|
||||
|
||||
return MOD_OK;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user