Skip to content

Commit

Permalink
Merge pull request HarbourMasters#831 from leggettc18/custom-messages
Browse files Browse the repository at this point in the history
System for Creating and Storing Custom Messages
  • Loading branch information
briaguya-ai authored Aug 9, 2022
2 parents 5581f45 + e63d84b commit fa090c5
Show file tree
Hide file tree
Showing 11 changed files with 572 additions and 217 deletions.
15 changes: 15 additions & 0 deletions soh/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,13 @@ set(Header_Files__soh__Enhancements__randomizer__3drando
)
source_group("Header Files\\soh\\Enhancements\\randomizer\\3drando" FILES ${Header_Files__soh__Enhancements__randomizer__3drando})

set(Header_Files__soh__Enhancements__custom_message
"soh/Enhancements/custom-message/CustomMessageTypes.h"
"soh/Enhancements/custom-message/CustomMessageManager.h"
)

source_group("Header Files\\soh\\Enhancements\\custom-message" FILES ${Header_Files__soh__Enhancements__custom_message})

set(Source_Files__soh
"soh/GbiWrap.cpp"
"soh/OTRAudio.h"
Expand Down Expand Up @@ -326,6 +333,12 @@ set(Source_Files__soh__Enhancements__randomizer__3drando__location_access
)
source_group("Source Files\\soh\\Enhancements\\randomizer\\3drando\\location_access" FILES ${Source_Files__soh__Enhancements__randomizer__3drando__location_access})

set(Source_Files__soh__Enhancements__custom_message
"soh/Enhancements/custom-message/CustomMessageManager.cpp"
)

source_group("Source Files\\soh\\Enhancements\\custom-message" FILES ${Source_Files__soh__Enhancements__custom_message})

set(Source_Files__src__boot
"src/boot/assert.c"
"src/boot/boot_main.c"
Expand Down Expand Up @@ -1534,6 +1547,7 @@ set(ALL_FILES
${Header_Files__soh__Enhancements__debugger}
${Header_Files__soh__Enhancements__randomizer}
${Header_Files__soh__Enhancements__randomizer__3drando}
${Header_Files__soh__Enhancements__custom_message}
${Source_Files__soh}
${Source_Files__soh__Enhancements}
${Source_Files__soh__Enhancements__cosmetics}
Expand All @@ -1542,6 +1556,7 @@ set(ALL_FILES
${Source_Files__soh__Enhancements__randomizer__3drando}
${Source_Files__soh__Enhancements__randomizer__3drando__hint_list}
${Source_Files__soh__Enhancements__randomizer__3drando__location_access}
${Source_Files__soh__Enhancements__custom_message}
${Source_Files__src__boot}
${Source_Files__src__buffers}
${Source_Files__src__code}
Expand Down
150 changes: 150 additions & 0 deletions soh/soh/Enhancements/custom-message/CustomMessageManager.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
#include "CustomMessageManager.h"
#include <algorithm>

using namespace std::literals::string_literals;

CustomMessageManager::CustomMessageManager() {
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 } };
}

CustomMessageManager::~CustomMessageManager() {
this->textBoxSpecialCharacters.clear();
this->colors.clear();
this->messageTables.clear();
}

void CustomMessageManager::ReplaceSpecialCharacters(std::string& string) {
// add special characters
for (auto specialCharacterPair : this->textBoxSpecialCharacters) {
size_t start_pos = 0;
std::string textBoxSpecialCharacterString = ""s;
textBoxSpecialCharacterString += specialCharacterPair.second;
while ((start_pos = string.find(specialCharacterPair.first, 0)) != std::string::npos) {
string.replace(start_pos, specialCharacterPair.first.length(), textBoxSpecialCharacterString);
start_pos += textBoxSpecialCharacterString.length();
}
}
}

void CustomMessageManager::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 CustomMessageManager::FormatCustomMessage(std::string& message, ItemID iid) {
message.insert(0, ITEM_OBTAINED(iid));
size_t start_pos = 0;
std::replace(message.begin(), message.end(), '&', NEWLINE()[0]);
while ((start_pos = message.find('^', start_pos)) != std::string::npos) {
message.replace(start_pos, 1, WAIT_FOR_INPUT() + ITEM_OBTAINED(iid));
start_pos += 3;
}
std::replace(message.begin(), message.end(), '@', PLAYER_NAME()[0]);
ReplaceSpecialCharacters(message);
ReplaceColors(message);
message += MESSAGE_END();
}

void CustomMessageManager::FormatCustomMessage(std::string& message) {
size_t start_pos = 0;
std::replace(message.begin(), message.end(), '&', NEWLINE()[0]);
std::replace(message.begin(), message.end(), '^', WAIT_FOR_INPUT()[0]);
std::replace(message.begin(), message.end(), '@', PLAYER_NAME()[0]);
ReplaceSpecialCharacters(message);
ReplaceColors(message);
message += MESSAGE_END();
}

bool CustomMessageManager::InsertCustomMessage(std::string tableID, uint16_t textID, CustomMessageEntry messages) {
auto foundMessageTable = messageTables.find(tableID);
if (foundMessageTable == messageTables.end()) {
return false;
}
auto& messageTable = foundMessageTable->second;
auto messageInsertResult = messageTable.emplace(textID, messages);
return messageInsertResult.second;
}



bool CustomMessageManager::CreateGetItemMessage(std::string tableID, GetItemID giid, ItemID iid, CustomMessageEntry messageEntry) {
FormatCustomMessage(messageEntry.english, iid);
FormatCustomMessage(messageEntry.german, iid);
FormatCustomMessage(messageEntry.french, iid);
const uint16_t textID = giid;
return InsertCustomMessage(tableID, textID, messageEntry);
}

bool CustomMessageManager::CreateMessage(std::string tableID, uint16_t textID, CustomMessageEntry messageEntry) {
FormatCustomMessage(messageEntry.english);
FormatCustomMessage(messageEntry.german);
FormatCustomMessage(messageEntry.french);
return InsertCustomMessage(tableID, textID, messageEntry);
}

CustomMessageEntry CustomMessageManager::RetrieveMessage(std::string tableID, uint16_t textID) {
std::unordered_map<std::string, CustomMessageTable>::const_iterator foundMessageTable = messageTables.find(tableID);
if (foundMessageTable == messageTables.end()) {
return NULL_CUSTOM_MESSAGE;
}
CustomMessageTable messageTable = foundMessageTable->second;
std::unordered_map<uint16_t, CustomMessageEntry>::const_iterator foundMessage = messageTable.find(textID);
if (foundMessage == messageTable.end()) {
return NULL_CUSTOM_MESSAGE;
}
CustomMessageEntry message = foundMessage->second;
return message;
}

bool CustomMessageManager::ClearMessageTable(std::string tableID) {
auto foundMessageTable = messageTables.find(tableID);
if (foundMessageTable == messageTables.end()) {
return false;
}
auto& messageTable = foundMessageTable->second;
messageTable.clear();
}

bool CustomMessageManager::AddCustomMessageTable(std::string tableID) {
CustomMessageTable newMessageTable;
return messageTables.emplace(tableID, newMessageTable).second;
}

std::string CustomMessageManager::MESSAGE_END() {
return "\x02"s;
}

std::string CustomMessageManager::ITEM_OBTAINED(uint8_t x) {
return "\x13"s + char(x);
}

std::string CustomMessageManager::NEWLINE() {
return "\x01"s;
}

std::string CustomMessageManager::COLOR(uint8_t x) {
return "\x05"s + char(x);
}

std::string CustomMessageManager::WAIT_FOR_INPUT() {
return "\x04"s;
}

std::string CustomMessageManager::PLAYER_NAME() {
return "\x0F"s;
}
133 changes: 133 additions & 0 deletions soh/soh/Enhancements/custom-message/CustomMessageManager.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
#pragma once
#include <string>
#include <unordered_map>
#include "../../../include/z64item.h"

#undef MESSAGE_END

#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

#ifndef MESSAGE_DATA_STATIC_H

typedef enum {
/* 0 */ TEXTBOX_TYPE_BLACK,
/* 1 */ TEXTBOX_TYPE_WOODEN,
/* 2 */ TEXTBOX_TYPE_BLUE,
/* 3 */ TEXTBOX_TYPE_OCARINA,
/* 4 */ TEXTBOX_TYPE_NONE_BOTTOM,
/* 5 */ TEXTBOX_TYPE_NONE_NO_SHADOW,
/* 11 */ TEXTBOX_TYPE_CREDITS = 11
} TextBoxType;

typedef enum {
/* 0 */ TEXTBOX_BG_CROSS
} TextBoxBackground;

typedef enum {
/* 0 */ TEXTBOX_POS_VARIABLE,
/* 1 */ TEXTBOX_POS_TOP,
/* 2 */ TEXTBOX_POS_MIDDLE,
/* 3 */ TEXTBOX_POS_BOTTOM
} TextBoxPosition;

#endif

typedef struct {
TextBoxType textBoxType;
TextBoxPosition textBoxPos;
std::string english;
std::string german;
std::string french;
} CustomMessageEntry;

// Message Entry without the text type and position, useful for when
// you need an array of these to loop over for registration
// that will all have the same textbox type and position.
typedef struct {
std::string english;
std::string german;
std::string french;
} CustomMessageMinimal;

#define NULL_CUSTOM_MESSAGE \
{ (TextBoxType)(-1), (TextBoxPosition)(-1), "", "", "" }

typedef std::unordered_map<uint16_t, CustomMessageEntry> CustomMessageTable;

class CustomMessageManager {
private:
std::unordered_map<std::string, char> textBoxSpecialCharacters;
std::unordered_map<std::string, char> colors;
std::unordered_map<std::string, CustomMessageTable> messageTables;

void ReplaceSpecialCharacters(std::string &string);
void ReplaceColors(std::string& string);
bool InsertCustomMessage(std::string tableID, uint16_t textID, CustomMessageEntry messages);

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 CustomMessageManager* Instance;

CustomMessageManager();
~CustomMessageManager();

/*
Formats the provided Custom Message Entry and inserts it into the table with the provided tableID,
with the provided giid (getItemID) as its key. This function also inserts the icon corresponding to
the provided iid (itemID) at the beginning of each page of the textbox.
*/
bool CreateGetItemMessage(std::string tableID, GetItemID giid, ItemID iid, CustomMessageEntry messages);

/*
Formats the provided Custom Message Entry and inserts it into the table with the provided tableID,
with the provided textID as its key.
*/
bool CreateMessage(std::string tableID, uint16_t textID, CustomMessageEntry messages);

/*
Retrieves a message from the table with id tableID with the provided textID.
Returns a NULL_CUSTOM_MESSAGE if the message or table does not exist.
*/
CustomMessageEntry RetrieveMessage(std::string tableID, uint16_t textID);

/*
Empties out the message table identified by tableID.
Returns true if successful and false if not (for instance
if a table with the provided tableID does not exist).
*/
bool ClearMessageTable(std::string tableID);

/*
Creates an empty CustomMessageTable accessible at the provided
tableID, returns true if creation was successful and false
if not.
*/
bool AddCustomMessageTable(std::string tableID);

/*
Replaces special characters and certain symbols with control codes
& for newline, ^ for wait-for-input, and @ for the player name,
as well as %<letter> for colors (i.e. %r for red and %w for white).
*/
void FormatCustomMessage(std::string& message, ItemID iid);

/*
Replaces special characters and certain symbols with control codes
& for newline, ^ for wait-for-input, and @ for the player name,
as well as %<letter> for colors (i.e. %r for red and %w for white).
*/
void FormatCustomMessage(std::string& message);
};
33 changes: 33 additions & 0 deletions soh/soh/Enhancements/custom-message/CustomMessageTypes.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#pragma once

typedef enum {
TEXT_GS_NO_FREEZE = 0xB4,
TEXT_GS_FREEZE = 0xB5,
TEXT_RANDOMIZER_CUSTOM_ITEM = 0xF8,
TEXT_SCRUB_POH = 0x10A2,
TEXT_SCRUB_STICK_UPGRADE = 0x10DC,
TEXT_SCRUB_NUT_UPGRADE = 0x10DD,
TEXT_RANDOMIZER_GOSSIP_STONE_HINTS = 0x2053,
TEXT_ALTAR_CHILD = 0x7040,
TEXT_ALTAR_ADULT = 0x7088,
TEXT_GANONDORF = 0x70CC,
TEXT_GANONDORF_NOHINT = 0x70CD
} TextIDs;

#ifdef __cplusplus

typedef struct {
GetItemID giid;
ItemID iid;
std::string english;
std::string german;
std::string french;
} GetItemMessage;

#define GIMESSAGE(giid, iid, english, german, french) \
{ giid, iid, english, german, french }

#define GIMESSAGE_UNTRANSLATED(giid, iid, message) \
{ giid, iid, message, message, message }

#endif
Loading

0 comments on commit fa090c5

Please sign in to comment.