Merge pull request #831 from leggettc18/custom-messages
System for Creating and Storing Custom Messagespull/1104/head
commit
fa090c51f6
@ -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;
|
||||
}
|
@ -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);
|
||||
};
|
@ -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…
Reference in New Issue