yaze 0.2.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
message_data.h
Go to the documentation of this file.
1#ifndef YAZE_APP_EDITOR_MESSAGE_MESSAGE_DATA_H
2#define YAZE_APP_EDITOR_MESSAGE_MESSAGE_DATA_H
3
4#include <regex>
5#include <string>
6#include <vector>
7
8#include "absl/strings/str_format.h"
9#include "absl/strings/str_replace.h"
10#include "app/rom.h"
11
12namespace yaze {
13namespace editor {
14
15const uint8_t kMessageTerminator = 0x7F;
16const std::string kBankToken = "BANK";
17const std::string DICTIONARYTOKEN = "D";
18constexpr uint8_t DICTOFF = 0x88;
19
20static const std::unordered_map<uint8_t, wchar_t> CharEncoder = {
21 {0x00, 'A'}, {0x01, 'B'}, {0x02, 'C'}, {0x03, 'D'}, {0x04, 'E'},
22 {0x05, 'F'}, {0x06, 'G'}, {0x07, 'H'}, {0x08, 'I'}, {0x09, 'J'},
23 {0x0A, 'K'}, {0x0B, 'L'}, {0x0C, 'M'}, {0x0D, 'N'}, {0x0E, 'O'},
24 {0x0F, 'P'}, {0x10, 'Q'}, {0x11, 'R'}, {0x12, 'S'}, {0x13, 'T'},
25 {0x14, 'U'}, {0x15, 'V'}, {0x16, 'W'}, {0x17, 'X'}, {0x18, 'Y'},
26 {0x19, 'Z'}, {0x1A, 'a'}, {0x1B, 'b'}, {0x1C, 'c'}, {0x1D, 'd'},
27 {0x1E, 'e'}, {0x1F, 'f'}, {0x20, 'g'}, {0x21, 'h'}, {0x22, 'i'},
28 {0x23, 'j'}, {0x24, 'k'}, {0x25, 'l'}, {0x26, 'm'}, {0x27, 'n'},
29 {0x28, 'o'}, {0x29, 'p'}, {0x2A, 'q'}, {0x2B, 'r'}, {0x2C, 's'},
30 {0x2D, 't'}, {0x2E, 'u'}, {0x2F, 'v'}, {0x30, 'w'}, {0x31, 'x'},
31 {0x32, 'y'}, {0x33, 'z'}, {0x34, '0'}, {0x35, '1'}, {0x36, '2'},
32 {0x37, '3'}, {0x38, '4'}, {0x39, '5'}, {0x3A, '6'}, {0x3B, '7'},
33 {0x3C, '8'}, {0x3D, '9'}, {0x3E, '!'}, {0x3F, '?'}, {0x40, '-'},
34 {0x41, '.'}, {0x42, ','}, {0x44, '>'}, {0x45, '('}, {0x46, ')'},
35 {0x4C, '"'}, {0x51, '\''}, {0x59, ' '}, {0x5A, '<'}, {0x5F, L'¡'},
36 {0x60, L'¡'}, {0x61, L'¡'}, {0x62, L' '}, {0x63, L' '}, {0x64, L' '},
37 {0x65, ' '}, {0x66, '_'},
38};
39
40uint8_t FindMatchingCharacter(char value);
41int8_t FindDictionaryEntry(uint8_t value);
42std::vector<uint8_t> ParseMessageToData(std::string str);
43
45 uint8_t ID = 0;
46 std::string Contents = "";
47 std::vector<uint8_t> Data;
48 int Length = 0;
49 std::string Token = "";
50
51 DictionaryEntry() = default;
52 DictionaryEntry(uint8_t i, std::string s)
53 : Contents(s), ID(i), Length(s.length()) {
54 Token = absl::StrFormat("[%s:%02X]", DICTIONARYTOKEN, ID);
56 }
57
58 bool ContainedInString(std::string s) const {
59 return s.find(Contents) != std::string::npos;
60 }
61
62 std::string ReplaceInstancesOfIn(std::string s) const {
63 std::string replaced_string = s;
64 size_t pos = replaced_string.find(Contents);
65 while (pos != std::string::npos) {
66 replaced_string.replace(pos, Contents.length(), Token);
67 pos = replaced_string.find(Contents, pos + Token.length());
68 }
69 return replaced_string;
70 }
71};
72
73constexpr int kTextData = 0xE0000;
74constexpr int kTextDataEnd = 0xE7FFF;
75constexpr int kNumDictionaryEntries = 0x61;
76constexpr int kPointersDictionaries = 0x74703;
77constexpr uint8_t kScrollVertical = 0x73;
78constexpr uint8_t kLine1 = 0x74;
79constexpr uint8_t kLine2 = 0x75;
80constexpr uint8_t kLine3 = 0x76;
81
82std::vector<DictionaryEntry> BuildDictionaryEntries(Rom *rom);
83std::string ReplaceAllDictionaryWords(std::string str,
84 std::vector<DictionaryEntry> dictionary);
85
86// Inserted into commands to protect them from dictionary replacements.
87const std::string CHEESE = "\uBEBE";
88
90 int ID = 0;
91 int Address = 0;
92 std::string RawString;
93 std::string ContentsParsed;
94 std::vector<uint8_t> Data;
95 std::vector<uint8_t> DataParsed;
96
97 MessageData() = default;
98 MessageData(int id, int address, const std::string &rawString,
99 const std::vector<uint8_t> &rawData,
100 const std::string &parsedString,
101 const std::vector<uint8_t> &parsedData)
102 : ID(id),
103 Address(address),
104 RawString(rawString),
105 Data(rawData),
106 DataParsed(parsedData),
107 ContentsParsed(parsedString) {}
108
109 // Copy constructor
110 MessageData(const MessageData &other) {
111 ID = other.ID;
112 Address = other.Address;
113 RawString = other.RawString;
114 Data = other.Data;
115 DataParsed = other.DataParsed;
117 }
118
119 std::string ToString() const {
120 return absl::StrFormat("%0X - %s", ID, ContentsParsed);
121 }
122
124 std::string message_string,
125 const std::vector<DictionaryEntry> &dictionary) {
126 std::stringstream protons;
127 bool command = false;
128 for (const auto &c : message_string) {
129 if (c == '[') {
130 command = true;
131 } else if (c == ']') {
132 command = false;
133 }
134
135 protons << c;
136 if (command) {
137 protons << CHEESE;
138 }
139 }
140
141 std::string protons_string = protons.str();
142 std::string replaced_string =
143 ReplaceAllDictionaryWords(protons_string, dictionary);
144 std::string final_string =
145 absl::StrReplaceAll(replaced_string, {{CHEESE, ""}});
146
147 return final_string;
148 }
149
150 void SetMessage(const std::string &message,
151 const std::vector<DictionaryEntry> &dictionary) {
152 RawString = message;
153 ContentsParsed = OptimizeMessageForDictionary(message, dictionary);
154 }
155};
156
158 uint8_t ID;
159 std::string Token;
160 std::string GenericToken;
161 std::string Pattern;
162 std::string StrictPattern;
163 std::string Description;
165
166 TextElement() = default;
167 TextElement(uint8_t id, const std::string &token, bool arg,
168 const std::string &description) {
169 ID = id;
170 Token = token;
171 if (arg) {
172 GenericToken = absl::StrFormat("[%s:##]", Token);
173 } else {
174 GenericToken = absl::StrFormat("[%s]", Token);
175 }
176 HasArgument = arg;
177 Description = description;
178 if (arg) {
179 Pattern = absl::StrFormat(
180 "\\[%s(:[0-9A-F]{1,2})?\\]",
181 absl::StrReplaceAll(Token, {{"[", "\\["}, {"]", "\\]"}}));
182 } else {
183 Pattern = absl::StrFormat(
184 "\\[%s\\]", absl::StrReplaceAll(Token, {{"[", "\\["}, {"]", "\\]"}}));
185 }
186 StrictPattern = absl::StrFormat("^%s$", Pattern);
187 }
188
189 std::string GetParamToken(uint8_t value = 0) const {
190 if (HasArgument) {
191 return absl::StrFormat("[%s:%02X]", Token, value);
192 } else {
193 return absl::StrFormat("[%s]", Token);
194 }
195 }
196
197 std::string ToString() const {
198 return absl::StrFormat("%s %s", GenericToken, Description);
199 }
200
201 std::smatch MatchMe(std::string dfrag) const {
202 std::regex pattern(StrictPattern);
203 std::smatch match;
204 std::regex_match(dfrag, match, pattern);
205 return match;
206 }
207
208 bool Empty() const { return ID == 0; }
209
210 // Comparison operator
211 bool operator==(const TextElement &other) const { return ID == other.ID; }
212};
213
214const static std::string kWindowBorder = "Window border";
215const static std::string kWindowPosition = "Window position";
216const static std::string kScrollSpeed = "Scroll speed";
217const static std::string kTextDrawSpeed = "Text draw speed";
218const static std::string kTextColor = "Text color";
219const static std::string kPlayerName = "Player name";
220const static std::string kLine1Str = "Line 1";
221const static std::string kLine2Str = "Line 2";
222const static std::string kLine3Str = "Line 3";
223const static std::string kWaitForKey = "Wait for key";
224const static std::string kScrollText = "Scroll text";
225const static std::string kDelayX = "Delay X";
226const static std::string kBCDNumber = "BCD number";
227const static std::string kSoundEffect = "Sound effect";
228const static std::string kChoose3 = "Choose 3";
229const static std::string kChoose2High = "Choose 2 high";
230const static std::string kChoose2Low = "Choose 2 low";
231const static std::string kChoose2Indented = "Choose 2 indented";
232const static std::string kChooseItem = "Choose item";
233const static std::string kNextAttractImage = "Next attract image";
234const static std::string kBankMarker = "Bank marker (automatic)";
235const static std::string kCrash = "Crash";
236
237static const std::vector<TextElement> TextCommands = {
238 TextElement(0x6B, "W", true, kWindowBorder),
239 TextElement(0x6D, "P", true, kWindowPosition),
240 TextElement(0x6E, "SPD", true, kScrollSpeed),
241 TextElement(0x7A, "S", true, kTextDrawSpeed),
242 TextElement(0x77, "C", true, kTextColor),
243 TextElement(0x6A, "L", false, kPlayerName),
244 TextElement(0x74, "1", false, kLine1Str),
245 TextElement(0x75, "2", false, kLine2Str),
246 TextElement(0x76, "3", false, kLine3Str),
247 TextElement(0x7E, "K", false, kWaitForKey),
248 TextElement(0x73, "V", false, kScrollText),
249 TextElement(0x78, "WT", true, kDelayX),
250 TextElement(0x6C, "N", true, kBCDNumber),
251 TextElement(0x79, "SFX", true, kSoundEffect),
252 TextElement(0x71, "CH3", false, kChoose3),
253 TextElement(0x72, "CH2", false, kChoose2High),
254 TextElement(0x6F, "CH2L", false, kChoose2Low),
255 TextElement(0x68, "CH2I", false, kChoose2Indented),
256 TextElement(0x69, "CHI", false, kChooseItem),
257 TextElement(0x67, "IMG", false, kNextAttractImage),
258 TextElement(0x80, kBankToken, false, kBankMarker),
259 TextElement(0x70, "NONO", false, kCrash),
260};
261
262std::optional<TextElement> FindMatchingCommand(uint8_t b);
263
264static const std::vector<TextElement> SpecialChars = {
265 TextElement(0x43, "...", false, "Ellipsis …"),
266 TextElement(0x4D, "UP", false, "Arrow ↑"),
267 TextElement(0x4E, "DOWN", false, "Arrow ↓"),
268 TextElement(0x4F, "LEFT", false, "Arrow ←"),
269 TextElement(0x50, "RIGHT", false, "Arrow →"),
270 TextElement(0x5B, "A", false, "Button Ⓐ"),
271 TextElement(0x5C, "B", false, "Button Ⓑ"),
272 TextElement(0x5D, "X", false, "Button ⓧ"),
273 TextElement(0x5E, "Y", false, "Button ⓨ"),
274 TextElement(0x52, "HP1L", false, "1 HP left"),
275 TextElement(0x53, "HP1R", false, "1 HP right"),
276 TextElement(0x54, "HP2L", false, "2 HP left"),
277 TextElement(0x55, "HP3L", false, "3 HP left"),
278 TextElement(0x56, "HP3R", false, "3 HP right"),
279 TextElement(0x57, "HP4L", false, "4 HP left"),
280 TextElement(0x58, "HP4R", false, "4 HP right"),
281 TextElement(0x47, "HY0", false, "Hieroglyph ☥"),
282 TextElement(0x48, "HY1", false, "Hieroglyph 𓈗"),
283 TextElement(0x49, "HY2", false, "Hieroglyph Ƨ"),
284 TextElement(0x4A, "LFL", false, "Link face left"),
285 TextElement(0x4B, "LFR", false, "Link face right"),
286};
287
288std::optional<TextElement> FindMatchingSpecial(uint8_t b);
289
292 uint8_t Value;
293 bool Active = false;
294
295 ParsedElement() = default;
296 ParsedElement(TextElement textElement, uint8_t value) {
297 Parent = textElement;
298 Value = value;
299 Active = true;
300 }
301};
302
303ParsedElement FindMatchingElement(const std::string &str);
304
305std::string ParseTextDataByte(uint8_t value);
306
307absl::StatusOr<MessageData> ParseSingleMessage(
308 const std::vector<uint8_t> &rom_data, int *current_pos);
309
310std::vector<std::string> ParseMessageData(
311 std::vector<MessageData> &message_data,
312 const std::vector<DictionaryEntry> &dictionary_entries);
313
314constexpr int kTextData2 = 0x75F40;
315constexpr int kTextData2End = 0x773FF;
316
317// Reads all text data from the ROM and returns a vector of MessageData objects.
318void ReadAllTextData(Rom *rom, std::vector<MessageData> &list_of_texts_);
319
320std::vector<std::string> ImportMessageData(std::string_view filename);
321
322} // namespace editor
323} // namespace yaze
324
325#endif // YAZE_APP_EDITOR_MESSAGE_MESSAGE_DATA_H
The Rom class is used to load, save, and modify Rom data.
Definition rom.h:59
Editors are the view controllers for the application.
uint8_t FindMatchingCharacter(char value)
const std::string kBankToken
const std::string CHEESE
const uint8_t kMessageTerminator
const std::string DICTIONARYTOKEN
constexpr uint8_t kScrollVertical
std::string ParseTextDataByte(uint8_t value)
constexpr uint8_t kLine1
constexpr int kTextData
constexpr int kTextData2
constexpr uint8_t kLine2
std::string ReplaceAllDictionaryWords(std::string str, std::vector< DictionaryEntry > dictionary)
constexpr int kPointersDictionaries
constexpr int kNumDictionaryEntries
absl::StatusOr< MessageData > ParseSingleMessage(const std::vector< uint8_t > &rom_data, int *current_pos)
std::vector< std::string > ParseMessageData(std::vector< MessageData > &message_data, const std::vector< DictionaryEntry > &dictionary_entries)
std::optional< TextElement > FindMatchingSpecial(uint8_t value)
void ReadAllTextData(Rom *rom, std::vector< MessageData > &list_of_texts_)
constexpr int kTextData2End
std::vector< DictionaryEntry > BuildDictionaryEntries(Rom *rom)
std::vector< std::string > ImportMessageData(std::string_view filename)
std::vector< uint8_t > ParseMessageToData(std::string str)
constexpr uint8_t DICTOFF
std::optional< TextElement > FindMatchingCommand(uint8_t b)
ParsedElement FindMatchingElement(const std::string &str)
constexpr uint8_t kLine3
int8_t FindDictionaryEntry(uint8_t value)
constexpr int kTextDataEnd
Main namespace for the application.
Definition controller.cc:18
bool ContainedInString(std::string s) const
DictionaryEntry(uint8_t i, std::string s)
std::vector< uint8_t > Data
std::string ReplaceInstancesOfIn(std::string s) const
MessageData(const MessageData &other)
std::vector< uint8_t > Data
std::vector< uint8_t > DataParsed
std::string OptimizeMessageForDictionary(std::string message_string, const std::vector< DictionaryEntry > &dictionary)
std::string ToString() const
void SetMessage(const std::string &message, const std::vector< DictionaryEntry > &dictionary)
MessageData(int id, int address, const std::string &rawString, const std::vector< uint8_t > &rawData, const std::string &parsedString, const std::vector< uint8_t > &parsedData)
ParsedElement(TextElement textElement, uint8_t value)
std::string ToString() const
TextElement(uint8_t id, const std::string &token, bool arg, const std::string &description)
std::smatch MatchMe(std::string dfrag) const
bool operator==(const TextElement &other) const
std::string GetParamToken(uint8_t value=0) const