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