mirror of
https://github.com/TwilitRealm/dusklight
synced 2026-06-12 04:57:06 -04:00
implement custom item text
This commit is contained in:
@@ -1521,6 +1521,8 @@ set(DUSK_FILES
|
||||
# Randomizer files
|
||||
src/dusk/randomizer/game/flags.cpp
|
||||
src/dusk/randomizer/game/flags.h
|
||||
src/dusk/randomizer/game/messages.cpp
|
||||
src/dusk/randomizer/game/messages.hpp
|
||||
src/dusk/randomizer/game/stages.cpp
|
||||
src/dusk/randomizer/game/stages.h
|
||||
src/dusk/randomizer/game/tools.cpp
|
||||
|
||||
@@ -7,6 +7,10 @@
|
||||
|
||||
#include "JSystem/JMessage/control.h"
|
||||
|
||||
#if TARGET_PC
|
||||
#include "dusk/randomizer/game/messages.hpp"
|
||||
#endif
|
||||
|
||||
JMessage::TControl::TControl()
|
||||
: pSequenceProcessor_(NULL),
|
||||
pRenderingProcessor_(NULL),
|
||||
@@ -90,6 +94,10 @@ bool JMessage::TControl::setMessageCode_inSequence_(JMessage::TProcessor const*
|
||||
JUT_ASSERT(155, pResourceCache_!=NULL);
|
||||
|
||||
pMessageText_begin_ = pResourceCache_->getMessageText_messageEntry(pEntry_);
|
||||
#if TARGET_PC
|
||||
// Feels kinda hacky to have to hijack this deep into JSystem, but works for now
|
||||
HandleTextOverrides(this, pProcessor, uMessageGroupID_, uMessageID_);
|
||||
#endif
|
||||
pMessageText_current_ = pMessageText_begin_;
|
||||
oStack_renderingProcessor_.clear();
|
||||
return true;
|
||||
|
||||
+16
-4
@@ -213,12 +213,18 @@ static bool isOutfontKanjiCode(int iCharacter) {
|
||||
}
|
||||
|
||||
static u32 getFontCCColorTable(u8 i_colorNo, u8 i_fukiKind) {
|
||||
static const u32 colorTable[9] = {
|
||||
static const u32 colorTable[DUSK_IF_ELSE(12, 9)] = {
|
||||
0xFFFFFFFF, 0xF07878FF, 0xAADC8CFF, 0xA0B4DCFF, 0xDCDC82FF,
|
||||
0xB4C8E6FF, 0xC8A0DCFF, 0xFFFFFFFF, 0xDCAA78FF,
|
||||
#if TARGET_PC
|
||||
// Extra text colors for randomizer
|
||||
0x4BBE4BFF, // Dark Green
|
||||
0x4B96D7FF, // Blue
|
||||
0xBFBFBFFF, // Silver
|
||||
#endif
|
||||
};
|
||||
|
||||
if (i_colorNo > 8) {
|
||||
if (i_colorNo > DUSK_IF_ELSE(11, 8)) {
|
||||
return 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
@@ -247,12 +253,18 @@ static u32 getFontCCColorTable(u8 i_colorNo, u8 i_fukiKind) {
|
||||
}
|
||||
|
||||
static u32 getFontGCColorTable(u8 i_colorNo, u8 i_fukiKind) {
|
||||
static const u32 colorTable[9] = {
|
||||
static const u32 colorTable[DUSK_IF_ELSE(12, 9)] = {
|
||||
0xFFFFFFFF, 0xF07878FF, 0xAADC8CFF, 0xA0B4DCFF, 0xDCDC82FF,
|
||||
0xB4C8E6FF, 0xC8A0DCFF, 0xFFFFFFFF, 0xDCAA78FF,
|
||||
#if TARGET_PC
|
||||
// Extra text colors for randomizer
|
||||
0x4BBE4BFF, // Dark Green
|
||||
0x4B96D7FF, // Blue
|
||||
0xBFBFBFFF, // Silver
|
||||
#endif
|
||||
};
|
||||
|
||||
if (i_colorNo > 8) {
|
||||
if (i_colorNo > DUSK_IF_ELSE(11, 8)) {
|
||||
return 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
|
||||
@@ -523,7 +523,8 @@ int dMsgFlow_c::setNormalMsg(mesg_flow_node* i_flowNode_p, fopAc_ac_c* i_speaker
|
||||
if (flowItemOverrides.contains(key)) {
|
||||
u8 itemId = verifyProgressiveItem(flowItemOverrides[key]);
|
||||
msg_no = getItemMessageID(itemId);
|
||||
execItemGet(itemId);
|
||||
// Store this itemId so that we can give the item when the textbox closes
|
||||
g_randomizerState.mFlowMessageItemId = itemId;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
+14
-4
@@ -697,13 +697,14 @@ u32 dMsgObject_c::getMessageIndex(u32 param_0) {
|
||||
u32 dMsgObject_c::getRevoMessageIndex(u32 param_1) {
|
||||
#if TARGET_PC
|
||||
if (randomizer_IsActive()) {
|
||||
// Special case for Ilia Memory Reward Text
|
||||
// Special case for Ilia Memory Reward Text (param_1 is msgId)
|
||||
// If we're in the sanctuary cutscene where we get the reward, override the text.
|
||||
// Otherwise we override the text whenever we get the regular horse call
|
||||
// Otherwise the regular item text for the horse call would be overriden if we find it
|
||||
if (param_1 == 233 && playerIsInRoomStage(0, "R_SP109") && dComIfGp_getLayerNo() == 9) {
|
||||
u8 itemId = verifyProgressiveItem(randomizer_getItemAtLocation("Ilia Memory Reward"));
|
||||
param_1 = getItemMessageID(itemId);
|
||||
execItemGet(itemId);
|
||||
// Store this itemId so that we can give the item when the textbox closes
|
||||
g_randomizerState.mFlowMessageItemId = itemId;
|
||||
} else {
|
||||
// Else override the text if we have an override
|
||||
u32 key = (dMsgObject_getGroupID() << 16) | param_1;
|
||||
@@ -711,7 +712,8 @@ u32 dMsgObject_c::getRevoMessageIndex(u32 param_1) {
|
||||
if (flowItemOverrides.contains(key)) {
|
||||
u8 itemId = verifyProgressiveItem(flowItemOverrides[key]);
|
||||
param_1 = getItemMessageID(itemId);
|
||||
execItemGet(itemId);
|
||||
// Store this itemId so that we can give the item when the textbox closes
|
||||
g_randomizerState.mFlowMessageItemId = itemId;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -814,6 +816,14 @@ void dMsgObject_c::waitProc() {
|
||||
}
|
||||
}
|
||||
}
|
||||
#if TARGET_PC
|
||||
// If we have a randomizer item to give because of a flow message override
|
||||
// then give it if the textbox has been fully closed.
|
||||
if (randomizer_IsActive() && g_randomizerState.mFlowMessageItemId != 0 && mpScrnDraw == NULL) {
|
||||
execItemGet(g_randomizerState.mFlowMessageItemId);
|
||||
g_randomizerState.mFlowMessageItemId = 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void dMsgObject_c::openProc() {
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
#include "messages.hpp"
|
||||
|
||||
#include "JSystem/JMessage/control.h"
|
||||
#include "d/d_msg_class.h"
|
||||
#include "randomizer_context.hpp"
|
||||
|
||||
#include <format>
|
||||
|
||||
// Format certain messages that need to have dynamic info in them
|
||||
const char* GetFormatedTextOverride(u32 key, const std::string& text) {
|
||||
// Store formatted message in static buffer so it never goes away.
|
||||
// This is fine as long as we only ever need to format messages
|
||||
// for textboxes, but will cause issues if we need to use it for
|
||||
// other UI elements
|
||||
static std::array<char, 256> buf;
|
||||
u32 value{};
|
||||
char* outIt;
|
||||
// For item counts, execItemGet hasn't run yet, so add one to the count
|
||||
switch (key) {
|
||||
case (0 << 16) | 325: // Group 0, id 325
|
||||
// Poe Soul get item text
|
||||
value = dComIfGs_getPohSpiritNum() + 1;
|
||||
outIt = std::vformat_to(buf.data(), text, std::make_format_args(value));
|
||||
break;
|
||||
case (0 << 16) | 335: // Group 0, id 335
|
||||
// Sky book characters get item text
|
||||
value = dComIfGs_getAncientDocumentNum() + 1;
|
||||
outIt = std::vformat_to(buf.data(), text, std::make_format_args(value));
|
||||
break;
|
||||
default:
|
||||
// No override, return original text
|
||||
return text.data();
|
||||
}
|
||||
|
||||
// Null-terminate
|
||||
size_t len = std::distance(buf.data(), outIt);
|
||||
buf[len] = '\0';
|
||||
|
||||
// Return overriden text
|
||||
return buf.data();
|
||||
}
|
||||
|
||||
void HandleTextOverrides(JMessage::TControl* control, JMessage::TProcessor const* pProcessor, int groupID, int index) {
|
||||
if (randomizer_IsActive()) {
|
||||
// Get the entry for this message
|
||||
auto entry = static_cast<JMSMesgEntry_c*>(pProcessor->getMessageEntry_messageCode(groupID, index));
|
||||
if (!entry) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If the message id is >= 5000 then it's part of the stage file's message group
|
||||
// Otherwise it's part of group 0
|
||||
auto msgId = entry->message_id.host();
|
||||
u16 group = 0;
|
||||
if (msgId >= 5000) {
|
||||
group = dComIfGp_getStageStagInfo()->mMsgGroup;
|
||||
}
|
||||
|
||||
u32 key = (group << 16) | msgId;
|
||||
auto& textOverrides = randomizer_GetContext().mTextOverrides;
|
||||
if (textOverrides.contains(key)) {
|
||||
control->pMessageText_begin_ = GetFormatedTextOverride(key, textOverrides[key]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
// Forward declaration
|
||||
namespace JMessage {
|
||||
struct TProcessor;
|
||||
struct TControl;
|
||||
}
|
||||
|
||||
void HandleTextOverrides(JMessage::TControl* control, JMessage::TProcessor const* pProcessor, int groupID, int index);
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "dusk/randomizer/generator/utility/endian.hpp"
|
||||
#include "dusk/randomizer/generator/utility/yaml.hpp"
|
||||
#include "dusk/randomizer/generator/randomizer.hpp"
|
||||
#include "dusk/randomizer/generator/utility/text.hpp"
|
||||
|
||||
#include "SDL3/SDL_filesystem.h"
|
||||
#include <zlib-ng.h>
|
||||
@@ -93,7 +94,20 @@ std::optional<std::string> RandomizerContext::WriteToFile() {
|
||||
|
||||
out["mFlowPatches"] = this->mFlowPatches;
|
||||
|
||||
// Dump text overrides as binary to avoid losing intentional null characters
|
||||
YAML::Emitter textData;
|
||||
textData << YAML::BeginMap;
|
||||
textData << YAML::Key << "mTextOverrides";
|
||||
textData << YAML::BeginMap;
|
||||
for (const auto& [key, text] : this->mTextOverrides) {
|
||||
textData << YAML::Key << key;
|
||||
textData << YAML::Value << YAML::Binary(reinterpret_cast<const unsigned char*>(text.data()), text.size());
|
||||
}
|
||||
textData << YAML::EndMap;
|
||||
textData << YAML::EndMap;
|
||||
|
||||
seedData << YAML::Dump(out);
|
||||
seedData << '\n' << textData.c_str();
|
||||
seedData.close();
|
||||
|
||||
return std::nullopt;
|
||||
@@ -227,6 +241,14 @@ std::optional<std::string> RandomizerContext::LoadFromHash(const std::string& ha
|
||||
this->mFlowPatches[key] = value;
|
||||
}
|
||||
|
||||
// Text Overrides
|
||||
for (const auto& textNode: in["mTextOverrides"]) {
|
||||
auto key = textNode.first.as<u32>();
|
||||
auto binary = textNode.second.as<YAML::Binary>();
|
||||
std::string text(reinterpret_cast<const char*>(binary.data()), binary.size());
|
||||
this->mTextOverrides[key] = std::move(text);
|
||||
}
|
||||
|
||||
DuskLog.debug("Loaded Randomizer Seed {}", this->mHash);
|
||||
|
||||
return std::nullopt;
|
||||
@@ -1055,6 +1077,20 @@ RandomizerContext WriteSeedData(const std::unique_ptr<randomizer::logic::world::
|
||||
}
|
||||
}
|
||||
|
||||
// Text Overrides
|
||||
auto textOverrides = LoadYAML(RANDO_DATA_PATH "text/text_overrides.yaml");
|
||||
for (const auto& overrideNode : textOverrides) {
|
||||
const auto& name = overrideNode["Name"].as<std::string>();
|
||||
// TODO: Handle multiple languages
|
||||
auto language = randomizer::Text::ENGLISH;
|
||||
auto text = randomizer::getTextStr(name);
|
||||
u8 group = overrideNode["Group"].as<u8>();
|
||||
u16 messageId = overrideNode["Message Id"].as<u16>();
|
||||
u32 key = (group << 16) | messageId;
|
||||
randomizer::applyMessageCodes(text);
|
||||
randoData.mTextOverrides[key] = text;
|
||||
}
|
||||
|
||||
return std::move(randoData);
|
||||
}
|
||||
|
||||
|
||||
@@ -46,6 +46,12 @@ public:
|
||||
std::unordered_map<u32, std::unordered_map<u32, std::list<std::array<u8, 30>>>> mActorAdditions{};
|
||||
std::unordered_map<u32, u64> mFlowPatches{};
|
||||
|
||||
// struct TextOverride {
|
||||
// std::array<u8, 16> mAttributes{};
|
||||
// std::string mText{};
|
||||
// };
|
||||
std::unordered_map<u32, std::string> mTextOverrides{};
|
||||
|
||||
std::optional<std::string> WriteToFile();
|
||||
std::optional<std::string> LoadFromHash(const std::string& hash);
|
||||
std::string GetSeedDataPath() const;
|
||||
@@ -133,6 +139,12 @@ public:
|
||||
u8 mTimeChange{};
|
||||
u8 mEventItemQueue[EVENT_ITEM_QUEUE_SIZE];
|
||||
bool mRoomReloadingState{false};
|
||||
|
||||
// Used to store an item id for a flow message override so that we can give the item
|
||||
// once the textbox is closed instead of when the message appears. This lines up
|
||||
// more naturally with how the timing of how the game normally gives items and affects
|
||||
// things like the sound of the rupee counter going up.
|
||||
u8 mFlowMessageItemId{0};
|
||||
};
|
||||
|
||||
extern RandomizerState g_randomizerState;
|
||||
|
||||
@@ -106,6 +106,10 @@
|
||||
Importance: Junk
|
||||
Id: 0x18
|
||||
|
||||
#- Name: Water Bombs 3
|
||||
# Importance: Junk
|
||||
# Id: 0x19
|
||||
|
||||
- Name: Bomblings 5
|
||||
Importance: Junk
|
||||
Id: 0x1A
|
||||
|
||||
@@ -0,0 +1,325 @@
|
||||
Shadow Crystal Get Item Text:
|
||||
Standard:
|
||||
Text: |-
|
||||
<slow>You got the <red>Shadow Crystal<white>!
|
||||
This is a dark manifestation
|
||||
of <red>Zant's<white> power that allows
|
||||
you to transform at will!
|
||||
|
||||
Restored Dominion Rod Text:
|
||||
Standard:
|
||||
Text: |-
|
||||
<fast>Power has been restored to
|
||||
the <red>Dominion Rod<white>! Now it can
|
||||
be used to imbue statues
|
||||
with life in the present!
|
||||
|
||||
Forest Temple Small Key Get Item Text:
|
||||
Standard:
|
||||
Text: |-
|
||||
<fast>You got a <red>Small Key<white> for the
|
||||
<green>Forest Temple<white>!
|
||||
|
||||
Goron Mines Small Key Get Item Text:
|
||||
Standard:
|
||||
Text: |-
|
||||
<fast>You got a <red>Small Key<white> for
|
||||
<red>Goron Mines<white>!
|
||||
|
||||
Lakebed Temple Small Key Get Item Text:
|
||||
Standard:
|
||||
Text: |-
|
||||
<fast>You got a <red>Small Key<white> for the
|
||||
<blue>Lakebed Temple<white>!
|
||||
|
||||
Arbiters Grounds Small Key Get Item Text:
|
||||
Standard:
|
||||
Text: |-
|
||||
<fast>You got a <red>Small Key<white> for
|
||||
<orange>Arbiter's Grounds<white>!
|
||||
|
||||
Snowpeak Ruins Small Key Get Item Text:
|
||||
Standard:
|
||||
Text: |-
|
||||
<fast>You got a <red>Small Key<white> for
|
||||
<light blue>Snowpeak Ruins<white>!
|
||||
|
||||
Temple of Time Small Key Get Item Text:
|
||||
Standard:
|
||||
Text: |-
|
||||
<fast>You got a <red>Small Key<white> for the
|
||||
<dark green>Temple of Time<white>!
|
||||
|
||||
City in the Sky Small Key Get Item Text:
|
||||
Standard:
|
||||
Text: |-
|
||||
<fast>You got a <red>Small Key<white> for the
|
||||
<yellow>City in the Sky<white>!
|
||||
|
||||
Palace of Twilight Small Key Get Item Text:
|
||||
Standard:
|
||||
Text: |-
|
||||
<fast>You got a <red>Small Key<white> for the
|
||||
<purple>Palace of Twilight<white>!
|
||||
|
||||
Hyrule Castle Small Key Get Item Text:
|
||||
Standard:
|
||||
Text: |-
|
||||
<fast>You got a <red>Small Key<white> for
|
||||
<silver>Hyrule Castle<white>!
|
||||
|
||||
Bulblin Camp Small Key Get Item Text:
|
||||
Standard:
|
||||
Text: |-
|
||||
<fast>You got a <red>Small Key<white> for the
|
||||
<orange>Bulblin Camp<white>!
|
||||
|
||||
Forest Temple Big Key Get Item Text:
|
||||
Standard:
|
||||
Text: |-
|
||||
<fast>You got the <red>Big Key<white> for the
|
||||
<green>Forest Temple<white>!
|
||||
|
||||
Lakebed Temple Big Key Get Item Text:
|
||||
Standard:
|
||||
Text: |-
|
||||
<fast>You got the <red>Big Key<white> for the
|
||||
<blue>Lakebed Temple<white>!
|
||||
|
||||
Arbiters Grounds Big Key Get Item Text:
|
||||
Standard:
|
||||
Text: |-
|
||||
<fast>You got the <red>Big Key<white> for
|
||||
<orange>Arbiter's Grounds<white>!
|
||||
|
||||
Temple of Time Big Key Get Item Text:
|
||||
Standard:
|
||||
Text: |-
|
||||
<fast>You got the <red>Big Key<white> for the
|
||||
<dark green>Temple of Time<white>!
|
||||
|
||||
City in the Sky Big Key Get Item Text:
|
||||
Standard:
|
||||
Text: |-
|
||||
<fast>You got the <red>Big Key<white> for the
|
||||
<yellow>City in the Sky<white>!
|
||||
|
||||
Palace of Twilight Big Key Get Item Text:
|
||||
Standard:
|
||||
Text: |-
|
||||
<fast>You got the <red>Big Key<white> for the
|
||||
<purple>Palace of Twilight<white>!
|
||||
|
||||
Hyrule Castle Big Key Get Item Text:
|
||||
Standard:
|
||||
Text: |-
|
||||
<fast>You got the <red>Big Key<white> for
|
||||
<silver>Hyrule Castle<white>!
|
||||
|
||||
Forest Temple Compass Get Item Text:
|
||||
Standard:
|
||||
Text: |-
|
||||
<fast>You got the <red>Compass<white> for the
|
||||
<green>Forest Temple<white>!
|
||||
|
||||
Goron Mines Compass Get Item Text:
|
||||
Standard:
|
||||
Text: |-
|
||||
<fast>You got the <red>Compass<white> for
|
||||
<red>Goron Mines<white>!
|
||||
|
||||
Lakebed Temple Compass Get Item Text:
|
||||
Standard:
|
||||
Text: |-
|
||||
<fast>You got the <red>Compass<white> for the
|
||||
<blue>Lakebed Temple<white>!
|
||||
|
||||
Mirror Shard 2 Get item Text:
|
||||
Standard:
|
||||
Text: |-
|
||||
<fast>You got the second shard of
|
||||
the <red>Mirror of Twilight<white>! It
|
||||
has a beautiful shine to it
|
||||
and feels slightly <light blue>cold<white>...
|
||||
|
||||
Mirror Shard 3 Get item Text:
|
||||
Standard:
|
||||
Text: |-
|
||||
<fast>You got the third shard of
|
||||
the <red>Mirror of Twilight<white>! It
|
||||
is covered in dirt and
|
||||
<dark green>webs<white>...
|
||||
|
||||
Mirror Shard 4 Get item Text:
|
||||
Standard:
|
||||
Text: |-
|
||||
<fast>You got the final shard of
|
||||
the <red>Mirror of Twilight<white>! It
|
||||
feels lighter than <yellow>air<white>...
|
||||
|
||||
Arbiters Grounds Compass Get Item Text:
|
||||
Standard:
|
||||
Text: |-
|
||||
<fast>You got the <red>Compass<white> for
|
||||
<orange>Arbiter's Grounds<white>!
|
||||
|
||||
Snowpeak Ruins Compass Get Item Text:
|
||||
Standard:
|
||||
Text: |-
|
||||
<fast>You got the <red>Compass<white> for
|
||||
<light blue>Snowpeak Ruins<white>!
|
||||
|
||||
Temple of Time Compass Get Item Text:
|
||||
Standard:
|
||||
Text: |-
|
||||
<fast>You got the <red>Compass<white> for the
|
||||
<dark green>Temple of Time<white>!
|
||||
|
||||
City in the Sky Compass Get Item Text:
|
||||
Standard:
|
||||
Text: |-
|
||||
<fast>You got the <red>Compass<white> for the
|
||||
<yellow>City in the Sky<white>!
|
||||
|
||||
Palace of Twilight Compass Get Item Text:
|
||||
Standard:
|
||||
Text: |-
|
||||
<fast>You got the <red>Compass<white> for the
|
||||
<purple>Palace of Twilight<white>!
|
||||
|
||||
Hyrule Castle Compass Get Item Text:
|
||||
Standard:
|
||||
Text: |-
|
||||
<fast>You got the <red>Compass<white> for
|
||||
<silver>Hyrule Castle<white>!
|
||||
<fast>
|
||||
#
|
||||
Forest Temple Dungeon Map Get Item Text:
|
||||
Standard:
|
||||
Text: |-
|
||||
<fast>You got the <red>Dungeon Map<white> for the
|
||||
<green>Forest Temple<white>!
|
||||
|
||||
Goron Mines Dungeon Map Get Item Text:
|
||||
Standard:
|
||||
Text: |-
|
||||
<fast>You got the <red>Dungeon Map<white> for
|
||||
<red>Goron Mines<white>!
|
||||
|
||||
Lakebed Temple Dungeon Map Get Item Text:
|
||||
Standard:
|
||||
Text: |-
|
||||
<fast>You got the <red>Dungeon Map<white> for the
|
||||
<blue>Lakebed Temple<white>!
|
||||
|
||||
Snowpeak Ruins Dungeon Map Get Item Text:
|
||||
Standard:
|
||||
Text: |-
|
||||
<fast>You got the <red>Dungeon Map<white> for
|
||||
<light blue>Snowpeak Ruins<white>!
|
||||
|
||||
Arbiters Grounds Dungeon Map Get Item Text:
|
||||
Standard:
|
||||
Text: |-
|
||||
<fast>You got the <red>Dungeon Map<white> for
|
||||
<orange>Arbiter's Grounds<white>!
|
||||
|
||||
Temple of Time Dungeon Map Get Item Text:
|
||||
Standard:
|
||||
Text: |-
|
||||
<fast>You got the <red>Dungeon Map<white> for the
|
||||
<dark green>Temple of Time<white>!
|
||||
|
||||
City in the Sky Dungeon Map Get Item Text:
|
||||
Standard:
|
||||
Text: |-
|
||||
<fast>You got the <red>Dungeon Map<white> for the
|
||||
<yellow>City in the Sky<white>!
|
||||
|
||||
Palace of Twilight Dungeon Map Get Item Text:
|
||||
Standard:
|
||||
Text: |-
|
||||
<fast>You got the <red>Dungeon Map<white> for the
|
||||
<purple>Palace of Twilight<white>!
|
||||
|
||||
Hyrule Castle Dungeon Map Get Item Text:
|
||||
Standard:
|
||||
Text: |-
|
||||
<fast>You got the <red>Dungeon Map<white> for
|
||||
<silver>Hyrule Castle<white>!
|
||||
<fast>
|
||||
|
||||
Fused Shadow 1 Get Item Text:
|
||||
Standard:
|
||||
Text: |-
|
||||
<fast>You got a <red>Fused Shadow<white>!
|
||||
It seems to have some <green>moss<white>
|
||||
growing on it...
|
||||
|
||||
Fused Shadow 2 Get Item Text:
|
||||
Standard:
|
||||
Text: |-
|
||||
<fast>You got the second <red>Fused
|
||||
Shadow<white>! It feels <red>warm<white> to
|
||||
the touch...
|
||||
|
||||
Fused Shadow 3 Get Item Text:
|
||||
Standard:
|
||||
Text: |-
|
||||
<fast>You got the final <red>Fused
|
||||
Shadow<white>! It feels <blue>wet<white> and
|
||||
smells like fish...
|
||||
|
||||
Mirror Shard 1 Get Item Text:
|
||||
Standard:
|
||||
Text: |-
|
||||
<fast>You got the first shard of
|
||||
the <red>Mirror of Twilight<white>! It
|
||||
is covered in <orange>sand<white>...
|
||||
|
||||
Poe Soul Get Item Text:
|
||||
Standard:
|
||||
Text: |-
|
||||
<fast>You got a <red>Poe's Soul<white>!
|
||||
You've collected <red>{}<white> so far.
|
||||
|
||||
Ending Blow Get Item Text:
|
||||
Standard:
|
||||
Text: |-
|
||||
<fast>You learned the <red>Ending Blow<white>!
|
||||
|
||||
Shield Attack Get Item Text:
|
||||
Standard:
|
||||
Text: |-
|
||||
<fast>You learned the <red>Shield Attack<white>!
|
||||
|
||||
Back Slice Get Item Text:
|
||||
Standard:
|
||||
Text: |-
|
||||
<fast>You learned the <red>Back Slice<white>!
|
||||
|
||||
Helm Splitter Get Item Text:
|
||||
Standard:
|
||||
Text: |-
|
||||
<fast>You learned the <red>Helm Splitter<white>!
|
||||
|
||||
Mortal Draw Get Item Text:
|
||||
Standard:
|
||||
Text: |-
|
||||
<fast>You learned the <red>Mortal Draw<white>!
|
||||
|
||||
Jump Strike Get Item Text:
|
||||
Standard:
|
||||
Text: |-
|
||||
<fast>You learned the <red>Jump Strike<white>!
|
||||
|
||||
Great Spin Get Item Text:
|
||||
Standard:
|
||||
Text: |-
|
||||
<fast>You learned the <red>Great Spin<white>!
|
||||
|
||||
Partially Filled Sky Book Get Item Text:
|
||||
Standard:
|
||||
Text: |-
|
||||
<fast>You got a <red>Sky Character<white>!
|
||||
You've collected <red>{}<white> so far.
|
||||
@@ -0,0 +1,223 @@
|
||||
#- Name: Foolish Get Item Text
|
||||
# Group: 0
|
||||
# Message Id: 120
|
||||
#
|
||||
#- Name: Ordon Spring Portal Get Item Text
|
||||
# Group: 0
|
||||
# Message Id: 121
|
||||
#
|
||||
#- Name: South Faron Portal Get Item Text
|
||||
# Group: 0
|
||||
# Message Id: 122
|
||||
|
||||
- Name: Shadow Crystal Get Item Text
|
||||
Group: 0
|
||||
Message Id: 151
|
||||
|
||||
- Name: Restored Dominion Rod Text
|
||||
Group: 0
|
||||
Message Id: 177
|
||||
|
||||
- Name: Forest Temple Small Key Get Item Text
|
||||
Group: 0
|
||||
Message Id: 234
|
||||
|
||||
- Name: Goron Mines Small Key Get Item Text
|
||||
Group: 0
|
||||
Message Id: 235
|
||||
|
||||
- Name: Lakebed Temple Small Key Get Item Text
|
||||
Group: 0
|
||||
Message Id: 236
|
||||
|
||||
- Name: Arbiters Grounds Small Key Get Item Text
|
||||
Group: 0
|
||||
Message Id: 237
|
||||
|
||||
- Name: Snowpeak Ruins Small Key Get Item Text
|
||||
Group: 0
|
||||
Message Id: 238
|
||||
|
||||
- Name: Temple of Time Small Key Get Item Text
|
||||
Group: 0
|
||||
Message Id: 239
|
||||
|
||||
- Name: City in the Sky Small Key Get Item Text
|
||||
Group: 0
|
||||
Message Id: 240
|
||||
|
||||
- Name: Palace of Twilight Small Key Get Item Text
|
||||
Group: 0
|
||||
Message Id: 241
|
||||
|
||||
- Name: Hyrule Castle Small Key Get Item Text
|
||||
Group: 0
|
||||
Message Id: 242
|
||||
|
||||
- Name: Bulblin Camp Small Key Get Item Text
|
||||
Group: 0
|
||||
Message Id: 243
|
||||
|
||||
- Name: Forest Temple Big Key Get Item Text
|
||||
Group: 0
|
||||
Message Id: 247
|
||||
|
||||
- Name: Lakebed Temple Big Key Get Item Text
|
||||
Group: 0
|
||||
Message Id: 248
|
||||
|
||||
- Name: Arbiters Grounds Big Key Get Item Text
|
||||
Group: 0
|
||||
Message Id: 249
|
||||
|
||||
- Name: Temple of Time Big Key Get Item Text
|
||||
Group: 0
|
||||
Message Id: 250
|
||||
|
||||
- Name: City in the Sky Big Key Get Item Text
|
||||
Group: 0
|
||||
Message Id: 251
|
||||
|
||||
- Name: Palace of Twilight Big Key Get Item Text
|
||||
Group: 0
|
||||
Message Id: 252
|
||||
|
||||
- Name: Hyrule Castle Big Key Get Item Text
|
||||
Group: 0
|
||||
Message Id: 253
|
||||
|
||||
- Name: Forest Temple Compass Get Item Text
|
||||
Group: 0
|
||||
Message Id: 254
|
||||
|
||||
- Name: Goron Mines Compass Get Item Text
|
||||
Group: 0
|
||||
Message Id: 255
|
||||
|
||||
- Name: Lakebed Temple Compass Get Item Text
|
||||
Group: 0
|
||||
Message Id: 256
|
||||
|
||||
- Name: Mirror Shard 2 Get item Text
|
||||
Group: 0
|
||||
Message Id: 266
|
||||
|
||||
- Name: Mirror Shard 3 Get item Text
|
||||
Group: 0
|
||||
Message Id: 267
|
||||
|
||||
- Name: Mirror Shard 4 Get item Text
|
||||
Group: 0
|
||||
Message Id: 268
|
||||
|
||||
- Name: Arbiters Grounds Compass Get Item Text
|
||||
Group: 0
|
||||
Message Id: 269
|
||||
|
||||
- Name: Snowpeak Ruins Compass Get Item Text
|
||||
Group: 0
|
||||
Message Id: 270
|
||||
|
||||
- Name: Temple of Time Compass Get Item Text
|
||||
Group: 0
|
||||
Message Id: 271
|
||||
|
||||
- Name: City in the Sky Compass Get Item Text
|
||||
Group: 0
|
||||
Message Id: 272
|
||||
|
||||
- Name: Palace of Twilight Compass Get Item Text
|
||||
Group: 0
|
||||
Message Id: 273
|
||||
|
||||
- Name: Hyrule Castle Compass Get Item Text
|
||||
Group: 0
|
||||
Message Id: 274
|
||||
|
||||
- Name: Forest Temple Dungeon Map Get Item Text
|
||||
Group: 0
|
||||
Message Id: 283
|
||||
|
||||
- Name: Goron Mines Dungeon Map Get Item Text
|
||||
Group: 0
|
||||
Message Id: 284
|
||||
|
||||
- Name: Lakebed Temple Dungeon Map Get Item Text
|
||||
Group: 0
|
||||
Message Id: 285
|
||||
|
||||
- Name: Arbiters Grounds Dungeon Map Get Item Text
|
||||
Group: 0
|
||||
Message Id: 286
|
||||
|
||||
- Name: Snowpeak Ruins Dungeon Map Get Item Text
|
||||
Group: 0
|
||||
Message Id: 287
|
||||
|
||||
- Name: Temple of Time Dungeon Map Get Item Text
|
||||
Group: 0
|
||||
Message Id: 288
|
||||
|
||||
- Name: City in the Sky Dungeon Map Get Item Text
|
||||
Group: 0
|
||||
Message Id: 289
|
||||
|
||||
- Name: Palace of Twilight Dungeon Map Get Item Text
|
||||
Group: 0
|
||||
Message Id: 290
|
||||
|
||||
- Name: Hyrule Castle Dungeon Map Get Item Text
|
||||
Group: 0
|
||||
Message Id: 291
|
||||
|
||||
- Name: Fused Shadow 1 Get Item Text
|
||||
Group: 0
|
||||
Message Id: 317
|
||||
|
||||
- Name: Fused Shadow 2 Get Item Text
|
||||
Group: 0
|
||||
Message Id: 318
|
||||
|
||||
- Name: Fused Shadow 3 Get Item Text
|
||||
Group: 0
|
||||
Message Id: 319
|
||||
|
||||
- Name: Mirror Shard 1 Get Item Text
|
||||
Group: 0
|
||||
Message Id: 320
|
||||
|
||||
- Name: Poe Soul Get Item Text
|
||||
Group: 0
|
||||
Message Id: 325
|
||||
|
||||
- Name: Ending Blow Get Item Text
|
||||
Group: 0
|
||||
Message Id: 326
|
||||
|
||||
- Name: Shield Attack Get Item Text
|
||||
Group: 0
|
||||
Message Id: 327
|
||||
|
||||
- Name: Back Slice Get Item Text
|
||||
Group: 0
|
||||
Message Id: 328
|
||||
|
||||
- Name: Helm Splitter Get Item Text
|
||||
Group: 0
|
||||
Message Id: 329
|
||||
|
||||
- Name: Mortal Draw Get Item Text
|
||||
Group: 0
|
||||
Message Id: 330
|
||||
|
||||
- Name: Jump Strike Get Item Text
|
||||
Group: 0
|
||||
Message Id: 331
|
||||
|
||||
- Name: Great Spin Get Item Text
|
||||
Group: 0
|
||||
Message Id: 332
|
||||
|
||||
- Name: Partially Filled Sky Book Get Item Text
|
||||
Group: 0
|
||||
Message Id: 335
|
||||
@@ -1,178 +1,291 @@
|
||||
// #include "../utility/text.hpp"
|
||||
// #include "../utility/string.hpp"
|
||||
// #include <filetypes/util/msbtMacros.hpp"
|
||||
// #include <command/Log.hpp"
|
||||
#include "text.hpp"
|
||||
|
||||
// #include <unordered_map>
|
||||
#include <unordered_map>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
|
||||
// namespace Text {
|
||||
#include "yaml.hpp"
|
||||
|
||||
// std::array<std::string, 3> supported_languages = {"English", "Spanish", "French"};
|
||||
namespace randomizer {
|
||||
|
||||
// static std::unordered_map<Text::Color, std::u16string> nameToColor = {
|
||||
// {Text::Color::NONE, TEXT_COLOR_DEFAULT},
|
||||
// {Text::Color::RED, TEXT_COLOR_RED},
|
||||
// {Text::Color::GREEN, TEXT_COLOR_GREEN},
|
||||
// {Text::Color::BLUE, TEXT_COLOR_BLUE},
|
||||
// {Text::Color::YELLOW, TEXT_COLOR_YELLOW},
|
||||
// {Text::Color::CYAN, TEXT_COLOR_CYAN},
|
||||
// {Text::Color::MAGENTA, TEXT_COLOR_MAGENTA},
|
||||
// {Text::Color::GRAY, TEXT_COLOR_GRAY},
|
||||
// {Text::Color::ORANGE, TEXT_COLOR_ORANGE},
|
||||
// };
|
||||
// std::array<std::string, 3> supported_languages = {"English", "Spanish", "French"};
|
||||
//
|
||||
// static std::unordered_map<Text::Color, std::u16string> nameToColor = {
|
||||
// {Text::Color::NONE, TEXT_COLOR_DEFAULT},
|
||||
// {Text::Color::RED, TEXT_COLOR_RED},
|
||||
// {Text::Color::GREEN, TEXT_COLOR_GREEN},
|
||||
// {Text::Color::BLUE, TEXT_COLOR_BLUE},
|
||||
// {Text::Color::YELLOW, TEXT_COLOR_YELLOW},
|
||||
// {Text::Color::CYAN, TEXT_COLOR_CYAN},
|
||||
// {Text::Color::MAGENTA, TEXT_COLOR_MAGENTA},
|
||||
// {Text::Color::GRAY, TEXT_COLOR_GRAY},
|
||||
// {Text::Color::ORANGE, TEXT_COLOR_ORANGE},
|
||||
// };
|
||||
//
|
||||
// std::u16string apply_name_color(std::u16string str, const Color& color)
|
||||
// {
|
||||
// // Return the raw text (bars included)
|
||||
// if (color == Color::RAW)
|
||||
// {
|
||||
// return str;
|
||||
// }
|
||||
// // If there are no '|'s then just return with the color surrounding the whole string
|
||||
// if (str.find('|') == std::string::npos)
|
||||
// {
|
||||
// auto textColor = nameToColor[color];
|
||||
// return textColor + str + TEXT_COLOR_DEFAULT;
|
||||
// }
|
||||
//
|
||||
// // Alternate between the text color and default incase there are multiple
|
||||
// // pairs of bars
|
||||
// auto textColor = nameToColor[color];
|
||||
// bool insertColor = false;
|
||||
// for (size_t pos = 0; pos < str.length(); pos++)
|
||||
// {
|
||||
// if (str[pos] == '|')
|
||||
// {
|
||||
// insertColor = !insertColor;
|
||||
// str.erase(pos, 1);
|
||||
// str.insert(pos, insertColor ? textColor : TEXT_COLOR_DEFAULT);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// return str;
|
||||
// }
|
||||
//
|
||||
// std::u16string word_wrap_string(const std::u16string& string, const size_t& max_line_len) {
|
||||
// size_t index_in_str = 0;
|
||||
// std::u16string wordwrapped_str;
|
||||
// std::u16string current_word;
|
||||
// size_t curr_word_len = 0;
|
||||
// size_t len_curr_line = 0;
|
||||
//
|
||||
// while (index_in_str < string.length()) { //length is weird because its utf-16
|
||||
// char16_t character = string[index_in_str];
|
||||
//
|
||||
// if (character == u'\x0E') { //need to parse the commands, only implementing a few necessary ones for now (will break with other commands)
|
||||
// std::u16string substr;
|
||||
// size_t code_len = 0;
|
||||
// if (string[index_in_str + 1] == u'\x00') {
|
||||
// if (string[index_in_str + 2] == u'\x03') { //color command
|
||||
// if (string[index_in_str + 4] == u'\xFFFF') { //text color white, weird length
|
||||
// code_len = 10;
|
||||
// }
|
||||
// else {
|
||||
// code_len = 5;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// else if (string[index_in_str + 1] == u'\x01') { //all implemented commands in this group have length 4
|
||||
// code_len = 4;
|
||||
// }
|
||||
// else if (string[index_in_str + 1] == u'\x02') { //all implemented commands in this group have length 4
|
||||
// code_len = 4;
|
||||
// }
|
||||
// else if (string[index_in_str + 1] == u'\x03') { //all implemented commands in this group have length 4
|
||||
// code_len = 4;
|
||||
// }
|
||||
// else if (string[index_in_str + 1] == u'\x04') { //all implemented commands in this group have length 4. Only used for Ho Ho sound
|
||||
// code_len = 4;
|
||||
// }
|
||||
//
|
||||
// substr = string.substr(index_in_str, code_len);
|
||||
// current_word += substr;
|
||||
// index_in_str += code_len;
|
||||
// }
|
||||
// else if (character == u'\n') {
|
||||
// wordwrapped_str += current_word;
|
||||
// wordwrapped_str += character;
|
||||
// len_curr_line = 0;
|
||||
// current_word = u"";
|
||||
// curr_word_len = 0;
|
||||
// index_in_str += 1;
|
||||
// }
|
||||
// else if (character == u' ') {
|
||||
// wordwrapped_str += current_word;
|
||||
// wordwrapped_str += character;
|
||||
// len_curr_line += curr_word_len + 1;
|
||||
// current_word = u"";
|
||||
// curr_word_len = 0;
|
||||
// index_in_str += 1;
|
||||
// }
|
||||
// else {
|
||||
// current_word += character;
|
||||
// curr_word_len += 1;
|
||||
// index_in_str += 1;
|
||||
//
|
||||
// if (len_curr_line + curr_word_len > max_line_len) {
|
||||
// wordwrapped_str += u'\n';
|
||||
// len_curr_line = 0;
|
||||
//
|
||||
// if (curr_word_len > max_line_len) {
|
||||
// wordwrapped_str += current_word + u'\n';
|
||||
// current_word = u"";
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// wordwrapped_str += current_word;
|
||||
//
|
||||
// return wordwrapped_str;
|
||||
// }
|
||||
//
|
||||
// std::string pad_str_4_lines(const std::string& string)
|
||||
// {
|
||||
// std::vector<std::string> lines = randomizer::utility::str::Split(string, '\n');
|
||||
//
|
||||
// unsigned int padding_lines_needed = (4 - lines.size() % 4) % 4;
|
||||
// for (unsigned int i = 0; i < padding_lines_needed; i++)
|
||||
// {
|
||||
// lines.push_back("");
|
||||
// }
|
||||
//
|
||||
// return randomizer::utility::str::Merge(lines, '\n');
|
||||
// }
|
||||
//
|
||||
// std::u16string pad_str_4_lines(const std::u16string& string)
|
||||
// {
|
||||
// std::vector<std::u16string> lines = randomizer::utility::str::Split(string, u'\n');
|
||||
//
|
||||
// unsigned int padding_lines_needed = (4 - lines.size() % 4) % 4;
|
||||
// for (unsigned int i = 0; i < padding_lines_needed; i++)
|
||||
// {
|
||||
// lines.push_back(u"");
|
||||
// }
|
||||
//
|
||||
// return randomizer::utility::str::erge(lines, u'\n');
|
||||
// }
|
||||
|
||||
// std::u16string apply_name_color(std::u16string str, const Color& color)
|
||||
// {
|
||||
// // Return the raw text (bars included)
|
||||
// if (color == Color::RAW)
|
||||
// {
|
||||
// return str;
|
||||
// }
|
||||
// // If there are no '|'s then just return with the color surrounding the whole string
|
||||
// if (str.find('|') == std::string::npos)
|
||||
// {
|
||||
// auto textColor = nameToColor[color];
|
||||
// return textColor + str + TEXT_COLOR_DEFAULT;
|
||||
// }
|
||||
|
||||
// // Alternate between the text color and default incase there are multiple
|
||||
// // pairs of bars
|
||||
// auto textColor = nameToColor[color];
|
||||
// bool insertColor = false;
|
||||
// for (size_t pos = 0; pos < str.length(); pos++)
|
||||
// {
|
||||
// if (str[pos] == '|')
|
||||
// {
|
||||
// insertColor = !insertColor;
|
||||
// str.erase(pos, 1);
|
||||
// str.insert(pos, insertColor ? textColor : TEXT_COLOR_DEFAULT);
|
||||
// }
|
||||
// }
|
||||
Text::Type string_to_type(const std::string& str) {
|
||||
std::unordered_map<std::string, Text::Type> strToType = {
|
||||
{"Standard", Text::Type::STANDARD},
|
||||
{"Pretty", Text::Type::PRETTY},
|
||||
{"Cryptic", Text::Type::CRYPTIC},
|
||||
};
|
||||
|
||||
// return str;
|
||||
// }
|
||||
if (strToType.contains(str))
|
||||
{
|
||||
return strToType.at(str);
|
||||
}
|
||||
|
||||
// std::u16string word_wrap_string(const std::u16string& string, const size_t& max_line_len) {
|
||||
// size_t index_in_str = 0;
|
||||
// std::u16string wordwrapped_str;
|
||||
// std::u16string current_word;
|
||||
// size_t curr_word_len = 0;
|
||||
// size_t len_curr_line = 0;
|
||||
throw std::runtime_error("Text type \"" + str + "\" is not recognized.");
|
||||
}
|
||||
|
||||
// while (index_in_str < string.length()) { //length is weird because its utf-16
|
||||
// char16_t character = string[index_in_str];
|
||||
Text::Language string_to_language(const std::string& str) {
|
||||
std::unordered_map<std::string, Text::Language> strToLanguage = {
|
||||
{"english", Text::Language::ENGLISH},
|
||||
};
|
||||
|
||||
// if (character == u'\x0E') { //need to parse the commands, only implementing a few necessary ones for now (will break with other commands)
|
||||
// std::u16string substr;
|
||||
// size_t code_len = 0;
|
||||
// if (string[index_in_str + 1] == u'\x00') {
|
||||
// if (string[index_in_str + 2] == u'\x03') { //color command
|
||||
// if (string[index_in_str + 4] == u'\xFFFF') { //text color white, weird length
|
||||
// code_len = 10;
|
||||
// }
|
||||
// else {
|
||||
// code_len = 5;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// else if (string[index_in_str + 1] == u'\x01') { //all implemented commands in this group have length 4
|
||||
// code_len = 4;
|
||||
// }
|
||||
// else if (string[index_in_str + 1] == u'\x02') { //all implemented commands in this group have length 4
|
||||
// code_len = 4;
|
||||
// }
|
||||
// else if (string[index_in_str + 1] == u'\x03') { //all implemented commands in this group have length 4
|
||||
// code_len = 4;
|
||||
// }
|
||||
// else if (string[index_in_str + 1] == u'\x04') { //all implemented commands in this group have length 4. Only used for Ho Ho sound
|
||||
// code_len = 4;
|
||||
// }
|
||||
if (strToLanguage.contains(str))
|
||||
{
|
||||
return strToLanguage.at(str);
|
||||
}
|
||||
|
||||
// substr = string.substr(index_in_str, code_len);
|
||||
// current_word += substr;
|
||||
// index_in_str += code_len;
|
||||
// }
|
||||
// else if (character == u'\n') {
|
||||
// wordwrapped_str += current_word;
|
||||
// wordwrapped_str += character;
|
||||
// len_curr_line = 0;
|
||||
// current_word = u"";
|
||||
// curr_word_len = 0;
|
||||
// index_in_str += 1;
|
||||
// }
|
||||
// else if (character == u' ') {
|
||||
// wordwrapped_str += current_word;
|
||||
// wordwrapped_str += character;
|
||||
// len_curr_line += curr_word_len + 1;
|
||||
// current_word = u"";
|
||||
// curr_word_len = 0;
|
||||
// index_in_str += 1;
|
||||
// }
|
||||
// else {
|
||||
// current_word += character;
|
||||
// curr_word_len += 1;
|
||||
// index_in_str += 1;
|
||||
throw std::runtime_error("Language \"" + str + "\" is not recognized.");
|
||||
}
|
||||
|
||||
// if (len_curr_line + curr_word_len > max_line_len) {
|
||||
// wordwrapped_str += u'\n';
|
||||
// len_curr_line = 0;
|
||||
Text::Gender string_to_gender(const std::string& str)
|
||||
{
|
||||
std::unordered_map<std::string, Text::Gender> strToGender = {
|
||||
{"Masculine", Text::Gender::MASCULINE},
|
||||
{"Feminine", Text::Gender::FEMININE}
|
||||
};
|
||||
|
||||
// if (curr_word_len > max_line_len) {
|
||||
// wordwrapped_str += current_word + u'\n';
|
||||
// current_word = u"";
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// wordwrapped_str += current_word;
|
||||
if (strToGender.contains(str))
|
||||
{
|
||||
return strToGender.at(str);
|
||||
}
|
||||
|
||||
// return wordwrapped_str;
|
||||
// }
|
||||
return Text::Gender::NUETRAL;
|
||||
}
|
||||
|
||||
// std::string pad_str_4_lines(const std::string& string)
|
||||
// {
|
||||
// std::vector<std::string> lines = randomizer::utility::str::Split(string, '\n');
|
||||
Text::Plurality string_to_plurality(const std::string& str)
|
||||
{
|
||||
if (str == "Plural") return Text::Plurality::PLURAL;
|
||||
return Text::Plurality::SINGULAR;
|
||||
}
|
||||
|
||||
// unsigned int padding_lines_needed = (4 - lines.size() % 4) % 4;
|
||||
// for (unsigned int i = 0; i < padding_lines_needed; i++)
|
||||
// {
|
||||
// lines.push_back("");
|
||||
// }
|
||||
static void LoadTextData(TextDatabase& tb) {
|
||||
std::string dataPath = RANDO_DATA_PATH "text/languages";
|
||||
for (const auto& entry : std::filesystem::directory_iterator(dataPath)) {
|
||||
if (entry.is_regular_file() && entry.path().extension() == ".yaml") {
|
||||
auto language = string_to_language(entry.path().stem().string());
|
||||
auto textData = LoadYAML(entry.path());
|
||||
for (const auto& textNode : textData) {
|
||||
const auto& name = textNode.first.as<std::string>();
|
||||
for (const auto& typeNode : textNode.second) {
|
||||
auto type = string_to_type(typeNode.first.as<std::string>());
|
||||
auto typeData = typeNode.second;
|
||||
const auto& text = typeData["Text"].as<std::string>();
|
||||
tb[name][type].mtext[language] = text;
|
||||
if (typeData["Gender"]) {
|
||||
tb[name][type].mGender[language] = string_to_gender(typeData["Gender"].as<std::string>());
|
||||
}
|
||||
if (typeData["Plurality"]) {
|
||||
tb[name][type].mPlurality[language] = string_to_plurality(typeData["Plurality"].as<std::string>());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// return randomizer::utility::str::Merge(lines, '\n');
|
||||
// }
|
||||
const TextDatabase& getTextDatabase() {
|
||||
static TextDatabase tb{};
|
||||
|
||||
// std::u16string pad_str_4_lines(const std::u16string& string)
|
||||
// {
|
||||
// std::vector<std::u16string> lines = randomizer::utility::str::Split(string, u'\n');
|
||||
// If database is empty, load it up
|
||||
if (tb.empty()) {
|
||||
LoadTextData(tb);
|
||||
}
|
||||
|
||||
// unsigned int padding_lines_needed = (4 - lines.size() % 4) % 4;
|
||||
// for (unsigned int i = 0; i < padding_lines_needed; i++)
|
||||
// {
|
||||
// lines.push_back(u"");
|
||||
// }
|
||||
return tb;
|
||||
}
|
||||
|
||||
// return randomizer::utility::str::erge(lines, u'\n');
|
||||
// }
|
||||
const Text& getTextObject(const std::string& name, Text::Type type /*= Text::STANDARD*/)
|
||||
{
|
||||
const auto& tb = getTextDatabase();
|
||||
if (!tb.contains(name)) {
|
||||
throw std::runtime_error("Text name \"" + name + "\" is not recognized.");
|
||||
}
|
||||
return tb.at(name).at(type);
|
||||
}
|
||||
|
||||
// Gender string_to_gender(const std::string& str)
|
||||
// {
|
||||
// std::unordered_map<std::string, Gender> strToGender = {
|
||||
// {"Male", Gender::MALE},
|
||||
// {"Female", Gender::FEMALE}
|
||||
// };
|
||||
const std::string& getTextStr(const std::string& name,
|
||||
Text::Type type /*= Text::STANDARD*/,
|
||||
Text::Language language /*= Text::ENGLISH*/)
|
||||
{
|
||||
const auto& tb = getTextDatabase();
|
||||
if (!tb.contains(name)) {
|
||||
throw std::runtime_error("Text name \"" + name + "\" is not recognized.");
|
||||
}
|
||||
return tb.at(name).at(type).mtext.at(language);
|
||||
}
|
||||
|
||||
// if (strToGender.contains(str))
|
||||
// {
|
||||
// return strToGender.at(str);
|
||||
// }
|
||||
void applyMessageCodes(std::string& str) {
|
||||
using namespace std::string_literals;
|
||||
const static std::unordered_map<std::string, std::string> messageCodes = {
|
||||
{"<fast>", "\x1A\x05\x00\x00\x01"s },
|
||||
{"<slow>", "\x1A\x05\x00\x00\x02"s },
|
||||
{"<white>", "\x1A\x06\xFF\x00\x00\x00"s},
|
||||
{"<red>", "\x1A\x06\xFF\x00\x00\x01"s},
|
||||
{"<green>", "\x1A\x06\xFF\x00\x00\x02"s},
|
||||
{"<light blue>", "\x1A\x06\xFF\x00\x00\x03"s},
|
||||
{"<yellow>", "\x1A\x06\xFF\x00\x00\x04"s},
|
||||
{"<purple>", "\x1A\x06\xFF\x00\x00\x06"s},
|
||||
{"<orange>", "\x1A\x06\xFF\x00\x00\x08"s},
|
||||
// custom colors
|
||||
{"<dark green>", "\x1A\x06\xFF\x00\x00\x09"s},
|
||||
{"<blue>", "\x1A\x06\xFF\x00\x00\x0A"s},
|
||||
{"<silver>", "\x1A\x06\xFF\x00\x00\x0B"s},
|
||||
};
|
||||
|
||||
// return Gender::NONE;
|
||||
// }
|
||||
|
||||
// Plurality string_to_plurality(const std::string& str)
|
||||
// {
|
||||
// if (str == "Plural") return Plurality::PLURAL;
|
||||
// return Plurality::SINGULAR;
|
||||
// }
|
||||
// }; // namespace Text
|
||||
for (const auto& [code, replacement] : messageCodes) {
|
||||
size_t pos = 0;
|
||||
while ((pos = str.find(code, pos)) != std::string::npos) {
|
||||
str.replace(pos, code.length(), replacement);
|
||||
pos += replacement.length();
|
||||
}
|
||||
}
|
||||
}
|
||||
}; // namespace Text
|
||||
|
||||
@@ -2,58 +2,77 @@
|
||||
|
||||
#include <string>
|
||||
#include <array>
|
||||
#include <map>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace Text
|
||||
{
|
||||
enum struct Type
|
||||
{
|
||||
STANDARD = 0,
|
||||
PRETTY,
|
||||
CRYPTIC,
|
||||
namespace randomizer {
|
||||
class Text {
|
||||
public:
|
||||
enum Language {
|
||||
ENGLISH = 0,
|
||||
LANGUAGE_MAX
|
||||
};
|
||||
|
||||
enum Type
|
||||
{
|
||||
STANDARD = 0,
|
||||
PRETTY,
|
||||
CRYPTIC,
|
||||
TYPE_MAX
|
||||
};
|
||||
|
||||
enum Color
|
||||
{
|
||||
RAW = 0,
|
||||
NONE,
|
||||
RED,
|
||||
GREEN,
|
||||
BLUE,
|
||||
YELLOW,
|
||||
CYAN,
|
||||
MAGENTA,
|
||||
GRAY,
|
||||
ORANGE,
|
||||
};
|
||||
|
||||
enum Gender
|
||||
{
|
||||
NUETRAL = 0,
|
||||
MASCULINE,
|
||||
FEMININE,
|
||||
GENDER_MAX,
|
||||
};
|
||||
|
||||
enum Plurality
|
||||
{
|
||||
SINGULAR = 0,
|
||||
PLURAL,
|
||||
PLURALITY_MAX,
|
||||
};
|
||||
|
||||
std::array<std::string, LANGUAGE_MAX> mtext{};
|
||||
std::array<Gender, LANGUAGE_MAX> mGender{};
|
||||
std::array<Plurality, LANGUAGE_MAX> mPlurality{};
|
||||
};
|
||||
|
||||
enum struct Color
|
||||
{
|
||||
RAW = 0,
|
||||
NONE,
|
||||
RED,
|
||||
GREEN,
|
||||
BLUE,
|
||||
YELLOW,
|
||||
CYAN,
|
||||
MAGENTA,
|
||||
GRAY,
|
||||
ORANGE,
|
||||
inline constexpr std::array supported_languages = {
|
||||
Text::ENGLISH,
|
||||
};
|
||||
|
||||
enum struct Gender
|
||||
{
|
||||
NONE = 0,
|
||||
MALE,
|
||||
FEMALE,
|
||||
};
|
||||
// std::u16string apply_name_color(std::u16string str, const Color& color);
|
||||
// std::u16string word_wrap_string(const std::u16string& string, const size_t& max_line_len); //IMPROVEMENT: use font data to do this "properly"
|
||||
// std::string pad_str_4_lines(const std::string& string);
|
||||
// std::u16string pad_str_4_lines(const std::u16string& string);
|
||||
|
||||
enum struct Plurality
|
||||
{
|
||||
SINGULAR,
|
||||
PLURAL,
|
||||
};
|
||||
Text::Gender string_to_gender(const std::string& str);
|
||||
Text::Plurality string_to_plurality(const std::string& str);
|
||||
|
||||
struct Translation
|
||||
{
|
||||
std::map<Text::Type, std::string> types;
|
||||
Gender gender;
|
||||
Plurality plurality;
|
||||
};
|
||||
// Retrieval of Text objects keyed by name and type (standard, pretty, criptic)
|
||||
using TextDatabase = std::unordered_map<std::string, std::array<Text, Text::TYPE_MAX>>;
|
||||
|
||||
extern std::array<std::string, 3> supported_languages;
|
||||
const TextDatabase& getTextDatabase();
|
||||
|
||||
std::u16string apply_name_color(std::u16string str, const Color& color);
|
||||
std::u16string word_wrap_string(const std::u16string& string, const size_t& max_line_len); //IMPROVEMENT: use font data to do this "properly"
|
||||
std::string pad_str_4_lines(const std::string& string);
|
||||
std::u16string pad_str_4_lines(const std::u16string& string);
|
||||
const std::string& getTextStr(const std::string& name, Text::Type type = Text::STANDARD, Text::Language language = Text::ENGLISH);
|
||||
|
||||
Gender string_to_gender(const std::string& str);
|
||||
Plurality string_to_plurality(const std::string& str);
|
||||
// Replaces the message codes in the string with the ingame hex equivalents
|
||||
void applyMessageCodes(std::string&);
|
||||
}; // namespace Text
|
||||
|
||||
Reference in New Issue
Block a user