Refactors CustomMessages to not be rando specific.

Pulls the Custom Message related code out into it's own class, which has an initialization phase where other enhancements / future features can create messages during an initialization phase to be stored and retrieved later. Along with this refactoring, the 4 bottle messages from the previous rando-specific system are now created and stored during intialization and retrieved by their getItemId.

Now that it isn't rando specific, the goal is to move anything text changes that are hard-coded into z_message_PAL.c and refactor it so that future text additions/overrides can be done without modifying that file.
This commit is contained in:
Christopher Leggett 2022-07-17 12:34:56 -04:00
parent 3f2111a3e6
commit 4eaf70b859
No known key found for this signature in database
GPG Key ID: 7093AE5FF7037D79
10 changed files with 182 additions and 70 deletions

View File

@ -179,6 +179,7 @@
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="soh\Enhancements\custom_message\CustomMessage.cpp" />
<ClCompile Include="soh\Enhancements\cosmetics\CosmeticsEditor.cpp" />
<ClCompile Include="soh\Enhancements\debugger\actorViewer.cpp" />
<ClCompile Include="soh\Enhancements\gfx.c" />
@ -942,9 +943,9 @@
<ClCompile Include="src\overlays\misc\ovl_kaleido_scope\z_lmap_mark.c" />
<ClCompile Include="src\overlays\misc\ovl_kaleido_scope\z_lmap_mark_data.c" />
<ClCompile Include="src\overlays\misc\ovl_map_mark_data\z_map_mark_data.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="soh\Enhancements\custom_message\CustomMessage.h" />
<ClInclude Include="soh\Enhancements\cosmetics\CosmeticsEditor.h" />
<ClInclude Include="soh\Enhancements\debugger\actorViewer.h" />
<ClCompile Include="soh\Enhancements\randomizer\randomizer.h" />
@ -985,7 +986,6 @@
<ClInclude Include="soh\Enhancements\randomizer\3drando\trial.hpp" />
<ClInclude Include="soh\Enhancements\randomizer\3drando\utils.hpp" />
<ClInclude Include="randomizerTypes.h" />
<ClInclude Include="soh\Enhancements\randomizer\randomizer_custom_messages.h" />
<ClInclude Include="soh\Enhancements\randomizer\randomizer_item_tracker.h" />
<ClInclude Include="soh\frame_interpolation.h" />
<ClInclude Include="include\alloca.h" />

View File

@ -0,0 +1,108 @@
#include "CustomMessage.h"
#include <algorithm>
using namespace std::literals::string_literals;
CustomMessage::CustomMessage() {
this->textBoxSpecialCharacters = { { "À", 0x80 }, { "î", 0x81 }, { "Â", 0x82 }, { "Ä", 0x83 }, { "Ç", 0x84 },
{ "È", 0x85 }, { "É", 0x86 }, { "Ê", 0x87 }, { "Ë", 0x88 }, { "Ï", 0x89 },
{ "Ô", 0x8A }, { "Ö", 0x8B }, { "Ù", 0x8C }, { "Û", 0x8D }, { "Ü", 0x8E },
{ "ß", 0x8F }, { "à", 0x90 }, { "á", 0x91 }, { "â", 0x92 }, { "ä", 0x93 },
{ "ç", 0x94 }, { "è", 0x95 }, { "é", 0x96 }, { "ê", 0x97 }, { "ë", 0x98 },
{ "ï", 0x99 }, { "ô", 0x9A }, { "ö", 0x9B }, { "ù", 0x9C }, { "û", 0x9D },
{ "ü", 0x9E } };
this->colors = { { "w", QM_WHITE }, { "r", QM_RED }, { "g", QM_GREEN }, { "b", QM_BLUE },
{ "c", QM_LBLUE }, { "p", QM_PINK }, { "y", QM_YELLOW }, { "B", QM_BLACK } };
}
CustomMessage::~CustomMessage() {
this->textBoxSpecialCharacters.clear();
}
void CustomMessage::ReplaceSpecialCharacters(std::string& string) {
// add special characters
for (auto specialCharacterPair : textBoxSpecialCharacters) {
size_t start_pos = 0;
std::string textBoxSpecialCharacterString = "";
textBoxSpecialCharacterString += specialCharacterPair.second;
while ((start_pos = string.find(specialCharacterPair.first, start_pos)) != std::string::npos) {
string.replace(start_pos, specialCharacterPair.first.length(), textBoxSpecialCharacterString);
start_pos += textBoxSpecialCharacterString.length();
}
}
}
void CustomMessage::ReplaceColors(std::string& string) {
for (auto colorPair : colors) {
std::string textToReplace = "%";
textToReplace += colorPair.first;
size_t start_pos = 0;
while ((start_pos = string.find(textToReplace)) != std::string::npos) {
string.replace(start_pos, textToReplace.length(), COLOR(colorPair.second));
start_pos += textToReplace.length();
}
}
}
void CustomMessage::CreateGetItemMessage(GetItemID giid, ItemID iid, std::string messages[LANGUAGE_MAX]) {
for (int i = 0; i < LANGUAGE_MAX; i++) {
if (!(messages[i].empty())) {
std::string message = messages[i];
std::string formattedMessage = ITEM_OBTAINED(iid) + message;
size_t start_pos = 0;
std::replace(formattedMessage.begin(), formattedMessage.end(), '&', NEWLINE()[0]);
while ((start_pos = formattedMessage.find('^', start_pos)) != std::string::npos) {
formattedMessage.replace(start_pos, 1, WAIT_FOR_INPUT() + ITEM_OBTAINED(iid));
start_pos += 3;
}
std::replace(formattedMessage.begin(), formattedMessage.end(), '@', PLAYER_NAME()[0]);
ReplaceSpecialCharacters(formattedMessage);
ReplaceColors(formattedMessage);
formattedMessage += MESSAGE_END();
this->getItemMessageTable[i].emplace(giid, formattedMessage);
} else {
this->getItemMessageTable[i].emplace(giid, MESSAGE_END());
}
}
}
std::string CustomMessage::RetrieveGetItemMessage(GetItemID giid) {
std::unordered_map<GetItemID, std::string>::const_iterator result =
getItemMessageTable[gSaveContext.language].find(giid);
if (result == getItemMessageTable[gSaveContext.language].end()) {
switch (gSaveContext.language) {
case LANGUAGE_FRA:
return "Il n'y a pas de message personnalisé pour cet élément.";
case LANGUAGE_GER:
return "Für diesen Artikel gibt es keine benutzerdefinierte Nachricht.";
case LANGUAGE_ENG:
default:
return "There is no custom message for this item.";
}
}
return result->second;
}
std::string CustomMessage::MESSAGE_END() {
return "\x02"s;
}
std::string CustomMessage::ITEM_OBTAINED(uint8_t x) {
return "\x13"s + char(x);
}
std::string CustomMessage::NEWLINE() {
return "\x01"s;
}
std::string CustomMessage::COLOR(uint8_t x) {
return "\x05"s + char(x);
}
std::string CustomMessage::WAIT_FOR_INPUT() {
return "\x04"s;
}
std::string CustomMessage::PLAYER_NAME() {
return "\x0F"s;
}

View File

@ -0,0 +1,39 @@
#pragma once
#include <string>
#include <unordered_map>
#include "variables.h"
#define QM_WHITE 0x00
#define QM_RED 0x41
#define QM_GREEN 0x42
#define QM_BLUE 0x43
#define QM_LBLUE 0x44
#define QM_PINK 0x45
#define QM_YELLOW 0x46
#define QM_BLACK 0x47
class CustomMessage {
private:
std::unordered_map<std::string, char> textBoxSpecialCharacters;
std::unordered_map<std::string, char> colors;
std::unordered_map<GetItemID, std::string> getItemMessageTable[LANGUAGE_MAX];
void ReplaceSpecialCharacters(std::string &string);
void ReplaceColors(std::string& string);
std::string MESSAGE_END();
std::string ITEM_OBTAINED(uint8_t x);
std::string NEWLINE();
std::string COLOR(uint8_t x);
std::string WAIT_FOR_INPUT();
std::string PLAYER_NAME();
public:
static CustomMessage* Instance;
CustomMessage();
~CustomMessage();
void CreateGetItemMessage(GetItemID giid, ItemID iid, std::string messages[LANGUAGE_MAX]);
std::string RetrieveGetItemMessage(GetItemID giid);
};

View File

@ -4748,6 +4748,7 @@ void DrawRandoEditor(bool& open) {
void InitRando() {
SohImGui::AddWindow("Randomizer", "Randomizer Settings", DrawRandoEditor);
Randomizer::CreateCustomMessages();
}
extern "C" {

View File

@ -5,6 +5,7 @@
#include "../../../include/ultra64.h"
#include "../../../include/z64item.h"
#include <randomizerTypes.h>
#include <memory>
class Randomizer {
private:
@ -42,6 +43,7 @@ class Randomizer {
GetItemID GetRandomizedItemIdFromKnownCheck(RandomizerCheck randomizerCheck, GetItemID ogId);
GetItemID GetRandomizedItemId(GetItemID ogId, s16 actorId, s16 actorParams, s16 sceneNum);
std::string GetCustomGetItemMessage(GetItemID giid);
static void CreateCustomMessages();
};
#ifdef __cplusplus

View File

@ -1,54 +1,33 @@
#include "randomizer_custom_messages.h"
#include "randomizer.h"
#include <variables.h>
#include "soh/Enhancements/custom_message/CustomMessage.h"
using namespace std::literals::string_literals;
#define MESSAGES(eng, ger, fra) (new std::string[]{eng, ger, fra})
void Randomizer::CreateCustomMessages() {
CustomMessage* customMessage = CustomMessage::Instance;
customMessage->CreateGetItemMessage(
GI_BOTTLE_WITH_BLUE_FIRE, ITEM_BLUE_FIRE,
MESSAGES("You got a %rBottle with Blue &Fire%w! Use it to melt Red Ice!", "", ""));
customMessage->CreateGetItemMessage(
GI_BOTTLE_WITH_BIG_POE, ITEM_BIG_POE,
MESSAGES("You got a %rBig Poe in a bottle%w!&Sell it to the Ghost Shop!", "", ""));
customMessage->CreateGetItemMessage(
GI_BOTTLE_WITH_BLUE_POTION, ITEM_POTION_BLUE,
MESSAGES("You got a %rBottle of Blue Potion%w!&Drink it to replenish your&%ghealth%w and %bmagic%w!", "", ""));
customMessage->CreateGetItemMessage(
GI_BOTTLE_WITH_FISH, ITEM_FISH,
MESSAGES("You got a %rFish in a bottle%w!&It looks fresh and delicious!&They say Jabu-Jabu loves them!", "",
""));
}
std::string Randomizer::GetCustomGetItemMessage(GetItemID giid) {
if (!gSaveContext.n64ddFlag) {
return "Not Randomized.";
}
switch (giid) {
case GI_BOTTLE_WITH_BLUE_FIRE:
switch (gSaveContext.language) {
case LANGUAGE_FRA:
case LANGUAGE_GER:
case LANGUAGE_ENG:
default:
return ITEM_OBTAINED(ITEM_BLUE_FIRE) + "You got a " + COLOR(QM_RED) + "Bottle with Blue " +
NEWLINE() + "Fire" + COLOR(QM_WHITE) + "! Use it to melt Red Ice!" +
MESSAGE_END();
}
default:
switch (gSaveContext.language) {
case LANGUAGE_FRA:
return "Il n'y a pas de message personnalisé pour cet élément.";
case LANGUAGE_GER:
return "Für diesen Artikel gibt es keine benutzerdefinierte Nachricht.";
case LANGUAGE_ENG:
default:
return "There is no custom message for this item.";
}
}
}
std::string MESSAGE_END() {
return "\x02"s;
}
std::string ITEM_OBTAINED(uint8_t x) {
return "\x13"s + char(x);
}
std::string NEWLINE() {
return "\x01"s;
}
std::string COLOR(uint8_t x) {
return "\x05"s + char(x);
}
std::string WAIT_FOR_INPUT() {
return "\x04"s;
return CustomMessage::Instance->RetrieveGetItemMessage(giid);
}

View File

@ -1,19 +0,0 @@
#pragma once
#include <string>
#include "../../../include/z64item.h"
#define QM_WHITE 0x00
#define QM_RED 0x41
#define QM_GREEN 0x42
#define QM_BLUE 0x43
#define QM_LBLUE 0x44
#define QM_PINK 0x45
#define QM_YELLOW 0x46
#define QM_BLACK 0x47
std::string MESSAGE_END();
std::string ITEM_OBTAINED(uint8_t x);
std::string NEWLINE();
std::string COLOR(uint8_t x);
std::string WAIT_FOR_INPUT();

View File

@ -38,6 +38,7 @@
#include "Enhancements/debugger/debugger.h"
#include "Enhancements/randomizer/randomizer.h"
#include <soh/Enhancements/randomizer/randomizer_item_tracker.h>
#include <soh/Enhancements/custom_message/CustomMessage.h>
#include "Enhancements/n64_weird_frame_data.inc"
#include "soh/frame_interpolation.h"
#include "Utils/BitConverter.h"
@ -55,6 +56,7 @@
OTRGlobals* OTRGlobals::Instance;
SaveManager* SaveManager::Instance;
CustomMessage* CustomMessage::Instance;
OTRGlobals::OTRGlobals() {
context = Ship::GlobalCtx2::CreateInstance("Ship of Harkinian");
@ -106,6 +108,7 @@ extern "C" void OTRExtScanner() {
extern "C" void InitOTR() {
OTRGlobals::Instance = new OTRGlobals();
SaveManager::Instance = new SaveManager();
CustomMessage::Instance = new CustomMessage();
auto t = OTRGlobals::Instance->context->GetResourceManager()->LoadFile("version");
if (!t->bHasLoadError)

View File

@ -9,7 +9,6 @@
#ifdef __cplusplus
#include "Enhancements/savestates.h"
#include "Enhancements/randomizer/randomizer.h"
class OTRGlobals
{
public:

View File

@ -654,13 +654,13 @@ static GetItemEntry sGetItemTable[] = {
GET_ITEM(ITEM_BOTTLE_WITH_RED_POTION, OBJECT_GI_LIQUID, GID_POTION_RED, 0x43, 0x80, CHEST_ANIM_LONG),
GET_ITEM(ITEM_BOTTLE_WITH_GREEN_POTION, OBJECT_GI_LIQUID, GID_POTION_GREEN, 0x44, 0x80, CHEST_ANIM_LONG),
GET_ITEM(ITEM_BOTTLE_WITH_BLUE_POTION, OBJECT_GI_LIQUID, GID_POTION_BLUE, 0x45, 0x80, CHEST_ANIM_LONG),
GET_ITEM(ITEM_BOTTLE_WITH_BLUE_POTION, OBJECT_GI_LIQUID, GID_POTION_BLUE, 0xF8, 0x80, CHEST_ANIM_LONG),
GET_ITEM(ITEM_BOTTLE_WITH_FAIRY, OBJECT_GI_BOTTLE, GID_BOTTLE, 0x46, 0x80, CHEST_ANIM_LONG),
GET_ITEM(ITEM_BOTTLE_WITH_FISH, OBJECT_GI_FISH, GID_FISH, 0x47, 0x80, CHEST_ANIM_LONG),
GET_ITEM(ITEM_BOTTLE_WITH_FISH, OBJECT_GI_FISH, GID_FISH, 0xF8, 0x80, CHEST_ANIM_LONG),
GET_ITEM(ITEM_BOTTLE_WITH_BLUE_FIRE, OBJECT_GI_FIRE, GID_BLUE_FIRE, 0xF8, 0x80, CHEST_ANIM_LONG),
GET_ITEM(ITEM_BOTTLE_WITH_BUGS, OBJECT_GI_INSECT, GID_BUG, 0x7A, 0x80, CHEST_ANIM_LONG),
GET_ITEM(ITEM_BOTTLE_WITH_POE, OBJECT_GI_GHOST, GID_POE, 0x97, 0x80, CHEST_ANIM_LONG),
GET_ITEM(ITEM_BOTTLE_WITH_BIG_POE, OBJECT_GI_GHOST, GID_BIG_POE, 0xF9, 0x80, CHEST_ANIM_LONG),
GET_ITEM(ITEM_BOTTLE_WITH_POE, OBJECT_GI_GHOST, GID_POE, 0xF8, 0x80, CHEST_ANIM_LONG),
GET_ITEM(ITEM_BOTTLE_WITH_BIG_POE, OBJECT_GI_GHOST, GID_BIG_POE, 0xF8, 0x80, CHEST_ANIM_LONG),
GET_ITEM_NONE,
GET_ITEM_NONE,