mirror of https://github.com/OpenRCT2/OpenRCT2.git
Refactor format tokens
This commit is contained in:
parent
157c984d4c
commit
b6a688e540
|
@ -89,7 +89,6 @@ void TextComposition::HandleMessage(const SDL_Event* e)
|
|||
}
|
||||
|
||||
utf8* newText = String::Duplicate(e->text.text);
|
||||
utf8_remove_formatting(newText, false);
|
||||
Insert(newText);
|
||||
Memory::Free(newText);
|
||||
|
||||
|
@ -186,7 +185,6 @@ void TextComposition::HandleMessage(const SDL_Event* e)
|
|||
if ((modifier & KEYBOARD_PRIMARY_MODIFIER) && SDL_HasClipboardText())
|
||||
{
|
||||
utf8* text = SDL_GetClipboardText();
|
||||
utf8_remove_formatting(text, false);
|
||||
Insert(text);
|
||||
SDL_free(text);
|
||||
window_update_textbox();
|
||||
|
|
|
@ -199,13 +199,13 @@ void InGameConsole::Toggle()
|
|||
}
|
||||
}
|
||||
|
||||
void InGameConsole::WriteLine(const std::string& input, uint32_t colourFormat)
|
||||
void InGameConsole::WriteLine(const std::string& input, FormatToken colourFormat)
|
||||
{
|
||||
// Include text colour format only for special cases
|
||||
// The draw function handles the default text colour differently
|
||||
utf8 colourCodepoint[4]{};
|
||||
if (colourFormat != FORMAT_WINDOW_COLOUR_2)
|
||||
utf8_write_codepoint(colourCodepoint, colourFormat);
|
||||
auto colourCodepoint = "";
|
||||
if (colourFormat != FormatToken::ColourWindow2)
|
||||
colourCodepoint = "{";
|
||||
|
||||
std::string line;
|
||||
std::size_t splitPos = 0;
|
||||
|
@ -254,9 +254,6 @@ void InGameConsole::Update()
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Remove unwanted characters in console input
|
||||
utf8_remove_format_codes(_consoleCurrentLine, false);
|
||||
}
|
||||
|
||||
// Flash the caret
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <openrct2/interface/InteractiveConsole.h>
|
||||
#include <openrct2/localisation/FormatCodes.h>
|
||||
#include <openrct2/world/Location.hpp>
|
||||
|
||||
namespace OpenRCT2::Ui
|
||||
|
@ -52,7 +53,7 @@ namespace OpenRCT2::Ui
|
|||
void Close() override;
|
||||
void Hide() override;
|
||||
void Toggle();
|
||||
void WriteLine(const std::string& s, uint32_t colourFormat) override;
|
||||
void WriteLine(const std::string& s, FormatToken colourFormat) override;
|
||||
|
||||
void Input(ConsoleInput input);
|
||||
void RefreshCaret(size_t position = 0);
|
||||
|
|
|
@ -270,7 +270,7 @@ namespace OpenRCT2::Ui::Windows
|
|||
result.MaxWidth = GetOptionalInt(desc["maxWidth"]);
|
||||
result.MinHeight = GetOptionalInt(desc["minHeight"]);
|
||||
result.MaxHeight = GetOptionalInt(desc["maxHeight"]);
|
||||
result.Title = language_convert_string(desc["title"].as_string());
|
||||
result.Title = desc["title"].as_string();
|
||||
result.Id = GetOptionalInt(desc["id"]);
|
||||
result.TabIndex = GetOptionalInt(desc["tabIndex"]);
|
||||
|
||||
|
@ -1077,7 +1077,7 @@ namespace OpenRCT2::Ui::Windows
|
|||
auto customWidgetInfo = customInfo.GetCustomWidgetDesc(w, widgetIndex);
|
||||
if (customWidgetInfo != nullptr)
|
||||
{
|
||||
customWidgetInfo->Text = language_convert_string(value);
|
||||
customWidgetInfo->Text = value;
|
||||
w->widgets[widgetIndex].string = customWidgetInfo->Text.data();
|
||||
widget_invalidate(w, widgetIndex);
|
||||
}
|
||||
|
|
|
@ -314,7 +314,7 @@ namespace OpenRCT2::Scripting
|
|||
auto widget = GetWidget();
|
||||
if (widget != nullptr && (widget->flags & WIDGET_FLAGS::TEXT_IS_STRING) && widget->string != nullptr)
|
||||
{
|
||||
return language_convert_string_to_tokens(widget->string);
|
||||
return widget->string;
|
||||
}
|
||||
}
|
||||
return "";
|
||||
|
|
|
@ -243,7 +243,7 @@ namespace OpenRCT2::Scripting
|
|||
auto w = GetWindow();
|
||||
if (w != nullptr && w->classification == WC_CUSTOM)
|
||||
{
|
||||
return language_convert_string_to_tokens(GetWindowTitle(w));
|
||||
return GetWindowTitle(w);
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
@ -252,7 +252,7 @@ namespace OpenRCT2::Scripting
|
|||
auto w = GetWindow();
|
||||
if (w != nullptr && w->classification == WC_CUSTOM)
|
||||
{
|
||||
UpdateWindowTitle(w, language_convert_string(value));
|
||||
UpdateWindowTitle(w, value);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -236,13 +236,6 @@ static void window_changelog_process_changelog_text(const std::string& text)
|
|||
while ((pos = text.find("\n", prev)) != std::string::npos)
|
||||
{
|
||||
std::string line = text.substr(prev, pos - prev);
|
||||
for (char* ch = line.data(); *ch != '\0'; ch++)
|
||||
{
|
||||
if (utf8_is_format_code(*ch))
|
||||
{
|
||||
*ch = FORMAT_OUTLINE_OFF;
|
||||
}
|
||||
}
|
||||
_changelogLines.push_back(line);
|
||||
prev = pos + 1;
|
||||
}
|
||||
|
|
|
@ -329,13 +329,12 @@ void window_player_overview_paint(rct_window* w, rct_drawpixelinfo* dpi)
|
|||
if (groupindex != -1)
|
||||
{
|
||||
rct_widget* widget = &window_player_overview_widgets[WIDX_GROUP];
|
||||
char buffer[300];
|
||||
char* lineCh;
|
||||
lineCh = buffer;
|
||||
lineCh = utf8_write_codepoint(lineCh, FORMAT_WINDOW_COLOUR_2);
|
||||
safe_strcpy(lineCh, network_get_group_name(groupindex), sizeof(buffer) - (lineCh - buffer));
|
||||
|
||||
thread_local std::string buffer;
|
||||
buffer.assign("{WINDOW_COLOUR_2}");
|
||||
buffer += network_get_group_name(groupindex);
|
||||
auto ft = Formatter();
|
||||
ft.Add<const char*>(buffer);
|
||||
ft.Add<const char*>(buffer.c_str());
|
||||
|
||||
DrawTextEllipsised(
|
||||
dpi, w->windowPos + ScreenCoordsXY{ widget->midX() - 5, widget->top }, widget->width() - 8, STR_STRING, ft,
|
||||
|
|
|
@ -85,7 +85,6 @@ void window_text_input_open(
|
|||
if (existing_text != STR_NONE)
|
||||
format_string(buffer, maxLength, existing_text, &existing_args);
|
||||
|
||||
utf8_remove_format_codes(buffer, false);
|
||||
window_text_input_raw_open(call_w, call_widget, title, description, buffer, maxLength);
|
||||
}
|
||||
|
||||
|
|
|
@ -771,18 +771,6 @@ namespace String
|
|||
return res;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool ContainsColourCode(const std::string& string)
|
||||
{
|
||||
for (unsigned char c : string)
|
||||
{
|
||||
if (c >= FORMAT_COLOUR_CODE_START && c <= FORMAT_COLOUR_CODE_END)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
} // namespace String
|
||||
|
||||
char32_t CodepointView::iterator::GetNextCodepoint(const char* ch, const char** next)
|
||||
|
|
|
@ -111,12 +111,6 @@ namespace String
|
|||
* Returns an uppercased version of a UTF-8 string.
|
||||
*/
|
||||
std::string ToUpper(const std::string_view& src);
|
||||
|
||||
/**
|
||||
* Returns true if the string contains an RCT2 colour code.
|
||||
*/
|
||||
bool ContainsColourCode(const std::string& string);
|
||||
|
||||
} // namespace String
|
||||
|
||||
class CodepointView
|
||||
|
|
|
@ -50,7 +50,7 @@ int32_t gfx_get_string_width_new_lined(std::string_view text)
|
|||
FmtString fmt(text);
|
||||
for (const auto& token : fmt)
|
||||
{
|
||||
if (token.kind == FORMAT_NEWLINE || token.kind == FORMAT_NEWLINE_SMALLER)
|
||||
if (token.kind == FormatToken::Newline || token.kind == FormatToken::NewlineSmall)
|
||||
{
|
||||
auto width = gfx_get_string_width(buffer);
|
||||
if (!maxWidth || maxWidth > width)
|
||||
|
@ -222,7 +222,7 @@ int32_t gfx_wrap_string(utf8* text, int32_t width, int32_t* outNumLines, int32_t
|
|||
}
|
||||
}
|
||||
}
|
||||
else if (token.kind == FORMAT_NEWLINE)
|
||||
else if (token.kind == FormatToken::Newline)
|
||||
{
|
||||
buffer.push_back('\0');
|
||||
|
||||
|
@ -352,13 +352,12 @@ int32_t string_get_height_raw(char* buffer)
|
|||
else if (fontBase == FONT_SPRITE_BASE_TINY)
|
||||
height += 6;
|
||||
|
||||
char* ch = buffer;
|
||||
while (*ch != 0)
|
||||
FmtString fmt(buffer);
|
||||
for (const auto& token : fmt)
|
||||
{
|
||||
char c = *ch++;
|
||||
switch (c)
|
||||
switch (token.kind)
|
||||
{
|
||||
case FORMAT_NEWLINE:
|
||||
case FormatToken::Newline:
|
||||
if (fontBase == FONT_SPRITE_BASE_SMALL || fontBase == FONT_SPRITE_BASE_MEDIUM)
|
||||
{
|
||||
height += 10;
|
||||
|
@ -371,7 +370,7 @@ int32_t string_get_height_raw(char* buffer)
|
|||
}
|
||||
height += 18;
|
||||
break;
|
||||
case FORMAT_NEWLINE_SMALLER:
|
||||
case FormatToken::NewlineSmall:
|
||||
if (fontBase == FONT_SPRITE_BASE_SMALL || fontBase == FONT_SPRITE_BASE_MEDIUM)
|
||||
{
|
||||
height += 5;
|
||||
|
@ -384,33 +383,17 @@ int32_t string_get_height_raw(char* buffer)
|
|||
}
|
||||
height += 9;
|
||||
break;
|
||||
case FORMAT_TINYFONT:
|
||||
case FormatToken::FontTiny:
|
||||
fontBase = FONT_SPRITE_BASE_TINY;
|
||||
break;
|
||||
case FORMAT_MEDIUMFONT:
|
||||
case FormatToken::FontMedium:
|
||||
fontBase = FONT_SPRITE_BASE_MEDIUM;
|
||||
break;
|
||||
case FORMAT_SMALLFONT:
|
||||
case FormatToken::FontSmall:
|
||||
fontBase = FONT_SPRITE_BASE_SMALL;
|
||||
break;
|
||||
default:
|
||||
if (c >= 32)
|
||||
continue;
|
||||
if (c <= 4)
|
||||
{
|
||||
ch++;
|
||||
continue;
|
||||
}
|
||||
if (c <= 16)
|
||||
continue;
|
||||
ch += 2;
|
||||
if (c <= 22)
|
||||
continue;
|
||||
ch += 2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return height;
|
||||
}
|
||||
|
||||
|
@ -452,21 +435,27 @@ void gfx_draw_string_centred_wrapped_partial(
|
|||
{
|
||||
int32_t halfWidth = gfx_get_string_width(buffer) / 2;
|
||||
|
||||
utf8* ch = buffer;
|
||||
utf8* nextCh;
|
||||
int32_t codepoint;
|
||||
while ((codepoint = utf8_get_next(ch, const_cast<const utf8**>(&nextCh))) != 0)
|
||||
FmtString fmt(buffer);
|
||||
for (const auto& token : fmt)
|
||||
{
|
||||
if (!utf8_is_format_code(codepoint))
|
||||
bool doubleBreak = false;
|
||||
if (token.IsLiteral())
|
||||
{
|
||||
numCharactersDrawn++;
|
||||
if (numCharactersDrawn > numCharactersToDraw)
|
||||
CodepointView codepoints(token.text);
|
||||
for (auto it = codepoints.begin(); it != codepoints.end(); it++)
|
||||
{
|
||||
*ch = 0;
|
||||
break;
|
||||
numCharactersDrawn++;
|
||||
if (numCharactersDrawn > numCharactersToDraw)
|
||||
{
|
||||
auto ch = const_cast<char*>(&token.text[it.GetIndex()]);
|
||||
*ch = '\0';
|
||||
doubleBreak = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
ch = nextCh;
|
||||
if (doubleBreak)
|
||||
break;
|
||||
}
|
||||
|
||||
screenCoords = { coords.x - halfWidth, lineY };
|
||||
|
@ -679,51 +668,51 @@ static void ttf_process_format_code(rct_drawpixelinfo* dpi, const FmtString::tok
|
|||
{
|
||||
switch (token.kind)
|
||||
{
|
||||
case FORMAT_MOVE_X:
|
||||
case FormatToken::Move:
|
||||
info->x = info->startX + token.parameter;
|
||||
break;
|
||||
case FORMAT_NEWLINE:
|
||||
case FormatToken::Newline:
|
||||
info->x = info->startX;
|
||||
info->y += font_get_line_height(info->font_sprite_base);
|
||||
break;
|
||||
case FORMAT_NEWLINE_SMALLER:
|
||||
case FormatToken::NewlineSmall:
|
||||
info->x = info->startX;
|
||||
info->y += font_get_line_height_small(info->font_sprite_base);
|
||||
break;
|
||||
case FORMAT_TINYFONT:
|
||||
case FormatToken::FontTiny:
|
||||
info->font_sprite_base = FONT_SPRITE_BASE_TINY;
|
||||
break;
|
||||
case FORMAT_SMALLFONT:
|
||||
case FormatToken::FontSmall:
|
||||
info->font_sprite_base = FONT_SPRITE_BASE_SMALL;
|
||||
break;
|
||||
case FORMAT_MEDIUMFONT:
|
||||
case FormatToken::FontMedium:
|
||||
info->font_sprite_base = FONT_SPRITE_BASE_MEDIUM;
|
||||
break;
|
||||
case FORMAT_OUTLINE:
|
||||
case FormatToken::OutlineEnable:
|
||||
info->flags |= TEXT_DRAW_FLAG_OUTLINE;
|
||||
break;
|
||||
case FORMAT_OUTLINE_OFF:
|
||||
case FormatToken::OutlineDisable:
|
||||
info->flags &= ~TEXT_DRAW_FLAG_OUTLINE;
|
||||
break;
|
||||
case FORMAT_WINDOW_COLOUR_1:
|
||||
case FormatToken::ColourWindow1:
|
||||
{
|
||||
uint16_t flags = info->flags;
|
||||
colour_char_window(gCurrentWindowColours[0], &flags, info->palette);
|
||||
break;
|
||||
}
|
||||
case FORMAT_WINDOW_COLOUR_2:
|
||||
case FormatToken::ColourWindow2:
|
||||
{
|
||||
uint16_t flags = info->flags;
|
||||
colour_char_window(gCurrentWindowColours[1], &flags, info->palette);
|
||||
break;
|
||||
}
|
||||
case FORMAT_WINDOW_COLOUR_3:
|
||||
case FormatToken::ColourWindow3:
|
||||
{
|
||||
uint16_t flags = info->flags;
|
||||
colour_char_window(gCurrentWindowColours[2], &flags, info->palette);
|
||||
break;
|
||||
}
|
||||
case FORMAT_INLINE_SPRITE:
|
||||
case FormatToken::InlineSprite:
|
||||
{
|
||||
auto g1 = gfx_get_g1_element(token.parameter & 0x7FFFF);
|
||||
if (g1 != nullptr)
|
||||
|
@ -737,10 +726,11 @@ static void ttf_process_format_code(rct_drawpixelinfo* dpi, const FmtString::tok
|
|||
break;
|
||||
}
|
||||
default:
|
||||
if (token.kind >= FORMAT_COLOUR_CODE_START && token.kind <= FORMAT_COLOUR_CODE_END)
|
||||
if (FormatTokenIsColour(token.kind))
|
||||
{
|
||||
uint16_t flags = info->flags;
|
||||
colour_char(token.kind - FORMAT_COLOUR_CODE_START, &flags, info->palette);
|
||||
auto colourIndex = FormatTokenGetTextColourIndex(token.kind);
|
||||
colour_char(static_cast<uint8_t>(colourIndex), &flags, info->palette);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -240,7 +240,7 @@ void font_sprite_initialise_characters()
|
|||
int32_t width = 0;
|
||||
if (g1 != nullptr)
|
||||
{
|
||||
if (glyphIndex < (FORMAT_ARGUMENT_CODE_START - 32) || glyphIndex >= (FORMAT_COLOUR_CODE_END - 32))
|
||||
if (glyphIndex < 91 || glyphIndex >= 109)
|
||||
{
|
||||
width = (g1->width + 2 * g1->x_offset) - 1;
|
||||
}
|
||||
|
|
|
@ -1540,12 +1540,12 @@ static void scrolling_text_set_bitmap_for_sprite(
|
|||
}
|
||||
}
|
||||
}
|
||||
else if (token.kind <= FORMAT_COLOUR_CODE_END && token.kind >= FORMAT_COLOUR_CODE_START)
|
||||
else if (FormatTokenIsColour(token.kind))
|
||||
{
|
||||
auto g1 = gfx_get_g1_element(SPR_TEXT_PALETTE);
|
||||
if (g1 != nullptr)
|
||||
{
|
||||
auto colourIndex = token.kind - FORMAT_COLOUR_CODE_START;
|
||||
auto colourIndex = FormatTokenGetTextColourIndex(token.kind);
|
||||
characterColour = g1->offset[colourIndex * 4];
|
||||
}
|
||||
}
|
||||
|
@ -1574,12 +1574,12 @@ static void scrolling_text_set_bitmap_for_ttf(
|
|||
{
|
||||
ttfBuffer.append(token.text);
|
||||
}
|
||||
else if (token.kind >= FORMAT_COLOUR_CODE_START && token.kind <= FORMAT_COLOUR_CODE_END)
|
||||
else if (FormatTokenIsColour(token.kind))
|
||||
{
|
||||
auto g1 = gfx_get_g1_element(SPR_TEXT_PALETTE);
|
||||
if (g1 != nullptr)
|
||||
{
|
||||
auto colourIndex = token.kind - FORMAT_COLOUR_CODE_START;
|
||||
auto colourIndex = FormatTokenGetTextColourIndex(token.kind);
|
||||
colour = g1->offset[colourIndex * 4];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1931,17 +1931,17 @@ void InteractiveConsole::Execute(const std::string& s)
|
|||
|
||||
void InteractiveConsole::WriteLine(const std::string& s)
|
||||
{
|
||||
WriteLine(s, FORMAT_WINDOW_COLOUR_2);
|
||||
WriteLine(s, FormatToken::ColourWindow2);
|
||||
}
|
||||
|
||||
void InteractiveConsole::WriteLineError(const std::string& s)
|
||||
{
|
||||
WriteLine(s, FORMAT_RED);
|
||||
WriteLine(s, FormatToken::ColourRed);
|
||||
}
|
||||
|
||||
void InteractiveConsole::WriteLineWarning(const std::string& s)
|
||||
{
|
||||
WriteLine(s, FORMAT_YELLOW);
|
||||
WriteLine(s, FormatToken::ColourYellow);
|
||||
}
|
||||
|
||||
void InteractiveConsole::WriteFormatLine(const char* format, ...)
|
||||
|
|
|
@ -46,7 +46,7 @@ public:
|
|||
virtual void Clear() abstract;
|
||||
virtual void Close() abstract;
|
||||
virtual void Hide() abstract;
|
||||
virtual void WriteLine(const std::string& s, uint32_t colourFormat) abstract;
|
||||
virtual void WriteLine(const std::string& s, FormatToken colourFormat) abstract;
|
||||
};
|
||||
|
||||
class StdInOutConsole final : public InteractiveConsole
|
||||
|
@ -68,5 +68,5 @@ public:
|
|||
{
|
||||
InteractiveConsole::WriteLine(s);
|
||||
}
|
||||
void WriteLine(const std::string& s, uint32_t colourFormat) override;
|
||||
void WriteLine(const std::string& s, FormatToken colourFormat) override;
|
||||
};
|
||||
|
|
|
@ -108,17 +108,17 @@ void StdInOutConsole::Close()
|
|||
openrct2_finish();
|
||||
}
|
||||
|
||||
void StdInOutConsole::WriteLine(const std::string& s, uint32_t colourFormat)
|
||||
void StdInOutConsole::WriteLine(const std::string& s, FormatToken colourFormat)
|
||||
{
|
||||
std::string formatBegin;
|
||||
if (colourFormat != FORMAT_WINDOW_COLOUR_2)
|
||||
if (colourFormat != FormatToken::ColourWindow2)
|
||||
{
|
||||
switch (colourFormat)
|
||||
{
|
||||
case FORMAT_RED:
|
||||
case FormatToken::ColourRed:
|
||||
formatBegin = "\033[31m";
|
||||
break;
|
||||
case FORMAT_YELLOW:
|
||||
case FormatToken::ColourYellow:
|
||||
formatBegin = "\033[33m";
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -17,54 +17,54 @@
|
|||
// clang-format off
|
||||
const encoding_convert_entry RCT2ToUnicodeTable[] =
|
||||
{
|
||||
{ 1, FORMAT_MOVE_X },
|
||||
{ 2, FORMAT_ADJUST_PALETTE },
|
||||
{ 5, FORMAT_NEWLINE },
|
||||
{ 6, FORMAT_NEWLINE_SMALLER },
|
||||
{ 7, FORMAT_TINYFONT },
|
||||
{ 8, FORMAT_BIGFONT },
|
||||
{ 9, FORMAT_MEDIUMFONT },
|
||||
{ 10, FORMAT_SMALLFONT },
|
||||
{ 11, FORMAT_OUTLINE },
|
||||
{ 12, FORMAT_OUTLINE_OFF },
|
||||
{ 13, FORMAT_WINDOW_COLOUR_1 },
|
||||
{ 14, FORMAT_WINDOW_COLOUR_2 },
|
||||
{ 15, FORMAT_WINDOW_COLOUR_3 },
|
||||
{ 17, FORMAT_NEWLINE_X_Y },
|
||||
{ 23, FORMAT_INLINE_SPRITE },
|
||||
{ 123, FORMAT_COMMA32 },
|
||||
{ 124, FORMAT_INT32 },
|
||||
{ 125, FORMAT_COMMA2DP32 },
|
||||
{ 126, FORMAT_COMMA16 },
|
||||
{ 127, FORMAT_UINT16 },
|
||||
{ 128, FORMAT_CURRENCY2DP },
|
||||
{ 129, FORMAT_CURRENCY },
|
||||
{ 130, FORMAT_STRINGID },
|
||||
{ 131, FORMAT_STRINGID2 },
|
||||
{ 132, FORMAT_STRING },
|
||||
{ 133, FORMAT_MONTHYEAR },
|
||||
{ 134, FORMAT_MONTH },
|
||||
{ 135, FORMAT_VELOCITY },
|
||||
{ 136, FORMAT_POP16 },
|
||||
{ 137, FORMAT_PUSH16 },
|
||||
{ 138, FORMAT_DURATION },
|
||||
{ 139, FORMAT_REALTIME },
|
||||
{ 140, FORMAT_LENGTH },
|
||||
{ 141, FORMAT_SPRITE },
|
||||
{ 142, FORMAT_BLACK },
|
||||
{ 143, FORMAT_GREY },
|
||||
{ 144, FORMAT_WHITE },
|
||||
{ 145, FORMAT_RED },
|
||||
{ 146, FORMAT_GREEN },
|
||||
{ 147, FORMAT_YELLOW },
|
||||
{ 148, FORMAT_TOPAZ },
|
||||
{ 149, FORMAT_CELADON },
|
||||
{ 150, FORMAT_BABYBLUE },
|
||||
{ 151, FORMAT_PALELAVENDER },
|
||||
{ 152, FORMAT_PALEGOLD },
|
||||
{ 153, FORMAT_LIGHTPINK },
|
||||
{ 154, FORMAT_PEARLAQUA },
|
||||
{ 155, FORMAT_PALESILVER },
|
||||
// { 1, FORMAT_MOVE_X },
|
||||
// { 2, FORMAT_ADJUST_PALETTE },
|
||||
// { 5, FORMAT_NEWLINE },
|
||||
// { 6, FORMAT_NEWLINE_SMALLER },
|
||||
// { 7, FORMAT_TINYFONT },
|
||||
// { 8, FORMAT_BIGFONT },
|
||||
// { 9, FORMAT_MEDIUMFONT },
|
||||
// { 10, FORMAT_SMALLFONT },
|
||||
// { 11, FORMAT_OUTLINE },
|
||||
// { 12, FORMAT_OUTLINE_OFF },
|
||||
// { 13, FORMAT_WINDOW_COLOUR_1 },
|
||||
// { 14, FORMAT_WINDOW_COLOUR_2 },
|
||||
// { 15, FORMAT_WINDOW_COLOUR_3 },
|
||||
// { 17, FORMAT_NEWLINE_X_Y },
|
||||
// { 23, FORMAT_INLINE_SPRITE },
|
||||
// { 123, FORMAT_COMMA32 },
|
||||
// { 124, FORMAT_INT32 },
|
||||
// { 125, FORMAT_COMMA2DP32 },
|
||||
// { 126, FORMAT_COMMA16 },
|
||||
// { 127, FORMAT_UINT16 },
|
||||
// { 128, FORMAT_CURRENCY2DP },
|
||||
// { 129, FORMAT_CURRENCY },
|
||||
// { 130, FORMAT_STRINGID },
|
||||
// { 131, FORMAT_STRINGID2 },
|
||||
// { 132, FORMAT_STRING },
|
||||
// { 133, FORMAT_MONTHYEAR },
|
||||
// { 134, FORMAT_MONTH },
|
||||
// { 135, FORMAT_VELOCITY },
|
||||
// { 136, FORMAT_POP16 },
|
||||
// { 137, FORMAT_PUSH16 },
|
||||
// { 138, FORMAT_DURATION },
|
||||
// { 139, FORMAT_REALTIME },
|
||||
// { 140, FORMAT_LENGTH },
|
||||
// { 141, FORMAT_SPRITE },
|
||||
// { 142, FORMAT_BLACK },
|
||||
// { 143, FORMAT_GREY },
|
||||
// { 144, FORMAT_WHITE },
|
||||
// { 145, FORMAT_RED },
|
||||
// { 146, FORMAT_GREEN },
|
||||
// { 147, FORMAT_YELLOW },
|
||||
// { 148, FORMAT_TOPAZ },
|
||||
// { 149, FORMAT_CELADON },
|
||||
// { 150, FORMAT_BABYBLUE },
|
||||
// { 151, FORMAT_PALELAVENDER },
|
||||
// { 152, FORMAT_PALEGOLD },
|
||||
// { 153, FORMAT_LIGHTPINK },
|
||||
// { 154, FORMAT_PEARLAQUA },
|
||||
// { 155, FORMAT_PALESILVER },
|
||||
{ CSChar::a_ogonek_uc, UnicodeChar::a_ogonek_uc },
|
||||
{ CSChar::up, UnicodeChar::up },
|
||||
{ CSChar::c_acute_uc, UnicodeChar::c_acute_uc },
|
||||
|
|
|
@ -9,90 +9,174 @@
|
|||
|
||||
#include "FormatCodes.h"
|
||||
|
||||
#include "../common.h"
|
||||
#include "../core/String.hpp"
|
||||
#include "Localisation.h"
|
||||
|
||||
#include <iterator>
|
||||
|
||||
#pragma region Format codes
|
||||
|
||||
struct format_code_token
|
||||
{
|
||||
uint32_t code;
|
||||
const char* token;
|
||||
};
|
||||
#include <unordered_map>
|
||||
|
||||
// clang-format off
|
||||
static constexpr const format_code_token format_code_tokens[] = {
|
||||
{ FORMAT_MOVE_X, "MOVE_X" },
|
||||
{ FORMAT_ADJUST_PALETTE, "ADJUST_PALETTE" },
|
||||
{ FORMAT_NEWLINE, "NEWLINE" },
|
||||
{ FORMAT_NEWLINE_SMALLER, "NEWLINE_SMALLER" },
|
||||
{ FORMAT_TINYFONT, "TINYFONT" },
|
||||
{ FORMAT_BIGFONT, "BIGFONT" },
|
||||
{ FORMAT_MEDIUMFONT, "MEDIUMFONT" },
|
||||
{ FORMAT_SMALLFONT, "SMALLFONT" },
|
||||
{ FORMAT_OUTLINE, "OUTLINE" },
|
||||
{ FORMAT_OUTLINE_OFF, "OUTLINE_OFF" },
|
||||
{ FORMAT_WINDOW_COLOUR_1, "WINDOW_COLOUR_1" },
|
||||
{ FORMAT_WINDOW_COLOUR_2, "WINDOW_COLOUR_2" },
|
||||
{ FORMAT_WINDOW_COLOUR_3, "WINDOW_COLOUR_3" },
|
||||
{ FORMAT_NEWLINE_X_Y, "NEWLINE_X_Y" },
|
||||
{ FORMAT_INLINE_SPRITE, "INLINE_SPRITE" },
|
||||
{ FORMAT_COMMA32, "COMMA32" },
|
||||
{ FORMAT_INT32, "INT32" },
|
||||
{ FORMAT_COMMA2DP32, "COMMA2DP32" },
|
||||
{ FORMAT_COMMA16, "COMMA16" },
|
||||
{ FORMAT_UINT16, "UINT16" },
|
||||
{ FORMAT_CURRENCY2DP, "CURRENCY2DP" },
|
||||
{ FORMAT_CURRENCY, "CURRENCY" },
|
||||
{ FORMAT_STRINGID, "STRINGID" },
|
||||
{ FORMAT_STRINGID2, "STRINGID2" },
|
||||
{ FORMAT_STRING, "STRING" },
|
||||
{ FORMAT_MONTHYEAR, "MONTHYEAR" },
|
||||
{ FORMAT_MONTH, "MONTH" },
|
||||
{ FORMAT_VELOCITY, "VELOCITY" },
|
||||
{ FORMAT_POP16, "POP16" },
|
||||
{ FORMAT_PUSH16, "PUSH16" },
|
||||
{ FORMAT_DURATION, "DURATION" },
|
||||
{ FORMAT_REALTIME, "REALTIME" },
|
||||
{ FORMAT_LENGTH, "LENGTH" },
|
||||
{ FORMAT_SPRITE, "SPRITE" },
|
||||
{ FORMAT_BLACK, "BLACK" },
|
||||
{ FORMAT_GREY, "GREY" },
|
||||
{ FORMAT_WHITE, "WHITE" },
|
||||
{ FORMAT_RED, "RED" },
|
||||
{ FORMAT_GREEN, "GREEN" },
|
||||
{ FORMAT_YELLOW, "YELLOW" },
|
||||
{ FORMAT_TOPAZ, "TOPAZ" },
|
||||
{ FORMAT_CELADON, "CELADON" },
|
||||
{ FORMAT_BABYBLUE, "BABYBLUE" },
|
||||
{ FORMAT_PALELAVENDER, "PALELAVENDER" },
|
||||
{ FORMAT_PALEGOLD, "PALEGOLD" },
|
||||
{ FORMAT_LIGHTPINK, "LIGHTPINK" },
|
||||
{ FORMAT_PEARLAQUA, "PEARLAQUA" },
|
||||
{ FORMAT_PALESILVER, "PALESILVER" },
|
||||
{ FORMAT_COMMA1DP16, "COMMA1DP16" }
|
||||
static const std::unordered_map<std::string_view, FormatToken> FormatTokenMap = {
|
||||
{ "MOVE_X", FormatToken::Move, },
|
||||
{ "NEWLINE", FormatToken::Newline, },
|
||||
{ "NEWLINE_SMALLER", FormatToken::NewlineSmall, },
|
||||
{ "TINYFONT", FormatToken::FontTiny, },
|
||||
{ "BIGFONT", FormatToken::FontBig, },
|
||||
{ "MEDIUMFONT", FormatToken::FontMedium, },
|
||||
{ "SMALLFONT", FormatToken::FontSmall, },
|
||||
{ "OUTLINE", FormatToken::OutlineEnable, },
|
||||
{ "OUTLINE_OFF", FormatToken::OutlineDisable, },
|
||||
{ "WINDOW_COLOUR_1", FormatToken::ColourWindow1, },
|
||||
{ "WINDOW_COLOUR_2", FormatToken::ColourWindow2, },
|
||||
{ "WINDOW_COLOUR_3", FormatToken::ColourWindow3, },
|
||||
{ "INLINE_SPRITE", FormatToken::InlineSprite, },
|
||||
{ "COMMA32", FormatToken::Comma32, },
|
||||
{ "INT32", FormatToken::Int32, },
|
||||
{ "COMMA1DP16", FormatToken::Comma1dp16, },
|
||||
{ "COMMA2DP32", FormatToken::Comma2dp32, },
|
||||
{ "COMMA16", FormatToken::Comma16, },
|
||||
{ "UINT16", FormatToken::Uint16, },
|
||||
{ "CURRENCY2DP", FormatToken::Currency2dp, },
|
||||
{ "CURRENCY", FormatToken::Currency, },
|
||||
{ "STRINGID", FormatToken::StringId, },
|
||||
{ "STRING", FormatToken::String, },
|
||||
{ "MONTHYEAR", FormatToken::MonthYear, },
|
||||
{ "MONTH", FormatToken::Month, },
|
||||
{ "VELOCITY", FormatToken::Velocity, },
|
||||
{ "POP16", FormatToken::Pop16, },
|
||||
{ "PUSH16", FormatToken::Push16, },
|
||||
{ "DURATION", FormatToken::DurationShort, },
|
||||
{ "REALTIME", FormatToken::DurationLong, },
|
||||
{ "LENGTH", FormatToken::Length, },
|
||||
{ "SPRITE", FormatToken::Sprite, },
|
||||
{ "BLACK", FormatToken::ColourBlack, },
|
||||
{ "GREY", FormatToken::ColourGrey, },
|
||||
{ "WHITE", FormatToken::ColourWhite, },
|
||||
{ "RED", FormatToken::ColourRed, },
|
||||
{ "GREEN", FormatToken::ColourGreen, },
|
||||
{ "YELLOW", FormatToken::ColourYellow, },
|
||||
{ "TOPAZ", FormatToken::ColourTopaz, },
|
||||
{ "CELADON", FormatToken::ColourCeladon, },
|
||||
{ "BABYBLUE", FormatToken::ColourBabyBlue, },
|
||||
{ "PALELAVENDER", FormatToken::ColourPaleLavender, },
|
||||
{ "PALEGOLD", FormatToken::ColourPaleGold, },
|
||||
{ "LIGHTPINK", FormatToken::ColourLightPink, },
|
||||
{ "PEARLAQUA", FormatToken::ColourPearlAqua, },
|
||||
{ "PALESILVER", FormatToken::ColourPaleSilver, },
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
uint32_t format_get_code(std::string_view token)
|
||||
FormatToken FormatTokenFromString(std::string_view token)
|
||||
{
|
||||
auto result = std::find_if(std::begin(format_code_tokens), std::end(format_code_tokens), [token](auto& fct) {
|
||||
return String::Equals(token, fct.token, true);
|
||||
});
|
||||
return result != std::end(format_code_tokens) ? result->code : 0;
|
||||
auto result = FormatTokenMap.find(token);
|
||||
return result != std::end(FormatTokenMap) ? result->second : FormatToken::Unknown;
|
||||
}
|
||||
|
||||
const char* format_get_token(uint32_t code)
|
||||
std::string_view FormatTokenToString(FormatToken token)
|
||||
{
|
||||
for (uint32_t i = 0; i < std::size(format_code_tokens); i++)
|
||||
for (const auto& t : FormatTokenMap)
|
||||
{
|
||||
if (code == format_code_tokens[i].code)
|
||||
return format_code_tokens[i].token;
|
||||
if (t.second == token)
|
||||
{
|
||||
return t.first;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
return {};
|
||||
}
|
||||
|
||||
bool FormatTokenTakesArgument(FormatToken token)
|
||||
{
|
||||
switch (token)
|
||||
{
|
||||
case FormatToken::Comma32:
|
||||
case FormatToken::Int32:
|
||||
case FormatToken::Comma1dp16:
|
||||
case FormatToken::Comma2dp32:
|
||||
case FormatToken::Comma16:
|
||||
case FormatToken::Uint16:
|
||||
case FormatToken::Currency2dp:
|
||||
case FormatToken::Currency:
|
||||
case FormatToken::StringId:
|
||||
case FormatToken::String:
|
||||
case FormatToken::MonthYear:
|
||||
case FormatToken::Month:
|
||||
case FormatToken::Velocity:
|
||||
case FormatToken::DurationShort:
|
||||
case FormatToken::DurationLong:
|
||||
case FormatToken::Length:
|
||||
case FormatToken::Sprite:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool FormatTokenIsColour(FormatToken token)
|
||||
{
|
||||
switch (token)
|
||||
{
|
||||
case FormatToken::ColourBlack:
|
||||
case FormatToken::ColourGrey:
|
||||
case FormatToken::ColourWhite:
|
||||
case FormatToken::ColourRed:
|
||||
case FormatToken::ColourGreen:
|
||||
case FormatToken::ColourYellow:
|
||||
case FormatToken::ColourTopaz:
|
||||
case FormatToken::ColourCeladon:
|
||||
case FormatToken::ColourBabyBlue:
|
||||
case FormatToken::ColourPaleLavender:
|
||||
case FormatToken::ColourPaleGold:
|
||||
case FormatToken::ColourLightPink:
|
||||
case FormatToken::ColourPearlAqua:
|
||||
case FormatToken::ColourPaleSilver:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t FormatTokenGetTextColourIndex(FormatToken token)
|
||||
{
|
||||
switch (token)
|
||||
{
|
||||
case FormatToken::ColourBlack:
|
||||
return 0;
|
||||
case FormatToken::ColourGrey:
|
||||
return 1;
|
||||
case FormatToken::ColourWhite:
|
||||
return 2;
|
||||
case FormatToken::ColourRed:
|
||||
return 3;
|
||||
case FormatToken::ColourGreen:
|
||||
return 4;
|
||||
case FormatToken::ColourYellow:
|
||||
return 5;
|
||||
case FormatToken::ColourTopaz:
|
||||
return 6;
|
||||
case FormatToken::ColourCeladon:
|
||||
return 7;
|
||||
case FormatToken::ColourBabyBlue:
|
||||
return 8;
|
||||
case FormatToken::ColourPaleLavender:
|
||||
return 9;
|
||||
case FormatToken::ColourPaleGold:
|
||||
return 10;
|
||||
case FormatToken::ColourLightPink:
|
||||
return 11;
|
||||
case FormatToken::ColourPearlAqua:
|
||||
return 12;
|
||||
case FormatToken::ColourPaleSilver:
|
||||
return 13;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
FormatToken FormatTokenFromTextColour(size_t textColour)
|
||||
{
|
||||
static constexpr const FormatToken tokens[] = {
|
||||
FormatToken::ColourBlack, FormatToken::ColourGrey, FormatToken::ColourWhite,
|
||||
FormatToken::ColourRed, FormatToken::ColourGreen, FormatToken::ColourYellow,
|
||||
FormatToken::ColourTopaz, FormatToken::ColourCeladon, FormatToken::ColourBabyBlue,
|
||||
FormatToken::ColourPaleLavender, FormatToken::ColourPaleGold, FormatToken::ColourLightPink,
|
||||
FormatToken::ColourPearlAqua, FormatToken::ColourPaleSilver,
|
||||
};
|
||||
if (textColour > std::size(tokens))
|
||||
return FormatToken::ColourBlack;
|
||||
return tokens[textColour];
|
||||
}
|
||||
|
||||
bool utf8_should_use_sprite_for_codepoint(char32_t codepoint)
|
||||
|
@ -119,5 +203,3 @@ bool utf8_should_use_sprite_for_codepoint(char32_t codepoint)
|
|||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
|
|
@ -13,92 +13,75 @@
|
|||
|
||||
#include <string_view>
|
||||
|
||||
uint32_t format_get_code(std::string_view token);
|
||||
const char* format_get_token(uint32_t code);
|
||||
|
||||
enum
|
||||
enum class FormatToken
|
||||
{
|
||||
// Font format codes
|
||||
Unknown,
|
||||
Literal,
|
||||
|
||||
// The next byte specifies the X coordinate
|
||||
FORMAT_MOVE_X = 1,
|
||||
// The next byte specifies the palette
|
||||
FORMAT_ADJUST_PALETTE,
|
||||
Newline,
|
||||
NewlineSmall,
|
||||
|
||||
FORMAT_3,
|
||||
FORMAT_4,
|
||||
// With parameters
|
||||
Move,
|
||||
InlineSprite,
|
||||
|
||||
// Moves to the next line
|
||||
FORMAT_NEWLINE = 5,
|
||||
// Moves less than NEWLINE
|
||||
FORMAT_NEWLINE_SMALLER,
|
||||
// With arguments
|
||||
Comma32,
|
||||
Int32,
|
||||
Comma1dp16,
|
||||
Comma2dp32,
|
||||
Comma16,
|
||||
Uint16,
|
||||
Currency2dp,
|
||||
Currency,
|
||||
StringId,
|
||||
String,
|
||||
MonthYear,
|
||||
Month,
|
||||
Velocity,
|
||||
DurationShort,
|
||||
DurationLong,
|
||||
Length,
|
||||
Sprite,
|
||||
Pop16,
|
||||
Push16,
|
||||
|
||||
FORMAT_TINYFONT,
|
||||
FORMAT_BIGFONT,
|
||||
FORMAT_MEDIUMFONT,
|
||||
FORMAT_SMALLFONT,
|
||||
// Colours
|
||||
ColourWindow1,
|
||||
ColourWindow2,
|
||||
ColourWindow3,
|
||||
ColourBlack,
|
||||
ColourGrey,
|
||||
ColourWhite,
|
||||
ColourRed,
|
||||
ColourGreen,
|
||||
ColourYellow,
|
||||
ColourTopaz,
|
||||
ColourCeladon,
|
||||
ColourBabyBlue,
|
||||
ColourPaleLavender,
|
||||
ColourPaleGold,
|
||||
ColourLightPink,
|
||||
ColourPearlAqua,
|
||||
ColourPaleSilver,
|
||||
|
||||
FORMAT_OUTLINE,
|
||||
FORMAT_OUTLINE_OFF,
|
||||
// Fonts
|
||||
FontTiny,
|
||||
FontSmall,
|
||||
FontMedium,
|
||||
FontBig,
|
||||
|
||||
// Changes the colour of the text to a predefined window colour.
|
||||
FORMAT_WINDOW_COLOUR_1,
|
||||
FORMAT_WINDOW_COLOUR_2,
|
||||
FORMAT_WINDOW_COLOUR_3,
|
||||
|
||||
FORMAT_16,
|
||||
|
||||
// The next 2 bytes specify the X and Y coordinates
|
||||
FORMAT_NEWLINE_X_Y = 17,
|
||||
|
||||
// The next 4 bytes specify the sprite
|
||||
FORMAT_INLINE_SPRITE = 23,
|
||||
|
||||
// Argument format codes
|
||||
FORMAT_ARGUMENT_CODE_START = 123, // 'z' == 122 or 0x7A
|
||||
FORMAT_COMMA32 = 123,
|
||||
FORMAT_INT32,
|
||||
FORMAT_COMMA2DP32,
|
||||
FORMAT_COMMA16,
|
||||
FORMAT_UINT16,
|
||||
FORMAT_CURRENCY2DP,
|
||||
FORMAT_CURRENCY,
|
||||
FORMAT_STRINGID,
|
||||
FORMAT_STRINGID2,
|
||||
FORMAT_STRING,
|
||||
FORMAT_MONTHYEAR,
|
||||
FORMAT_MONTH,
|
||||
FORMAT_VELOCITY,
|
||||
FORMAT_POP16,
|
||||
FORMAT_PUSH16,
|
||||
FORMAT_DURATION,
|
||||
FORMAT_REALTIME,
|
||||
FORMAT_LENGTH,
|
||||
FORMAT_SPRITE,
|
||||
FORMAT_ARGUMENT_CODE_END = FORMAT_SPRITE,
|
||||
|
||||
// Colour format codes
|
||||
FORMAT_COLOUR_CODE_START = 142,
|
||||
FORMAT_BLACK = 142,
|
||||
FORMAT_GREY,
|
||||
FORMAT_WHITE,
|
||||
FORMAT_RED,
|
||||
FORMAT_GREEN,
|
||||
FORMAT_YELLOW,
|
||||
FORMAT_TOPAZ,
|
||||
FORMAT_CELADON,
|
||||
FORMAT_BABYBLUE,
|
||||
FORMAT_PALELAVENDER,
|
||||
FORMAT_PALEGOLD,
|
||||
FORMAT_LIGHTPINK,
|
||||
FORMAT_PEARLAQUA,
|
||||
FORMAT_PALESILVER,
|
||||
FORMAT_COLOUR_CODE_END = FORMAT_PALESILVER,
|
||||
|
||||
// Format codes that need suitable Unicode allocations
|
||||
FORMAT_COMMA1DP16 = 20004
|
||||
OutlineEnable,
|
||||
OutlineDisable,
|
||||
};
|
||||
|
||||
FormatToken FormatTokenFromString(std::string_view token);
|
||||
std::string_view FormatTokenToString(FormatToken token);
|
||||
bool FormatTokenTakesArgument(FormatToken token);
|
||||
bool FormatTokenIsColour(FormatToken token);
|
||||
size_t FormatTokenGetTextColourIndex(FormatToken token);
|
||||
FormatToken FormatTokenFromTextColour(size_t textColour);
|
||||
|
||||
constexpr uint8_t CS_SPRITE_FONT_OFFSET = 32;
|
||||
|
||||
namespace CSChar
|
||||
|
|
|
@ -60,7 +60,7 @@ namespace OpenRCT2
|
|||
|
||||
bool FmtString::token::IsLiteral() const
|
||||
{
|
||||
return kind == 0;
|
||||
return kind == FormatToken::Literal;
|
||||
}
|
||||
|
||||
FmtString::iterator::iterator(std::string_view s, size_t i)
|
||||
|
@ -104,7 +104,7 @@ namespace OpenRCT2
|
|||
{
|
||||
p = *p0;
|
||||
}
|
||||
current = token(FORMAT_MOVE_X, str.substr(startIndex, i - startIndex), p);
|
||||
current = token(FormatToken::Move, str.substr(startIndex, i - startIndex), p);
|
||||
return;
|
||||
}
|
||||
else if (inner == "INLINE_SPRITE")
|
||||
|
@ -121,7 +121,7 @@ namespace OpenRCT2
|
|||
p |= (*p2) << 16;
|
||||
p |= (*p3) << 24;
|
||||
}
|
||||
current = token(FORMAT_INLINE_SPRITE, str.substr(startIndex, i - startIndex), p);
|
||||
current = token(FormatToken::InlineSprite, str.substr(startIndex, i - startIndex), p);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -151,14 +151,14 @@ namespace OpenRCT2
|
|||
std::string_view sztoken = str.substr(index, len);
|
||||
if (sztoken.size() >= 2 && sztoken[0] == '{' && sztoken[1] != '{')
|
||||
{
|
||||
auto kind = format_get_code(sztoken.substr(1, len - 2));
|
||||
auto kind = FormatTokenFromString(sztoken.substr(1, len - 2));
|
||||
return token(kind, sztoken);
|
||||
}
|
||||
else if (sztoken == "\n" || sztoken == "\r")
|
||||
{
|
||||
return token(FORMAT_NEWLINE, sztoken);
|
||||
return token(FormatToken::Newline, sztoken);
|
||||
}
|
||||
return token(0, sztoken);
|
||||
return token(FormatToken::Literal, sztoken);
|
||||
}
|
||||
|
||||
const FmtString::token* FmtString::iterator::operator->() const
|
||||
|
@ -433,21 +433,21 @@ namespace OpenRCT2
|
|||
{
|
||||
switch (token)
|
||||
{
|
||||
case FORMAT_UINT16:
|
||||
case FORMAT_INT32:
|
||||
case FormatToken::Uint16:
|
||||
case FormatToken::Int32:
|
||||
if constexpr (std::is_integral<T>())
|
||||
{
|
||||
FormatNumber<0, false>(ss, arg);
|
||||
}
|
||||
break;
|
||||
case FORMAT_COMMA16:
|
||||
case FORMAT_COMMA32:
|
||||
case FormatToken::Comma16:
|
||||
case FormatToken::Comma32:
|
||||
if constexpr (std::is_integral<T>())
|
||||
{
|
||||
FormatNumber<0, true>(ss, arg);
|
||||
}
|
||||
break;
|
||||
case FORMAT_COMMA1DP16:
|
||||
case FormatToken::Comma1dp16:
|
||||
if constexpr (std::is_integral<T>())
|
||||
{
|
||||
FormatNumber<1, true>(ss, arg);
|
||||
|
@ -457,7 +457,7 @@ namespace OpenRCT2
|
|||
FormatNumber<1, true>(ss, std::round(arg * 10));
|
||||
}
|
||||
break;
|
||||
case FORMAT_COMMA2DP32:
|
||||
case FormatToken::Comma2dp32:
|
||||
if constexpr (std::is_integral<T>())
|
||||
{
|
||||
FormatNumber<2, true>(ss, arg);
|
||||
|
@ -467,19 +467,19 @@ namespace OpenRCT2
|
|||
FormatNumber<2, true>(ss, std::round(arg * 100));
|
||||
}
|
||||
break;
|
||||
case FORMAT_CURRENCY2DP:
|
||||
case FormatToken::Currency2dp:
|
||||
if constexpr (std::is_integral<T>())
|
||||
{
|
||||
FormatCurrency<2, true>(ss, arg);
|
||||
}
|
||||
break;
|
||||
case FORMAT_CURRENCY:
|
||||
case FormatToken::Currency:
|
||||
if constexpr (std::is_integral<T>())
|
||||
{
|
||||
FormatCurrency<0, true>(ss, arg);
|
||||
}
|
||||
break;
|
||||
case FORMAT_VELOCITY:
|
||||
case FormatToken::Velocity:
|
||||
if constexpr (std::is_integral<T>())
|
||||
{
|
||||
switch (gConfigGeneral.measurement_format)
|
||||
|
@ -497,19 +497,19 @@ namespace OpenRCT2
|
|||
}
|
||||
}
|
||||
break;
|
||||
case FORMAT_DURATION:
|
||||
case FormatToken::DurationShort:
|
||||
if constexpr (std::is_integral<T>())
|
||||
{
|
||||
FormatMinutesSeconds(ss, arg);
|
||||
}
|
||||
break;
|
||||
case FORMAT_REALTIME:
|
||||
case FormatToken::DurationLong:
|
||||
if constexpr (std::is_integral<T>())
|
||||
{
|
||||
FormatHoursMinutes(ss, arg);
|
||||
}
|
||||
break;
|
||||
case FORMAT_LENGTH:
|
||||
case FormatToken::Length:
|
||||
if constexpr (std::is_integral<T>())
|
||||
{
|
||||
switch (gConfigGeneral.measurement_format)
|
||||
|
@ -525,7 +525,7 @@ namespace OpenRCT2
|
|||
}
|
||||
}
|
||||
break;
|
||||
case FORMAT_MONTHYEAR:
|
||||
case FormatToken::MonthYear:
|
||||
if constexpr (std::is_integral<T>())
|
||||
{
|
||||
auto month = date_get_month(arg);
|
||||
|
@ -533,7 +533,7 @@ namespace OpenRCT2
|
|||
FormatStringId(ss, STR_DATE_FORMAT_MY, month, year);
|
||||
}
|
||||
break;
|
||||
case FORMAT_MONTH:
|
||||
case FormatToken::Month:
|
||||
if constexpr (std::is_integral<T>())
|
||||
{
|
||||
auto szMonth = language_get_string(DateGameMonthNames[date_get_month(arg)]);
|
||||
|
@ -543,7 +543,7 @@ namespace OpenRCT2
|
|||
}
|
||||
}
|
||||
break;
|
||||
case FORMAT_STRING:
|
||||
case FormatToken::String:
|
||||
if constexpr (std::is_same<T, const char*>())
|
||||
{
|
||||
ss << arg;
|
||||
|
@ -553,7 +553,7 @@ namespace OpenRCT2
|
|||
ss << arg.c_str();
|
||||
}
|
||||
break;
|
||||
case FORMAT_SPRITE:
|
||||
case FormatToken::Sprite:
|
||||
if constexpr (std::is_integral<T>())
|
||||
{
|
||||
auto idx = static_cast<uint32_t>(arg);
|
||||
|
@ -567,17 +567,10 @@ namespace OpenRCT2
|
|||
}
|
||||
}
|
||||
|
||||
template void FormatArgument(std::stringstream&, uint32_t, uint16_t);
|
||||
template void FormatArgument(std::stringstream&, uint32_t, int16_t);
|
||||
template void FormatArgument(std::stringstream&, uint32_t, int32_t);
|
||||
template void FormatArgument(std::stringstream&, uint32_t, const char*);
|
||||
|
||||
bool CanFormatToken(FormatToken t)
|
||||
{
|
||||
if (t == FORMAT_PUSH16 || t == FORMAT_POP16)
|
||||
return false;
|
||||
return t == FORMAT_COMMA1DP16 || (t >= FORMAT_ARGUMENT_CODE_START && t <= FORMAT_ARGUMENT_CODE_END);
|
||||
}
|
||||
template void FormatArgument(std::stringstream&, FormatToken, uint16_t);
|
||||
template void FormatArgument(std::stringstream&, FormatToken, int16_t);
|
||||
template void FormatArgument(std::stringstream&, FormatToken, int32_t);
|
||||
template void FormatArgument(std::stringstream&, FormatToken, const char*);
|
||||
|
||||
bool IsRealNameStringId(rct_string_id id)
|
||||
{
|
||||
|
@ -635,7 +628,7 @@ namespace OpenRCT2
|
|||
{
|
||||
for (const auto& token : fmt)
|
||||
{
|
||||
if (token.kind == FORMAT_STRINGID || token.kind == FORMAT_STRINGID2)
|
||||
if (token.kind == FormatToken::StringId)
|
||||
{
|
||||
if (argIndex < args.size())
|
||||
{
|
||||
|
@ -658,7 +651,7 @@ namespace OpenRCT2
|
|||
argIndex++;
|
||||
}
|
||||
}
|
||||
else if (CanFormatToken(token.kind))
|
||||
else if (FormatTokenTakesArgument(token.kind))
|
||||
{
|
||||
if (argIndex < args.size())
|
||||
{
|
||||
|
@ -666,7 +659,7 @@ namespace OpenRCT2
|
|||
}
|
||||
argIndex++;
|
||||
}
|
||||
else if (token.kind != FORMAT_PUSH16 && token.kind != FORMAT_POP16)
|
||||
else if (token.kind != FormatToken::Push16 && token.kind != FormatToken::Pop16)
|
||||
{
|
||||
ss << token.text;
|
||||
}
|
||||
|
@ -703,42 +696,41 @@ namespace OpenRCT2
|
|||
{
|
||||
switch (t.kind)
|
||||
{
|
||||
case FORMAT_COMMA32:
|
||||
case FORMAT_INT32:
|
||||
case FORMAT_COMMA2DP32:
|
||||
case FORMAT_CURRENCY2DP:
|
||||
case FORMAT_CURRENCY:
|
||||
case FORMAT_SPRITE:
|
||||
case FormatToken::Comma32:
|
||||
case FormatToken::Int32:
|
||||
case FormatToken::Comma2dp32:
|
||||
case FormatToken::Currency2dp:
|
||||
case FormatToken::Currency:
|
||||
case FormatToken::Sprite:
|
||||
anyArgs.push_back(ReadFromArgs<int32_t>(args));
|
||||
break;
|
||||
case FORMAT_COMMA16:
|
||||
case FORMAT_UINT16:
|
||||
case FORMAT_MONTHYEAR:
|
||||
case FORMAT_MONTH:
|
||||
case FORMAT_VELOCITY:
|
||||
case FORMAT_DURATION:
|
||||
case FORMAT_REALTIME:
|
||||
case FORMAT_LENGTH:
|
||||
case FormatToken::Comma16:
|
||||
case FormatToken::Uint16:
|
||||
case FormatToken::MonthYear:
|
||||
case FormatToken::Month:
|
||||
case FormatToken::Velocity:
|
||||
case FormatToken::DurationShort:
|
||||
case FormatToken::DurationLong:
|
||||
case FormatToken::Length:
|
||||
anyArgs.push_back(ReadFromArgs<uint16_t>(args));
|
||||
break;
|
||||
case FORMAT_STRINGID:
|
||||
case FORMAT_STRINGID2:
|
||||
case FormatToken::StringId:
|
||||
{
|
||||
auto stringId = ReadFromArgs<rct_string_id>(args);
|
||||
anyArgs.push_back(stringId);
|
||||
BuildAnyArgListFromLegacyArgBuffer(GetFmtStringById(stringId), anyArgs, args);
|
||||
break;
|
||||
}
|
||||
case FORMAT_STRING:
|
||||
case FormatToken::String:
|
||||
{
|
||||
auto sz = ReadFromArgs<const char*>(args);
|
||||
anyArgs.push_back(sz);
|
||||
break;
|
||||
}
|
||||
case FORMAT_POP16:
|
||||
case FormatToken::Pop16:
|
||||
args = reinterpret_cast<const char*>(reinterpret_cast<uintptr_t>(args) + 2);
|
||||
break;
|
||||
case FORMAT_PUSH16:
|
||||
case FormatToken::Push16:
|
||||
args = reinterpret_cast<const char*>(reinterpret_cast<uintptr_t>(args) - 2);
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -23,7 +23,6 @@
|
|||
|
||||
namespace OpenRCT2
|
||||
{
|
||||
using FormatToken = uint32_t;
|
||||
using FormatArg_t = std::variant<uint16_t, int32_t, const char*>;
|
||||
|
||||
class FmtString
|
||||
|
@ -77,7 +76,6 @@ namespace OpenRCT2
|
|||
|
||||
template<typename T> void FormatArgument(std::stringstream& ss, FormatToken token, T arg);
|
||||
|
||||
bool CanFormatToken(FormatToken t);
|
||||
bool IsRealNameStringId(rct_string_id id);
|
||||
void FormatRealName(std::stringstream& ss, rct_string_id id);
|
||||
FmtString GetFmtStringById(rct_string_id id);
|
||||
|
@ -92,7 +90,7 @@ namespace OpenRCT2
|
|||
while (!it.eol())
|
||||
{
|
||||
const auto& token = *it++;
|
||||
if (!CanFormatToken(token.kind))
|
||||
if (!FormatTokenTakesArgument(token.kind))
|
||||
{
|
||||
ss << token.text;
|
||||
}
|
||||
|
@ -110,7 +108,7 @@ namespace OpenRCT2
|
|||
while (!it.eol())
|
||||
{
|
||||
const auto& token = *it++;
|
||||
if (token.kind == FORMAT_STRINGID || token.kind == FORMAT_STRINGID2)
|
||||
if (token.kind == FormatToken::StringId)
|
||||
{
|
||||
if constexpr (std::is_integral<TArg0>())
|
||||
{
|
||||
|
@ -128,7 +126,7 @@ namespace OpenRCT2
|
|||
FormatString(ss, stack, argN...);
|
||||
}
|
||||
}
|
||||
else if (CanFormatToken(token.kind))
|
||||
else if (FormatTokenTakesArgument(token.kind))
|
||||
{
|
||||
FormatArgument(ss, token.kind, arg0);
|
||||
return FormatString(ss, stack, argN...);
|
||||
|
|
|
@ -51,21 +51,6 @@ const language_descriptor LanguagesDescriptors[LANGUAGE_COUNT] =
|
|||
};
|
||||
// clang-format on
|
||||
|
||||
void utf8_remove_format_codes(utf8* text, bool allowcolours)
|
||||
{
|
||||
const utf8* ch = text;
|
||||
utf8* dstCh = text;
|
||||
int32_t codepoint;
|
||||
while ((codepoint = String::GetNextCodepoint(ch, &ch)) != 0)
|
||||
{
|
||||
if (!utf8_is_format_code(codepoint) || (allowcolours && utf8_is_colour_code(codepoint)))
|
||||
{
|
||||
dstCh = String::WriteCodepoint(dstCh, codepoint);
|
||||
}
|
||||
}
|
||||
*dstCh = 0;
|
||||
}
|
||||
|
||||
uint8_t language_get_id_from_locale(const char* locale)
|
||||
{
|
||||
uint8_t i = 0;
|
||||
|
@ -125,113 +110,3 @@ rct_string_id language_allocate_object_string(const std::string& target)
|
|||
auto& localisationService = OpenRCT2::GetContext()->GetLocalisationService();
|
||||
return localisationService.AllocateObjectString(target);
|
||||
}
|
||||
|
||||
std::string language_convert_string_to_tokens(const std::string_view& s)
|
||||
{
|
||||
std::string result;
|
||||
result.reserve(s.size() * 4);
|
||||
std::string input = std::string(s);
|
||||
auto readPtr = input.c_str();
|
||||
while (true)
|
||||
{
|
||||
char32_t code = utf8_get_next(readPtr, const_cast<const utf8**>(&readPtr));
|
||||
if (code == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else if (code == '\n')
|
||||
{
|
||||
result.push_back('\n');
|
||||
}
|
||||
else if (utf8_is_format_code(code))
|
||||
{
|
||||
auto token = format_get_token(code);
|
||||
result.push_back('{');
|
||||
result.append(token);
|
||||
result.push_back('}');
|
||||
}
|
||||
else
|
||||
{
|
||||
char buffer[8]{};
|
||||
utf8_write_codepoint(buffer, code);
|
||||
result.append(buffer);
|
||||
}
|
||||
}
|
||||
result.shrink_to_fit();
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string language_convert_string(const std::string_view& s)
|
||||
{
|
||||
enum class PARSE_STATE
|
||||
{
|
||||
DEFAULT,
|
||||
CR,
|
||||
TOKEN,
|
||||
};
|
||||
|
||||
std::string result;
|
||||
std::string token;
|
||||
PARSE_STATE state{};
|
||||
token.reserve(64);
|
||||
result.reserve(s.size() * 2);
|
||||
for (char c : s)
|
||||
{
|
||||
switch (state)
|
||||
{
|
||||
case PARSE_STATE::CR:
|
||||
result.push_back(FORMAT_NEWLINE);
|
||||
state = PARSE_STATE::DEFAULT;
|
||||
[[fallthrough]];
|
||||
case PARSE_STATE::DEFAULT:
|
||||
switch (c)
|
||||
{
|
||||
case '\r':
|
||||
state = PARSE_STATE::CR;
|
||||
break;
|
||||
case '\n':
|
||||
result.push_back(FORMAT_NEWLINE);
|
||||
break;
|
||||
case '{':
|
||||
token.clear();
|
||||
state = PARSE_STATE::TOKEN;
|
||||
break;
|
||||
default:
|
||||
if (static_cast<uint8_t>(c) >= 32)
|
||||
{
|
||||
result.push_back(c);
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case PARSE_STATE::TOKEN:
|
||||
if (c == '}')
|
||||
{
|
||||
auto code = format_get_code(token.c_str());
|
||||
if (code == 0)
|
||||
{
|
||||
int32_t number{};
|
||||
if (sscanf(token.c_str(), "%d", &number) == 1)
|
||||
{
|
||||
auto b = static_cast<uint8_t>(std::clamp(number, 0, 255));
|
||||
token.push_back(b);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
char buffer[8]{};
|
||||
utf8_write_codepoint(buffer, code);
|
||||
result.append(buffer);
|
||||
}
|
||||
state = PARSE_STATE::DEFAULT;
|
||||
}
|
||||
else
|
||||
{
|
||||
token.push_back(c);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
result.shrink_to_fit();
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -98,7 +98,6 @@ bool language_open(int32_t id);
|
|||
uint32_t utf8_get_next(const utf8* char_ptr, const utf8** nextchar_ptr);
|
||||
int32_t utf8_insert_codepoint(utf8* dst, uint32_t codepoint);
|
||||
bool utf8_is_codepoint_start(const utf8* text);
|
||||
void utf8_remove_format_codes(utf8* text, bool allowcolours);
|
||||
int32_t utf8_get_codepoint_length(char32_t codepoint);
|
||||
int32_t utf8_length(const utf8* text);
|
||||
|
||||
|
@ -107,8 +106,6 @@ std::string utf8_to_rct2(const std::string_view& src);
|
|||
bool language_get_localised_scenario_strings(const utf8* scenarioFilename, rct_string_id* outStringIds);
|
||||
void language_free_object_string(rct_string_id stringId);
|
||||
rct_string_id language_allocate_object_string(const std::string& target);
|
||||
std::string language_convert_string_to_tokens(const std::string_view& s);
|
||||
std::string language_convert_string(const std::string_view& s);
|
||||
|
||||
constexpr utf8* utf8_write_codepoint(utf8* dst, uint32_t codepoint)
|
||||
{
|
||||
|
|
|
@ -539,32 +539,8 @@ private:
|
|||
sb.Clear();
|
||||
while (reader->TryPeek(&codepoint) && !IsNewLine(codepoint))
|
||||
{
|
||||
// if (codepoint == '{')
|
||||
// {
|
||||
// uint32_t token;
|
||||
// bool isByte;
|
||||
// if (ParseToken(reader, &token, &isByte))
|
||||
// {
|
||||
// if (isByte)
|
||||
// {
|
||||
// sb.Append(reinterpret_cast<const utf8*>(&token), 1);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// sb.Append(static_cast<int32_t>(token));
|
||||
// }
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// // Syntax error or unknown token, ignore line entirely
|
||||
// return;
|
||||
// }
|
||||
// }
|
||||
// else
|
||||
{
|
||||
reader->Skip();
|
||||
sb.Append(codepoint);
|
||||
}
|
||||
reader->Skip();
|
||||
sb.Append(codepoint);
|
||||
}
|
||||
|
||||
std::string s;
|
||||
|
@ -599,47 +575,6 @@ private:
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool ParseToken(IStringReader* reader, uint32_t* token, bool* isByte)
|
||||
{
|
||||
auto sb = StringBuilder();
|
||||
codepoint_t codepoint;
|
||||
|
||||
// Skip open brace
|
||||
reader->Skip();
|
||||
|
||||
while (reader->TryPeek(&codepoint))
|
||||
{
|
||||
if (IsNewLine(codepoint))
|
||||
return false;
|
||||
if (IsWhitespace(codepoint))
|
||||
return false;
|
||||
|
||||
reader->Skip();
|
||||
|
||||
if (codepoint == '}')
|
||||
break;
|
||||
|
||||
sb.Append(codepoint);
|
||||
}
|
||||
|
||||
const utf8* tokenName = sb.GetBuffer();
|
||||
*token = format_get_code(tokenName);
|
||||
*isByte = false;
|
||||
|
||||
// Handle explicit byte values
|
||||
if (*token == 0)
|
||||
{
|
||||
int32_t number;
|
||||
if (sscanf(tokenName, "%d", &number) == 1)
|
||||
{
|
||||
*token = std::clamp(number, 0, 255);
|
||||
*isByte = true;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
namespace LanguagePackFactory
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -19,15 +19,10 @@
|
|||
|
||||
#include <string>
|
||||
|
||||
bool utf8_is_format_code(char32_t codepoint);
|
||||
bool utf8_is_colour_code(char32_t codepoint);
|
||||
bool utf8_should_use_sprite_for_codepoint(char32_t codepoint);
|
||||
int32_t utf8_get_format_code_arg_length(char32_t codepoint);
|
||||
void utf8_remove_formatting(utf8* string, bool allowColours);
|
||||
|
||||
std::string format_string(rct_string_id format, const void* args);
|
||||
void format_string(char* dest, size_t size, rct_string_id format, const void* args);
|
||||
void format_string_raw(char* dest, size_t size, const char* src, const void* args);
|
||||
void format_string_to_upper(char* dest, size_t size, rct_string_id format, const void* args);
|
||||
void generate_string_file();
|
||||
|
||||
|
@ -43,7 +38,6 @@ void format_readable_speed(char* buf, size_t bufSize, uint64_t sizeBytesPerSec);
|
|||
|
||||
utf8* get_string_end(const utf8* text);
|
||||
size_t get_string_size(const utf8* text);
|
||||
int32_t get_string_length(const utf8* text);
|
||||
|
||||
// The maximum number of characters allowed for string/money conversions (anything above will risk integer overflow issues)
|
||||
#define MONEY_STRING_MAXLENGTH 14
|
||||
|
|
|
@ -112,15 +112,7 @@ int32_t utf8_length(const utf8* text)
|
|||
*/
|
||||
utf8* get_string_end(const utf8* text)
|
||||
{
|
||||
int32_t codepoint;
|
||||
const utf8* ch = text;
|
||||
|
||||
while ((codepoint = utf8_get_next(ch, &ch)) != 0)
|
||||
{
|
||||
int32_t argLength = utf8_get_format_code_arg_length(codepoint);
|
||||
ch += argLength;
|
||||
}
|
||||
return const_cast<utf8*>(ch - 1);
|
||||
return const_cast<char*>(std::strchr(text, 0));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -130,83 +122,3 @@ size_t get_string_size(const utf8* text)
|
|||
{
|
||||
return get_string_end(text) - text + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of visible characters (excludes format codes) in the given UTF-8 string.
|
||||
*/
|
||||
int32_t get_string_length(const utf8* text)
|
||||
{
|
||||
char32_t codepoint;
|
||||
const utf8* ch = text;
|
||||
|
||||
int32_t count = 0;
|
||||
while ((codepoint = utf8_get_next(ch, &ch)) != 0)
|
||||
{
|
||||
if (utf8_is_format_code(codepoint))
|
||||
{
|
||||
ch += utf8_get_format_code_arg_length(codepoint);
|
||||
}
|
||||
else
|
||||
{
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
int32_t utf8_get_format_code_arg_length(char32_t codepoint)
|
||||
{
|
||||
switch (codepoint)
|
||||
{
|
||||
case FORMAT_MOVE_X:
|
||||
case FORMAT_ADJUST_PALETTE:
|
||||
case FORMAT_3:
|
||||
case FORMAT_4:
|
||||
return 1;
|
||||
case FORMAT_NEWLINE_X_Y:
|
||||
return 2;
|
||||
case FORMAT_INLINE_SPRITE:
|
||||
return 4;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void utf8_remove_formatting(utf8* string, bool allowColours)
|
||||
{
|
||||
utf8* readPtr = string;
|
||||
utf8* writePtr = string;
|
||||
|
||||
while (true)
|
||||
{
|
||||
char32_t code = utf8_get_next(readPtr, const_cast<const utf8**>(&readPtr));
|
||||
|
||||
if (code == 0)
|
||||
{
|
||||
*writePtr = 0;
|
||||
break;
|
||||
}
|
||||
else if (!utf8_is_format_code(code) || (allowColours && utf8_is_colour_code(code)))
|
||||
{
|
||||
writePtr = utf8_write_codepoint(writePtr, code);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool utf8_is_format_code(char32_t codepoint)
|
||||
{
|
||||
if (codepoint < 32)
|
||||
return true;
|
||||
if (codepoint >= FORMAT_ARGUMENT_CODE_START && codepoint <= FORMAT_ARGUMENT_CODE_END)
|
||||
return true;
|
||||
if (codepoint >= FORMAT_COLOUR_CODE_START && codepoint <= FORMAT_COLOUR_CODE_END)
|
||||
return true;
|
||||
if (codepoint == FORMAT_COMMA1DP16)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool utf8_is_colour_code(char32_t codepoint)
|
||||
{
|
||||
return codepoint >= FORMAT_COLOUR_CODE_START && codepoint <= FORMAT_COLOUR_CODE_END;
|
||||
}
|
||||
|
|
|
@ -695,23 +695,18 @@ NetworkGroup* NetworkBase::GetGroupByID(uint8_t id)
|
|||
|
||||
const char* NetworkBase::FormatChat(NetworkPlayer* fromplayer, const char* text)
|
||||
{
|
||||
static char formatted[1024];
|
||||
char* lineCh = formatted;
|
||||
formatted[0] = 0;
|
||||
static std::string formatted;
|
||||
formatted.clear();
|
||||
formatted += "{OUTLINE}";
|
||||
if (fromplayer)
|
||||
{
|
||||
lineCh = utf8_write_codepoint(lineCh, FORMAT_OUTLINE);
|
||||
lineCh = utf8_write_codepoint(lineCh, FORMAT_BABYBLUE);
|
||||
safe_strcpy(lineCh, static_cast<const char*>(fromplayer->Name.c_str()), sizeof(formatted) - (lineCh - formatted));
|
||||
safe_strcat(lineCh, ": ", sizeof(formatted) - (lineCh - formatted));
|
||||
lineCh = strchr(lineCh, '\0');
|
||||
formatted += "{BABYBLUE}";
|
||||
formatted += fromplayer->Name;
|
||||
formatted += ": ";
|
||||
}
|
||||
lineCh = utf8_write_codepoint(lineCh, FORMAT_OUTLINE);
|
||||
lineCh = utf8_write_codepoint(lineCh, FORMAT_WHITE);
|
||||
char* ptrtext = lineCh;
|
||||
safe_strcpy(lineCh, text, 800);
|
||||
utf8_remove_format_codes(ptrtext, true);
|
||||
return formatted;
|
||||
formatted += "{WHITE}";
|
||||
formatted += text;
|
||||
return formatted.c_str();
|
||||
}
|
||||
|
||||
void NetworkBase::SendPacketToClients(const NetworkPacket& packet, bool front, bool gameCmd)
|
||||
|
@ -1092,7 +1087,6 @@ void NetworkBase::AppendLog(std::ostream& fs, const std::string& s)
|
|||
if (strftime(buffer, sizeof(buffer), "[%Y/%m/%d %H:%M:%S] ", tmInfo) != 0)
|
||||
{
|
||||
String::Append(buffer, sizeof(buffer), s.c_str());
|
||||
utf8_remove_formatting(buffer, false);
|
||||
String::Append(buffer, sizeof(buffer), PLATFORM_NEWLINE);
|
||||
|
||||
fs.write(buffer, strlen(buffer));
|
||||
|
|
|
@ -19,7 +19,6 @@ void NetworkPlayer::SetName(const std::string& name)
|
|||
{
|
||||
// 36 == 31 + strlen(" #255");
|
||||
Name = name.substr(0, 36);
|
||||
utf8_remove_format_codes(static_cast<utf8*>(Name.data()), false);
|
||||
}
|
||||
|
||||
void NetworkPlayer::Read(NetworkPacket& packet)
|
||||
|
|
|
@ -3006,7 +3006,6 @@ private:
|
|||
const auto originalString = _s4.string_table[(stringId - USER_STRING_START) % 1024];
|
||||
std::string_view originalStringView(originalString, USER_STRING_MAX_LENGTH);
|
||||
auto asUtf8 = rct2_to_utf8(originalStringView, RCT2_LANGUAGE_ID_ENGLISH_UK);
|
||||
utf8_remove_format_codes(asUtf8.data(), /*allow colour*/ false);
|
||||
return asUtf8.data();
|
||||
}
|
||||
|
||||
|
|
|
@ -1371,7 +1371,7 @@ void S6Exporter::ExportBanner(RCT12Banner& dst, const Banner& src)
|
|||
if (!(src.flags & BANNER_FLAG_IS_WALL) && !(src.flags & BANNER_FLAG_IS_LARGE_SCENERY))
|
||||
{
|
||||
char codeBuffer[32]{};
|
||||
utf8_write_codepoint(codeBuffer, FORMAT_COLOUR_CODE_START + src.text_colour);
|
||||
utf8_write_codepoint(codeBuffer, 142 + src.text_colour);
|
||||
bannerText = codeBuffer + bannerText;
|
||||
}
|
||||
|
||||
|
|
|
@ -187,6 +187,18 @@ public:
|
|||
return false;
|
||||
}
|
||||
|
||||
static bool IsLikelyUtf8(const std::string_view s)
|
||||
{
|
||||
for (auto c : s)
|
||||
{
|
||||
if (static_cast<uint8_t>(c) >= 128)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Import() override
|
||||
{
|
||||
Initialise();
|
||||
|
@ -195,15 +207,7 @@ public:
|
|||
gS6Info = _s6.info;
|
||||
|
||||
// Some scenarios have their scenario details in UTF-8, due to earlier bugs in OpenRCT2.
|
||||
// This is hard to detect. Therefore, consider invalid characters like colour codes as a sign the text is in UTF-8.
|
||||
bool alreadyInUTF8 = false;
|
||||
|
||||
if (String::ContainsColourCode(_s6.info.name) || String::ContainsColourCode(_s6.info.details))
|
||||
{
|
||||
alreadyInUTF8 = true;
|
||||
}
|
||||
|
||||
if (!alreadyInUTF8)
|
||||
if (!IsLikelyUtf8(_s6.info.name) && !IsLikelyUtf8(_s6.info.details))
|
||||
{
|
||||
auto temp = rct2_to_utf8(_s6.info.name, RCT2_LANGUAGE_ID_ENGLISH_UK);
|
||||
safe_strcpy(gS6Info.name, temp.data(), sizeof(gS6Info.name));
|
||||
|
@ -1668,7 +1672,6 @@ public:
|
|||
const auto originalString = _s6.custom_strings[(stringId - USER_STRING_START) % 1024];
|
||||
std::string_view originalStringView(originalString, USER_STRING_MAX_LENGTH);
|
||||
auto asUtf8 = rct2_to_utf8(originalStringView, RCT2_LANGUAGE_ID_ENGLISH_UK);
|
||||
utf8_remove_format_codes(asUtf8.data(), /*allow colour*/ false);
|
||||
return asUtf8.data();
|
||||
}
|
||||
|
||||
|
|
|
@ -261,7 +261,7 @@ private:
|
|||
rct_s6_info info = chunkReader.ReadChunkAs<rct_s6_info>();
|
||||
// If the name or the details contain a colour code, they might be in UTF-8 already.
|
||||
// This is caused by a bug that was in OpenRCT2 for 3 years.
|
||||
if (!String::ContainsColourCode(info.name) && !String::ContainsColourCode(info.details))
|
||||
if (!IsLikelyUtf8(info.name) && !IsLikelyUtf8(info.details))
|
||||
{
|
||||
rct2_to_utf8_self(info.name, sizeof(info.name));
|
||||
rct2_to_utf8_self(info.details, sizeof(info.details));
|
||||
|
@ -283,6 +283,18 @@ private:
|
|||
return false;
|
||||
}
|
||||
|
||||
static bool IsLikelyUtf8(const std::string_view s)
|
||||
{
|
||||
for (auto c : s)
|
||||
{
|
||||
if (static_cast<uint8_t>(c) >= 128)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static scenario_index_entry CreateNewScenarioEntry(const std::string& path, uint64_t timestamp, rct_s6_info* s6Info)
|
||||
{
|
||||
scenario_index_entry entry = {};
|
||||
|
|
|
@ -63,7 +63,7 @@ namespace OpenRCT2::Scripting
|
|||
result.MonthYear = value["month"].as_int();
|
||||
result.Day = value["day"].as_int();
|
||||
|
||||
auto text = language_convert_string(value["text"].as_string());
|
||||
auto text = value["text"].as_string();
|
||||
String::Set(result.Text, sizeof(result.Text), text.c_str());
|
||||
return result;
|
||||
}
|
||||
|
@ -207,7 +207,7 @@ namespace OpenRCT2::Scripting
|
|||
auto msg = GetMessage();
|
||||
if (msg != nullptr)
|
||||
{
|
||||
return language_convert_string_to_tokens(msg->Text);
|
||||
return msg->Text;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -218,8 +218,7 @@ namespace OpenRCT2::Scripting
|
|||
auto msg = GetMessage();
|
||||
if (msg != nullptr)
|
||||
{
|
||||
auto text = language_convert_string(value);
|
||||
String::Set(msg->Text, sizeof(msg->Text), text.c_str());
|
||||
String::Set(msg->Text, sizeof(msg->Text), value.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -395,12 +394,12 @@ namespace OpenRCT2::Scripting
|
|||
std::string text;
|
||||
if (message.type() == DukValue::Type::STRING)
|
||||
{
|
||||
text = language_convert_string(message.as_string());
|
||||
text = message.as_string();
|
||||
}
|
||||
else
|
||||
{
|
||||
type = GetParkMessageType(message["type"].as_string());
|
||||
text = language_convert_string(message["text"].as_string());
|
||||
text = message["text"].as_string();
|
||||
if (type == News::ItemType::Blank)
|
||||
{
|
||||
assoc = static_cast<uint32_t>(((COORDS_NULL & 0xFFFF) << 16) | (COORDS_NULL & 0xFFFF));
|
||||
|
|
|
@ -1267,7 +1267,7 @@ std::string OpenRCT2::Scripting::Stringify(const DukValue& val)
|
|||
std::string OpenRCT2::Scripting::ProcessString(const DukValue& value)
|
||||
{
|
||||
if (value.type() == DukValue::Type::STRING)
|
||||
return language_convert_string(value.as_string());
|
||||
return value.as_string();
|
||||
return {};
|
||||
}
|
||||
|
||||
|
|
|
@ -429,17 +429,13 @@ bool title_is_previewing_sequence()
|
|||
|
||||
void DrawOpenRCT2(rct_drawpixelinfo* dpi, const ScreenCoordsXY& screenCoords)
|
||||
{
|
||||
utf8 buffer[256];
|
||||
|
||||
// Write format codes
|
||||
utf8* ch = buffer;
|
||||
ch = utf8_write_codepoint(ch, FORMAT_MEDIUMFONT);
|
||||
ch = utf8_write_codepoint(ch, FORMAT_OUTLINE);
|
||||
ch = utf8_write_codepoint(ch, FORMAT_WHITE);
|
||||
thread_local std::string buffer;
|
||||
buffer.clear();
|
||||
buffer.assign("{MEDIUMFONT}{OUTLINE}{WHITE}");
|
||||
|
||||
// Write name and version information
|
||||
openrct2_write_full_version_info(ch, sizeof(buffer) - (ch - buffer));
|
||||
gfx_draw_string(dpi, buffer, COLOUR_BLACK, screenCoords + ScreenCoordsXY(5, 5 - 13));
|
||||
buffer += gVersionInfoFull;
|
||||
gfx_draw_string(dpi, buffer.c_str(), COLOUR_BLACK, screenCoords + ScreenCoordsXY(5, 5 - 13));
|
||||
|
||||
// Invalidate screen area
|
||||
int16_t width = static_cast<int16_t>(gfx_get_string_width(buffer));
|
||||
|
@ -447,6 +443,9 @@ void DrawOpenRCT2(rct_drawpixelinfo* dpi, const ScreenCoordsXY& screenCoords)
|
|||
{ screenCoords, screenCoords + ScreenCoordsXY{ width, 30 } }); // 30 is an arbitrary height to catch both strings
|
||||
|
||||
// Write platform information
|
||||
snprintf(ch, 256 - (ch - buffer), "%s (%s)", OPENRCT2_PLATFORM, OPENRCT2_ARCHITECTURE);
|
||||
gfx_draw_string(dpi, buffer, COLOUR_BLACK, screenCoords + ScreenCoordsXY(5, 5));
|
||||
buffer.assign(OPENRCT2_PLATFORM);
|
||||
buffer.append(" (");
|
||||
buffer.append(OPENRCT2_ARCHITECTURE);
|
||||
buffer.append(")");
|
||||
gfx_draw_string(dpi, buffer.c_str(), COLOUR_BLACK, screenCoords + ScreenCoordsXY(5, 5));
|
||||
}
|
||||
|
|
|
@ -33,30 +33,6 @@
|
|||
|
||||
static Banner _banners[MAX_BANNERS];
|
||||
|
||||
namespace
|
||||
{
|
||||
template<uint32_t TFrom, uint32_t TTo> struct CodePointToUtf8
|
||||
{
|
||||
constexpr CodePointToUtf8()
|
||||
{
|
||||
for (uint32_t i = TFrom; i <= TTo; ++i)
|
||||
{
|
||||
utf8_write_codepoint(m_colors[i - TFrom], i);
|
||||
}
|
||||
}
|
||||
|
||||
constexpr auto operator()(uint8_t colourId) const
|
||||
{
|
||||
return m_colors[colourId];
|
||||
}
|
||||
|
||||
using Utf8Colour = utf8[5]; // A 32bit codepoint uses at most 4 bytes in utf8
|
||||
Utf8Colour m_colors[TTo - TFrom + 1]{};
|
||||
};
|
||||
} // namespace
|
||||
|
||||
static constexpr CodePointToUtf8<FORMAT_COLOUR_CODE_START, FORMAT_COLOUR_CODE_END> colourToUtf8;
|
||||
|
||||
std::string Banner::GetText() const
|
||||
{
|
||||
Formatter ft;
|
||||
|
@ -68,7 +44,10 @@ void Banner::FormatTextTo(Formatter& ft, bool addColour) const
|
|||
{
|
||||
if (addColour)
|
||||
{
|
||||
ft.Add<rct_string_id>(STR_STRING_STRINGID).Add<const char*>(colourToUtf8(text_colour));
|
||||
auto formatToken = FormatTokenFromTextColour(text_colour);
|
||||
auto tokenText = FormatTokenToString(formatToken);
|
||||
ft.Add<rct_string_id>(STR_STRING_STRINGID);
|
||||
ft.Add<const char*>(tokenText.data());
|
||||
}
|
||||
|
||||
FormatTextTo(ft);
|
||||
|
|
Loading…
Reference in New Issue