Files
jak-project/common/util/FontUtils.cpp
T
2023-09-16 23:23:29 -04:00

1890 lines
55 KiB
C++
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*!
* @file FontUtils.cpp
*
* Code for handling text and strings in Jak 1's "large font" format.
*
* MAKE SURE THIS FILE IS ENCODED IN UTF-8!!! The various strings here depend on it.
* Always verify the encoding if string detection suddenly goes awry.
*/
#include "FontUtils.h"
#include <algorithm>
#include <stdexcept>
#include "string_util.h"
#include "common/util/Assert.h"
#include "third-party/fmt/core.h"
#include "third-party/fmt/format.h"
const std::unordered_map<std::string, GameTextVersion> sTextVerEnumMap = {
{"jak1-v1", GameTextVersion::JAK1_V1},
{"jak1-v2", GameTextVersion::JAK1_V2},
{"jak2", GameTextVersion::JAK2}};
const std::string& get_text_version_name(GameTextVersion version) {
for (auto& [name, ver] : sTextVerEnumMap) {
if (ver == version) {
return name;
}
}
throw std::runtime_error(fmt::format("invalid text version {}", fmt::underlying(version)));
}
GameTextVersion get_text_version_from_name(const std::string& name) {
return sTextVerEnumMap.at(name);
}
GameTextFontBank::GameTextFontBank(GameTextVersion version,
std::vector<EncodeInfo>* encode_info,
std::vector<ReplaceInfo>* replace_info,
std::unordered_set<char>* passthrus)
: m_version(version),
m_encode_info(encode_info),
m_replace_info(replace_info),
m_passthrus(passthrus) {
std::sort(
m_encode_info->begin(), m_encode_info->end(),
[](const EncodeInfo& a, const EncodeInfo& b) { return a.bytes.size() > b.bytes.size(); });
std::sort(
m_replace_info->begin(), m_replace_info->end(),
[](const ReplaceInfo& a, const ReplaceInfo& b) { return a.from.size() > b.from.size(); });
}
/*!
* Finds a remap info that best matches the byte sequence (is the longest match).
*/
const EncodeInfo* GameTextFontBank::find_encode_to_utf8(const char* in) const {
const EncodeInfo* best_info = nullptr;
for (auto& info : *m_encode_info) {
if (info.bytes.size() == 0)
continue;
bool found = true;
for (int i = 0; found && i < (int)info.bytes.size(); ++i) {
if (uint8_t(in[i]) != info.bytes.at(i)) {
found = false;
}
}
if (found && (!best_info || info.chars.length() > best_info->chars.length())) {
best_info = &info;
}
}
return best_info;
}
/*!
* Finds a remap info that best matches the character sequence (is the longest match).
*/
const EncodeInfo* GameTextFontBank::find_encode_to_game(const std::string& in, int off) const {
const EncodeInfo* best_info = nullptr;
for (auto& info : *m_encode_info) {
if (info.chars.length() == 0)
continue;
bool found = true;
for (int i = 0; found && i < (int)info.chars.length() && i + off < (int)in.size(); ++i) {
if (in.at(i + off) != info.chars.at(i)) {
found = false;
}
}
if (found && (!best_info || info.chars.length() > best_info->chars.length())) {
best_info = &info;
}
}
return best_info;
}
/*!
* Finds a remap info that best matches the character sequence (is the longest match).
*/
const ReplaceInfo* GameTextFontBank::find_replace_to_utf8(const std::string& in, int off) const {
const ReplaceInfo* best_info = nullptr;
for (auto& info : *m_replace_info) {
if (info.from.empty() || in.size() - off < info.from.size())
continue;
bool found = memcmp(in.data() + off, info.from.data(), info.from.size()) == 0;
if (found && (!best_info || info.from.length() > best_info->from.length())) {
best_info = &info;
}
}
return best_info;
}
/*!
* Finds a remap info that best matches the character sequence (is the longest match).
*/
const ReplaceInfo* GameTextFontBank::find_replace_to_game(const std::string& in, int off) const {
const ReplaceInfo* best_info = nullptr;
for (auto& info : *m_replace_info) {
if (info.to.empty() || in.size() - off < info.to.size())
continue;
bool found = memcmp(in.data() + off, info.to.data(), info.to.size()) == 0;
if (found && (!best_info || info.to.length() > best_info->to.length())) {
best_info = &info;
}
}
return best_info;
}
/*!
* Try to replace specific substrings with better variants.
* These are for hiding confusing text transforms.
*/
std::string GameTextFontBank::replace_to_utf8(std::string& str) const {
std::string newstr;
for (int i = 0; i < (int)str.length();) {
auto remap = find_replace_to_utf8(str, i);
if (!remap) {
newstr.push_back(str.at(i));
i += 1;
} else {
for (auto b : remap->to) {
newstr.push_back(b);
}
i += remap->from.length();
}
}
str = newstr;
return str;
}
std::string GameTextFontBank::replace_to_game(std::string& str) const {
std::string newstr;
for (int i = 0; i < (int)str.length();) {
auto remap = find_replace_to_game(str, i);
if (!remap) {
newstr.push_back(str.at(i));
i += 1;
} else {
for (auto b : remap->from) {
newstr.push_back(b);
}
i += remap->to.length();
}
}
str = newstr;
return str;
}
std::string GameTextFontBank::encode_utf8_to_game(std::string& str) const {
std::string newstr;
for (int i = 0; i < (int)str.length();) {
auto remap = find_encode_to_game(str, i);
if (!remap) {
newstr.push_back(str.at(i));
i += 1;
} else {
for (auto b : remap->bytes) {
newstr.push_back(b);
}
i += remap->chars.length();
}
}
str = newstr;
return str;
}
/*!
* Turn a normal readable string into a string readable in the in-game font encoding and converts
* \cXX escape sequences
*/
// NOTE - the convert_utf8_to_game function is really really slow (about 80-90% of the
// time loading the text files)
// TODO - improve that as a follow up sometime in the future
std::string GameTextFontBank::convert_utf8_to_game(std::string str, bool escape) const {
std::string newstr;
if (escape) {
for (size_t i = 0; i < str.size(); ++i) {
auto c = str.at(i);
if (c == '"') {
newstr.push_back('"');
i += 1;
} else if (c == '\\') {
if (i + 1 >= str.size()) {
throw std::runtime_error("incomplete string escape code");
}
auto p = str.at(i + 1);
if (p == 'c') {
if (i + 3 >= str.size()) {
throw std::runtime_error("incomplete string escape code");
}
auto first = str.at(i + 2);
auto second = str.at(i + 3);
if (!str_util::hex_char(first) || !str_util::hex_char(second)) {
throw std::runtime_error("invalid character escape hex number");
}
char hex_num[3] = {first, second, '\0'};
std::size_t end = 0;
auto value = std::stoul(hex_num, &end, 16);
if (end != 2) {
throw std::runtime_error("invalid character escape");
}
ASSERT(value < 256);
newstr.push_back(char(value));
i += 3;
} else if (p == '"' || p == '\\') {
newstr.push_back(p);
i += 1;
} else {
throw std::runtime_error(
fmt::format("unknown string escape code '{}' (0x{:x})", p, u32(p)));
}
} else {
newstr.push_back(c);
}
}
} else {
newstr = str;
}
replace_to_game(newstr);
encode_utf8_to_game(newstr);
return newstr;
}
bool GameTextFontBank::valid_char_range(const char in) const {
if (m_version == GameTextVersion::JAK1_V1 || m_version == GameTextVersion::JAK1_V2) {
return ((in >= '0' && in <= '9') || (in >= 'A' && in <= 'Z') ||
m_passthrus->find(in) != m_passthrus->end()) &&
in != '\\';
} else if (m_version == GameTextVersion::JAK2) {
return ((in >= '0' && in <= '9') || (in >= 'A' && in <= 'Z') || (in >= 'a' && in <= 'z') ||
m_passthrus->find(in) != m_passthrus->end()) &&
in != '\\';
}
return false;
}
/*!
* Convert a string from the game-text font encoding to something normal.
* Unprintable characters become escape sequences, including tab and newline.
*/
std::string GameTextFontBank::convert_game_to_utf8(const char* in) const {
std::string temp;
std::string result;
while (*in) {
auto remap = find_encode_to_utf8(in);
if (remap != nullptr) {
temp.append(remap->chars);
in += remap->bytes.size() - 1;
} else if (valid_char_range(*in) || *in == '\n' || *in == '\t' || *in == '\\' || *in == '\"') {
temp.push_back(*in);
} else {
temp += fmt::format("\\c{:02x}", uint8_t(*in));
}
in++;
}
replace_to_utf8(temp);
for (size_t i = 0; i < temp.length(); ++i) {
auto c = temp.at(i);
if (c == '\n') {
result += "\\n";
} else if (c == '\t') {
result += "\\t";
} else if (c == '\\') {
if (i < temp.length() - 1 && temp.at(i + 1) == 'c') {
result.push_back(c);
} else {
result += "\\\\";
}
} else if (c == '"') {
result += "\\\"";
} else {
result.push_back(c);
}
}
return replace_to_utf8(result);
}
static std::vector<EncodeInfo> s_encode_info_null = {};
static std::vector<ReplaceInfo> s_replace_info_null = {};
/*!
* ===========================
* GAME TEXT FONT BANK - JAK 1
* ===========================
* This font is used in:
* - Jak & Daxter: The Precursor Legacy (Black Label)
*/
static std::unordered_set<char> s_passthrus_jak1 = {'~', ' ', ',', '.', '-', '+', '(', ')',
'!', ':', '?', '=', '%', '*', '/', '#',
';', '<', '>', '@', '[', '_'};
static std::vector<EncodeInfo> s_encode_info_jak1 = {
// random
{"ˇ", {0x10}}, // caron
{"`", {0x11}}, // grave accent
{"'", {0x12}}, // apostrophe
{"^", {0x13}}, // circumflex
{"<TIL>", {0x14}}, // tilde
{"¨", {0x15}}, // umlaut
{"º", {0x16}}, // numero/overring
{"¡", {0x17}}, // inverted exclamation mark
{"¿", {0x18}}, // inverted question mark
{"", {0x1a}}, // umi
{"Æ", {0x1b}}, // aesc
{"", {0x1c}}, // kai
{"Ç", {0x1d}}, // c-cedilla
{"", {0x1e}}, // gaku
{"ß", {0x1f}}, // eszett
{"", {0x24}}, // wa
{"", {0x26}}, // wo
{"", {0x27}}, // -n
{"", {0x5c}}, // iwa
{"", {0x5d}}, // kyuu
{"", {0x5e}}, // sora
//{"掘", {0x5f}}, // horu
{"", {0x60}}, // -wa
{"", {0x61}}, // utsu
{"", {0x62}}, // kashikoi
{"", {0x63}}, // mizuumi
{"", {0x64}}, // kuchi
{"", {0x65}}, // iku
{"", {0x66}}, // ai
{"", {0x67}}, // shi
{"", {0x68}}, // tera
{"", {0x69}}, // yama
{"", {0x6a}}, // mono
{"", {0x6b}}, // tokoro
{"", {0x6c}}, // kaku
{"", {0x6d}}, // shou
{"", {0x6e}}, // numa
{"", {0x6f}}, // ue
{"", {0x70}}, // shiro
{"", {0x71}}, // ba
{"", {0x72}}, // shutsu
{"", {0x73}}, // yami
{"", {0x74}}, // nokosu
{"", {0x75}}, // ki
{"", {0x76}}, // ya
{"", {0x77}}, // shita
{"", {0x78}}, // ie
{"", {0x79}}, // hi
{"", {0x7a}}, // hana
{"", {0x7b}}, // re
{"Œ", {0x7c}}, // oe
{"", {0x7d}}, // ro
{"", {0x7f}}, // ao
{"", {0x90}}, // nakaguro
{"", {0x91}}, // dakuten
{"", {0x92}}, // handakuten
{"", {0x93}}, // chouompu
{"", {0x94}}, // nijuukagikakko left
{"", {0x95}}, // nijuukagikakko right
// hiragana
{"", {0x96}}, // -a
{"", {0x97}}, // a
{"", {0x98}}, // -i
{"", {0x99}}, // i
{"", {0x9a}}, // -u
{"", {0x9b}}, // u
{"", {0x9c}}, // -e
{"", {0x9d}}, // e
{"", {0x9e}}, // -o
{"", {0x9f}}, // o
{"", {0xa0}}, // ka
{"", {0xa1}}, // ki
{"", {0xa2}}, // ku
{"", {0xa3}}, // ke
{"", {0xa4}}, // ko
{"", {0xa5}}, // sa
{"", {0xa6}}, // shi
{"", {0xa7}}, // su
{"", {0xa8}}, // se
{"", {0xa9}}, // so
{"", {0xaa}}, // ta
{"", {0xab}}, // chi
{"", {0xac}}, // sokuon
{"", {0xad}}, // tsu
{"", {0xae}}, // te
{"", {0xaf}}, // to
{"", {0xb0}}, // na
{"", {0xb1}}, // ni
{"", {0xb2}}, // nu
{"", {0xb3}}, // ne
{"", {0xb4}}, // no
{"", {0xb5}}, // ha
{"", {0xb6}}, // hi
{"", {0xb7}}, // hu
{"", {0xb8}}, // he
{"", {0xb9}}, // ho
{"", {0xba}}, // ma
{"", {0xbb}}, // mi
{"", {0xbc}}, // mu
{"", {0xbd}}, // me
{"", {0xbe}}, // mo
{"", {0xbf}}, // youon ya
{"", {0xc0}}, // ya
{"", {0xc1}}, // youon yu
{"", {0xc2}}, // yu
{"", {0xc3}}, // youon yo
{"", {0xc4}}, // yo
{"", {0xc5}}, // ra
{"", {0xc6}}, // ri
{"", {0xc7}}, // ru
{"", {0xc8}}, // re
{"", {0xc9}}, // ro
{"", {0xca}}, // -wa
{"", {0xcb}}, // wa
{"", {0xcc}}, // wo
{"", {0xcd}}, // -n
// katakana
{"", {0xce}}, // -a
{"", {0xcf}}, // a
{"", {0xd0}}, // -i
{"", {0xd1}}, // i
{"", {0xd2}}, // -u
{"", {0xd3}}, // u
{"", {0xd4}}, // -e
{"", {0xd5}}, // e
{"", {0xd6}}, // -o
{"", {0xd7}}, // o
{"", {0xd8}}, // ka
{"", {0xd9}}, // ki
{"", {0xda}}, // ku
{"", {0xdb}}, // ke
{"", {0xdc}}, // ko
{"", {0xdd}}, // sa
{"", {0xde}}, // shi
{"", {0xdf}}, // su
{"", {0xe0}}, // se
{"", {0xe1}}, // so
{"", {0xe2}}, // ta
{"", {0xe3}}, // chi
{"", {0xe4}}, // sokuon
{"", {0xe5}}, // tsu
{"", {0xe6}}, // te
{"", {0xe7}}, // to
{"", {0xe8}}, // na
{"", {0xe9}}, // ni
{"", {0xea}}, // nu
{"", {0xeb}}, // ne
{"", {0xec}}, // no
{"", {0xed}}, // ha
{"", {0xee}}, // hi
{"", {0xef}}, // hu
{"", {0xf0}}, // he
{"", {0xf1}}, // ho
{"", {0xf2}}, // ma
{"", {0xf3}}, // mi
{"", {0xf4}}, // mu
{"", {0xf5}}, // me
{"", {0xf6}}, // mo
{"", {0xf7}}, // youon ya
{"", {0xf8}}, // ya
{"", {0xf9}}, // youon yu
{"", {0xfa}}, // yu
{"", {0xfb}}, // youon yo
{"", {0xfc}}, // yo
{"", {0xfd}}, // ra
{"", {0xfe}}, // ri
{"", {0xff}}, // ru
// kanji 2
{"", {1, 0x01}}, // takara
{"", {1, 0x10}}, // ishi
{"", {1, 0x11}}, // aka
{"", {1, 0x12}}, // ato
{"", {1, 0x13}}, // kawa
{"", {1, 0x14}}, // ikusa
{"", {1, 0x15}}, // mura
{"", {1, 0x16}}, // tai
{"", {1, 0x17}}, // utena
{"", {1, 0x18}}, // osa
{"", {1, 0x19}}, // tori
{"", {1, 0x1a}}, // tei
{"", {1, 0x1b}}, // hora
{"", {1, 0x1c}}, // michi
{"", {1, 0x1d}}, // hatsu
{"", {1, 0x1e}}, // tobu
{"", {1, 0x1f}}, // fuku
{"", {1, 0xa0}}, // ike
{"", {1, 0xa1}}, // naka
{"", {1, 0xa2}}, // tou
{"", {1, 0xa3}}, // shima
{"", {1, 0xa4}}, // bu
{"", {1, 0xa5}}, // hou
{"", {1, 0xa6}}, // san
{"", {1, 0xa7}}, // kaerimiru
{"", {1, 0xa8}}, // chikara
{"", {1, 0xa9}}, // midori
{"", {1, 0xaa}}, // kishi
{"", {1, 0xab}}, // zou
{"", {1, 0xac}}, // tani
{"", {1, 0xad}}, // kokoro
{"", {1, 0xae}}, // mori
{"", {1, 0xaf}}, // mizu
{"", {1, 0xb0}}, // fune
{"", {1, 0xb1}}, // trademark
};
static std::vector<ReplaceInfo> s_replace_info_jak1 = {
// other
{"A~Y~-21H~-5Vº~Z", "Å"},
{"N~Y~-6Hº~Z~+10H", ""},
{"O~Y~-16H~-1V/~Z", "Ø"},
{"A~Y~-6H~+3V,~Z", "Ą"},
{"E~Y~-6H~+2V,~Z", "Ę"},
{"L~Y~-16H~+0V/~Z", "Ł"},
{"Z~Y~-21H~-5Vº~Z", "Ż"},
// tildes
{"N~Y~-22H~-4V<TIL>~Z", "Ñ"},
{"A~Y~-21H~-5V<TIL>~Z", "Ã"}, // custom
{"O~Y~-22H~-4V<TIL>~Z", "Õ"}, // custom
// acute accents
{"A~Y~-21H~-5V'~Z", "Á"},
{"E~Y~-22H~-5V'~Z", "É"},
{"I~Y~-19H~-5V'~Z", "Í"},
{"O~Y~-22H~-4V'~Z", "Ó"},
{"U~Y~-24H~-3V'~Z", "Ú"},
{"C~Y~-21H~-5V'~Z", "Ć"},
{"N~Y~-21H~-5V'~Z", "Ń"},
{"S~Y~-21H~-5V'~Z", "Ś"},
{"Z~Y~-21H~-5V'~Z", "Ź"},
// double acute accents
{"O~Y~-28H~-4V'~-9H'~Z", "Ő"}, // custom
{"U~Y~-27H~-4V'~-12H'~Z", "Ű"}, // custom
// circumflex
{"A~Y~-20H~-4V^~Z", "Â"}, // custom
{"E~Y~-20H~-5V^~Z", "Ê"},
{"I~Y~-19H~-5V^~Z", "Î"},
{"O~Y~-20H~-4V^~Z", "Ô"}, // custom
{"U~Y~-24H~-3V^~Z", "Û"},
// grave accents
{"A~Y~-21H~-5V`~Z", "À"},
{"E~Y~-22H~-5V`~Z", "È"},
{"I~Y~-19H~-5V`~Z", "Ì"},
{"O~Y~-22H~-4V`~Z", "Ò"}, // custom
{"U~Y~-24H~-3V`~Z", "Ù"},
// umlaut
{"A~Y~-21H~-5V¨~Z", "Ä"},
{"E~Y~-20H~-5V¨~Z", "Ë"},
{"I~Y~-19H~-5V¨~Z", "Ï"}, // custom
{"O~Y~-22H~-4V¨~Z", "Ö"},
{"O~Y~-22H~-3V¨~Z", "ö"}, // dumb
{"U~Y~-22H~-3V¨~Z", "Ü"},
// dakuten katakana
{"~Yウ~Z゛", ""},
{"~Yカ~Z゛", ""},
{"~Yキ~Z゛", ""},
{"~Yク~Z゛", ""},
{"~Yケ~Z゛", ""},
{"~Yコ~Z゛", ""},
{"~Yサ~Z゛", ""},
{"~Yシ~Z゛", ""},
{"~Yス~Z゛", ""},
{"~Yセ~Z゛", ""},
{"~Yソ~Z゛", ""},
{"~Yタ~Z゛", ""},
{"~Yチ~Z゛", ""},
{"~Yツ~Z゛", ""},
{"~Yテ~Z゛", ""},
{"~Yト~Z゛", ""},
{"~Yハ~Z゛", ""},
{"~Yヒ~Z゛", ""},
{"~Yフ~Z゛", ""},
{"~Yヘ~Z゛", ""},
{"~Yホ~Z゛", ""},
// handakuten katakana
{"~Yハ~Z゜", ""},
{"~Yヒ~Z゜", ""},
{"~Yフ~Z゜", ""},
{"~Yヘ~Z゜", ""},
{"~Yホ~Z゜", ""},
// dakuten hiragana
{"~Yか~Z゛", ""},
{"~Yき~Z゛", ""},
{"~Yく~Z゛", ""},
{"~Yけ~Z゛", ""},
{"~Yこ~Z゛", ""},
{"~Yさ~Z゛", ""},
{"~Yし~Z゛", ""},
{"~Yす~Z゛", ""},
{"~Yせ~Z゛", ""},
{"~Yそ~Z゛", ""},
{"~Yた~Z゛", ""},
{"~Yち~Z゛", ""},
{"~Yつ~Z゛", ""},
{"~Yて~Z゛", ""},
{"~Yと~Z゛", ""},
{"~Yは~Z゛", ""},
{"~Yひ~Z゛", ""},
{"~Yふ~Z゛", ""},
{"~Yへ~Z゛", ""},
{"~Yほ~Z゛", ""},
// handakuten hiragana
{"~Yは~Z゜", ""},
{"~Yひ~Z゜", ""},
{"~Yふ~Z゜", ""},
{"~Yへ~Z゜", ""},
{"~Yほ~Z゜", ""},
// japanese punctuation
{",~+8H", ""},
{"~+8H ", " "},
// (hack) special case kanji
{"~~", ""},
// playstation buttons
{"~Y~22L<~Z~Y~27L*~Z~Y~1L>~Z~Y~23L[~Z~+26H", "<PAD_X>"},
{"~Y~22L<~Z~Y~26L;~Z~Y~1L>~Z~Y~23L[~Z~+26H", "<PAD_TRIANGLE>"},
{"~Y~22L<~Z~Y~25L@~Z~Y~1L>~Z~Y~23L[~Z~+26H", "<PAD_CIRCLE>"},
{"~Y~22L<~Z~Y~24L#~Z~Y~1L>~Z~Y~23L[~Z~+26H", "<PAD_SQUARE>"}, // custom
};
GameTextFontBank g_font_bank_jak1_v1(GameTextVersion::JAK1_V1,
&s_encode_info_jak1,
&s_replace_info_jak1,
&s_passthrus_jak1);
/*!
* ================================
* GAME TEXT FONT BANK - JAK 1 (v2)
* ================================
* This font is used in:
* - Jak & Daxter: The Precursor Legacy (PAL)
* - ジャックXダクスター ~ 旧世界の遺産
* - Jak & Daxter: The Precursor Legacy (NTSC-U v2)
*
* It is the same as v1, but _ has been fixed and no longer overlaps 掘
*/
static std::vector<EncodeInfo> s_encode_info_jak1_v2 = {
// random
{"_", {0x03}}, // large space
{"ˇ", {0x10}}, // caron
{"`", {0x11}}, // grave accent
{"'", {0x12}}, // apostrophe
{"^", {0x13}}, // circumflex
{"<TIL>", {0x14}}, // tilde
{"¨", {0x15}}, // umlaut
{"º", {0x16}}, // numero/overring
{"¡", {0x17}}, // inverted exclamation mark
{"¿", {0x18}}, // inverted question mark
{"", {0x1a}}, // umi
{"Æ", {0x1b}}, // aesc
{"", {0x1c}}, // kai
{"Ç", {0x1d}}, // c-cedilla
{"", {0x1e}}, // gaku
{"ß", {0x1f}}, // eszett
{"", {0x24}}, // wa
{"", {0x26}}, // wo
{"", {0x27}}, // -n
{"", {0x5c}}, // iwa
{"", {0x5d}}, // kyuu
{"", {0x5e}}, // sora
{"", {0x5f}}, // horu
{"", {0x60}}, // -wa
{"", {0x61}}, // utsu
{"", {0x62}}, // kashikoi
{"", {0x63}}, // mizuumi
{"", {0x64}}, // kuchi
{"", {0x65}}, // iku
{"", {0x66}}, // ai
{"", {0x67}}, // shi
{"", {0x68}}, // tera
{"", {0x69}}, // yama
{"", {0x6a}}, // mono
{"", {0x6b}}, // tokoro
{"", {0x6c}}, // kaku
{"", {0x6d}}, // shou
{"", {0x6e}}, // numa
{"", {0x6f}}, // ue
{"", {0x70}}, // shiro
{"", {0x71}}, // ba
{"", {0x72}}, // shutsu
{"", {0x73}}, // yami
{"", {0x74}}, // nokosu
{"", {0x75}}, // ki
{"", {0x76}}, // ya
{"", {0x77}}, // shita
{"", {0x78}}, // ie
{"", {0x79}}, // hi
{"", {0x7a}}, // hana
{"", {0x7b}}, // re
{"Œ", {0x7c}}, // oe
{"", {0x7d}}, // ro
{"", {0x7f}}, // ao
{"", {0x90}}, // nakaguro
{"", {0x91}}, // dakuten
{"", {0x92}}, // handakuten
{"", {0x93}}, // chouompu
{"", {0x94}}, // nijuukagikakko left
{"", {0x95}}, // nijuukagikakko right
// hiragana
{"", {0x96}}, // -a
{"", {0x97}}, // a
{"", {0x98}}, // -i
{"", {0x99}}, // i
{"", {0x9a}}, // -u
{"", {0x9b}}, // u
{"", {0x9c}}, // -e
{"", {0x9d}}, // e
{"", {0x9e}}, // -o
{"", {0x9f}}, // o
{"", {0xa0}}, // ka
{"", {0xa1}}, // ki
{"", {0xa2}}, // ku
{"", {0xa3}}, // ke
{"", {0xa4}}, // ko
{"", {0xa5}}, // sa
{"", {0xa6}}, // shi
{"", {0xa7}}, // su
{"", {0xa8}}, // se
{"", {0xa9}}, // so
{"", {0xaa}}, // ta
{"", {0xab}}, // chi
{"", {0xac}}, // sokuon
{"", {0xad}}, // tsu
{"", {0xae}}, // te
{"", {0xaf}}, // to
{"", {0xb0}}, // na
{"", {0xb1}}, // ni
{"", {0xb2}}, // nu
{"", {0xb3}}, // ne
{"", {0xb4}}, // no
{"", {0xb5}}, // ha
{"", {0xb6}}, // hi
{"", {0xb7}}, // hu
{"", {0xb8}}, // he
{"", {0xb9}}, // ho
{"", {0xba}}, // ma
{"", {0xbb}}, // mi
{"", {0xbc}}, // mu
{"", {0xbd}}, // me
{"", {0xbe}}, // mo
{"", {0xbf}}, // youon ya
{"", {0xc0}}, // ya
{"", {0xc1}}, // youon yu
{"", {0xc2}}, // yu
{"", {0xc3}}, // youon yo
{"", {0xc4}}, // yo
{"", {0xc5}}, // ra
{"", {0xc6}}, // ri
{"", {0xc7}}, // ru
{"", {0xc8}}, // re
{"", {0xc9}}, // ro
{"", {0xca}}, // -wa
{"", {0xcb}}, // wa
{"", {0xcc}}, // wo
{"", {0xcd}}, // -n
// katakana
{"", {0xce}}, // -a
{"", {0xcf}}, // a
{"", {0xd0}}, // -i
{"", {0xd1}}, // i
{"", {0xd2}}, // -u
{"", {0xd3}}, // u
{"", {0xd4}}, // -e
{"", {0xd5}}, // e
{"", {0xd6}}, // -o
{"", {0xd7}}, // o
{"", {0xd8}}, // ka
{"", {0xd9}}, // ki
{"", {0xda}}, // ku
{"", {0xdb}}, // ke
{"", {0xdc}}, // ko
{"", {0xdd}}, // sa
{"", {0xde}}, // shi
{"", {0xdf}}, // su
{"", {0xe0}}, // se
{"", {0xe1}}, // so
{"", {0xe2}}, // ta
{"", {0xe3}}, // chi
{"", {0xe4}}, // sokuon
{"", {0xe5}}, // tsu
{"", {0xe6}}, // te
{"", {0xe7}}, // to
{"", {0xe8}}, // na
{"", {0xe9}}, // ni
{"", {0xea}}, // nu
{"", {0xeb}}, // ne
{"", {0xec}}, // no
{"", {0xed}}, // ha
{"", {0xee}}, // hi
{"", {0xef}}, // hu
{"", {0xf0}}, // he
{"", {0xf1}}, // ho
{"", {0xf2}}, // ma
{"", {0xf3}}, // mi
{"", {0xf4}}, // mu
{"", {0xf5}}, // me
{"", {0xf6}}, // mo
{"", {0xf7}}, // youon ya
{"", {0xf8}}, // ya
{"", {0xf9}}, // youon yu
{"", {0xfa}}, // yu
{"", {0xfb}}, // youon yo
{"", {0xfc}}, // yo
{"", {0xfd}}, // ra
{"", {0xfe}}, // ri
{"", {0xff}}, // ru
// kanji 2
{"", {1, 0x01}}, // takara
{"", {1, 0x10}}, // ishi
{"", {1, 0x11}}, // aka
{"", {1, 0x12}}, // ato
{"", {1, 0x13}}, // kawa
{"", {1, 0x14}}, // ikusa
{"", {1, 0x15}}, // mura
{"", {1, 0x16}}, // tai
{"", {1, 0x17}}, // utena
{"", {1, 0x18}}, // osa
{"", {1, 0x19}}, // tori
{"", {1, 0x1a}}, // tei
{"", {1, 0x1b}}, // hora
{"", {1, 0x1c}}, // michi
{"", {1, 0x1d}}, // hatsu
{"", {1, 0x1e}}, // tobu
{"", {1, 0x1f}}, // fuku
{"", {1, 0xa0}}, // ike
{"", {1, 0xa1}}, // naka
{"", {1, 0xa2}}, // tou
{"", {1, 0xa3}}, // shima
{"", {1, 0xa4}}, // bu
{"", {1, 0xa5}}, // hou
{"", {1, 0xa6}}, // san
{"", {1, 0xa7}}, // kaerimiru
{"", {1, 0xa8}}, // chikara
{"", {1, 0xa9}}, // midori
{"", {1, 0xaa}}, // kishi
{"", {1, 0xab}}, // zou
{"", {1, 0xac}}, // tani
{"", {1, 0xad}}, // kokoro
{"", {1, 0xae}}, // mori
{"", {1, 0xaf}}, // mizu
{"", {1, 0xb0}}, // fune
{"", {1, 0xb1}}, // trademark
};
GameTextFontBank g_font_bank_jak1_v2(GameTextVersion::JAK1_V2,
&s_encode_info_jak1_v2,
&s_replace_info_jak1,
&s_passthrus_jak1);
/*!
* ================================
* GAME TEXT FONT BANK - JAK 2
* ================================
* This font is used in:
* - Jak 2 - NTSC - v1
*/
static std::unordered_set<char> s_passthrus_jak2 = {'~', ' ', ',', '.', '-', '+', '(', ')',
'!', ':', '?', '=', '%', '*', '/', '#',
';', '<', '>', '@', '[', '_', ']'};
static std::vector<ReplaceInfo> s_replace_info_jak2 = {
// other
{"A~Y~-21H~-5Vº~Z", "Å"},
{"N~Y~-6Hº~Z~+10H", ""},
{"~+4Vç~-4V", ",c"},
// tildes
{"N~Y~-22H~-4V<TIL>~Z", "Ñ"},
{"n~Y~-24H~-4V<TIL>~Z", "ñ"},
{"A~Y~-21H~-5V<TIL>~Z", "Ã"},
{"O~Y~-22H~-4V<TIL>~Z", "Õ"},
// acute accents
{"A~Y~-21H~-5V'~Z", "Á"},
{"A~Y~-26H~-8V'~Z", "<Á_V2>"}, // unfortunate...
{"a~Y~-25H~-5V'~Z", "á"},
{"E~Y~-23H~-9V'~Z", "É"},
{"e~Y~-26H~-5V'~Z", "é"},
{"I~Y~-19H~-5V'~Z", "Í"},
{"i~Y~-19H~-8V'~Z", "í"},
{"O~Y~-22H~-4V'~Z", "Ó"},
{"o~Y~-26H~-4V'~Z", "ó"},
{"U~Y~-24H~-3V'~Z", "Ú"},
{"u~Y~-24H~-3V'~Z", "ú"},
// circumflex
{"A~Y~-20H~-4V^~Z", "Â"},
{"a~Y~-24H~-5V^~Z", "â"},
{"E~Y~-20H~-5V^~Z", "Ê"},
{"e~Y~-25H~-4V^~Zt", "ê"},
{"I~Y~-19H~-5V^~Z", "Î"},
{"i~Y~-19H~-8V^~Z", "î"},
{"O~Y~-20H~-4V^~Z", "Ô"},
{"o~Y~-25H~-4V^~Z", "ô"},
{"U~Y~-24H~-3V^~Z", "Û"},
{"u~Y~-23H~-3V^~Z", "û"},
// grave accents
{"A~Y~-26H~-8V`~Z", "À"},
{"a~Y~-25H~-5V`~Z", "à"},
{"E~Y~-23H~-9V`~Z", "È"},
{"e~Y~-26H~-5V`~Z", "è"},
{"I~Y~-19H~-5V`~Z", "Ì"},
{"i~Y~-19H~-8V`~Z", "ì"},
{"O~Y~-22H~-4V`~Z", "Ò"},
{"o~Y~-26H~-4V`~Z", "ò"},
{"U~Y~-24H~-3V`~Z", "Ù"},
{"u~Y~-24H~-3V`~Z", "ù"},
// umlaut
{"A~Y~-26H~-8V¨~Z", "Ä"},
{"a~Y~-25H~-5V¨~Z", "ä"},
{"E~Y~-20H~-5V¨~Z", "Ë"},
{"I~Y~-19H~-5V¨~Z", "Ï"},
{"O~Y~-26H~-8V¨~Z", "Ö"},
{"o~Y~-26H~-4V¨~Z", "ö"},
{"U~Y~-25H~-8V¨~Z", "Ü"},
{"u~Y~-24H~-3V¨~Z", "ü"},
// dakuten katakana
{"~Yウ~Z゛", ""},
{"~Yカ~Z゛", ""},
{"~Yキ~Z゛", ""},
{"~Yク~Z゛", ""},
{"~Yケ~Z゛", ""},
{"~Yコ~Z゛", ""},
{"~Yサ~Z゛", ""},
{"~Yシ~Z゛", ""},
{"~Yス~Z゛", ""},
{"~Yセ~Z゛", ""},
{"~Yソ~Z゛", ""},
{"~Yタ~Z゛", ""},
{"~Yチ~Z゛", ""},
{"~Yツ~Z゛", ""},
{"~Yテ~Z゛", ""},
{"~Yト~Z゛", ""},
{"~Yハ~Z゛", ""},
{"~Yヒ~Z゛", ""},
{"~Yフ~Z゛", ""},
{"~Yヘ~Z゛", ""},
{"~Yホ~Z゛", ""},
// handakuten katakana
{"~Yハ~Z゜", ""},
{"~Yヒ~Z゜", ""},
{"~Yフ~Z゜", ""},
{"~Yヘ~Z゜", ""},
{"~Yホ~Z゜", ""},
// dakuten hiragana
{"~Yか~Z゛", ""},
{"~Yき~Z゛", ""},
{"~Yく~Z゛", ""},
{"~Yけ~Z゛", ""},
{"~Yこ~Z゛", ""},
{"~Yさ~Z゛", ""},
{"~Yし~Z゛", ""},
{"~Yす~Z゛", ""},
{"~Yせ~Z゛", ""},
{"~Yそ~Z゛", ""},
{"~Yた~Z゛", ""},
{"~Yち~Z゛", ""},
{"~Yつ~Z゛", ""},
{"~Yて~Z゛", ""},
{"~Yと~Z゛", ""},
{"~Yは~Z゛", ""},
{"~Yひ~Z゛", ""},
{"~Yふ~Z゛", ""},
{"~Yへ~Z゛", ""},
{"~Yほ~Z゛", ""},
// handakuten hiragana
{"~Yは~Z゜", ""},
{"~Yひ~Z゜", ""},
{"~Yふ~Z゜", ""},
{"~Yへ~Z゜", ""},
{"~Yほ~Z゜", ""},
// japanese punctuation
{",~+8H", ""},
{"~+8H ", " "},
// playstation buttons
// - face
{"~Y~22L<~Z~Y~27L*~Z~Y~1L>~Z~Y~23L[~Z~+26H", "<PAD_X>"},
{"~Y~22L<~Z~Y~26L;~Z~Y~1L>~Z~Y~23L[~Z~+26H", "<PAD_TRIANGLE>"},
{"~Y~22L<~Z~Y~25L@~Z~Y~1L>~Z~Y~23L[~Z~+26H", "<PAD_CIRCLE>"},
{"~Y~22L<~Z~Y~24L#~Z~Y~1L>~Z~Y~23L[~Z~+26H", "<PAD_SQUARE>"},
// - dpad
{"~Y~22L<PAD_PART_DPAD_L>~Z~3L~+17H~-13V<PAD_PART_DPAD_U>~Z~22L~+17H~+14V<PAD_PART_DPAD_D>~Z~"
"22L~+32H<PAD_PART_DPAD_R>~Z~+56H",
"<PAD_DPAD_UP>"},
{"~Y~22L<PAD_PART_DPAD_L>~Z~3L~+17H~-13V<PAD_PART_DPAD_U>~Z~3L~+17H~+14V<PAD_PART_DPAD_D>~Z~"
"22L~+32H<PAD_PART_DPAD_R>~Z~+56H",
"<PAD_DPAD_DOWN>"},
{"~Y~22L<PAD_PART_DPAD_L>~Z~22L~+17H~-13V<PAD_PART_DPAD_U>~Z~22L~+17H~+14V<PAD_PART_DPAD_D>~Z~"
"22L~+32H<PAD_PART_DPAD_R>~Z~+56H",
"<PAD_DPAD_ANY>"},
// - shoulder
{"~Y~22L~-2H~-12V<PAD_PART_SHOULDER_TOP_LEFT><PAD_PART_SHOULDER_TOP_RIGHT>~Z~22L~-2H~+17V<PAD_"
"PART_SHOULDER_BOTTOM_LEFT><PAD_PART_SHOULDER_BOTTOM_RIGHT>~Z~1L~+4H~+3V<PAD_PART_L1_NAME>~Z~+"
"38H",
"<PAD_L1>"},
{"~Y~22L~-2H~-12V<PAD_PART_SHOULDER_TOP_LEFT><PAD_PART_SHOULDER_TOP_RIGHT>~Z~22L~-2H~+17V<PAD_"
"PART_SHOULDER_BOTTOM_LEFT><PAD_PART_SHOULDER_BOTTOM_RIGHT>~Z~1L~+6H~+3V<PAD_PART_R1_NAME>~Z~+"
"38H",
"<PAD_R1>"},
{"~Y~22L~-2H~-6V<PAD_PART_TRIGGER_TOP_LEFT><PAD_PART_TRIGGER_TOP_RIGHT>~Z~22L~-2H~+16V<PAD_"
"PART_TRIGGER_BOTTOM_LEFT><PAD_PART_TRIGGER_BOTTOM_RIGHT>~Z~1L~+5H~-2V<PAD_PART_R2_NAME>~Z~+"
"38H",
"<PAD_R2>"},
{"~Y~22L~-2H~-6V<PAD_PART_TRIGGER_TOP_LEFT><PAD_PART_TRIGGER_TOP_RIGHT>~Z~22L~-2H~+16V<PAD_"
"PART_TRIGGER_BOTTOM_LEFT><PAD_PART_TRIGGER_BOTTOM_RIGHT>~Z~1L~+5H~-2V<PAD_PART_L2_NAME>~Z~+"
"38H",
"<PAD_L2>"},
// - analog
{"~1L~+8H~Y<PAD_PART_STICK>~Z~6L~-16H<PAD_PART_STICK_LEFT>~Z~+16h~6L<PAD_PART_STICK_RIGHT>~Z~"
"6L~-15V<PAD_PART_STICK_DOWN>~Z~+13V~6L<PAD_PART_STICK_UP>~Z~-10H~+9V~6L<PAD_PART_STICK_UP_"
"LEFT>~Z~+10H~+9V~6L<PAD_PART_STICK_UP_RIGHT>~Z~-10H~-11V~6L<PAD_PART_STICK_DOWN_LEFT>~Z~+10H~"
"-11V~6L<PAD_PART_STICK_DOWN_RIGHT>~Z~+32H",
"<PAD_ANALOG_ANY>"},
{"~Y~1L~+8H<PAD_PART_STICK>~Z~6L~-8H<PAD_PART_STICK_LEFT>~Z~+24H~6L<PAD_PART_STICK_RIGHT>~Z~+"
"40H",
"<PAD_ANALOG_LEFT_RIGHT>"},
{"~Y~1L<PAD_PART_STICK>~Z~6L~-15V<PAD_PART_STICK_DOWN>~Z~+13V~6L<PAD_PART_STICK_UP>~Z~+26H",
"<PAD_ANALOG_UP_DOWN>"},
// icons
{"~Y~6L<~Z~Y~1L>~Z~Y~23L[~Z~+26H", "<ICON_MISSION_COMPLETE>"},
{"~Y~3L<~Z~Y~1L>~Z~Y~23L[~Z~+26H", "<ICON_MISSION_TODO>"},
// flags
{"~Y~6L<FLAG_PART_VERT_STRIPE_LARGE>~Z~+15H~1L<FLAG_PART_VERT_STRIPE_LARGE>~Z~+30H~3L<FLAG_"
"PART_VERT_STRIPE_LARGE>~Z~+45H",
"<FLAG_ITALIAN>"},
{"~Y~5L<FLAG_PART_FILL>~Z~3L<FLAG_PART_TOP_BOTTOM_STRIPE>~]~-1H~Y~5L<FLAG_PART_FILL>~Z~3L<FLAG_"
"PART_TOP_BOTTOM_STRIPE>~Z~+26H",
"<FLAG_SPAIN>"},
{"~Y~39L~~~Z~3L<FLAG_PART_HORZ_STRIPE_MIDDLE>~Z~5L<FLAG_PART_HORZ_STRIPE_BOTTOM>~]~-1H~Y~39L~~~"
"Z~3L<FLAG_PART_HORZ_STRIPE_MIDDLE>~Z~5L<FLAG_PART_HORZ_STRIPE_BOTTOM>~Z~+26H",
"<FLAG_GERMAN>"},
{"~Y~7L<FLAG_PART_VERT_STRIPE_LARGE>~Z~+15H~1L<FLAG_PART_VERT_STRIPE_LARGE>~Z~+30H~3L<FLAG_"
"PART_VERT_STRIPE_LARGE>~Z~+47H",
"<FLAG_FRANCE>"},
{"~Y~1L<FLAG_PART_FILL>~Z~3L<FLAG_PART_UK_CROSS_LEFT>~Z~7L<FLAG_PART_UK_FILL_LEFT>~]~-1H~Y~1L<"
"FLAG_PART_FILL>~Z~3L<FLAG_PART_UK_CROSS_RIGHT>~Z~7L<FLAG_PART_UK_FILL_RIGHT>~Z~+26H",
"<FLAG_UK>"},
{"~Y~1L<FLAG_PART_FILL>~Z~3L<FLAG_PART_USA_STRIPES_LEFT>~Z~7L<FLAG_PART_USA_STARS>~]~-1H~Y~1L<"
"FLAG_PART_FILL>~Z~3L<FLAG_PART_USA_STRIPES_RIGHT>~Z~+26H",
"<FLAG_USA>"},
{"~Y~1L<FLAG_PART_FILL>~Z~39L<FLAG_PART_KOREA_TRIGRAMS_LEFT>~]~-1H~Y~1L<FLAG_PART_FILL>~Z~39L<"
"FLAG_PART_KOREA_TRIGRAMS_RIGHT>~Z~-11H~7L<FLAG_PART_KOREA_CIRCLE_FILL>~Z~-11H~3L<FLAG_PART_"
"KOREA_CIRCLE_TOP>~Z~+26H",
"<FLAG_KOREA>"},
{"~Y~1L<FLAG_PART_FILL>~]~-1H~Y~1L<FLAG_PART_FILL>~Z~-11H~3L<FLAG_PART_JAPAN_SUN>~Z~+26H",
"<FLAG_JAPAN>"},
// weird stuff
// - descenders
{"~+7Vp~-7V", "p"},
{"~+7Vy~-7V", "y"},
{"~+7Vg~-7V", "g"},
{"~+7Vq~-7V", "q"},
{"~+1Vj~-1V", "j"},
{"\\\\",
"~%"}, // this is 2 slashes, duplicated because we use an escape sequence when decompiling
// - symbols and ligatures
{"~-4H~-3V<SOMETHING>~+3V~-4H",
"<SUPERSCRIPT_QUOTE>"}, // used for the 4<__> place in spanish. the 5th uses the same
// character but looks different...?
{"~Y~-6Hº~Z~+10H", "°"},
// Color / Emphasis
{"~[~0L", "<COLOR_DEFAULT>"},
{"~[~1L", "<COLOR_WHITE>"},
{"~[~2L", "<COLOR_TRANSPARENT>"},
{"~[~3L", "<COLOR_RED>"},
{"~[~4L", "<COLOR_ORANGE>"},
{"~[~5L", "<COLOR_YELLOW>"},
{"~[~6L", "<COLOR_GREEN>"},
{"~[~7L", "<COLOR_BLUE>"},
{"~[~8L", "<COLOR_CYAN>"},
{"~[~9L", "<COLOR_PINK>"},
{"~[~10L", "<COLOR_MENU-SELECTED>"},
{"~[~11L", "<COLOR_MENU-SELECTED-PARENT>"},
{"~[~12L", "<COLOR_MENU>"},
{"~[~13L", "<COLOR_MENU-PARENT>"},
{"~[~14L", "<COLOR_MENU-FUNC-BAD>"},
{"~[~15L", "<COLOR_MENU-FLAG-ON>"},
{"~[~16L", "<COLOR_MENU-FLAG-ON-PARENT>"},
{"~[~17L", "<COLOR_MENU-FLAG-OFF>"},
{"~[~18L", "<COLOR_MENU-FLAG-OFF-PARENT>"},
{"~[~19L", "<COLOR_MENU-INVALID>"},
{"~[~20L", "<COLOR_FLAT-YELLOW>"},
{"~[~21L", "<COLOR_COLOR-21>"},
{"~[~22L", "<COLOR_PAD-BACK>"},
{"~[~23L", "<COLOR_PAD-SHINE>"},
{"~[~24L", "<COLOR_PAD-SQUARE>"},
{"~[~25L", "<COLOR_PAD-CIRCLE>"},
{"~[~26L", "<COLOR_PAD-TRIANGLE>"},
{"~[~27L", "<COLOR_PAD-CROSS>"},
{"~[~28L", "<COLOR_PROGRESS-OLD-BLUE>"},
{"~[~29L", "<COLOR_PROGRESS-OLD-YELLOW>"},
{"~[~30L", "<COLOR_PROGRESS-OLD-SELECTED>"},
{"~[~31L", "<COLOR_PROGRESS-OLD-PERCENT>"},
{"~[~32L", "<COLOR_PROGRESS>"},
{"~[~33L", "<COLOR_PROGRESS-SELECTED>"},
{"~[~34L", "<COLOR_PROGRESS-FORCE-SELECTED>"},
{"~[~35L", "<COLOR_PROGRESS-OPTION-OFF>"},
{"~[~36L", "<COLOR_COLOR-36>"},
{"~[~37L", "<COLOR_CREDITS-STAFF-TITLE-1>"},
{"~[~38L", "<COLOR_CREDITS-STAFF-TITLE-2>"},
{"~[~39L", "<COLOR_COLOR-39>"}};
static std::vector<EncodeInfo> s_encode_info_jak2 = {
{"ˇ", {0x10}}, // caron
{"`", {0x11}}, // grave accent
{"'", {0x12}}, // apostrophe
{"^", {0x13}}, // circumflex
{"<TIL>", {0x14}}, // tilde
{"¨", {0x15}}, // umlaut
{"º", {0x16}}, // numero/overring
{"¡", {0x17}}, // inverted exclamation mark
{"¿", {0x18}}, // inverted question mark
{"<SOMETHING>", {0x19}},
{"ç", {0x1d}}, // c-cedilla
{"Ç", {0x1e}}, // c-cedilla
{"ß", {0x1f}}, // eszett
{"œ", {0x5e}}, // ligature o+e
{"<FLAG_PART_HORZ_STRIPE_MIDDLE>", {0x7f}},
{"<FLAG_PART_HORZ_STRIPE_BOTTOM>", {0x80}},
{"<FLAG_PART_VERT_STRIPE_LARGE>", {0x81}},
{"<FLAG_PART_VERT_STRIPE_RIGHT>", {0x82}},
{"<FLAG_PART_VERT_STRIPE_LEFT>", {0x83}},
{"<FLAG_PART_VERT_STRIPE_MIDDLE>", {0x84}},
{"<FLAG_PART_FILL>", {0x85}},
{"<FLAG_PART_JAPAN_SUN>", {0x86}},
{"<FLAG_PART_KOREA_TRIGRAMS_LEFT>", {0x87}},
{"<FLAG_PART_KOREA_TRIGRAMS_RIGHT>", {0x88}},
{"<FLAG_PART_KOREA_CIRCLE_TOP>", {0x89}},
{"<FLAG_PART_KOREA_CIRCLE_FILL>", {0x8a}},
{"<FLAG_PART_TOP_BOTTOM_STRIPE>", {0x8b}},
{"<FLAG_PART_UK_CROSS_LEFT>", {0x8c}},
{"<FLAG_PART_UK_CROSS_RIGHT>", {0x8d}},
{"<FLAG_PART_UK_FILL_LEFT>", {0x8e}},
{"<FLAG_PART_UK_FILL_RIGHT>", {0x8f}},
{"<FLAG_PART_USA_STRIPES_RIGHT>", {0x90}},
{"<PAD_PART_STICK>", {0x91}},
{"<PAD_PART_SELECT>", {0x92}},
{"<PAD_PART_TRIGGER_BACK>", {0x93}},
{"<PAD_PART_R1_NAME>", {0x94}},
{"<PAD_PART_L1_NAME>", {0x95}},
{"<PAD_PART_R2_NAME>", {0x96}},
{"<PAD_PART_L2_NAME>", {0x97}},
{"<PAD_PART_STICK_UP>", {0x98}},
{"<PAD_PART_STICK_UP_RIGHT>", {0x99}},
{"<FLAG_PART_USA_STRIPES_LEFT>", {0x9a}},
{"<FLAG_PART_USA_STARS>", {0x9b}},
{"<PAD_PART_STICK_DOWN>", {0x9c}},
{"<PAD_PART_STICK_DOWN_LEFT>", {0x9d}},
{"<PAD_PART_STICK_LEFT>", {0x9e}},
{"<PAD_PART_STICK_UP_LEFT>", {0x9f}},
{"<PAD_PART_DPAD_D>", {0xa0}},
{"<PAD_PART_DPAD_L>", {0xa1}},
{"<PAD_PART_DPAD_U>", {0xa2}},
{"<PAD_PART_DPAD_R>", {0xa3}},
{"<PAD_PART_STICK_RIGHT>", {0xa4}},
{"<PAD_PART_STICK_DOWN_RIGHT>", {0xa5}},
{"<PAD_PART_SHOULDER_TOP_LEFT>", {0xa6}},
{"<PAD_PART_SHOULDER_TOP_RIGHT>", {0xa7}},
{"<PAD_PART_TRIGGER_TOP_LEFT>", {0xa8}},
{"<PAD_PART_TRIGGER_TOP_RIGHT>", {0xa9}},
{"<PAD_PART_TRIGGER_SHIM1>", {0xaa}},
{"<PAD_PART_TRIGGER_SHIM2>", {0xab}},
{"<PAD_PART_SHOULDER_SHIM2>", {0xac}},
{"<PAD_PART_SHOULDER_BOTTOM_LEFT>", {0xb0}},
{"<PAD_PART_SHOULDER_BOTTOM_RIGHT>", {0xb1}},
{"<PAD_PART_TRIGGER_BOTTOM_LEFT>", {0xb2}},
{"<PAD_PART_TRIGGER_BOTTOM_RIGHT>", {0xb3}},
// {"入", {1, 0x00}},
// {"年", {1, 0x01}},
// punctuation
{"", {1, 0x10}},
{"", {1, 0x11}},
{"", {1, 0x12}},
{"", {1, 0x13}},
{"", {1, 0x14}},
{"", {1, 0x15}},
// hiragana
{"", {1, 0x16}}, // -a
{"", {1, 0x17}}, // a
{"", {1, 0x18}}, // -i
{"", {1, 0x19}}, // i
{"", {1, 0x1a}}, // -u
{"", {1, 0x1b}}, // u
{"", {1, 0x1c}}, // -e
{"", {1, 0x1d}}, // e
{"", {1, 0x1e}}, // -o
{"", {1, 0x1f}}, // o
{"", {1, 0x20}}, // ka
{"", {1, 0x21}}, // ki
{"", {1, 0x22}}, // ku
{"", {1, 0x23}}, // ke
{"", {1, 0x24}}, // ko
{"", {1, 0x25}}, // sa
{"", {1, 0x26}}, // shi
{"", {1, 0x27}}, // su
{"", {1, 0x28}}, // se
{"", {1, 0x29}}, // so
{"", {1, 0x2a}}, // ta
{"", {1, 0x2b}}, // chi
{"", {1, 0x2c}}, // sokuon
{"", {1, 0x2d}}, // tsu
{"", {1, 0x2e}}, // te
{"", {1, 0x2f}}, // to
{"", {1, 0x30}}, // na
{"", {1, 0x31}}, // ni
{"", {1, 0x32}}, // nu
{"", {1, 0x33}}, // ne
{"", {1, 0x34}}, // no
{"", {1, 0x35}}, // ha
{"", {1, 0x36}}, // hi
{"", {1, 0x37}}, // fu
{"", {1, 0x38}}, // he
{"", {1, 0x39}}, // ho
{"", {1, 0x3a}}, // ma
{"", {1, 0x3b}}, // mi
{"", {1, 0x3c}}, // mu
{"", {1, 0x3d}}, // me
{"", {1, 0x3e}}, // mo
{"", {1, 0x3f}}, // youon ya
{"", {1, 0x40}}, // ya
{"", {1, 0x41}}, // youon yu
{"", {1, 0x42}}, // yu
{"", {1, 0x43}}, // youon yo
{"", {1, 0x44}}, // yo
{"", {1, 0x45}}, // ra
{"", {1, 0x46}}, // ri
{"", {1, 0x47}}, // ru
{"", {1, 0x48}}, // re
{"", {1, 0x49}}, // ro
{"", {1, 0x4a}}, // -wa
{"", {1, 0x4b}}, // wa
{"", {1, 0x4c}}, // wo
{"", {1, 0x4d}}, // -n
// katakana
{"", {1, 0x4e}}, // -a
{"", {1, 0x4f}}, // a
{"", {1, 0x50}}, // -i
{"", {1, 0x51}}, // i
{"", {1, 0x52}}, // -u
{"", {1, 0x53}}, // u
{"", {1, 0x54}}, // -e
{"", {1, 0x55}}, // e
{"", {1, 0x56}}, // -o
{"", {1, 0x57}}, // o
{"", {1, 0x58}}, // ka
{"", {1, 0x59}}, // ki
{"", {1, 0x5a}}, // ku
{"", {1, 0x5b}}, // ke
{"", {1, 0x5c}}, // ko
{"", {1, 0x5d}}, // sa
{"", {1, 0x5e}}, // shi
{"", {1, 0x5f}}, // su
{"", {1, 0x60}}, // se
{"", {1, 0x61}}, // so
{"", {1, 0x62}}, // ta
{"", {1, 0x63}}, // chi
{"", {1, 0x64}}, // sokuon
{"", {1, 0x65}}, // tsu
{"", {1, 0x66}}, // te
{"", {1, 0x67}}, // to
{"", {1, 0x68}}, // na
{"", {1, 0x69}}, // ni
{"", {1, 0x6a}}, // nu
{"", {1, 0x6b}}, // ne
{"", {1, 0x6c}}, // no
{"", {1, 0x6d}}, // ha
{"", {1, 0x6e}}, // hi
{"", {1, 0x6f}}, // fu
{"", {1, 0x70}}, // he
{"", {1, 0x71}}, // ho
{"", {1, 0x72}}, // ma
{"", {1, 0x73}}, // mi
{"", {1, 0x74}}, // mu
{"", {1, 0x75}}, // me
{"", {1, 0x76}}, // mo
{"", {1, 0x77}}, // youon ya
{"", {1, 0x78}}, // ya
{"", {1, 0x79}}, // youon yu
{"", {1, 0x7a}}, // yu
{"", {1, 0x7b}}, // youon yo
{"", {1, 0x7c}}, // yo
{"", {1, 0x7d}}, // ra
{"", {1, 0x7e}}, // ri
{"", {1, 0x7f}}, // ru
{"", {1, 0x80}}, // re
{"", {1, 0x81}}, // ro
{"", {1, 0x82}}, // -wa
{"", {1, 0x83}}, // wa
{"", {1, 0x84}}, // wo
{"", {1, 0x85}}, // -n
{"", {1, 0x8c}},
{"", {1, 0x8d}},
{"", {1, 0x8e}},
{"", {1, 0x8f}},
{"", {1, 0x90}},
{"", {1, 0x91}},
{"", {1, 0x92}},
{"", {1, 0x93}},
{"", {1, 0x94}},
{"", {1, 0x95}},
{"", {1, 0x96}},
{"", {1, 0x97}},
{"", {1, 0x98}},
{"", {1, 0x99}},
{"", {1, 0x9a}},
{"", {1, 0x9b}},
{"", {1, 0x9c}},
{"", {1, 0x9d}},
{"", {1, 0x9e}},
{"", {1, 0x9f}},
{"", {1, 0xa0}},
{"", {1, 0xa1}},
{"", {1, 0xa2}},
{"", {1, 0xa3}},
{"", {1, 0xa4}},
{"", {1, 0xa5}},
{"", {1, 0xa6}},
{"", {1, 0xa7}},
{"", {1, 0xa8}},
{"", {1, 0xa9}},
{"", {1, 0xaa}},
{"", {1, 0xab}},
{"", {1, 0xac}},
{"", {1, 0xad}},
{"", {1, 0xae}},
{"", {1, 0xaf}},
{"", {1, 0xb0}},
{"", {1, 0xb1}},
{"", {1, 0xb2}},
{"", {1, 0xb3}},
{"", {1, 0xb4}},
{"", {1, 0xb5}},
{"", {1, 0xb6}},
{"", {1, 0xb7}},
{"", {1, 0xb8}},
{"", {1, 0xb9}},
{"", {1, 0xba}},
{"", {1, 0xbb}},
{"", {1, 0xbc}},
{"", {1, 0xbd}},
{"", {1, 0xbe}},
{"", {1, 0xbf}},
{"使", {1, 0xc0}},
{"", {1, 0xc1}},
{"", {1, 0xc2}},
{"", {1, 0xc3}},
{"", {1, 0xc4}},
{"", {1, 0xc5}},
{"", {1, 0xc6}},
{"", {1, 0xc7}},
{"", {1, 0xc8}},
{"", {1, 0xc9}},
{"", {1, 0xca}},
{"", {1, 0xcb}},
{"", {1, 0xcc}},
{"", {1, 0xcd}},
{"", {1, 0xce}},
{"", {1, 0xcf}},
{"", {1, 0xd0}},
{"", {1, 0xd1}},
{"", {1, 0xd2}},
{"", {1, 0xd3}},
{"", {1, 0xd4}},
{"", {1, 0xd5}},
{"", {1, 0xd6}},
{"", {1, 0xd7}},
{"", {1, 0xd8}},
{"", {1, 0xd9}},
{"", {1, 0xda}},
{"", {1, 0xdb}},
{"", {1, 0xdc}},
{"", {1, 0xdd}},
{"", {1, 0xde}},
{"", {1, 0xdf}},
{"", {1, 0xe0}},
{"", {1, 0xe1}},
{"", {1, 0xe2}},
{"", {1, 0xe3}},
{"", {1, 0xe4}},
{"", {1, 0xe5}},
{"", {1, 0xe6}},
{"", {1, 0xe7}},
{"", {1, 0xe8}},
{"", {1, 0xe9}},
{"", {1, 0xea}},
{"", {1, 0xeb}},
{"", {1, 0xec}},
{"", {1, 0xed}},
{"", {1, 0xee}},
{"", {1, 0xef}},
{"", {1, 0xf0}},
{"", {1, 0xf1}},
{"", {1, 0xf2}},
{"", {1, 0xf3}},
{"", {1, 0xf4}},
{"", {1, 0xf5}},
{"", {1, 0xf6}},
{"", {1, 0xf7}},
{"", {1, 0xf8}},
{"", {1, 0xf9}},
{"", {1, 0xfa}},
{"", {1, 0xfb}},
{"", {1, 0xfc}},
{"", {1, 0xfd}},
{"", {1, 0xfe}},
{"", {1, 0xff}},
{"", {2, 0x10}},
{"", {2, 0x11}},
{"", {2, 0x12}},
{"", {2, 0x13}},
{"", {2, 0x14}},
{"", {2, 0x15}},
{"", {2, 0x16}},
{"", {2, 0x17}},
{"", {2, 0x18}},
{"", {2, 0x19}},
{"", {2, 0x1a}},
{"", {2, 0x1b}},
{"", {2, 0x1c}},
{"", {2, 0x1d}},
{"", {2, 0x1e}},
{"", {2, 0x1f}},
{"", {2, 0x20}},
{"", {2, 0x21}},
{"", {2, 0x22}},
{"", {2, 0x23}},
{"", {2, 0x24}},
{"", {2, 0x25}},
{"", {2, 0x26}},
{"", {2, 0x27}},
{"", {2, 0x28}},
{"", {2, 0x29}},
{"", {2, 0x2a}},
{"", {2, 0x2b}},
{"", {2, 0x2c}},
{"", {2, 0x2d}},
{"", {2, 0x2e}},
{"", {2, 0x2f}},
{"", {2, 0x30}},
{"", {2, 0x31}},
{"", {2, 0x32}},
{"", {2, 0x33}},
// {"成", {2, 0x34}},
{"", {2, 0x35}},
{"", {2, 0x36}},
{"", {2, 0x37}},
{"", {2, 0x38}},
{"", {2, 0x39}},
{"", {2, 0x3a}},
{"", {2, 0x3b}},
{"", {2, 0x3c}},
{"", {2, 0x3d}},
{"", {2, 0x3e}},
{"", {2, 0x3f}},
{"", {2, 0x40}},
{"", {2, 0x41}},
// {"乗", {2, 0x42}},
{"", {2, 0x43}},
{"", {2, 0x44}},
{"", {2, 0x45}},
{"", {2, 0x46}},
{"", {2, 0x47}},
{"", {2, 0x48}},
{"", {2, 0x49}},
{"", {2, 0x4a}},
{"", {2, 0x4b}},
// {"対", {2, 0x4c}},
{"", {2, 0x4d}},
{"", {2, 0x4e}},
{"", {2, 0x4f}},
{"", {2, 0x50}},
{"", {2, 0x56}},
{"", {2, 0x57}},
{"", {2, 0x58}},
{"", {2, 0x59}},
{"", {2, 0x5a}},
{"", {2, 0x5b}},
{"", {2, 0x5c}},
{"", {2, 0x5d}},
{"", {2, 0x5e}},
{"", {2, 0x5f}},
{"", {2, 0x60}},
{"", {2, 0x61}},
{"", {2, 0x62}},
{"", {2, 0x63}},
{"", {2, 0x64}},
// {"高", {2, 0x65}},
{"", {2, 0x66}},
{"", {2, 0x67}},
{"", {2, 0x68}},
{"", {2, 0x69}},
{"", {2, 0x6a}},
{"", {2, 0x6b}},
{"", {2, 0x6c}},
{"", {2, 0x6d}},
{"", {2, 0x6e}},
{"", {2, 0x6f}},
{"", {2, 0x70}},
{"", {2, 0x71}},
{"", {2, 0x72}},
{"", {2, 0x73}},
{"", {2, 0x74}},
{"", {2, 0x75}},
{"退", {2, 0x76}},
{"", {2, 0x77}},
{"", {2, 0x78}},
{"", {2, 0x79}},
{"", {2, 0x7a}},
{"", {2, 0x7b}},
{"", {2, 0x7c}},
{"", {2, 0x7d}},
{"", {2, 0x7e}},
{"", {2, 0x7f}},
{"", {2, 0x80}},
{"", {2, 0x81}},
{"", {2, 0x82}},
{"", {2, 0x83}},
{"", {2, 0x84}},
{"", {2, 0x85}},
{"", {2, 0x86}},
{"", {2, 0x88}},
{"", {2, 0x89}},
{"", {2, 0x8a}},
{"", {2, 0x8b}},
{"", {2, 0x8c}},
{"", {2, 0x8d}},
{"<K300>", {3, 0x00}},
{"<K301>", {3, 0x01}},
{"<K302>", {3, 0x02}},
{"<K303>", {3, 0x03}},
{"<K304>", {3, 0x04}},
{"<K305>", {3, 0x05}},
{"<K306>", {3, 0x06}},
{"<K307>", {3, 0x07}},
{"<K308>", {3, 0x08}},
{"<K309>", {3, 0x09}},
{"<K30a>", {3, 0x0a}},
{"<K30b>", {3, 0x0b}},
{"<K30c>", {3, 0x0c}},
{"<K30d>", {3, 0x0d}},
{"<K30e>", {3, 0x0e}},
{"<K30f>", {3, 0x0f}},
{"<K310>", {3, 0x10}},
{"<K311>", {3, 0x11}},
{"<K312>", {3, 0x12}},
{"<K313>", {3, 0x13}},
{"<K314>", {3, 0x14}},
{"<K315>", {3, 0x15}},
{"<K316>", {3, 0x16}},
{"<K317>", {3, 0x17}},
{"<K318>", {3, 0x18}},
{"<K319>", {3, 0x19}},
{"<K31a>", {3, 0x1a}},
{"<K31b>", {3, 0x1b}},
{"<K31c>", {3, 0x1c}},
{"<K31d>", {3, 0x1d}},
{"<K31e>", {3, 0x1e}},
{"<K31f>", {3, 0x1f}},
{"<K320>", {3, 0x20}},
{"<K321>", {3, 0x21}},
{"<K322>", {3, 0x22}},
{"<K323>", {3, 0x23}},
{"<K324>", {3, 0x24}},
{"<K325>", {3, 0x25}},
{"<K326>", {3, 0x26}},
{"<K327>", {3, 0x27}},
{"<K328>", {3, 0x28}},
{"<K329>", {3, 0x29}},
{"<K32a>", {3, 0x2a}},
{"<K32b>", {3, 0x2b}},
{"<K32c>", {3, 0x2c}},
{"<K32d>", {3, 0x2d}},
{"<K32e>", {3, 0x2e}},
{"<K32f>", {3, 0x2f}},
{"<K330>", {3, 0x30}},
{"<K331>", {3, 0x31}},
{"<K332>", {3, 0x32}},
{"<K333>", {3, 0x33}},
{"<K334>", {3, 0x34}},
{"<K335>", {3, 0x35}},
{"<K336>", {3, 0x36}},
{"<K337>", {3, 0x37}},
{"<K338>", {3, 0x38}},
{"<K339>", {3, 0x39}},
{"<K33a>", {3, 0x3a}},
{"<K33b>", {3, 0x3b}},
{"<K33c>", {3, 0x3c}},
{"<K33d>", {3, 0x3d}},
{"<K33e>", {3, 0x3e}},
{"<K33f>", {3, 0x3f}},
{"<K340>", {3, 0x40}},
{"<K341>", {3, 0x41}},
{"<K342>", {3, 0x42}},
{"<K343>", {3, 0x43}},
{"<K344>", {3, 0x44}},
{"<K345>", {3, 0x45}},
{"<K346>", {3, 0x46}},
{"<K347>", {3, 0x47}},
{"<K348>", {3, 0x48}},
{"<K349>", {3, 0x49}},
{"<K34a>", {3, 0x4a}},
{"<K34b>", {3, 0x4b}},
{"<K34c>", {3, 0x4c}},
{"<K34d>", {3, 0x4d}},
{"<K34e>", {3, 0x4e}},
{"<K34f>", {3, 0x4f}},
{"<K350>", {3, 0x50}},
{"<K351>", {3, 0x51}},
{"<K352>", {3, 0x52}},
{"<K353>", {3, 0x53}},
{"<K354>", {3, 0x54}},
{"<K355>", {3, 0x55}},
{"<K356>", {3, 0x56}},
{"<K357>", {3, 0x57}},
{"<K358>", {3, 0x58}},
{"<K359>", {3, 0x59}},
{"<K35a>", {3, 0x5a}},
{"<K35b>", {3, 0x5b}},
{"<K35c>", {3, 0x5c}},
{"<K35d>", {3, 0x5d}},
{"<K35e>", {3, 0x5e}},
{"<K35f>", {3, 0x5f}},
{"<K360>", {3, 0x60}},
{"<K361>", {3, 0x61}},
{"<K362>", {3, 0x62}},
{"<K363>", {3, 0x63}},
{"<K364>", {3, 0x64}},
{"<K365>", {3, 0x65}},
{"<K366>", {3, 0x66}},
{"<K367>", {3, 0x67}},
{"<K368>", {3, 0x68}},
{"<K369>", {3, 0x69}},
{"<K36a>", {3, 0x6a}},
{"<K36b>", {3, 0x6b}},
{"<K36c>", {3, 0x6c}},
{"<K36d>", {3, 0x6d}},
{"<K36e>", {3, 0x6e}},
{"<K36f>", {3, 0x6f}},
{"<K370>", {3, 0x70}},
{"<K371>", {3, 0x71}},
{"<K372>", {3, 0x72}},
{"<K373>", {3, 0x73}},
{"<K374>", {3, 0x74}},
{"<K375>", {3, 0x75}},
{"<K376>", {3, 0x76}},
{"<K377>", {3, 0x77}},
{"<K378>", {3, 0x78}},
{"<K379>", {3, 0x79}},
{"<K37a>", {3, 0x7a}},
{"<K37b>", {3, 0x7b}},
{"<K37c>", {3, 0x7c}},
{"<K37d>", {3, 0x7d}},
{"<K37e>", {3, 0x7e}},
{"<K37f>", {3, 0x7f}},
{"<K380>", {3, 0x80}},
{"<K381>", {3, 0x81}},
{"<K382>", {3, 0x82}},
{"<K383>", {3, 0x83}},
{"<K384>", {3, 0x84}},
{"<K385>", {3, 0x85}},
{"<K386>", {3, 0x86}},
{"<K387>", {3, 0x87}},
{"<K388>", {3, 0x88}},
{"<K389>", {3, 0x89}},
{"<K38a>", {3, 0x8a}},
{"<K38b>", {3, 0x8b}},
{"<K38c>", {3, 0x8c}},
{"<K38d>", {3, 0x8d}},
{"<K38e>", {3, 0x8e}},
{"<K38f>", {3, 0x8f}},
{"<K390>", {3, 0x90}},
{"<K391>", {3, 0x91}},
{"<K392>", {3, 0x92}},
{"<K393>", {3, 0x93}},
{"<K394>", {3, 0x94}},
{"<K395>", {3, 0x95}},
{"<K396>", {3, 0x96}},
{"<K397>", {3, 0x97}},
{"<K398>", {3, 0x98}},
{"<K399>", {3, 0x99}},
{"<K39a>", {3, 0x9a}},
{"<K39b>", {3, 0x9b}},
{"<K39c>", {3, 0x9c}},
{"<K39d>", {3, 0x9d}},
{"<K39e>", {3, 0x9e}},
{"<K39f>", {3, 0x9f}},
{"<K3a0>", {3, 0xa0}},
{"<K3a1>", {3, 0xa1}},
{"<K3a2>", {3, 0xa2}},
{"<K3a3>", {3, 0xa3}},
{"<K3a4>", {3, 0xa4}},
{"<K3a5>", {3, 0xa5}},
{"<K3a6>", {3, 0xa6}},
{"<K3a7>", {3, 0xa7}},
{"<K3a8>", {3, 0xa8}},
{"<K3a9>", {3, 0xa9}},
{"<K3aa>", {3, 0xaa}},
{"<K3ab>", {3, 0xab}},
{"<K3ac>", {3, 0xac}},
{"<K3ad>", {3, 0xad}},
{"<K3ae>", {3, 0xae}},
{"<K3af>", {3, 0xaf}},
{"<K3b0>", {3, 0xb0}},
{"<K3b1>", {3, 0xb1}},
{"<K3b2>", {3, 0xb2}},
{"<K3b3>", {3, 0xb3}},
{"<K3b4>", {3, 0xb4}},
{"<K3b5>", {3, 0xb5}},
{"<K3b6>", {3, 0xb6}},
{"<K3b7>", {3, 0xb7}},
{"<K3b8>", {3, 0xb8}},
{"<K3b9>", {3, 0xb9}},
{"<K3ba>", {3, 0xba}},
{"<K3bb>", {3, 0xbb}},
{"<K3bc>", {3, 0xbc}},
{"<K3bd>", {3, 0xbd}},
{"<K3be>", {3, 0xbe}},
{"<K3bf>", {3, 0xbf}},
{"<K3c0>", {3, 0xc0}},
{"<K3c1>", {3, 0xc1}},
{"<K3c2>", {3, 0xc2}},
{"<K3c3>", {3, 0xc3}},
{"<K3c4>", {3, 0xc4}},
{"<K3c5>", {3, 0xc5}},
{"<K3c6>", {3, 0xc6}},
{"<K3c7>", {3, 0xc7}},
{"<K3c8>", {3, 0xc8}},
{"<K3c9>", {3, 0xc9}},
{"<K3ca>", {3, 0xca}},
{"<K3cb>", {3, 0xcb}},
{"<K3cc>", {3, 0xcc}},
{"<K3cd>", {3, 0xcd}},
{"<K3ce>", {3, 0xce}},
{"<K3cf>", {3, 0xcf}},
{"<K3d0>", {3, 0xd0}},
{"<K3d1>", {3, 0xd1}},
{"<K3d2>", {3, 0xd2}},
{"<K3d3>", {3, 0xd3}},
{"<K3d4>", {3, 0xd4}},
{"<K3d5>", {3, 0xd5}},
{"<K3d6>", {3, 0xd6}},
{"<K3d7>", {3, 0xd7}},
{"<K3d8>", {3, 0xd8}},
{"<K3d9>", {3, 0xd9}},
{"<K3da>", {3, 0xda}},
{"<K3db>", {3, 0xdb}},
{"<K3dc>", {3, 0xdc}},
{"<K3dd>", {3, 0xdd}},
{"<K3de>", {3, 0xde}},
{"<K3df>", {3, 0xdf}},
{"<K3e0>", {3, 0xe0}},
{"<K3e1>", {3, 0xe1}},
{"<K3e2>", {3, 0xe2}},
{"<K3e3>", {3, 0xe3}},
{"<K3e4>", {3, 0xe4}},
{"<K3e5>", {3, 0xe5}},
{"<K3e6>", {3, 0xe6}},
{"<K3e7>", {3, 0xe7}},
{"<K3e8>", {3, 0xe8}},
{"<K3e9>", {3, 0xe9}},
{"<K3ea>", {3, 0xea}},
{"<K3eb>", {3, 0xeb}},
{"<K3ec>", {3, 0xec}},
{"<K3ed>", {3, 0xed}},
{"<K3ee>", {3, 0xee}},
{"<K3ef>", {3, 0xef}},
{"<K3f0>", {3, 0xf0}},
{"<K3f1>", {3, 0xf1}},
{"<K3f2>", {3, 0xf2}},
{"<K3f3>", {3, 0xf3}},
{"<K3f4>", {3, 0xf4}},
{"<K3f5>", {3, 0xf5}},
{"<K3f6>", {3, 0xf6}},
{"<K3f7>", {3, 0xf7}},
{"<K3f8>", {3, 0xf8}},
{"<K3f9>", {3, 0xf9}},
{"<K3fa>", {3, 0xfa}},
{"<K3fb>", {3, 0xfb}},
{"<K3fc>", {3, 0xfc}},
{"<K3fd>", {3, 0xfd}},
{"<K3fe>", {3, 0xfe}},
{"<K3ff>", {3, 0xff}},
};
GameTextFontBank g_font_bank_jak2(GameTextVersion::JAK2,
&s_encode_info_jak2,
&s_replace_info_jak2,
&s_passthrus_jak2);
/*!
* ========================
* GAME TEXT FONT BANK LIST
* ========================
* The list of available font banks and a couple of helper functions.
*/
std::map<GameTextVersion, GameTextFontBank*> g_font_banks = {
{GameTextVersion::JAK1_V1, &g_font_bank_jak1_v1},
{GameTextVersion::JAK1_V2, &g_font_bank_jak1_v2},
{GameTextVersion::JAK2, &g_font_bank_jak2}};
const GameTextFontBank* get_font_bank(GameTextVersion version) {
return g_font_banks.at(version);
}
const GameTextFontBank* get_font_bank(const std::string& name) {
if (auto it = sTextVerEnumMap.find(name); it == sTextVerEnumMap.end()) {
throw std::runtime_error(fmt::format("unknown text version {}", name));
} else {
return get_font_bank(it->second);
}
}
bool font_bank_exists(GameTextVersion version) {
return g_font_banks.find(version) != g_font_banks.cend();
}