diff --git a/src/gamedata/fonts/font.cpp b/src/gamedata/fonts/font.cpp index 480b9a4c4..b3de95197 100644 --- a/src/gamedata/fonts/font.cpp +++ b/src/gamedata/fonts/font.cpp @@ -1107,6 +1107,53 @@ int FFont::StringWidth(const uint8_t *string) const return MAX(maxw, w); } +//========================================================================== +// +// Get the largest ascender in the first line of this text. +// +//========================================================================== + +int FFont::GetMaxAscender(const uint8_t* string) const +{ + int retval = 0; + + while (*string) + { + auto chr = GetCharFromString(string); + if (chr == TEXTCOLOR_ESCAPE) + { + // We do not need to check for UTF-8 in here. + if (*string == '[') + { + while (*string != '\0' && *string != ']') + { + ++string; + } + } + if (*string != '\0') + { + ++string; + } + continue; + } + else if (chr == '\n') + { + break; + } + else + { + auto ctex = GetChar(chr, CR_UNTRANSLATED, nullptr); + if (ctex) + { + auto offs = int(ctex->GetScaledTopOffset(0)); + if (offs > retval) retval = offs; + } + } + } + + return retval; +} + //========================================================================== // // FFont :: LoadTranslations diff --git a/src/gamedata/fonts/v_font.h b/src/gamedata/fonts/v_font.h index 6eff7e009..2c9d1aeb6 100644 --- a/src/gamedata/fonts/v_font.h +++ b/src/gamedata/fonts/v_font.h @@ -103,6 +103,9 @@ public: int GetSpaceWidth () const { return SpaceWidth; } int GetHeight () const { return FontHeight; } int GetDefaultKerning () const { return GlobalKerning; } + int GetMaxAscender(const uint8_t* text) const; + int GetMaxAscender(const char* text) const { return GetMaxAscender((uint8_t*)text); } + int GetMaxAscender(const FString &text) const { return GetMaxAscender((uint8_t*)text.GetChars()); } virtual void LoadTranslations(); FName GetName() const { return FontName; } diff --git a/src/scripting/vmthunks.cpp b/src/scripting/vmthunks.cpp index d2ffc0c73..fbf412890 100644 --- a/src/scripting/vmthunks.cpp +++ b/src/scripting/vmthunks.cpp @@ -2032,6 +2032,19 @@ DEFINE_ACTION_FUNCTION_NATIVE(FFont, StringWidth, StringWidth) ACTION_RETURN_INT(StringWidth(self, str)); } +static int GetMaxAscender(FFont* font, const FString& str) +{ + const char* txt = str[0] == '$' ? GStrings(&str[1]) : str.GetChars(); + return font->GetMaxAscender(txt); +} + +DEFINE_ACTION_FUNCTION_NATIVE(FFont, GetMaxAscender, GetMaxAscender) +{ + PARAM_SELF_STRUCT_PROLOGUE(FFont); + PARAM_STRING(str); + ACTION_RETURN_INT(GetMaxAscender(self, str)); +} + static int CanPrint(FFont *font, const FString &str) { const char *txt = str[0] == '$' ? GStrings(&str[1]) : str.GetChars(); diff --git a/wadsrc/static/zscript/base.zs b/wadsrc/static/zscript/base.zs index 3d343e896..3b52b2730 100644 --- a/wadsrc/static/zscript/base.zs +++ b/wadsrc/static/zscript/base.zs @@ -320,6 +320,7 @@ struct Font native native int GetCharWidth(int code); native int StringWidth(String code); + native int GetMaxAscender(String code); native bool CanPrint(String code); native int GetHeight(); native int GetDisplacement(); diff --git a/wadsrc/static/zscript/ui/statscreen/statscreen.zs b/wadsrc/static/zscript/ui/statscreen/statscreen.zs index 699790308..10160efc2 100644 --- a/wadsrc/static/zscript/ui/statscreen/statscreen.zs +++ b/wadsrc/static/zscript/ui/statscreen/statscreen.zs @@ -149,7 +149,7 @@ class StatusScreen abstract play version("2.5") // //==================================================================== - int, int DrawName(int y, TextureID tex, String levelname) + int DrawName(int y, TextureID tex, String levelname) { // draw if (tex.isValid()) @@ -161,7 +161,7 @@ class StatusScreen abstract play version("2.5") // patches with vast amounts of empty space at the bottom. size.Y = TexMan.CheckRealHeight(tex); } - return y + int(Size.Y), (BigFont.GetHeight() - BigFont.GetDisplacement()) * CleanYfac / 4; + return y + int(Size.Y) * CleanYfac; } else if (levelname.Length() > 0) { @@ -176,9 +176,9 @@ class StatusScreen abstract play version("2.5") screen.DrawText(mapname.mFont, mapname.mColor, (screen.GetWidth() - lines.StringWidth(i) * CleanXfac) / 2, y + h, lines.StringAt(i), DTA_CleanNoMove, true); h += lumph; } - return y + h, (mapname.mFont.GetHeight() - mapname.mFont.GetDisplacement())/4; + return y + h; } - return 0, 0; + return 0; } //==================================================================== @@ -232,17 +232,35 @@ class StatusScreen abstract play version("2.5") virtual int drawLF () { - int y = TITLEY * CleanYfac; + bool ispatch = wbs.LName0.isValid(); + int oldy = TITLEY * CleanYfac; int h; + + if (!ispatch) + { + let asc = mapname.mFont.GetMaxAscender(lnametexts[1]); + if (asc > TITLEY - 2) + { + oldy = (asc+2) * CleanYfac; + } + } + + int y = DrawName(oldy, wbs.LName0, lnametexts[0]); - [y, h] = DrawName(y, wbs.LName0, lnametexts[0]); - - // Adjustment for different font sizes for map name and 'finished'. - let fontspace1 = finished.mFont.GetDisplacement(); - let fontspace2 = ((h + (finished.mFont.GetHeight() - fontspace1)/4)) / 2; - - y += max(0, fontspace2 - fontspace1) * CleanYFac; - + // If the displayed info is made of patches we need some additional offsetting here. + if (ispatch) + { + int h1 = BigFont.GetHeight() - BigFont.GetDisplacement(); + int h2 = (y - oldy) / CleanYfac / 4; + let disp = min(h1, h2); + // The offset getting applied here must at least be as tall as the largest ascender in the following text to avoid overlaps. + if (!TexMan.OkForLocalization(finishedPatch, "$WI_FINISHED")) + { + disp += finished.mFont.GetMaxAscender("$WI_FINISHED"); + } + y += disp * CleanYfac; + } + // draw "Finished!" int statsy = multiplayer? NG_STATSY : SP_STATSY * CleanYFac; @@ -266,19 +284,36 @@ class StatusScreen abstract play version("2.5") virtual void drawEL () { - int y = TITLEY * CleanYfac; + bool ispatch = TexMan.OkForLocalization(enteringPatch, "$WI_ENTERING"); + int oldy = TITLEY * CleanYfac; - y = DrawPatchOrText(y, entering, enteringPatch, "$WI_ENTERING"); - let h = (entering.mFont.GetHeight() - entering.mFont.GetDisplacement()) / 4; - - if (!wbs.LName1.isValid()) + if (!ispatch) { - // Factor out the font's displacement here. - let fontspace1 = mapname.mFont.GetDisplacement(); - let fontspace2 = ((h + (mapname.mFont.GetHeight() - fontspace1)/4)) / 2; - h = max(0, fontspace2 - fontspace1) * CleanYFac; - } - y += h * CleanYFac; + let asc = entering.mFont.GetMaxAscender("$WI_ENTERING"); + if (asc > TITLEY - 2) + { + oldy = (asc+2) * CleanYfac; + } + } + + int y = DrawPatchOrText(oldy, entering, enteringPatch, "$WI_ENTERING"); + + // If the displayed info is made of patches we need some additional offsetting here. + + if (ispatch) + { + int h1 = BigFont.GetHeight() - BigFont.GetDisplacement(); + let size = TexMan.GetScaledSize(enteringPatch); + int h2 = int(size.Y); + let disp = min(h1, h2) / 4; + // The offset getting applied here must at least be as tall as the largest ascender in the following text to avoid overlaps. + if (!wbs.LName1.isValid()) + { + disp += mapname.mFont.GetMaxAscender(lnametexts[1]); + } + y += disp * CleanYfac; + } + DrawName(y, wbs.LName1, lnametexts[1]); }