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_cat.h"
9#include "absl/strings/str_format.h"
10#include "absl/strings/str_replace.h"
11#include "app/rom.h"
12
13namespace yaze {
14namespace editor {
15
16const uint8_t kMessageTerminator = 0x7F;
17const std::string kBankToken = "BANK";
18const std::string DICTIONARYTOKEN = "D";
19constexpr uint8_t DICTOFF = 0x88;
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);
42uint8_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:%00X]", 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 = 97;
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);
86
87// Inserted into commands to protect them from dictionary replacements.
88const std::string CHEESE = "\uBEBE";
89
91 int ID = 0;
92 int Address = 0;
93 std::string RawString;
94 std::string ContentsParsed;
95 std::vector<uint8_t> Data;
96 std::vector<uint8_t> DataParsed;
97
98 MessageData() = default;
99 MessageData(int id, int address, const std::string &rawString,
100 const std::vector<uint8_t> &rawData,
101 const std::string &parsedString,
102 const std::vector<uint8_t> &parsedData)
103 : ID(id),
104 Address(address),
105 RawString(rawString),
106 Data(rawData),
107 DataParsed(parsedData),
108 ContentsParsed(parsedString) {}
109
110 // Copy constructor
111 MessageData(const MessageData &other) {
112 ID = other.ID;
113 Address = other.Address;
114 RawString = other.RawString;
115 Data = other.Data;
116 DataParsed = other.DataParsed;
118 }
119
120 std::string ToString() const {
121 return absl::StrFormat("%0X - %s", ID, ContentsParsed);
122 }
123
125 std::string message_string,
126 const std::vector<DictionaryEntry> &dictionary) {
127 std::stringstream protons;
128 bool command = false;
129 for (const auto &c : message_string) {
130 if (c == '[') {
131 command = true;
132 } else if (c == ']') {
133 command = false;
134 }
135
136 protons << c;
137 if (command) {
138 protons << CHEESE;
139 }
140 }
141
142 std::string protons_string = protons.str();
143 std::string replaced_string =
144 ReplaceAllDictionaryWords(protons_string, dictionary);
145 std::string final_string =
146 absl::StrReplaceAll(replaced_string, {{CHEESE, ""}});
147
148 return final_string;
149 }
150
151 void SetMessage(const std::string &message,
152 const std::vector<DictionaryEntry> &dictionary) {
153 RawString = message;
154 ContentsParsed = OptimizeMessageForDictionary(message, dictionary);
155 }
156};
157
159 uint8_t ID;
160 std::string Token;
161 std::string GenericToken;
162 std::string Pattern;
163 std::string StrictPattern;
164 std::string Description;
166
167 TextElement() = default;
168 TextElement(uint8_t id, const std::string &token, bool arg,
169 const std::string &description) {
170 ID = id;
171 Token = token;
172 if (arg) {
173 GenericToken = absl::StrFormat("[%s:##]", Token);
174 } else {
175 GenericToken = absl::StrFormat("[%s]", Token);
176 }
177 HasArgument = arg;
178 Description = description;
179 Pattern =
180 arg ? "\\[" + Token + ":?([0-9A-F]{1,2})\\]" : "\\[" + Token + "\\]";
181 Pattern = absl::StrReplaceAll(Pattern, {{"[", "\\["}, {"]", "\\]"}});
182 StrictPattern = absl::StrCat("^", Pattern, "$");
183 StrictPattern = "^" + Pattern + "$";
184 }
185
186 std::string GetParamToken(uint8_t value = 0) const {
187 if (HasArgument) {
188 return absl::StrFormat("[%s:%02X]", Token, value);
189 } else {
190 return absl::StrFormat("[%s]", Token);
191 }
192 }
193
194 std::string ToString() const {
195 return absl::StrFormat("%s %s", GenericToken, Description);
196 }
197
198 std::smatch MatchMe(std::string dfrag) const {
199 std::regex pattern(StrictPattern);
200 std::smatch match;
201 std::regex_match(dfrag, match, pattern);
202 return match;
203 }
204
205 bool Empty() const { return ID == 0; }
206
207 // Comparison operator
208 bool operator==(const TextElement &other) const { return ID == other.ID; }
209};
210
211const static std::string kWindowBorder = "Window border";
212const static std::string kWindowPosition = "Window position";
213const static std::string kScrollSpeed = "Scroll speed";
214const static std::string kTextDrawSpeed = "Text draw speed";
215const static std::string kTextColor = "Text color";
216const static std::string kPlayerName = "Player name";
217const static std::string kLine1Str = "Line 1";
218const static std::string kLine2Str = "Line 2";
219const static std::string kLine3Str = "Line 3";
220const static std::string kWaitForKey = "Wait for key";
221const static std::string kScrollText = "Scroll text";
222const static std::string kDelayX = "Delay X";
223const static std::string kBCDNumber = "BCD number";
224const static std::string kSoundEffect = "Sound effect";
225const static std::string kChoose3 = "Choose 3";
226const static std::string kChoose2High = "Choose 2 high";
227const static std::string kChoose2Low = "Choose 2 low";
228const static std::string kChoose2Indented = "Choose 2 indented";
229const static std::string kChooseItem = "Choose item";
230const static std::string kNextAttractImage = "Next attract image";
231const static std::string kBankMarker = "Bank marker (automatic)";
232const static std::string kCrash = "Crash";
233
234static const std::vector<TextElement> TextCommands = {
235 TextElement(0x6B, "W", true, kWindowBorder),
236 TextElement(0x6D, "P", true, kWindowPosition),
237 TextElement(0x6E, "SPD", true, kScrollSpeed),
238 TextElement(0x7A, "S", true, kTextDrawSpeed),
239 TextElement(0x77, "C", true, kTextColor),
240 TextElement(0x6A, "L", false, kPlayerName),
241 TextElement(0x74, "1", false, kLine1Str),
242 TextElement(0x75, "2", false, kLine2Str),
243 TextElement(0x76, "3", false, kLine3Str),
244 TextElement(0x7E, "K", false, kWaitForKey),
245 TextElement(0x73, "V", false, kScrollText),
246 TextElement(0x78, "WT", true, kDelayX),
247 TextElement(0x6C, "N", true, kBCDNumber),
248 TextElement(0x79, "SFX", true, kSoundEffect),
249 TextElement(0x71, "CH3", false, kChoose3),
250 TextElement(0x72, "CH2", false, kChoose2High),
251 TextElement(0x6F, "CH2L", false, kChoose2Low),
252 TextElement(0x68, "CH2I", false, kChoose2Indented),
253 TextElement(0x69, "CHI", false, kChooseItem),
254 TextElement(0x67, "IMG", false, kNextAttractImage),
255 TextElement(0x80, kBankToken, false, kBankMarker),
256 TextElement(0x70, "NONO", false, kCrash),
257};
258
259TextElement FindMatchingCommand(uint8_t b);
260
261static const std::vector<TextElement> SpecialChars = {
262 TextElement(0x43, "...", false, "Ellipsis …"),
263 TextElement(0x4D, "UP", false, "Arrow ↑"),
264 TextElement(0x4E, "DOWN", false, "Arrow ↓"),
265 TextElement(0x4F, "LEFT", false, "Arrow ←"),
266 TextElement(0x50, "RIGHT", false, "Arrow →"),
267 TextElement(0x5B, "A", false, "Button Ⓐ"),
268 TextElement(0x5C, "B", false, "Button Ⓑ"),
269 TextElement(0x5D, "X", false, "Button ⓧ"),
270 TextElement(0x5E, "Y", false, "Button ⓨ"),
271 TextElement(0x52, "HP1L", false, "1 HP left"),
272 TextElement(0x53, "HP1R", false, "1 HP right"),
273 TextElement(0x54, "HP2L", false, "2 HP left"),
274 TextElement(0x55, "HP3L", false, "3 HP left"),
275 TextElement(0x56, "HP3R", false, "3 HP right"),
276 TextElement(0x57, "HP4L", false, "4 HP left"),
277 TextElement(0x58, "HP4R", false, "4 HP right"),
278 TextElement(0x47, "HY0", false, "Hieroglyph ☥"),
279 TextElement(0x48, "HY1", false, "Hieroglyph 𓈗"),
280 TextElement(0x49, "HY2", false, "Hieroglyph Ƨ"),
281 TextElement(0x4A, "LFL", false, "Link face left"),
282 TextElement(0x4B, "LFR", false, "Link face right"),
283};
284
286
289 uint8_t Value;
290 bool Active = false;
291
292 ParsedElement() = default;
293 ParsedElement(TextElement textElement, uint8_t value) {
294 Parent = textElement;
295 Value = value;
296 Active = true;
297 }
298};
299
300ParsedElement FindMatchingElement(const std::string &str);
301
302std::string ParseTextDataByte(uint8_t value);
303
304absl::StatusOr<MessageData> ParseSingleMessage(
305 const std::vector<uint8_t> &rom_data, int *current_pos);
306
307std::vector<std::string> ParseMessageData(
308 std::vector<MessageData> &message_data,
309 const std::vector<DictionaryEntry> &dictionary_entries);
310
311std::vector<std::string> ImportMessageData(std::string_view filename);
312
313} // namespace editor
314} // namespace yaze
315
316#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
uint8_t FindDictionaryEntry(uint8_t value)
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::vector< DictionaryEntry > BuildDictionaryEntries(Rom *rom)
std::vector< std::string > ImportMessageData(std::string_view filename)
TextElement FindMatchingSpecial(uint8_t value)
std::vector< uint8_t > ParseMessageToData(std::string str)
constexpr uint8_t DICTOFF
ParsedElement FindMatchingElement(const std::string &str)
TextElement FindMatchingCommand(uint8_t b)
constexpr uint8_t kLine3
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