2021-10-19 00:02:18 -04:00
|
|
|
|
/*!
|
|
|
|
|
* @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.
|
|
|
|
|
*/
|
|
|
|
|
|
2022-02-07 19:15:37 -05:00
|
|
|
|
#include <algorithm>
|
2021-10-19 00:02:18 -04:00
|
|
|
|
#include "FontUtils.h"
|
|
|
|
|
#include "third-party/fmt/core.h"
|
|
|
|
|
|
2022-02-07 19:15:37 -05:00
|
|
|
|
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(); });
|
2022-02-24 22:33:10 -05:00
|
|
|
|
(void)m_version;
|
2022-02-07 19:15:37 -05:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
* 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;
|
2022-02-08 19:02:47 -05:00
|
|
|
|
for (int i = 0; found && i < (int)info.chars.length() && i + off < (int)in.size(); ++i) {
|
2022-02-07 19:15:37 -05:00
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
* 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 {
|
|
|
|
|
for (auto& info : *m_replace_info) {
|
|
|
|
|
auto pos = str.find(info.from);
|
|
|
|
|
while (pos != std::string::npos) {
|
|
|
|
|
str.replace(pos, info.from.size(), info.to);
|
|
|
|
|
pos = str.find(info.from, pos + info.to.size());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return str;
|
|
|
|
|
}
|
|
|
|
|
std::string GameTextFontBank::replace_to_game(std::string& str) const {
|
|
|
|
|
for (auto& info : *m_replace_info) {
|
|
|
|
|
auto pos = str.find(info.to);
|
|
|
|
|
while (pos != std::string::npos) {
|
|
|
|
|
str.replace(pos, info.to.size(), info.from);
|
|
|
|
|
pos = str.find(info.to, pos + info.from.size());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return str;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string GameTextFontBank::encode_utf8_to_game(std::string& str) const {
|
|
|
|
|
std::string new_str;
|
|
|
|
|
|
2022-02-08 19:02:47 -05:00
|
|
|
|
for (int i = 0; i < (int)str.length();) {
|
2022-02-07 19:15:37 -05:00
|
|
|
|
auto remap = find_encode_to_game(str, i);
|
|
|
|
|
if (!remap) {
|
|
|
|
|
new_str.push_back(str.at(i));
|
|
|
|
|
i += 1;
|
|
|
|
|
} else {
|
|
|
|
|
for (auto b : remap->bytes) {
|
|
|
|
|
new_str.push_back(b);
|
|
|
|
|
}
|
|
|
|
|
i += remap->chars.length();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
str = new_str;
|
|
|
|
|
return str;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
* Turn a normal readable string into a string readable in the Jak 1 font encoding.
|
|
|
|
|
*/
|
|
|
|
|
std::string GameTextFontBank::convert_utf8_to_game(std::string str) const {
|
|
|
|
|
replace_to_game(str);
|
|
|
|
|
encode_utf8_to_game(str);
|
|
|
|
|
return str;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
* 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 result;
|
|
|
|
|
while (*in) {
|
|
|
|
|
auto remap = find_encode_to_utf8(in);
|
|
|
|
|
if (remap != nullptr) {
|
|
|
|
|
result.append(remap->chars);
|
|
|
|
|
in += remap->bytes.size() - 1;
|
|
|
|
|
} else if (((*in >= '0' && *in <= '9') || (*in >= 'A' && *in <= 'Z') ||
|
|
|
|
|
m_passthrus->find(*in) != m_passthrus->end()) &&
|
|
|
|
|
*in != '\\') {
|
|
|
|
|
result.push_back(*in);
|
|
|
|
|
} else if (*in == '\n') {
|
|
|
|
|
result += "\\n";
|
|
|
|
|
} else if (*in == '\t') {
|
|
|
|
|
result += "\\t";
|
|
|
|
|
} else if (*in == '\\') {
|
|
|
|
|
result += "\\\\";
|
|
|
|
|
} else {
|
|
|
|
|
result += fmt::format("\\c{:02x}", uint8_t(*in));
|
|
|
|
|
}
|
|
|
|
|
in++;
|
|
|
|
|
}
|
|
|
|
|
return replace_to_utf8(result);
|
|
|
|
|
}
|
2021-10-19 00:02:18 -04:00
|
|
|
|
|
|
|
|
|
/*!
|
2022-02-07 19:15:37 -05:00
|
|
|
|
* ===========================
|
|
|
|
|
* GAME TEXT FONT BANK - JAK 1
|
|
|
|
|
* ===========================
|
|
|
|
|
* This font is used in:
|
|
|
|
|
* - Jak & Daxter: The Precursor Legacy (Black Label)
|
2021-10-19 00:02:18 -04:00
|
|
|
|
*/
|
2022-02-07 19:15:37 -05:00
|
|
|
|
|
|
|
|
|
static std::unordered_set<char> passthrus = {'~', ' ', ',', '.', '-', '+', '(', ')', '!', ':', '?',
|
|
|
|
|
'=', '%', '*', '/', '#', ';', '<', '>', '@', '[', '_'};
|
|
|
|
|
|
|
|
|
|
static std::vector<EncodeInfo> g_encode_info_jak1 = {
|
2021-10-19 00:02:18 -04:00
|
|
|
|
// 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
|
|
|
|
|
|
|
|
|
|
{"\"", {0x22}}, // double-quotes
|
|
|
|
|
|
|
|
|
|
{"ワ", {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
|
|
|
|
|
};
|
2022-02-07 19:15:37 -05:00
|
|
|
|
|
|
|
|
|
static std::vector<ReplaceInfo> g_replace_info_jak1 = {
|
2021-10-19 00:02:18 -04:00
|
|
|
|
// \" -> " (confusing)
|
|
|
|
|
{"\\\"", "\""},
|
|
|
|
|
|
|
|
|
|
// other
|
|
|
|
|
{"A~Y~-21H~-5Vº~Z", "Å"},
|
|
|
|
|
{"N~Y~-6Hº~Z~+10H", "Nº"},
|
|
|
|
|
|
|
|
|
|
// 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", "Ú"},
|
|
|
|
|
|
|
|
|
|
// 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
|
|
|
|
|
};
|
|
|
|
|
|
2022-02-07 19:15:37 -05:00
|
|
|
|
GameTextFontBank g_font_bank_jak1(GameTextVersion::JAK1_V1,
|
|
|
|
|
&g_encode_info_jak1,
|
|
|
|
|
&g_replace_info_jak1,
|
|
|
|
|
&passthrus);
|
2021-10-19 00:02:18 -04:00
|
|
|
|
|
|
|
|
|
/*!
|
2022-02-07 19:15:37 -05:00
|
|
|
|
* ========================
|
|
|
|
|
* GAME TEXT FONT BANK LIST
|
|
|
|
|
* ========================
|
|
|
|
|
* The list of available font banks and a couple of helper functions.
|
2021-10-19 00:02:18 -04:00
|
|
|
|
*/
|
|
|
|
|
|
2022-02-07 19:15:37 -05:00
|
|
|
|
std::map<GameTextVersion, GameTextFontBank*> g_font_banks = {
|
|
|
|
|
{GameTextVersion::JAK1_V1, &g_font_bank_jak1}};
|
2021-10-19 00:02:18 -04:00
|
|
|
|
|
2022-02-07 19:15:37 -05:00
|
|
|
|
const GameTextFontBank* get_font_bank(GameTextVersion version) {
|
|
|
|
|
return g_font_banks.at(version);
|
2021-10-19 00:02:18 -04:00
|
|
|
|
}
|
|
|
|
|
|
2022-02-07 19:15:37 -05:00
|
|
|
|
bool font_bank_exists(GameTextVersion version) {
|
|
|
|
|
return g_font_banks.find(version) != g_font_banks.cend();
|
2021-10-19 00:02:18 -04:00
|
|
|
|
}
|