Browse Source

Implement new font rendering

pull/2731/head
Anders Jenbo 5 years ago
parent
commit
7169882b1f
  1. 1
      CMakeLists.txt
  2. BIN
      Packaging/resources/devilutionx.mpq
  3. 6
      Source/DiabloUI/art.h
  4. 33
      Source/DiabloUI/art_draw.cpp
  5. 2
      Source/DiabloUI/art_draw.h
  6. 40
      Source/DiabloUI/diabloui.cpp
  7. 41
      Source/DiabloUI/fonts.cpp
  8. 17
      Source/DiabloUI/fonts.h
  9. 4
      Source/DiabloUI/mainmenu.cpp
  10. 23
      Source/DiabloUI/selconn.cpp
  11. 71
      Source/DiabloUI/selgame.cpp
  12. 66
      Source/DiabloUI/selhero.cpp
  13. 14
      Source/DiabloUI/selok.cpp
  14. 11
      Source/DiabloUI/selyesno.cpp
  15. 57
      Source/DiabloUI/text.cpp
  16. 12
      Source/DiabloUI/text.h
  17. 34
      Source/DiabloUI/text_draw.cpp
  18. 2
      Source/DiabloUI/text_draw.h
  19. 4
      Source/DiabloUI/title.cpp
  20. 69
      Source/DiabloUI/ui_item.h
  21. 2
      Source/automap.cpp
  22. 2
      Source/capture.cpp
  23. 51
      Source/control.cpp
  24. 2
      Source/controls/modifier_hints.cpp
  25. 16
      Source/diablo.cpp
  26. 266
      Source/engine/render/text_render.cpp
  27. 33
      Source/engine/render/text_render.hpp
  28. 14
      Source/engine/size.hpp
  29. 4
      Source/error.cpp
  30. 20
      Source/gmenu.cpp
  31. 6
      Source/help.cpp
  32. 2
      Source/inv.cpp
  33. 4
      Source/items.cpp
  34. 6
      Source/minitext.cpp
  35. 12
      Source/palette.cpp
  36. 2
      Source/palette.h
  37. 240
      Source/panels/charpanel.cpp
  38. 2
      Source/panels/charpanel.hpp
  39. 4
      Source/plrmsg.cpp
  40. 8
      Source/qol/itemlabels.cpp
  41. 14
      Source/qol/monhealthbar.cpp
  42. 9
      Source/quests.cpp
  43. 30
      Source/scrollrt.cpp
  44. 8
      Source/stores.cpp

1
CMakeLists.txt

@ -441,7 +441,6 @@ set(libdevilutionx_SRCS
Source/DiabloUI/selok.cpp
Source/DiabloUI/selyesno.cpp
Source/DiabloUI/support_lines.cpp
Source/DiabloUI/text.cpp
Source/DiabloUI/text_draw.cpp
Source/DiabloUI/title.cpp
Source/DiabloUI/ttf_render_wrapped.cpp

BIN
Packaging/resources/devilutionx.mpq

Binary file not shown.

6
Source/DiabloUI/art.h

@ -36,6 +36,12 @@ struct Art {
{
surface = nullptr;
}
~Art()
{
if (surface != nullptr)
Unload();
}
};
void LoadArt(const char *pszFile, Art *art, int frames = 1, SDL_Color *pPalette = nullptr, const std::array<uint8_t, 256> *colorMapping = nullptr);

33
Source/DiabloUI/art_draw.cpp

@ -3,9 +3,27 @@
#include "DiabloUI/diabloui.h"
#include "utils/display.h"
#include "utils/sdl_compat.h"
#include "palette.h"
namespace devilution {
void UpdatePalette(Art *art, const SDL_Surface *output)
{
if (art->surface->format->BitsPerPixel != 8)
return;
if (art->palette_version == pal_surface_palette_version)
return;
if (output == nullptr || output->format->BitsPerPixel != 8)
output = pal_surface;
if (SDLC_SetSurfaceColors(art->surface.get(), output->format->palette) <= -1)
ErrSdl();
art->palette_version = pal_surface_palette_version;
}
void DrawArt(Point screenPosition, Art *art, int nFrame, Uint16 srcW, Uint16 srcH)
{
if (screenPosition.y >= gnScreenHeight || screenPosition.x >= gnScreenWidth || art->surface == nullptr)
@ -26,11 +44,7 @@ void DrawArt(Point screenPosition, Art *art, int nFrame, Uint16 srcW, Uint16 src
SDL_Rect dstRect = MakeSdlRect(screenPosition.x, screenPosition.y, srcRect.w, srcRect.h);
ScaleOutputRect(&dstRect);
if (art->surface->format->BitsPerPixel == 8 && art->palette_version != pal_surface_palette_version) {
if (SDLC_SetSurfaceColors(art->surface.get(), pal_surface->format->palette) <= -1)
ErrSdl();
art->palette_version = pal_surface_palette_version;
}
UpdatePalette(art);
if (SDL_BlitSurface(art->surface.get(), &srcRect, DiabloUiSurface(), &dstRect) < 0)
ErrSdl();
@ -51,13 +65,10 @@ void DrawArt(const Surface &out, Point screenPosition, Art *art, int nFrame, Uin
srcRect.w = srcW;
if (srcH != 0 && srcH < srcRect.h)
srcRect.h = srcH;
SDL_Rect dstRect = MakeSdlRect(screenPosition.x, screenPosition.y, srcRect.w, srcRect.h);
out.Clip(&srcRect, &screenPosition);
SDL_Rect dstRect { screenPosition.x + out.region.x, screenPosition.y + out.region.y, 0, 0 };
if (art->surface->format->BitsPerPixel == 8 && art->palette_version != pal_surface_palette_version) {
if (SDLC_SetSurfaceColors(art->surface.get(), out.surface->format->palette) <= -1)
ErrSdl();
art->palette_version = pal_surface_palette_version;
}
UpdatePalette(art, out.surface);
if (SDL_BlitSurface(art->surface.get(), &srcRect, out.surface, &dstRect) < 0)
ErrSdl();

2
Source/DiabloUI/art_draw.h

@ -5,6 +5,8 @@
namespace devilution {
void UpdatePalette(Art *art, const SDL_Surface *output = nullptr);
void DrawArt(Point screenPosition, Art *art, int nFrame = 0, Uint16 srcW = 0, Uint16 srcH = 0);
void DrawArt(const Surface &out, Point screenPosition, Art *art, int nFrame = 0, Uint16 srcW = 0, Uint16 srcH = 0);

40
Source/DiabloUI/diabloui.cpp

@ -12,6 +12,7 @@
#include "controls/controller.h"
#include "controls/menu_controls.h"
#include "dx.h"
#include "engine/render/text_render.hpp"
#include "hwcursor.hpp"
#include "palette.h"
#include "storm/storm.h"
@ -21,6 +22,7 @@
#include "utils/sdl_wrap.h"
#include "utils/stubs.h"
#include "utils/utf8.h"
#include "utils/language.h"
#ifdef __SWITCH__
// for virtual keyboard on Switch
@ -541,7 +543,15 @@ void UnloadUiGFX()
void UiInitialize()
{
LoadUiGFX();
LoadArtFonts();
LoadFont(GameFont12, ColorSilver, "fonts\\grayui.trn");
LoadFont(GameFont12, ColorGold, "fonts\\goldui.trn");
LoadFont(GameFont24, ColorSilver, "fonts\\grayui.trn");
LoadFont(GameFont24, ColorGold, "fonts\\goldui.trn");
LoadFont(GameFont30, ColorSilver, "fonts\\grayui.trn");
LoadFont(GameFont30, ColorGold, "fonts\\goldui.trn");
LoadFont(GameFont42, ColorGold, "fonts\\goldui.trn");
if (ArtCursor.surface != nullptr) {
if (SDL_ShowCursor(SDL_DISABLE) <= -1) {
ErrSdl();
@ -552,7 +562,7 @@ void UiInitialize()
void UiDestroy()
{
UnloadTtfFont();
UnloadArtFonts();
UnloadFonts();
UnloadUiGFX();
}
@ -726,7 +736,10 @@ void Render(UiText *uiText)
void Render(const UiArtText *uiArtText)
{
DrawArtStr(uiArtText->text(), uiArtText->m_rect, uiArtText->m_iFlags);
Rectangle rect { { uiArtText->m_rect.x, uiArtText->m_rect.y }, { uiArtText->m_rect.w, uiArtText->m_rect.h } };
const Surface &out = Surface(DiabloUiSurface());
DrawString(out, uiArtText->text(), rect, uiArtText->m_iFlags, uiArtText->spacing(), uiArtText->lineHeight());
}
void Render(const UiImage *uiImage)
@ -745,17 +758,24 @@ void Render(const UiImage *uiImage)
void Render(const UiArtTextButton *uiButton)
{
DrawArtStr(uiButton->m_text, uiButton->m_rect, uiButton->m_iFlags);
Rectangle rect { { uiButton->m_rect.x, uiButton->m_rect.y }, { uiButton->m_rect.w, uiButton->m_rect.h } };
const Surface &out = Surface(DiabloUiSurface());
DrawString(out, uiButton->m_text, rect, uiButton->m_iFlags);
}
void Render(const UiList *uiList)
{
const Surface &out = Surface(DiabloUiSurface());
for (std::size_t i = 0; i < uiList->m_vecItems.size(); ++i) {
SDL_Rect rect = uiList->itemRect(i);
const UiListItem *item = uiList->GetItem(i);
if (i + (ListOffset == nullptr ? 0 : *ListOffset) == SelectedItem)
DrawSelector(rect);
DrawArtStr(item->m_text, rect, uiList->m_iFlags);
Rectangle rectangle { { rect.x, rect.y }, { rect.w, rect.h } };
DrawString(out, item->m_text, rectangle, uiList->m_iFlags, uiList->spacing());
}
}
@ -794,11 +814,11 @@ void Render(const UiScrollbar *uiSb)
void Render(const UiEdit *uiEdit)
{
DrawSelector(uiEdit->m_rect);
SDL_Rect rect = uiEdit->m_rect;
rect.x += 43;
rect.y += 1;
rect.w -= 86;
DrawArtStr(uiEdit->m_value, rect, uiEdit->m_iFlags, /*drawTextCursor=*/true);
Rectangle rect { { uiEdit->m_rect.x + 43, uiEdit->m_rect.y + 1 }, { uiEdit->m_rect.w - 86, uiEdit->m_rect.h } };
const Surface &out = Surface(DiabloUiSurface());
DrawString(out, uiEdit->m_value, rect, uiEdit->m_iFlags | UiFlags::TextCursor);
}
void RenderItem(UiItemBase *item)

41
Source/DiabloUI/fonts.cpp

@ -9,50 +9,9 @@
namespace devilution {
TTF_Font *font = nullptr;
std::unique_ptr<uint8_t[]> FontTables[4];
Art ArtFonts[4][2];
/** This is so we know ttf has been init when we get to the diablo_deinit() function */
bool was_fonts_init = false;
namespace {
void LoadArtFont(const char *pszFile, int size, int color)
{
LoadMaskedArt(pszFile, &ArtFonts[size][color], 256, 32);
}
} // namespace
void LoadArtFonts()
{
FontTables[AFT_SMALL] = LoadFileInMem<uint8_t>("ui_art\\font16.bin");
FontTables[AFT_MED] = LoadFileInMem<uint8_t>("ui_art\\font24.bin");
FontTables[AFT_BIG] = LoadFileInMem<uint8_t>("ui_art\\font30.bin");
FontTables[AFT_HUGE] = LoadFileInMem<uint8_t>("ui_art\\font42.bin");
LoadArtFont("ui_art\\font16s.pcx", AFT_SMALL, AFC_SILVER);
LoadArtFont("ui_art\\font16g.pcx", AFT_SMALL, AFC_GOLD);
LoadArtFont("ui_art\\font24s.pcx", AFT_MED, AFC_SILVER);
LoadArtFont("ui_art\\font24g.pcx", AFT_MED, AFC_GOLD);
LoadArtFont("ui_art\\font30s.pcx", AFT_BIG, AFC_SILVER);
LoadArtFont("ui_art\\font30g.pcx", AFT_BIG, AFC_GOLD);
LoadArtFont("ui_art\\font42g.pcx", AFT_HUGE, AFC_GOLD);
}
void UnloadArtFonts()
{
ArtFonts[AFT_SMALL][AFC_SILVER].Unload();
ArtFonts[AFT_SMALL][AFC_GOLD].Unload();
ArtFonts[AFT_MED][AFC_SILVER].Unload();
ArtFonts[AFT_MED][AFC_GOLD].Unload();
ArtFonts[AFT_BIG][AFC_SILVER].Unload();
ArtFonts[AFT_BIG][AFC_GOLD].Unload();
ArtFonts[AFT_HUGE][AFC_GOLD].Unload();
FontTables[AFT_SMALL] = nullptr;
FontTables[AFT_MED] = nullptr;
FontTables[AFT_BIG] = nullptr;
FontTables[AFT_HUGE] = nullptr;
}
void LoadTtfFont()
{
if (TTF_WasInit() == 0) {

17
Source/DiabloUI/fonts.h

@ -9,24 +9,7 @@
namespace devilution {
enum _artFontTables : uint8_t {
AFT_SMALL,
AFT_MED,
AFT_BIG,
AFT_HUGE,
};
enum _artFontColors : uint8_t {
AFC_SILVER,
AFC_GOLD,
};
extern TTF_Font *font;
extern std::unique_ptr<uint8_t[]> FontTables[4];
extern Art ArtFonts[4][2];
void LoadArtFonts();
void UnloadArtFonts();
void LoadTtfFont();
void UnloadTtfFont();

4
Source/DiabloUI/mainmenu.cpp

@ -51,10 +51,10 @@ void MainmenuLoad(const char *name, void (*fnSound)(const char *file))
UiAddBackground(&vecMainMenuDialog);
UiAddLogo(&vecMainMenuDialog);
vecMainMenuDialog.push_back(std::make_unique<UiList>(vecMenuItems, PANEL_LEFT + 64, (UI_OFFSET_Y + 192), 510, 43, UiFlags::FontHuge | UiFlags::ColorGold | UiFlags::AlignCenter));
vecMainMenuDialog.push_back(std::make_unique<UiList>(vecMenuItems, PANEL_LEFT + 64, (UI_OFFSET_Y + 192), 510, 43, UiFlags::FontSize42 | UiFlags::ColorGold | UiFlags::AlignCenter, 5));
SDL_Rect rect = { 17, (Sint16)(gnScreenHeight - 36), 605, 21 };
vecMainMenuDialog.push_back(std::make_unique<UiArtText>(name, rect, UiFlags::FontSmall));
vecMainMenuDialog.push_back(std::make_unique<UiArtText>(name, rect, UiFlags::FontSize12 | UiFlags::ColorSilver));
UiInitList(vecMenuItems.size(), nullptr, UiMainMenuSelect, MainmenuEsc, vecMainMenuDialog, true);
}

23
Source/DiabloUI/selconn.cpp

@ -1,7 +1,6 @@
#include <fmt/format.h>
#include "DiabloUI/diabloui.h"
#include "DiabloUI/text.h"
#include "stores.h"
#include "storm/storm.h"
#include "utils/language.h"
@ -45,36 +44,36 @@ void SelconnLoad()
UiAddLogo(&vecSelConnDlg);
SDL_Rect rect1 = { (Sint16)(PANEL_LEFT + 24), (Sint16)(Sint16)(UI_OFFSET_Y + 161), 590, 35 };
vecSelConnDlg.push_back(std::make_unique<UiArtText>(_("Multi Player Game"), rect1, UiFlags::AlignCenter | UiFlags::FontBig));
vecSelConnDlg.push_back(std::make_unique<UiArtText>(_("Multi Player Game"), rect1, UiFlags::AlignCenter | UiFlags::FontSize30 | UiFlags::ColorSilver, 3));
SDL_Rect rect2 = { (Sint16)(PANEL_LEFT + 35), (Sint16)(UI_OFFSET_Y + 218), DESCRIPTION_WIDTH, 21 };
vecSelConnDlg.push_back(std::make_unique<UiArtText>(selconn_MaxPlayers, rect2));
vecSelConnDlg.push_back(std::make_unique<UiArtText>(selconn_MaxPlayers, rect2, UiFlags::FontSize12 | UiFlags::ColorSilver));
SDL_Rect rect3 = { (Sint16)(PANEL_LEFT + 35), (Sint16)(UI_OFFSET_Y + 256), DESCRIPTION_WIDTH, 21 };
vecSelConnDlg.push_back(std::make_unique<UiArtText>(_("Requirements:"), rect3));
vecSelConnDlg.push_back(std::make_unique<UiArtText>(_("Requirements:"), rect3, UiFlags::FontSize12 | UiFlags::ColorSilver));
SDL_Rect rect4 = { (Sint16)(PANEL_LEFT + 35), (Sint16)(UI_OFFSET_Y + 275), DESCRIPTION_WIDTH, 66 };
vecSelConnDlg.push_back(std::make_unique<UiArtText>(selconn_Description, rect4));
vecSelConnDlg.push_back(std::make_unique<UiArtText>(selconn_Description, rect4, UiFlags::FontSize12 | UiFlags::ColorSilver, 1, 16));
SDL_Rect rect5 = { (Sint16)(PANEL_LEFT + 30), (Sint16)(UI_OFFSET_Y + 356), 220, 31 };
vecSelConnDlg.push_back(std::make_unique<UiArtText>(_("no gateway needed"), rect5, UiFlags::AlignCenter | UiFlags::FontMedium));
vecSelConnDlg.push_back(std::make_unique<UiArtText>(_("no gateway needed"), rect5, UiFlags::AlignCenter | UiFlags::FontSize24 | UiFlags::ColorSilver, 0));
SDL_Rect rect6 = { (Sint16)(PANEL_LEFT + 35), (Sint16)(UI_OFFSET_Y + 393), DESCRIPTION_WIDTH, 21 };
vecSelConnDlg.push_back(std::make_unique<UiArtText>(selconn_Gateway, rect6, UiFlags::AlignCenter));
vecSelConnDlg.push_back(std::make_unique<UiArtText>(selconn_Gateway, rect6, UiFlags::AlignCenter | UiFlags::FontSize12 | UiFlags::ColorSilver));
SDL_Rect rect7 = { (Sint16)(PANEL_LEFT + 300), (Sint16)(UI_OFFSET_Y + 211), 295, 33 };
vecSelConnDlg.push_back(std::make_unique<UiArtText>(_("Select Connection"), rect7, UiFlags::AlignCenter | UiFlags::FontBig));
vecSelConnDlg.push_back(std::make_unique<UiArtText>(_("Select Connection"), rect7, UiFlags::AlignCenter | UiFlags::FontSize30 | UiFlags::ColorSilver, 3));
SDL_Rect rect8 = { (Sint16)(PANEL_LEFT + 16), (Sint16)(UI_OFFSET_Y + 427), 250, 35 };
vecSelConnDlg.push_back(std::make_unique<UiArtTextButton>(_("Change Gateway"), nullptr, rect8, UiFlags::AlignCenter | UiFlags::VerticalCenter | UiFlags::FontBig | UiFlags::ColorGold | UiFlags::ElementHidden));
vecSelConnDlg.push_back(std::make_unique<UiArtTextButton>(_("Change Gateway"), nullptr, rect8, UiFlags::AlignCenter | UiFlags::VerticalCenter | UiFlags::FontSize30 | UiFlags::ColorGold | UiFlags::ElementHidden));
vecSelConnDlg.push_back(std::make_unique<UiList>(vecConnItems, PANEL_LEFT + 305, (UI_OFFSET_Y + 256), 285, 26, UiFlags::AlignCenter | UiFlags::VerticalCenter | UiFlags::ColorGold));
SDL_Rect rect9 = { (Sint16)(PANEL_LEFT + 299), (Sint16)(UI_OFFSET_Y + 427), 140, 35 };
vecSelConnDlg.push_back(std::make_unique<UiArtTextButton>(_("OK"), &UiFocusNavigationSelect, rect9, UiFlags::AlignCenter | UiFlags::VerticalCenter | UiFlags::FontBig | UiFlags::ColorGold));
vecSelConnDlg.push_back(std::make_unique<UiArtTextButton>(_("OK"), &UiFocusNavigationSelect, rect9, UiFlags::AlignCenter | UiFlags::VerticalCenter | UiFlags::FontSize30 | UiFlags::ColorGold));
SDL_Rect rect10 = { (Sint16)(PANEL_LEFT + 454), (Sint16)(UI_OFFSET_Y + 427), 140, 35 };
vecSelConnDlg.push_back(std::make_unique<UiArtTextButton>(_("Cancel"), &UiFocusNavigationEsc, rect10, UiFlags::AlignCenter | UiFlags::VerticalCenter | UiFlags::FontBig | UiFlags::ColorGold));
vecSelConnDlg.push_back(std::make_unique<UiArtTextButton>(_("Cancel"), &UiFocusNavigationEsc, rect10, UiFlags::AlignCenter | UiFlags::VerticalCenter | UiFlags::FontSize30 | UiFlags::ColorGold));
UiInitList(vecConnItems.size(), SelconnFocus, SelconnSelect, SelconnEsc, vecSelConnDlg, true);
}
@ -113,7 +112,7 @@ void SelconnFocus(int value)
}
strncpy(selconn_MaxPlayers, fmt::format(_("Players Supported: {:d}"), players).c_str(), sizeof(selconn_MaxPlayers));
WordWrapArtStr(selconn_Description, DESCRIPTION_WIDTH);
WordWrapString(selconn_Description, DESCRIPTION_WIDTH);
}
void SelconnSelect(int value)

71
Source/DiabloUI/selgame.cpp

@ -6,7 +6,6 @@
#include "DiabloUI/dialogs.h"
#include "DiabloUI/selhero.h"
#include "DiabloUI/selok.h"
#include "DiabloUI/text.h"
#include "config.h"
#include "control.h"
#include "menu.h"
@ -75,27 +74,27 @@ void selgame_GameSelection_Init()
UiAddLogo(&vecSelGameDialog);
SDL_Rect rect1 = { (Sint16)(PANEL_LEFT + 24), (Sint16)(UI_OFFSET_Y + 161), 590, 35 };
vecSelGameDialog.push_back(std::make_unique<UiArtText>(_("Client-Server (TCP)"), rect1, UiFlags::AlignCenter | UiFlags::FontBig));
vecSelGameDialog.push_back(std::make_unique<UiArtText>(_("Client-Server (TCP)"), rect1, UiFlags::AlignCenter | UiFlags::FontSize30 | UiFlags::ColorSilver, 3));
SDL_Rect rect2 = { (Sint16)(PANEL_LEFT + 35), (Sint16)(UI_OFFSET_Y + 211), 205, 192 };
vecSelGameDialog.push_back(std::make_unique<UiArtText>(_("Description:"), rect2, UiFlags::FontMedium));
vecSelGameDialog.push_back(std::make_unique<UiArtText>(_("Description:"), rect2, UiFlags::FontSize24 | UiFlags::ColorSilver));
SDL_Rect rect3 = { (Sint16)(PANEL_LEFT + 35), (Sint16)(UI_OFFSET_Y + 256), DESCRIPTION_WIDTH, 192 };
vecSelGameDialog.push_back(std::make_unique<UiArtText>(selgame_Description, rect3));
vecSelGameDialog.push_back(std::make_unique<UiArtText>(selgame_Description, rect3, UiFlags::FontSize12 | UiFlags::ColorSilver, 1, 16));
SDL_Rect rect4 = { (Sint16)(PANEL_LEFT + 300), (Sint16)(UI_OFFSET_Y + 211), 295, 33 };
vecSelGameDialog.push_back(std::make_unique<UiArtText>(_("Select Action"), rect4, UiFlags::AlignCenter | UiFlags::FontBig));
vecSelGameDialog.push_back(std::make_unique<UiArtText>(_("Select Action"), rect4, UiFlags::AlignCenter | UiFlags::FontSize30 | UiFlags::ColorSilver, 3));
vecSelGameDlgItems.push_back(std::make_unique<UiListItem>(_("Create Game"), 0));
vecSelGameDlgItems.push_back(std::make_unique<UiListItem>(_("Join Game"), 1));
vecSelGameDialog.push_back(std::make_unique<UiList>(vecSelGameDlgItems, PANEL_LEFT + 305, (UI_OFFSET_Y + 255), 285, 26, UiFlags::AlignCenter | UiFlags::FontMedium | UiFlags::ColorGold));
vecSelGameDialog.push_back(std::make_unique<UiList>(vecSelGameDlgItems, PANEL_LEFT + 305, (UI_OFFSET_Y + 255), 285, 26, UiFlags::AlignCenter | UiFlags::FontSize24 | UiFlags::ColorGold));
SDL_Rect rect5 = { (Sint16)(PANEL_LEFT + 299), (Sint16)(UI_OFFSET_Y + 427), 140, 35 };
vecSelGameDialog.push_back(std::make_unique<UiArtTextButton>(_("OK"), &UiFocusNavigationSelect, rect5, UiFlags::AlignCenter | UiFlags::VerticalCenter | UiFlags::FontBig | UiFlags::ColorGold));
vecSelGameDialog.push_back(std::make_unique<UiArtTextButton>(_("OK"), &UiFocusNavigationSelect, rect5, UiFlags::AlignCenter | UiFlags::VerticalCenter | UiFlags::FontSize30 | UiFlags::ColorGold));
SDL_Rect rect6 = { (Sint16)(PANEL_LEFT + 449), (Sint16)(UI_OFFSET_Y + 427), 140, 35 };
vecSelGameDialog.push_back(std::make_unique<UiArtTextButton>(_("CANCEL"), &UiFocusNavigationEsc, rect6, UiFlags::AlignCenter | UiFlags::VerticalCenter | UiFlags::FontBig | UiFlags::ColorGold));
vecSelGameDialog.push_back(std::make_unique<UiArtTextButton>(_("CANCEL"), &UiFocusNavigationEsc, rect6, UiFlags::AlignCenter | UiFlags::VerticalCenter | UiFlags::FontSize30 | UiFlags::ColorGold));
UiInitList(vecSelGameDlgItems.size(), selgame_GameSelection_Focus, selgame_GameSelection_Select, selgame_GameSelection_Esc, vecSelGameDialog, true);
}
@ -110,7 +109,7 @@ void selgame_GameSelection_Focus(int value)
strncpy(selgame_Description, _("Enter an IP or a hostname and join a game already in progress at that address."), sizeof(selgame_Description) - 1);
break;
}
WordWrapArtStr(selgame_Description, DESCRIPTION_WIDTH);
WordWrapString(selgame_Description, DESCRIPTION_WIDTH);
}
/**
@ -139,32 +138,32 @@ void selgame_GameSelection_Select(int value)
UiAddLogo(&vecSelGameDialog);
SDL_Rect rect1 = { (Sint16)(PANEL_LEFT + 24), (Sint16)(UI_OFFSET_Y + 161), 590, 35 };
vecSelGameDialog.push_back(std::make_unique<UiArtText>(&title, rect1, UiFlags::AlignCenter | UiFlags::FontBig));
vecSelGameDialog.push_back(std::make_unique<UiArtText>(&title, rect1, UiFlags::AlignCenter | UiFlags::FontSize30 | UiFlags::ColorSilver, 3));
SDL_Rect rect2 = { (Sint16)(PANEL_LEFT + 34), (Sint16)(UI_OFFSET_Y + 211), 205, 33 };
vecSelGameDialog.push_back(std::make_unique<UiArtText>(selgame_Label, rect2, UiFlags::AlignCenter | UiFlags::FontBig));
vecSelGameDialog.push_back(std::make_unique<UiArtText>(selgame_Label, rect2, UiFlags::AlignCenter | UiFlags::FontSize30 | UiFlags::ColorSilver, 3));
SDL_Rect rect3 = { (Sint16)(PANEL_LEFT + 35), (Sint16)(UI_OFFSET_Y + 256), DESCRIPTION_WIDTH, 192 };
vecSelGameDialog.push_back(std::make_unique<UiArtText>(selgame_Description, rect3));
vecSelGameDialog.push_back(std::make_unique<UiArtText>(selgame_Description, rect3, UiFlags::FontSize12 | UiFlags::ColorSilver, 1, 16));
switch (value) {
case 0: {
title = _("Create Game");
SDL_Rect rect4 = { (Sint16)(PANEL_LEFT + 299), (Sint16)(UI_OFFSET_Y + 211), 295, 35 };
vecSelGameDialog.push_back(std::make_unique<UiArtText>(_("Select Difficulty"), rect4, UiFlags::AlignCenter | UiFlags::FontBig));
vecSelGameDialog.push_back(std::make_unique<UiArtText>(_("Select Difficulty"), rect4, UiFlags::AlignCenter | UiFlags::FontSize30 | UiFlags::ColorSilver, 3));
vecSelGameDlgItems.push_back(std::make_unique<UiListItem>(_("Normal"), DIFF_NORMAL));
vecSelGameDlgItems.push_back(std::make_unique<UiListItem>(_("Nightmare"), DIFF_NIGHTMARE));
vecSelGameDlgItems.push_back(std::make_unique<UiListItem>(_("Hell"), DIFF_HELL));
vecSelGameDialog.push_back(std::make_unique<UiList>(vecSelGameDlgItems, PANEL_LEFT + 300, (UI_OFFSET_Y + 282), 295, 26, UiFlags::AlignCenter | UiFlags::FontMedium | UiFlags::ColorGold));
vecSelGameDialog.push_back(std::make_unique<UiList>(vecSelGameDlgItems, PANEL_LEFT + 300, (UI_OFFSET_Y + 282), 295, 26, UiFlags::AlignCenter | UiFlags::FontSize24 | UiFlags::ColorGold));
SDL_Rect rect5 = { (Sint16)(PANEL_LEFT + 299), (Sint16)(UI_OFFSET_Y + 427), 140, 35 };
vecSelGameDialog.push_back(std::make_unique<UiArtTextButton>(_("OK"), &UiFocusNavigationSelect, rect5, UiFlags::AlignCenter | UiFlags::VerticalCenter | UiFlags::FontBig | UiFlags::ColorGold));
vecSelGameDialog.push_back(std::make_unique<UiArtTextButton>(_("OK"), &UiFocusNavigationSelect, rect5, UiFlags::AlignCenter | UiFlags::VerticalCenter | UiFlags::FontSize30 | UiFlags::ColorGold));
SDL_Rect rect6 = { (Sint16)(PANEL_LEFT + 449), (Sint16)(UI_OFFSET_Y + 427), 140, 35 };
vecSelGameDialog.push_back(std::make_unique<UiArtTextButton>(_("CANCEL"), &UiFocusNavigationEsc, rect6, UiFlags::AlignCenter | UiFlags::VerticalCenter | UiFlags::FontBig | UiFlags::ColorGold));
vecSelGameDialog.push_back(std::make_unique<UiArtTextButton>(_("CANCEL"), &UiFocusNavigationEsc, rect6, UiFlags::AlignCenter | UiFlags::VerticalCenter | UiFlags::FontSize30 | UiFlags::ColorGold));
UiInitList(vecSelGameDlgItems.size(), selgame_Diff_Focus, selgame_Diff_Select, selgame_Diff_Esc, vecSelGameDialog, true);
break;
@ -173,16 +172,16 @@ void selgame_GameSelection_Select(int value)
title = _("Join TCP Games");
SDL_Rect rect4 = { (Sint16)(PANEL_LEFT + 305), (Sint16)(UI_OFFSET_Y + 211), 285, 33 };
vecSelGameDialog.push_back(std::make_unique<UiArtText>(_("Enter address"), rect4, UiFlags::AlignCenter | UiFlags::FontBig));
vecSelGameDialog.push_back(std::make_unique<UiArtText>(_("Enter address"), rect4, UiFlags::AlignCenter | UiFlags::FontSize30 | UiFlags::ColorSilver, 3));
SDL_Rect rect5 = { (Sint16)(PANEL_LEFT + 305), (Sint16)(UI_OFFSET_Y + 314), 285, 33 };
vecSelGameDialog.push_back(std::make_unique<UiEdit>(_("Enter address"), selgame_Ip, 128, rect5, UiFlags::FontMedium | UiFlags::ColorGold));
vecSelGameDialog.push_back(std::make_unique<UiEdit>(_("Enter address"), selgame_Ip, 128, rect5, UiFlags::FontSize24 | UiFlags::ColorGold));
SDL_Rect rect6 = { (Sint16)(PANEL_LEFT + 299), (Sint16)(UI_OFFSET_Y + 427), 140, 35 };
vecSelGameDialog.push_back(std::make_unique<UiArtTextButton>(_("OK"), &UiFocusNavigationSelect, rect6, UiFlags::AlignCenter | UiFlags::VerticalCenter | UiFlags::FontBig | UiFlags::ColorGold));
vecSelGameDialog.push_back(std::make_unique<UiArtTextButton>(_("OK"), &UiFocusNavigationSelect, rect6, UiFlags::AlignCenter | UiFlags::VerticalCenter | UiFlags::FontSize30 | UiFlags::ColorGold));
SDL_Rect rect7 = { (Sint16)(PANEL_LEFT + 449), (Sint16)(UI_OFFSET_Y + 427), 140, 35 };
vecSelGameDialog.push_back(std::make_unique<UiArtTextButton>(_("CANCEL"), &UiFocusNavigationEsc, rect7, UiFlags::AlignCenter | UiFlags::VerticalCenter | UiFlags::FontBig | UiFlags::ColorGold));
vecSelGameDialog.push_back(std::make_unique<UiArtTextButton>(_("CANCEL"), &UiFocusNavigationEsc, rect7, UiFlags::AlignCenter | UiFlags::VerticalCenter | UiFlags::FontSize30 | UiFlags::ColorGold));
UiInitList(0, nullptr, selgame_Password_Init, selgame_GameSelection_Init, vecSelGameDialog);
break;
@ -213,7 +212,7 @@ void selgame_Diff_Focus(int value)
strncpy(selgame_Description, _("Hell Difficulty\nThe most powerful of the underworld's creatures lurk at the gateway into Hell. Only the most experienced characters should venture in this realm."), sizeof(selgame_Description) - 1);
break;
}
WordWrapArtStr(selgame_Description, DESCRIPTION_WIDTH);
WordWrapString(selgame_Description, DESCRIPTION_WIDTH);
}
bool IsDifficultyAllowed(int value)
@ -293,29 +292,29 @@ void selgame_GameSpeedSelection()
UiAddLogo(&vecSelGameDialog);
SDL_Rect rect1 = { (Sint16)(PANEL_LEFT + 24), (Sint16)(UI_OFFSET_Y + 161), 590, 35 };
vecSelGameDialog.push_back(std::make_unique<UiArtText>(_("Create Game"), rect1, UiFlags::AlignCenter | UiFlags::FontBig));
vecSelGameDialog.push_back(std::make_unique<UiArtText>(_("Create Game"), rect1, UiFlags::AlignCenter | UiFlags::FontSize30 | UiFlags::ColorSilver, 3));
SDL_Rect rect2 = { (Sint16)(PANEL_LEFT + 34), (Sint16)(UI_OFFSET_Y + 211), 205, 33 };
vecSelGameDialog.push_back(std::make_unique<UiArtText>(selgame_Label, rect2, UiFlags::AlignCenter | UiFlags::FontBig));
vecSelGameDialog.push_back(std::make_unique<UiArtText>(selgame_Label, rect2, UiFlags::AlignCenter | UiFlags::FontSize30 | UiFlags::ColorSilver, 3));
SDL_Rect rect3 = { (Sint16)(PANEL_LEFT + 35), (Sint16)(UI_OFFSET_Y + 256), DESCRIPTION_WIDTH, 192 };
vecSelGameDialog.push_back(std::make_unique<UiArtText>(selgame_Description, rect3));
vecSelGameDialog.push_back(std::make_unique<UiArtText>(selgame_Description, rect3, UiFlags::FontSize12 | UiFlags::ColorSilver, 1, 16));
SDL_Rect rect4 = { (Sint16)(PANEL_LEFT + 299), (Sint16)(UI_OFFSET_Y + 211), 295, 35 };
vecSelGameDialog.push_back(std::make_unique<UiArtText>(_("Select Game Speed"), rect4, UiFlags::AlignCenter | UiFlags::FontBig));
vecSelGameDialog.push_back(std::make_unique<UiArtText>(_("Select Game Speed"), rect4, UiFlags::AlignCenter | UiFlags::FontSize30 | UiFlags::ColorSilver, 3));
vecSelGameDlgItems.push_back(std::make_unique<UiListItem>(_("Normal"), 20));
vecSelGameDlgItems.push_back(std::make_unique<UiListItem>(_("Fast"), 30));
vecSelGameDlgItems.push_back(std::make_unique<UiListItem>(_("Faster"), 40));
vecSelGameDlgItems.push_back(std::make_unique<UiListItem>(_("Fastest"), 50));
vecSelGameDialog.push_back(std::make_unique<UiList>(vecSelGameDlgItems, PANEL_LEFT + 300, (UI_OFFSET_Y + 279), 295, 26, UiFlags::AlignCenter | UiFlags::FontMedium | UiFlags::ColorGold));
vecSelGameDialog.push_back(std::make_unique<UiList>(vecSelGameDlgItems, PANEL_LEFT + 300, (UI_OFFSET_Y + 279), 295, 26, UiFlags::AlignCenter | UiFlags::FontSize24 | UiFlags::ColorGold));
SDL_Rect rect5 = { (Sint16)(PANEL_LEFT + 299), (Sint16)(UI_OFFSET_Y + 427), 140, 35 };
vecSelGameDialog.push_back(std::make_unique<UiArtTextButton>(_("OK"), &UiFocusNavigationSelect, rect5, UiFlags::AlignCenter | UiFlags::VerticalCenter | UiFlags::FontBig | UiFlags::ColorGold));
vecSelGameDialog.push_back(std::make_unique<UiArtTextButton>(_("OK"), &UiFocusNavigationSelect, rect5, UiFlags::AlignCenter | UiFlags::VerticalCenter | UiFlags::FontSize30 | UiFlags::ColorGold));
SDL_Rect rect6 = { (Sint16)(PANEL_LEFT + 449), (Sint16)(UI_OFFSET_Y + 427), 140, 35 };
vecSelGameDialog.push_back(std::make_unique<UiArtTextButton>(_("CANCEL"), &UiFocusNavigationEsc, rect6, UiFlags::AlignCenter | UiFlags::VerticalCenter | UiFlags::FontBig | UiFlags::ColorGold));
vecSelGameDialog.push_back(std::make_unique<UiArtTextButton>(_("CANCEL"), &UiFocusNavigationEsc, rect6, UiFlags::AlignCenter | UiFlags::VerticalCenter | UiFlags::FontSize30 | UiFlags::ColorGold));
UiInitList(vecSelGameDlgItems.size(), selgame_Speed_Focus, selgame_Speed_Select, selgame_Speed_Esc, vecSelGameDialog, true);
}
@ -340,7 +339,7 @@ void selgame_Speed_Focus(int value)
strncpy(selgame_Description, _("Fastest Speed\nThe minions of the underworld will rush to attack without hesitation. Only a true speed demon should enter at this pace."), sizeof(selgame_Description) - 1);
break;
}
WordWrapArtStr(selgame_Description, DESCRIPTION_WIDTH);
WordWrapString(selgame_Description, DESCRIPTION_WIDTH);
}
void selgame_Speed_Esc()
@ -370,25 +369,25 @@ void selgame_Password_Init(int /*value*/)
UiAddLogo(&vecSelGameDialog);
SDL_Rect rect1 = { (Sint16)(PANEL_LEFT + 24), (Sint16)(UI_OFFSET_Y + 161), 590, 35 };
vecSelGameDialog.push_back(std::make_unique<UiArtText>(_("Client-Server (TCP)"), rect1, UiFlags::AlignCenter | UiFlags::FontBig));
vecSelGameDialog.push_back(std::make_unique<UiArtText>(_("Client-Server (TCP)"), rect1, UiFlags::AlignCenter | UiFlags::FontSize30 | UiFlags::ColorSilver, 3));
SDL_Rect rect2 = { (Sint16)(PANEL_LEFT + 35), (Sint16)(UI_OFFSET_Y + 211), 205, 192 };
vecSelGameDialog.push_back(std::make_unique<UiArtText>(_("Description:"), rect2, UiFlags::FontMedium));
vecSelGameDialog.push_back(std::make_unique<UiArtText>(_("Description:"), rect2, UiFlags::FontSize24 | UiFlags::ColorSilver));
SDL_Rect rect3 = { (Sint16)(PANEL_LEFT + 35), (Sint16)(UI_OFFSET_Y + 256), DESCRIPTION_WIDTH, 192 };
vecSelGameDialog.push_back(std::make_unique<UiArtText>(selgame_Description, rect3));
vecSelGameDialog.push_back(std::make_unique<UiArtText>(selgame_Description, rect3, UiFlags::FontSize12 | UiFlags::ColorSilver, 1, 16));
SDL_Rect rect4 = { (Sint16)(PANEL_LEFT + 305), (Sint16)(UI_OFFSET_Y + 211), 285, 33 };
vecSelGameDialog.push_back(std::make_unique<UiArtText>(_("Enter Password"), rect4, UiFlags::AlignCenter | UiFlags::FontBig));
vecSelGameDialog.push_back(std::make_unique<UiArtText>(_("Enter Password"), rect4, UiFlags::AlignCenter | UiFlags::FontSize30 | UiFlags::ColorSilver, 3));
SDL_Rect rect5 = { (Sint16)(PANEL_LEFT + 305), (Sint16)(UI_OFFSET_Y + 314), 285, 33 };
vecSelGameDialog.push_back(std::make_unique<UiEdit>(_("Enter Password"), selgame_Password, 15, rect5, UiFlags::FontMedium | UiFlags::ColorGold));
vecSelGameDialog.push_back(std::make_unique<UiEdit>(_("Enter Password"), selgame_Password, 15, rect5, UiFlags::FontSize24 | UiFlags::ColorGold));
SDL_Rect rect6 = { (Sint16)(PANEL_LEFT + 299), (Sint16)(UI_OFFSET_Y + 427), 140, 35 };
vecSelGameDialog.push_back(std::make_unique<UiArtTextButton>(_("OK"), &UiFocusNavigationSelect, rect6, UiFlags::AlignCenter | UiFlags::VerticalCenter | UiFlags::FontBig | UiFlags::ColorGold));
vecSelGameDialog.push_back(std::make_unique<UiArtTextButton>(_("OK"), &UiFocusNavigationSelect, rect6, UiFlags::AlignCenter | UiFlags::VerticalCenter | UiFlags::FontSize30 | UiFlags::ColorGold));
SDL_Rect rect7 = { (Sint16)(PANEL_LEFT + 449), (Sint16)(UI_OFFSET_Y + 427), 140, 35 };
vecSelGameDialog.push_back(std::make_unique<UiArtTextButton>(_("CANCEL"), &UiFocusNavigationEsc, rect7, UiFlags::AlignCenter | UiFlags::VerticalCenter | UiFlags::FontBig | UiFlags::ColorGold));
vecSelGameDialog.push_back(std::make_unique<UiArtTextButton>(_("CANCEL"), &UiFocusNavigationEsc, rect7, UiFlags::AlignCenter | UiFlags::VerticalCenter | UiFlags::FontSize30 | UiFlags::ColorGold));
UiInitList(0, nullptr, selgame_Password_Select, selgame_Password_Esc, vecSelGameDialog);
}

66
Source/DiabloUI/selhero.cpp

@ -127,7 +127,7 @@ void SelheroListFocus(int value)
{
const auto index = static_cast<std::size_t>(value);
SelheroScrollIntoView(index);
UiFlags baseFlags = UiFlags::AlignCenter | UiFlags::FontBig;
UiFlags baseFlags = UiFlags::AlignCenter | UiFlags::FontSize30;
if (selhero_SaveCount != 0 && index < selhero_SaveCount) {
memcpy(&selhero_heroInfo, &selhero_heros[index], sizeof(selhero_heroInfo));
SelheroSetStats();
@ -143,7 +143,7 @@ void SelheroListFocus(int value)
strncpy(textStats[3], "--", sizeof(textStats[3]) - 1);
strncpy(textStats[4], "--", sizeof(textStats[4]) - 1);
strncpy(textStats[5], "--", sizeof(textStats[5]) - 1);
SELLIST_DIALOG_DELETE_BUTTON->m_iFlags = baseFlags | UiFlags::ElementDisabled;
SELLIST_DIALOG_DELETE_BUTTON->m_iFlags = baseFlags | UiFlags::ColorSilver | UiFlags::ElementDisabled;
selhero_deleteEnabled = false;
}
@ -160,7 +160,7 @@ void SelheroListSelect(int value)
vecSelDlgItems.clear();
SDL_Rect rect1 = { (Sint16)(PANEL_LEFT + 264), (Sint16)(UI_OFFSET_Y + 211), 320, 33 };
vecSelDlgItems.push_back(std::make_unique<UiArtText>(_("Choose Class"), rect1, UiFlags::AlignCenter | UiFlags::FontBig));
vecSelDlgItems.push_back(std::make_unique<UiArtText>(_("Choose Class"), rect1, UiFlags::AlignCenter | UiFlags::FontSize30 | UiFlags::ColorSilver, 3));
vecSelHeroDlgItems.clear();
int itemH = 33;
@ -179,13 +179,13 @@ void SelheroListSelect(int value)
if (vecSelHeroDlgItems.size() > 4)
itemH = 26;
int itemY = 246 + (176 - vecSelHeroDlgItems.size() * itemH) / 2;
vecSelDlgItems.push_back(std::make_unique<UiList>(vecSelHeroDlgItems, PANEL_LEFT + 264, (UI_OFFSET_Y + itemY), 320, itemH, UiFlags::AlignCenter | UiFlags::FontMedium | UiFlags::ColorGold));
vecSelDlgItems.push_back(std::make_unique<UiList>(vecSelHeroDlgItems, PANEL_LEFT + 264, (UI_OFFSET_Y + itemY), 320, itemH, UiFlags::AlignCenter | UiFlags::FontSize24 | UiFlags::ColorGold));
SDL_Rect rect2 = { (Sint16)(PANEL_LEFT + 279), (Sint16)(UI_OFFSET_Y + 429), 140, 35 };
vecSelDlgItems.push_back(std::make_unique<UiArtTextButton>(_("OK"), &UiFocusNavigationSelect, rect2, UiFlags::AlignCenter | UiFlags::FontBig | UiFlags::ColorGold));
vecSelDlgItems.push_back(std::make_unique<UiArtTextButton>(_("OK"), &UiFocusNavigationSelect, rect2, UiFlags::AlignCenter | UiFlags::FontSize30 | UiFlags::ColorGold));
SDL_Rect rect3 = { (Sint16)(PANEL_LEFT + 429), (Sint16)(UI_OFFSET_Y + 429), 140, 35 };
vecSelDlgItems.push_back(std::make_unique<UiArtTextButton>(_("Cancel"), &UiFocusNavigationEsc, rect3, UiFlags::AlignCenter | UiFlags::FontBig | UiFlags::ColorGold));
vecSelDlgItems.push_back(std::make_unique<UiArtTextButton>(_("Cancel"), &UiFocusNavigationEsc, rect3, UiFlags::AlignCenter | UiFlags::FontSize30 | UiFlags::ColorGold));
UiInitList(vecSelHeroDlgItems.size(), SelheroClassSelectorFocus, SelheroClassSelectorSelect, SelheroClassSelectorEsc, vecSelDlgItems, true);
memset(&selhero_heroInfo.name, 0, sizeof(selhero_heroInfo.name));
@ -199,18 +199,18 @@ void SelheroListSelect(int value)
vecSelDlgItems.clear();
SDL_Rect rect1 = { (Sint16)(PANEL_LEFT + 264), (Sint16)(UI_OFFSET_Y + 211), 320, 33 };
vecSelDlgItems.push_back(std::make_unique<UiArtText>(_("Save File Exists"), rect1, UiFlags::AlignCenter | UiFlags::FontBig));
vecSelDlgItems.push_back(std::make_unique<UiArtText>(_("Save File Exists"), rect1, UiFlags::AlignCenter | UiFlags::FontSize30 | UiFlags::ColorSilver, 3));
vecSelHeroDlgItems.clear();
vecSelHeroDlgItems.push_back(std::make_unique<UiListItem>(_("Load Game"), 0));
vecSelHeroDlgItems.push_back(std::make_unique<UiListItem>(_("New Game"), 1));
vecSelDlgItems.push_back(std::make_unique<UiList>(vecSelHeroDlgItems, PANEL_LEFT + 265, (UI_OFFSET_Y + 285), 320, 33, UiFlags::AlignCenter | UiFlags::FontMedium | UiFlags::ColorGold));
vecSelDlgItems.push_back(std::make_unique<UiList>(vecSelHeroDlgItems, PANEL_LEFT + 265, (UI_OFFSET_Y + 285), 320, 33, UiFlags::AlignCenter | UiFlags::FontSize24 | UiFlags::ColorGold));
SDL_Rect rect2 = { (Sint16)(PANEL_LEFT + 279), (Sint16)(UI_OFFSET_Y + 427), 140, 35 };
vecSelDlgItems.push_back(std::make_unique<UiArtTextButton>(_("OK"), &UiFocusNavigationSelect, rect2, UiFlags::AlignCenter | UiFlags::VerticalCenter | UiFlags::FontBig | UiFlags::ColorGold));
vecSelDlgItems.push_back(std::make_unique<UiArtTextButton>(_("OK"), &UiFocusNavigationSelect, rect2, UiFlags::AlignCenter | UiFlags::VerticalCenter | UiFlags::FontSize30 | UiFlags::ColorGold));
SDL_Rect rect3 = { (Sint16)(PANEL_LEFT + 429), (Sint16)(UI_OFFSET_Y + 427), 140, 35 };
vecSelDlgItems.push_back(std::make_unique<UiArtTextButton>(_("Cancel"), &UiFocusNavigationEsc, rect3, UiFlags::AlignCenter | UiFlags::VerticalCenter | UiFlags::FontBig | UiFlags::ColorGold));
vecSelDlgItems.push_back(std::make_unique<UiArtTextButton>(_("Cancel"), &UiFocusNavigationEsc, rect3, UiFlags::AlignCenter | UiFlags::VerticalCenter | UiFlags::FontSize30 | UiFlags::ColorGold));
UiInitList(vecSelHeroDlgItems.size(), SelheroLoadFocus, SelheroLoadSelect, selhero_List_Init, vecSelDlgItems, true);
title = _("Single Player Characters");
@ -271,16 +271,16 @@ void SelheroClassSelectorSelect(int value)
strncpy(selhero_heroInfo.name, SelheroGenerateName(selhero_heroInfo.heroclass), sizeof(selhero_heroInfo.name) - 1);
vecSelDlgItems.clear();
SDL_Rect rect1 = { (Sint16)(PANEL_LEFT + 264), (Sint16)(UI_OFFSET_Y + 211), 320, 33 };
vecSelDlgItems.push_back(std::make_unique<UiArtText>(_("Enter Name"), rect1, UiFlags::AlignCenter | UiFlags::FontBig));
vecSelDlgItems.push_back(std::make_unique<UiArtText>(_("Enter Name"), rect1, UiFlags::AlignCenter | UiFlags::FontSize30 | UiFlags::ColorSilver, 3));
SDL_Rect rect2 = { (Sint16)(PANEL_LEFT + 265), (Sint16)(UI_OFFSET_Y + 317), 320, 33 };
vecSelDlgItems.push_back(std::make_unique<UiEdit>(_("Enter Name"), selhero_heroInfo.name, 15, rect2, UiFlags::FontMedium | UiFlags::ColorGold));
vecSelDlgItems.push_back(std::make_unique<UiEdit>(_("Enter Name"), selhero_heroInfo.name, 15, rect2, UiFlags::FontSize24 | UiFlags::ColorGold));
SDL_Rect rect3 = { (Sint16)(PANEL_LEFT + 279), (Sint16)(UI_OFFSET_Y + 429), 140, 35 };
vecSelDlgItems.push_back(std::make_unique<UiArtTextButton>(_("OK"), &UiFocusNavigationSelect, rect3, UiFlags::AlignCenter | UiFlags::FontBig | UiFlags::ColorGold));
vecSelDlgItems.push_back(std::make_unique<UiArtTextButton>(_("OK"), &UiFocusNavigationSelect, rect3, UiFlags::AlignCenter | UiFlags::FontSize30 | UiFlags::ColorGold));
SDL_Rect rect4 = { (Sint16)(PANEL_LEFT + 429), (Sint16)(UI_OFFSET_Y + 429), 140, 35 };
vecSelDlgItems.push_back(std::make_unique<UiArtTextButton>(_("Cancel"), &UiFocusNavigationEsc, rect4, UiFlags::AlignCenter | UiFlags::FontBig | UiFlags::ColorGold));
vecSelDlgItems.push_back(std::make_unique<UiArtTextButton>(_("Cancel"), &UiFocusNavigationEsc, rect4, UiFlags::AlignCenter | UiFlags::FontSize30 | UiFlags::ColorGold));
UiInitList(0, nullptr, SelheroNameSelect, SelheroNameEsc, vecSelDlgItems);
}
@ -456,7 +456,7 @@ void selhero_Init()
vecSelDlgItems.clear();
SDL_Rect rect1 = { (Sint16)(PANEL_LEFT + 24), (Sint16)(UI_OFFSET_Y + 161), 590, 35 };
vecSelHeroDialog.push_back(std::make_unique<UiArtText>(&title, rect1, UiFlags::AlignCenter | UiFlags::FontBig));
vecSelHeroDialog.push_back(std::make_unique<UiArtText>(&title, rect1, UiFlags::AlignCenter | UiFlags::FontSize30 | UiFlags::ColorSilver, 3));
SDL_Rect rect2 = { (Sint16)(PANEL_LEFT + 30), (Sint16)(UI_OFFSET_Y + 211), 180, 76 };
auto heroImg = std::make_unique<UiImage>(&ArtHero, rect2, UiFlags::None, /*bAnimated=*/false, static_cast<int>(enum_size<HeroClass>::value));
@ -464,38 +464,38 @@ void selhero_Init()
vecSelHeroDialog.push_back(std::move(heroImg));
SDL_Rect rect3 = { (Sint16)(PANEL_LEFT + 39), (Sint16)(UI_OFFSET_Y + 323), 110, 21 };
vecSelHeroDialog.push_back(std::make_unique<UiArtText>(_("Level:"), rect3, UiFlags::AlignRight));
vecSelHeroDialog.push_back(std::make_unique<UiArtText>(_("Level:"), rect3, UiFlags::AlignRight | UiFlags::FontSize12 | UiFlags::ColorSilver));
SDL_Rect rect4 = { (Sint16)(PANEL_LEFT + 39), (Sint16)(UI_OFFSET_Y + 323), 110, 21 };
vecSelHeroDialog.push_back(std::make_unique<UiArtText>(_("Level:"), rect4, UiFlags::AlignRight));
vecSelHeroDialog.push_back(std::make_unique<UiArtText>(_("Level:"), rect4, UiFlags::AlignRight | UiFlags::FontSize12 | UiFlags::ColorSilver));
SDL_Rect rect5 = { (Sint16)(PANEL_LEFT + 159), (Sint16)(UI_OFFSET_Y + 323), 40, 21 };
vecSelHeroDialog.push_back(std::make_unique<UiArtText>(textStats[0], rect5, UiFlags::AlignCenter));
vecSelHeroDialog.push_back(std::make_unique<UiArtText>(textStats[0], rect5, UiFlags::AlignCenter | UiFlags::FontSize12 | UiFlags::ColorSilver));
SDL_Rect rect6 = { (Sint16)(PANEL_LEFT + 39), (Sint16)(UI_OFFSET_Y + 358), 110, 21 };
vecSelHeroDialog.push_back(std::make_unique<UiArtText>(_("Strength:"), rect6, UiFlags::AlignRight));
vecSelHeroDialog.push_back(std::make_unique<UiArtText>(_("Strength:"), rect6, UiFlags::AlignRight | UiFlags::FontSize12 | UiFlags::ColorSilver));
SDL_Rect rect7 = { (Sint16)(PANEL_LEFT + 159), (Sint16)(UI_OFFSET_Y + 358), 40, 21 };
vecSelHeroDialog.push_back(std::make_unique<UiArtText>(textStats[1], rect7, UiFlags::AlignCenter));
vecSelHeroDialog.push_back(std::make_unique<UiArtText>(textStats[1], rect7, UiFlags::AlignCenter | UiFlags::FontSize12 | UiFlags::ColorSilver));
SDL_Rect rect8 = { (Sint16)(PANEL_LEFT + 39), (Sint16)(UI_OFFSET_Y + 380), 110, 21 };
vecSelHeroDialog.push_back(std::make_unique<UiArtText>(_("Magic:"), rect8, UiFlags::AlignRight));
vecSelHeroDialog.push_back(std::make_unique<UiArtText>(_("Magic:"), rect8, UiFlags::AlignRight | UiFlags::FontSize12 | UiFlags::ColorSilver));
SDL_Rect rect9 = { (Sint16)(PANEL_LEFT + 159), (Sint16)(UI_OFFSET_Y + 380), 40, 21 };
vecSelHeroDialog.push_back(std::make_unique<UiArtText>(textStats[2], rect9, UiFlags::AlignCenter));
vecSelHeroDialog.push_back(std::make_unique<UiArtText>(textStats[2], rect9, UiFlags::AlignCenter | UiFlags::FontSize12 | UiFlags::ColorSilver));
SDL_Rect rect10 = { (Sint16)(PANEL_LEFT + 39), (Sint16)(UI_OFFSET_Y + 401), 110, 21 };
vecSelHeroDialog.push_back(std::make_unique<UiArtText>(_("Dexterity:"), rect10, UiFlags::AlignRight));
vecSelHeroDialog.push_back(std::make_unique<UiArtText>(_("Dexterity:"), rect10, UiFlags::AlignRight | UiFlags::FontSize12 | UiFlags::ColorSilver));
SDL_Rect rect11 = { (Sint16)(PANEL_LEFT + 159), (Sint16)(UI_OFFSET_Y + 401), 40, 21 };
vecSelHeroDialog.push_back(std::make_unique<UiArtText>(textStats[3], rect11, UiFlags::AlignCenter));
vecSelHeroDialog.push_back(std::make_unique<UiArtText>(textStats[3], rect11, UiFlags::AlignCenter | UiFlags::FontSize12 | UiFlags::ColorSilver));
SDL_Rect rect12 = { (Sint16)(PANEL_LEFT + 39), (Sint16)(UI_OFFSET_Y + 422), 110, 21 };
vecSelHeroDialog.push_back(std::make_unique<UiArtText>(_("Vitality:"), rect12, UiFlags::AlignRight));
vecSelHeroDialog.push_back(std::make_unique<UiArtText>(_("Vitality:"), rect12, UiFlags::AlignRight | UiFlags::FontSize12 | UiFlags::ColorSilver));
SDL_Rect rect13 = { (Sint16)(PANEL_LEFT + 159), (Sint16)(UI_OFFSET_Y + 422), 40, 21 };
vecSelHeroDialog.push_back(std::make_unique<UiArtText>(textStats[4], rect13, UiFlags::AlignCenter));
vecSelHeroDialog.push_back(std::make_unique<UiArtText>(textStats[4], rect13, UiFlags::AlignCenter | UiFlags::FontSize12 | UiFlags::ColorSilver));
#if _DEBUG
SDL_Rect rect14 = { (Sint16)(PANEL_LEFT + 39), (Sint16)(UI_OFFSET_Y + 443), 110, 21 };
vecSelHeroDialog.push_back(std::make_unique<UiArtText>(_("Savegame:"), rect14, UiFlags::AlignRight));
vecSelHeroDialog.push_back(std::make_unique<UiArtText>(_("Savegame:"), rect14, UiFlags::AlignRight | UiFlags::FontSize12 | UiFlags::ColorSilver));
SDL_Rect rect15 = { (Sint16)(PANEL_LEFT + 159), (Sint16)(UI_OFFSET_Y + 443), 40, 21 };
vecSelHeroDialog.push_back(std::make_unique<UiArtText>(textStats[5], rect15, UiFlags::AlignCenter));
vecSelHeroDialog.push_back(std::make_unique<UiArtText>(textStats[5], rect15, UiFlags::AlignCenter | UiFlags::FontSize12 | UiFlags::ColorSilver));
#endif
}
@ -505,7 +505,7 @@ void selhero_List_Init()
vecSelDlgItems.clear();
SDL_Rect rect1 = { (Sint16)(PANEL_LEFT + 264), (Sint16)(UI_OFFSET_Y + 211), 320, 33 };
vecSelDlgItems.push_back(std::make_unique<UiArtText>(_("Select Hero"), rect1, UiFlags::AlignCenter | UiFlags::FontBig));
vecSelDlgItems.push_back(std::make_unique<UiArtText>(_("Select Hero"), rect1, UiFlags::AlignCenter | UiFlags::FontSize30 | UiFlags::ColorSilver, 3));
vecSelHeroDlgItems.clear();
const size_t numViewportHeroes = std::min(selhero_SaveCount + 1, MaxViewportItems);
@ -514,7 +514,7 @@ void selhero_List_Init()
}
SelheroUpdateViewportItems();
vecSelDlgItems.push_back(std::make_unique<UiList>(vecSelHeroDlgItems, PANEL_LEFT + 265, (UI_OFFSET_Y + 256), 320, 26, UiFlags::AlignCenter | UiFlags::FontMedium | UiFlags::ColorGold));
vecSelDlgItems.push_back(std::make_unique<UiList>(vecSelHeroDlgItems, PANEL_LEFT + 265, (UI_OFFSET_Y + 256), 320, 26, UiFlags::AlignCenter | UiFlags::FontSize24 | UiFlags::ColorGold));
SDL_Rect rect2 = { (Sint16)(PANEL_LEFT + 585), (Sint16)(UI_OFFSET_Y + 244), 25, 178 };
auto pinnedScrollBar = std::make_unique<UiScrollbar>(&ArtScrollBarBackground, &ArtScrollBarThumb, &ArtScrollBarArrow, rect2);
@ -522,15 +522,15 @@ void selhero_List_Init()
vecSelDlgItems.push_back(std::move(pinnedScrollBar));
SDL_Rect rect3 = { (Sint16)(PANEL_LEFT + 239), (Sint16)(UI_OFFSET_Y + 429), 120, 35 };
vecSelDlgItems.push_back(std::make_unique<UiArtTextButton>(_("OK"), &UiFocusNavigationSelect, rect3, UiFlags::AlignCenter | UiFlags::FontBig | UiFlags::ColorGold));
vecSelDlgItems.push_back(std::make_unique<UiArtTextButton>(_("OK"), &UiFocusNavigationSelect, rect3, UiFlags::AlignCenter | UiFlags::FontSize30 | UiFlags::ColorGold));
SDL_Rect rect4 = { (Sint16)(PANEL_LEFT + 364), (Sint16)(UI_OFFSET_Y + 429), 120, 35 };
auto setlistDialogDeleteButton = std::make_unique<UiArtTextButton>(_("Delete"), &SelheroUiFocusNavigationYesNo, rect4, UiFlags::AlignCenter | UiFlags::FontBig | UiFlags::ElementDisabled);
auto setlistDialogDeleteButton = std::make_unique<UiArtTextButton>(_("Delete"), &SelheroUiFocusNavigationYesNo, rect4, UiFlags::AlignCenter | UiFlags::FontSize30 | UiFlags::ColorSilver | UiFlags::ElementDisabled);
SELLIST_DIALOG_DELETE_BUTTON = setlistDialogDeleteButton.get();
vecSelDlgItems.push_back(std::move(setlistDialogDeleteButton));
SDL_Rect rect5 = { (Sint16)(PANEL_LEFT + 489), (Sint16)(UI_OFFSET_Y + 429), 120, 35 };
vecSelDlgItems.push_back(std::make_unique<UiArtTextButton>(_("Cancel"), &UiFocusNavigationEsc, rect5, UiFlags::AlignCenter | UiFlags::FontBig | UiFlags::ColorGold));
vecSelDlgItems.push_back(std::make_unique<UiArtTextButton>(_("Cancel"), &UiFocusNavigationEsc, rect5, UiFlags::AlignCenter | UiFlags::FontSize30 | UiFlags::ColorGold));
UiInitList(selhero_SaveCount + 1, SelheroListFocus, SelheroListSelect, SelheroListEsc, vecSelDlgItems, false, SelheroListDeleteYesNo);
UiInitScrollBar(scrollBar, MaxViewportItems, &listOffset);

14
Source/DiabloUI/selok.cpp

@ -1,9 +1,9 @@
#include "DiabloUI/selok.h"
#include "DiabloUI/diabloui.h"
#include "DiabloUI/text.h"
#include "control.h"
#include "utils/language.h"
#include "engine/render/text_render.hpp"
namespace devilution {
@ -18,7 +18,7 @@ bool selok_endMenu;
std::vector<std::unique_ptr<UiListItem>> vecSelOkDialogItems;
std::vector<std::unique_ptr<UiItemBase>> vecSelOkDialog;
#define MESSAGE_WIDTH 280
#define MESSAGE_WIDTH 400
void selok_Free()
{
@ -56,20 +56,20 @@ void UiSelOkDialog(const char *title, const char *body, bool background)
if (title != nullptr) {
SDL_Rect rect1 = { (Sint16)(PANEL_LEFT + 24), (Sint16)(UI_OFFSET_Y + 161), 590, 35 };
vecSelOkDialog.push_back(std::make_unique<UiArtText>(title, rect1, UiFlags::AlignCenter | UiFlags::FontBig));
vecSelOkDialog.push_back(std::make_unique<UiArtText>(title, rect1, UiFlags::AlignCenter | UiFlags::FontSize30 | UiFlags::ColorSilver, 3));
SDL_Rect rect2 = { (Sint16)(PANEL_LEFT + 140), (Sint16)(UI_OFFSET_Y + 210), 560, 168 };
vecSelOkDialog.push_back(std::make_unique<UiArtText>(dialogText, rect2, UiFlags::FontMedium));
vecSelOkDialog.push_back(std::make_unique<UiArtText>(dialogText, rect2, UiFlags::FontSize24 | UiFlags::ColorSilver));
} else {
SDL_Rect rect1 = { (Sint16)(PANEL_LEFT + 140), (Sint16)(UI_OFFSET_Y + 197), 560, 168 };
vecSelOkDialog.push_back(std::make_unique<UiArtText>(dialogText, rect1, UiFlags::FontMedium));
vecSelOkDialog.push_back(std::make_unique<UiArtText>(dialogText, rect1, UiFlags::FontSize24 | UiFlags::ColorSilver));
}
vecSelOkDialogItems.push_back(std::make_unique<UiListItem>(_("OK"), 0));
vecSelOkDialog.push_back(std::make_unique<UiList>(vecSelOkDialogItems, PANEL_LEFT + 230, (UI_OFFSET_Y + 390), 180, 35, UiFlags::AlignCenter | UiFlags::FontBig | UiFlags::ColorGold));
vecSelOkDialog.push_back(std::make_unique<UiList>(vecSelOkDialogItems, PANEL_LEFT + 230, (UI_OFFSET_Y + 390), 180, 35, UiFlags::AlignCenter | UiFlags::FontSize30 | UiFlags::ColorGold));
strncpy(dialogText, body, sizeof(dialogText) - 1);
WordWrapArtStr(dialogText, MESSAGE_WIDTH);
WordWrapString(dialogText, MESSAGE_WIDTH, GameFont24);
UiInitList(0, nullptr, selok_Select, selok_Esc, vecSelOkDialog, false, nullptr);

11
Source/DiabloUI/selyesno.cpp

@ -1,7 +1,6 @@
#include "selyesno.h"
#include "DiabloUI/diabloui.h"
#include "DiabloUI/text.h"
#include "control.h"
#include "utils/language.h"
@ -15,7 +14,7 @@ char selyesno_confirmationMessage[256];
std::vector<std::unique_ptr<UiListItem>> vecSelYesNoDialogItems;
std::vector<std::unique_ptr<UiItemBase>> vecSelYesNoDialog;
#define MESSAGE_WIDTH 280
#define MESSAGE_WIDTH 400
void SelyesnoFree()
{
@ -47,17 +46,17 @@ bool UiSelHeroYesNoDialog(const char *title, const char *body)
UiAddLogo(&vecSelYesNoDialog);
SDL_Rect rect1 = { (Sint16)(PANEL_LEFT + 24), (Sint16)(UI_OFFSET_Y + 161), 590, 35 };
vecSelYesNoDialog.push_back(std::make_unique<UiArtText>(title, rect1, UiFlags::AlignCenter | UiFlags::FontBig));
vecSelYesNoDialog.push_back(std::make_unique<UiArtText>(title, rect1, UiFlags::AlignCenter | UiFlags::FontSize30 | UiFlags::ColorSilver, 3));
SDL_Rect rect2 = { (Sint16)(PANEL_LEFT + 120), (Sint16)(UI_OFFSET_Y + 236), MESSAGE_WIDTH, 168 };
vecSelYesNoDialog.push_back(std::make_unique<UiArtText>(selyesno_confirmationMessage, rect2, UiFlags::FontMedium));
vecSelYesNoDialog.push_back(std::make_unique<UiArtText>(selyesno_confirmationMessage, rect2, UiFlags::FontSize24 | UiFlags::ColorSilver));
vecSelYesNoDialogItems.push_back(std::make_unique<UiListItem>(_("Yes"), 0));
vecSelYesNoDialogItems.push_back(std::make_unique<UiListItem>(_("No"), 1));
vecSelYesNoDialog.push_back(std::make_unique<UiList>(vecSelYesNoDialogItems, PANEL_LEFT + 230, (UI_OFFSET_Y + 390), 180, 35, UiFlags::AlignCenter | UiFlags::FontBig | UiFlags::ColorGold));
vecSelYesNoDialog.push_back(std::make_unique<UiList>(vecSelYesNoDialogItems, PANEL_LEFT + 230, (UI_OFFSET_Y + 390), 180, 35, UiFlags::AlignCenter | UiFlags::FontSize30 | UiFlags::ColorGold));
strncpy(selyesno_confirmationMessage, body, sizeof(selyesno_confirmationMessage) - 1);
WordWrapArtStr(selyesno_confirmationMessage, MESSAGE_WIDTH);
WordWrapString(selyesno_confirmationMessage, MESSAGE_WIDTH, GameFont24);
UiInitList(vecSelYesNoDialogItems.size(), nullptr, SelyesnoSelect, SelyesnoEsc, vecSelYesNoDialog, true, nullptr);

57
Source/DiabloUI/text.cpp

@ -1,57 +0,0 @@
#include "DiabloUI/text.h"
namespace devilution {
std::size_t GetArtStrWidth(const char *str, std::size_t size)
{
int strWidth = 0;
for (size_t i = 0, n = strlen(str); i < n; i++) {
uint8_t w = FontTables[size][(uint8_t)str[i] + 2];
strWidth += (w != 0) ? w : FontTables[size][0];
}
return strWidth;
}
void WordWrapArtStr(char *text, std::size_t width, std::size_t size)
{
const std::size_t textLength = strlen(text);
std::size_t lineStart = 0;
std::size_t lineWidth = 0;
for (std::size_t i = 0; i < textLength; i++) {
if (text[i] == '\n') { // Existing line break, scan next line
lineStart = i + 1;
lineWidth = 0;
continue;
}
uint8_t w = FontTables[size][(uint8_t)text[i] + 2];
lineWidth += (w != 0) ? w : FontTables[size][0];
if (lineWidth <= width) {
continue; // String is still within the limit, continue to the next line
}
std::size_t j; // Backtrack to the previous space
for (j = i; j >= lineStart; j--) {
if (text[j] == ' ') {
break;
}
}
if (j == lineStart) { // Single word longer than width
if (i == textLength)
break;
j = i;
}
// Break line and continue to next line
i = j;
text[i] = '\n';
lineStart = i + 1;
lineWidth = 0;
}
}
} // namespace devilution

12
Source/DiabloUI/text.h

@ -1,12 +0,0 @@
#pragma once
#include <cstddef>
#include "DiabloUI/fonts.h"
namespace devilution {
std::size_t GetArtStrWidth(const char *str, std::size_t size);
void WordWrapArtStr(char *text, std::size_t width, std::size_t size = AFT_SMALL);
} // namespace devilution

34
Source/DiabloUI/text_draw.cpp

@ -3,7 +3,6 @@
#include "DiabloUI/art_draw.h"
#include "DiabloUI/diabloui.h"
#include "DiabloUI/fonts.h"
#include "DiabloUI/text.h"
#include "DiabloUI/ttf_render_wrapped.h"
#include "DiabloUI/ui_item.h"
#include "utils/display.h"
@ -65,37 +64,4 @@ void DrawTTF(const char *text, const SDL_Rect &rectIn, UiFlags flags,
ErrSdl();
}
void DrawArtStr(const char *text, const SDL_Rect &rect, UiFlags flags, bool drawTextCursor)
{
_artFontTables size = AFT_SMALL;
_artFontColors color = HasAnyOf(flags, UiFlags::ColorGold) ? AFC_GOLD : AFC_SILVER;
if (HasAnyOf(flags, UiFlags::FontMedium))
size = AFT_MED;
else if (HasAnyOf(flags, UiFlags::FontBig))
size = AFT_BIG;
else if (HasAnyOf(flags, UiFlags::FontHuge))
size = AFT_HUGE;
const int x = rect.x + AlignXOffset(flags, rect, GetArtStrWidth(text, size));
const int y = rect.y + (HasAnyOf(flags, UiFlags::VerticalCenter) ? (rect.h - ArtFonts[size][color].h()) / 2 : 0);
int sx = x;
int sy = y;
for (size_t i = 0, n = strlen(text); i < n; i++) {
if (text[i] == '\n') {
sx = x;
sy += ArtFonts[size][color].h();
continue;
}
uint8_t w = FontTables[size][static_cast<uint8_t>(text[i]) + 2];
w = (w != 0) ? w : FontTables[size][0];
DrawArt({ sx, sy }, &ArtFonts[size][color], static_cast<uint8_t>(text[i]), w);
sx += w;
}
if (drawTextCursor && GetAnimationFrame(2, 500) != 0) {
DrawArt({ sx, sy }, &ArtFonts[size][color], '|');
}
}
} // namespace devilution

2
Source/DiabloUI/text_draw.h

@ -17,6 +17,4 @@ void DrawTTF(const char *text, const SDL_Rect &rect, UiFlags flags,
const SDL_Color &textColor, const SDL_Color &shadowColor,
TtfSurfaceCache &renderCache);
void DrawArtStr(const char *text, const SDL_Rect &rect, UiFlags flags, bool drawTextCursor = false);
} // namespace devilution

4
Source/DiabloUI/title.cpp

@ -40,8 +40,8 @@ void UiTitleDialog()
UiAddBackground(&vecTitleScreen);
UiAddLogo(&vecTitleScreen, LOGO_BIG, 182);
SDL_Rect rect = { (Sint16)(PANEL_LEFT + 49), (Sint16)(UI_OFFSET_Y + 410), 550, 26 };
vecTitleScreen.push_back(std::make_unique<UiArtText>(_("Copyright © 1996-2001 Blizzard Entertainment"), rect, UiFlags::FontMedium | UiFlags::AlignCenter));
SDL_Rect rect = { (Sint16)(PANEL_LEFT), (Sint16)(UI_OFFSET_Y + 410), 640, 26 };
vecTitleScreen.push_back(std::make_unique<UiArtText>(_("Copyright © 1996-2001 Blizzard Entertainment"), rect, UiFlags::AlignCenter | UiFlags::FontSize24 | UiFlags::ColorSilver));
}
TitleLoad();

69
Source/DiabloUI/ui_item.h

@ -25,21 +25,30 @@ enum class UiType {
enum class UiFlags {
// clang-format off
None = 0,
FontSmall = 1 << 0,
FontMedium = 1 << 1,
FontBig = 1 << 2,
FontHuge = 1 << 3,
AlignCenter = 1 << 4,
AlignRight = 1 << 5,
VerticalCenter = 1 << 6,
ColorSilver = 1 << 7,
ColorGold = 1 << 8,
ColorRed = 1 << 9,
ColorBlue = 1 << 10,
ColorBlack = 1 << 11,
ElementDisabled = 1 << 12,
ElementHidden = 1 << 13,
KerningFitSpacing = 1 << 14,
FontSize12 = 1 << 0,
FontSize24 = 1 << 1,
FontSize30 = 1 << 2,
FontSize42 = 1 << 3,
FontSize46 = 1 << 4,
ColorSilver = 1 << 5,
ColorGold = 1 << 6,
ColorRed = 1 << 7,
ColorBlue = 1 << 8,
ColorBlack = 1 << 9,
AlignCenter = 1 << 10,
AlignRight = 1 << 11,
VerticalCenter = 1 << 12,
KerningFitSpacing = 1 << 13,
ElementDisabled = 1 << 14,
ElementHidden = 1 << 15,
PentaCursor = 1 << 16,
TextCursor = 1 << 17,
// clang-format on
};
@ -153,9 +162,11 @@ public:
* @param rect screen region defining the area to draw the text
* @param flags UiFlags controlling color/alignment/size
*/
UiArtText(const char *text, SDL_Rect rect, UiFlags flags = UiFlags::None)
UiArtText(const char *text, SDL_Rect rect, UiFlags flags = UiFlags::None, int spacing = 1, int lineHeight = -1)
: UiItemBase(UiType::ArtText, rect, flags)
, m_text(text)
, m_spacing(spacing)
, m_lineHeight(lineHeight)
{
}
@ -165,9 +176,11 @@ public:
* @param rect screen region defining the area to draw the text
* @param flags UiFlags controlling color/alignment/size
*/
UiArtText(const char **ptext, SDL_Rect rect, UiFlags flags = UiFlags::None)
UiArtText(const char **ptext, SDL_Rect rect, UiFlags flags = UiFlags::None, int spacing = 1, int lineHeight = -1)
: UiItemBase(UiType::ArtText, rect, flags)
, m_ptext(ptext)
, m_spacing(spacing)
, m_lineHeight(lineHeight)
{
}
@ -178,11 +191,23 @@ public:
return *m_ptext;
}
int spacing() const
{
return m_spacing;
}
int lineHeight() const
{
return m_lineHeight;
}
~UiArtText() {};
private:
const char *m_text = nullptr;
const char **m_ptext = nullptr;
int m_spacing = 1;
int m_lineHeight = -1;
};
//=============================================================================
@ -280,7 +305,6 @@ public:
enum FrameKey : uint8_t {
DEFAULT,
PRESSED,
DISABLED
};
//private:
@ -315,12 +339,13 @@ typedef std::vector<std::unique_ptr<UiListItem>> vUiListItem;
class UiList : public UiItemBase {
public:
UiList(const vUiListItem &vItems, Sint16 x, Sint16 y, Uint16 item_width, Uint16 item_height, UiFlags flags = UiFlags::None)
UiList(const vUiListItem &vItems, Sint16 x, Sint16 y, Uint16 item_width, Uint16 item_height, UiFlags flags = UiFlags::None, int spacing = 1)
: UiItemBase(UiType::List, { x, y, item_width, static_cast<Uint16>(item_height * vItems.size()) }, flags)
, m_x(x)
, m_y(y)
, m_width(item_width)
, m_height(item_height)
, m_spacing(spacing)
{
for (auto &item : vItems)
m_vecItems.push_back(item.get());
@ -352,9 +377,15 @@ public:
return m_vecItems[i];
}
int spacing() const
{
return m_spacing;
}
//private:
Sint16 m_x, m_y;
Uint16 m_width, m_height;
std::vector<UiListItem *> m_vecItems;
int m_spacing;
};
} // namespace devilution

2
Source/automap.cpp

@ -461,7 +461,7 @@ AutomapTile GetAutomapTypeView(Point map)
void DrawAutomapText(const Surface &out)
{
char desc[256];
Point linePosition { 8, 20 };
Point linePosition { 8, 8 };
if (gbIsMultiplayer) {
if (strcasecmp("0.0.0.0", szPlayerName) != 0) {

2
Source/capture.cpp

@ -146,7 +146,7 @@ std::ofstream CaptureFile(std::string *dstPath)
*/
void RedPalette()
{
for (int i = 0; i < 255; i++) {
for (int i = 0; i < 256; i++) {
system_palette[i].g = 0;
system_palette[i].b = 0;
}

51
Source/control.cpp

@ -90,7 +90,6 @@ std::optional<CelSprite> talkButtons;
std::optional<CelSprite> pDurIcons;
std::optional<CelSprite> multiButtons;
std::optional<CelSprite> pPanelButtons;
std::optional<CelSprite> pChrPanel;
std::optional<CelSprite> pGBoxBuff;
std::optional<CelSprite> pSBkBtnCel;
std::optional<CelSprite> pSBkIconCels;
@ -109,19 +108,6 @@ bool WhisperList[MAX_PLRS];
char panelstr[4][64];
uint8_t SplTransTbl[256];
/**
* Line start position for info box text when displaying 1, 2, 3, 4 and 5 lines respectivly
*/
const int LineOffsets[5][5] = {
{ 82 },
{ 70, 94 },
{ 64, 82, 100 },
{ 60, 75, 89, 104 },
{ 58, 70, 82, 94, 105 },
};
/* data */
/** Maps from spell_id to spelicon.cel frame number. */
char SpellITbl[] = {
27,
@ -230,7 +216,7 @@ spell_id SpellPages[6][7] = {
#define SPLROWICONLS 10
#define SPLICONLAST (gbIsHellfire ? 52 : 43)
void CalculatePanelAreas(void)
void CalculatePanelAreas()
{
MainPanel = { { (gnScreenWidth - PANEL_WIDTH) / 2, gnScreenHeight - PANEL_HEIGHT }, { PANEL_WIDTH, PANEL_HEIGHT } };
LeftPanel = { { 0, 0 }, { SPANEL_WIDTH, SPANEL_HEIGHT } };
@ -320,7 +306,7 @@ void SetSpellTrans(spell_type t)
void PrintSBookHotkey(const Surface &out, Point position, const std::string &text)
{
// Align the hot key text with the top-right corner of the spell icon
position += Displacement { SPLICONLENGTH - (GetLineWidth(text.c_str()) + 5), 17 - SPLICONLENGTH };
position += Displacement { SPLICONLENGTH - (GetLineWidth(text.c_str()) + 5), 5 - SPLICONLENGTH };
// Draw a drop shadow below and to the left of the text
DrawString(out, text, position + Displacement { -1, 1 }, UiFlags::ColorBlack);
@ -412,19 +398,19 @@ void PrintInfo(const Surface &out)
if (talkflag)
return;
Rectangle line { { PANEL_X + 177, PANEL_Y + LineOffsets[pnumlines][0] }, { 288, 0 } };
const int LineStart[] = { 70, 58, 52, 48, 46 };
const int LineHeights[] = { 30, 24, 18, 15, 12 };
Rectangle line { { PANEL_X + 177, PANEL_Y + LineStart[pnumlines] }, { 288, 12 } };
int yo = 0;
int lo = 1;
if (infostr[0] != '\0') {
DrawString(out, infostr, line, InfoColor | UiFlags::AlignCenter | UiFlags::KerningFitSpacing, 2);
yo = 1;
lo = 0;
line.position.y += LineHeights[pnumlines];
}
for (int i = 0; i < pnumlines; i++) {
line.position.y = PANEL_Y + LineOffsets[pnumlines - lo][i + yo];
DrawString(out, panelstr[i], line, InfoColor | UiFlags::AlignCenter | UiFlags::KerningFitSpacing, 2);
line.position.y += LineHeights[pnumlines];
}
}
@ -918,7 +904,8 @@ void InitControlPan()
pManaBuff.emplace(88, 88);
pLifeBuff.emplace(88, 88);
pChrPanel = LoadCel("Data\\Char.CEL", SPANEL_WIDTH);
LoadCharPanel();
if (!gbIsHellfire)
pSpellCels = LoadCel("CtrlPan\\SpelIcon.CEL", SPLICONLENGTH);
else
@ -1301,7 +1288,6 @@ void FreeControlPan()
pBtmBuff = std::nullopt;
pManaBuff = std::nullopt;
pLifeBuff = std::nullopt;
pChrPanel = std::nullopt;
pSpellCels = std::nullopt;
pPanelButtons = std::nullopt;
multiButtons = std::nullopt;
@ -1313,6 +1299,7 @@ void FreeControlPan()
pSBkBtnCel = std::nullopt;
pSBkIconCels = std::nullopt;
pGBoxBuff = std::nullopt;
FreeCharPanel();
}
void DrawInfoBox(const Surface &out)
@ -1397,7 +1384,7 @@ void DrawLevelUpIcon(const Surface &out)
{
if (stextflag == STORE_NONE) {
int nCel = lvlbtndown ? 3 : 2;
DrawString(out, _("Level Up"), { { PANEL_LEFT + 0, PANEL_TOP - 49 }, { 120, 0 } }, UiFlags::ColorSilver | UiFlags::AlignCenter);
DrawString(out, _("Level Up"), { { PANEL_LEFT + 0, PANEL_TOP - 62 }, { 120, 0 } }, UiFlags::ColorSilver | UiFlags::AlignCenter);
CelDrawTo(out, { 40 + PANEL_X, -17 + PANEL_Y }, *pChrButtons, nCel);
}
}
@ -1512,13 +1499,13 @@ void DrawSpellBook(const Surface &out)
auto &myPlayer = Players[MyPlayerId];
uint64_t spl = myPlayer._pMemSpells | myPlayer._pISpells | myPlayer._pAblSpells;
int yp = 55;
int yp = 43;
for (int i = 1; i < 8; i++) {
spell_id sn = SpellPages[sbooktab][i - 1];
if (sn != SPL_INVALID && (spl & GetSpellBitmask(sn)) != 0) {
spell_type st = GetSBookTrans(sn, true);
SetSpellTrans(st);
const Point spellCellPosition = GetPanelPosition(UiPanels::Spell, { 11, yp });
const Point spellCellPosition = GetPanelPosition(UiPanels::Spell, { 11, yp + 12 });
DrawSpellCel(out, spellCellPosition, *pSBkIconCels, SpellITbl[sn]);
if (sn == myPlayer._pRSpell && st == myPlayer._pRSplType) {
SetSpellTrans(RSPLTYPE_SKILL);
@ -1612,12 +1599,12 @@ void DrawGoldSplit(const Surface &out, int amount)
tempstr[BufferSize - 1] = '\0';
// Pre-wrap the string at spaces, otherwise DrawString would hard wrap in the middle of words
WordWrapGameString(tempstr, 200);
WordWrapString(tempstr, 200);
// The split gold dialog is roughly 4 lines high, but we need at least one line for the player to input an amount.
// Using a clipping region 50 units high (approx 3 lines with a lineheight of 17) to ensure there is enough room left
// for the text entered by the player.
DrawString(out, tempstr, { GetPanelPosition(UiPanels::Inventory, { dialogX + 31, 87 }), { 200, 50 } }, UiFlags::ColorGold | UiFlags::AlignCenter, 1, 17);
DrawString(out, tempstr, { GetPanelPosition(UiPanels::Inventory, { dialogX + 31, 75 }), { 200, 50 } }, UiFlags::ColorGold | UiFlags::AlignCenter, 1, 17);
tempstr[0] = '\0';
if (amount > 0) {
@ -1626,7 +1613,7 @@ void DrawGoldSplit(const Surface &out, int amount)
}
// Even a ten digit amount of gold only takes up about half a line. There's no need to wrap or clip text here so we
// use the Point form of DrawString.
DrawString(out, tempstr, GetPanelPosition(UiPanels::Inventory, { dialogX + 37, 140 }), UiFlags::ColorSilver, 1, -1, true);
DrawString(out, tempstr, GetPanelPosition(UiPanels::Inventory, { dialogX + 37, 128 }), UiFlags::ColorSilver | UiFlags::PentaCursor);
}
void control_drop_gold(char vkey)
@ -1683,9 +1670,9 @@ void DrawTalkPan(const Surface &out)
char *msg = TalkMessage;
int x = PANEL_LEFT + 200;
int y = PANEL_Y + 22;
int y = PANEL_Y + 10;
int idx = DrawString(out, msg, { { x, y }, { 250, 39 } }, UiFlags::ColorSilver, 1, 13, true);
int idx = DrawString(out, msg, { { x, y }, { 250, 27 } }, UiFlags::ColorSilver | UiFlags::PentaCursor, 1, 13);
msg[idx] = '\0';
x += 46;

2
Source/controls/modifier_hints.cpp

@ -29,7 +29,7 @@ constexpr int LineHeight = 25;
constexpr int CircleMarginX = 16;
/** Distance between the panel top and the circle top. */
constexpr int CircleTop = 76;
constexpr int CircleTop = 101;
struct CircleMenuHint {
CircleMenuHint(bool isDpad, const char *top, const char *right, const char *bottom, const char *left)

16
Source/diablo.cpp

@ -1006,6 +1006,7 @@ void DiabloDeinit()
dx_cleanup(); // Cleanup SDL surfaces stuff, so we have to do it before SDL_Quit().
if (was_fonts_init)
FontsCleanup();
UnloadFonts();
if (SDL_WasInit(SDL_INIT_EVERYTHING & ~SDL_INIT_HAPTIC) != 0)
SDL_Quit();
}
@ -1509,6 +1510,18 @@ void InitKeymapActions()
});
}
void LoadGameFonts()
{
LoadFont(GameFont12, ColorSilver, "fonts\\white.trn");
LoadFont(GameFont12, ColorGold, "fonts\\whitegold.trn");
LoadFont(GameFont12, ColorRed, "fonts\\red.trn");
LoadFont(GameFont12, ColorBlue, "fonts\\blue.trn");
LoadFont(GameFont12, ColorBlack, "fonts\\black.trn");
LoadFont(GameFont30, ColorGold);
LoadFont(GameFont46, ColorGold);
LoadFont(GameFont46, ColorBlack, "fonts\\black.trn");
}
} // namespace
void FreeGameMem()
@ -1542,6 +1555,7 @@ bool StartGame(bool bNewGame, bool bSinglePlayer)
// Save 2.8 MiB of RAM by freeing all main menu resources
// before starting the game.
UiDestroy();
LoadGameFonts();
gbSelectProvider = false;
@ -1557,6 +1571,7 @@ bool StartGame(bool bNewGame, bool bSinglePlayer)
}
RunGameLoop(uMsg);
NetClose();
UnloadFonts();
// If the player left the game into the main menu,
// initialize main menu resources.
@ -1825,7 +1840,6 @@ void LoadGameLevel(bool firstflag, lvl_entry lvldir)
InitStores();
InitAutomapOnce();
InitHelp();
InitText();
}
SetRndSeed(glSeedTbl[currlevel]);

266
Source/engine/render/text_render.cpp

@ -5,196 +5,60 @@
*/
#include "text_render.hpp"
#include <array>
#include <unordered_map>
#include <utility>
#include "DiabloUI/art_draw.h"
#include "DiabloUI/diabloui.h"
#include "DiabloUI/ui_item.h"
#include "cel_render.hpp"
#include "engine.h"
#include "engine/load_cel.hpp"
#include "engine/load_file.hpp"
#include "engine/point.hpp"
#include "palette.h"
#include "utils/display.h"
#include "utils/sdl_compat.h"
namespace devilution {
namespace {
/**
* Maps ASCII character code to font index, as used by the
* small, medium and large sized fonts; which corresponds to smaltext.cel,
* medtexts.cel and bigtgold.cel respectively.
*/
const uint8_t FontIndex[256] = {
// clang-format off
'\0', 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
' ', '!', '\"', '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.', '/',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?',
'@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '[', '\\', ']', '^', '_',
'`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '{', '|', '}', '~', 0x01,
'C', 'u', 'e', 'a', 'a', 'a', 'a', 'c', 'e', 'e', 'e', 'i', 'i', 'i', 'A', 'A',
'E', 'a', 'A', 'o', 'o', 'o', 'u', 'u', 'y', 'O', 'U', 'c', 'L', 'Y', 'P', 'f',
'a', 'i', 'o', 'u', 'n', 'N', 'a', 'o', '?', 0x01, 0x01, 0x01, 0x01, '!', '<', '>',
'o', '+', '2', '3', '\'', 'u', 'P', '.', ',', '1', '0', '>', 0x01, 0x01, 0x01, '?',
'A', 'A', 'A', 'A', 'A', 'A', 'A', 'C', 'E', 'E', 'E', 'E', 'I', 'I', 'I', 'I',
'D', 'N', 'O', 'O', 'O', 'O', 'O', 'X', '0', 'U', 'U', 'U', 'U', 'Y', 'b', 'B',
'a', 'a', 'a', 'a', 'a', 'a', 'a', 'c', 'e', 'e', 'e', 'e', 'i', 'i', 'i', 'i',
'o', 'n', 'o', 'o', 'o', 'o', 'o', '/', '0', 'u', 'u', 'u', 'u', 'y', 'b', 'y',
// clang-format on
};
/** Maps from font index to cel frame number. */
const uint8_t FontFrame[3][128] = {
{
// clang-format off
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 54, 44, 57, 58, 56, 55, 47, 40, 41, 59, 39, 50, 37, 51, 52,
36, 27, 28, 29, 30, 31, 32, 33, 34, 35, 48, 49, 60, 38, 61, 53,
62, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 42, 63, 43, 64, 65,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 40, 66, 41, 67, 0,
// clang-format on
},
{
// clang-format off
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 37, 49, 38, 0, 39, 40, 47, 42, 43, 41, 45, 52, 44, 53, 55,
36, 27, 28, 29, 30, 31, 32, 33, 34, 35, 51, 50, 48, 46, 49, 54,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 42, 0, 43, 0, 0,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 48, 0, 49, 0, 0,
// clang-format on
},
{
// clang-format off
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 37, 49, 38, 0, 39, 40, 47, 42, 43, 41, 45, 52, 44, 53, 55,
36, 27, 28, 29, 30, 31, 32, 33, 34, 35, 51, 50, 0, 46, 0, 54,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 42, 0, 43, 0, 0,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 20, 0, 21, 0, 0,
// clang-format on
},
};
/**
* Maps from cel frame number to character width. Note, the character width
* may be distinct from the frame width, which is the same for every cel frame.
*/
const uint8_t FontKern[3][68] = {
{
// clang-format off
8, 10, 7, 9, 8, 7, 6, 8, 8, 3,
3, 8, 6, 11, 9, 10, 6, 9, 9, 6,
9, 11, 10, 13, 10, 11, 7, 5, 7, 7,
8, 7, 7, 7, 7, 7, 10, 4, 5, 6,
3, 3, 4, 3, 6, 6, 3, 3, 3, 3,
3, 2, 7, 6, 3, 10, 10, 6, 6, 7,
4, 4, 9, 6, 6, 12, 3, 7
// clang-format on
},
{
// clang-format off
5, 15, 10, 13, 14, 10, 9, 13, 11, 5,
5, 11, 10, 16, 13, 16, 10, 15, 12, 10,
14, 17, 17, 22, 17, 16, 11, 5, 11, 11,
11, 10, 11, 11, 11, 11, 15, 5, 10, 18,
15, 8, 6, 6, 7, 10, 9, 6, 10, 10,
5, 5, 5, 5, 11, 12
// clang-format on
},
{
// clang-format off
18, 33, 21, 26, 28, 19, 19, 26, 25, 11,
12, 25, 19, 34, 28, 32, 20, 32, 28, 20,
28, 36, 35, 46, 33, 33, 24, 11, 23, 22,
22, 21, 22, 21, 21, 21, 32, 10, 20, 36,
31, 17, 13, 12, 13, 18, 16, 11, 20, 21,
11, 10, 12, 11, 21, 23
// clang-format on
}
};
std::unordered_map<uint32_t, std::unique_ptr<Art>> Fonts;
enum text_color : uint8_t {
ColorWhite,
ColorBlue,
ColorRed,
ColorGold,
ColorBlack,
};
std::array<std::array<uint8_t, 256>, 5> FontKerns;
std::array<int, 5> FontSizes = { 12, 24, 30, 42, 46 };
std::array<int, 5> LineHeights = { 12, 26, 38, 42, 50 };
std::array<int, 5> BaseLineOffset = { -3, -2, -3, -6, -7 };
int LineHeights[3] = { 12, 38, 50 };
} // namespace
/** Graphics for the fonts */
std::array<std::optional<CelSprite>, 3> fonts;
void LoadFont(GameFontTables size, text_color color, const char *translationFile)
{
auto font = std::make_unique<Art>();
uint8_t fontColorTableGold[256];
uint8_t fontColorTableBlue[256];
uint8_t fontColorTableRed[256];
char path[32];
sprintf(path, "fonts\\%i-00.pcx", FontSizes[size]);
void DrawChar(const Surface &out, Point position, GameFontTables size, int nCel, text_color color)
{
switch (color) {
case ColorWhite:
CelDrawTo(out, position, *fonts[size], nCel);
return;
case ColorBlue:
CelDrawLightTo(out, position, *fonts[size], nCel, fontColorTableBlue);
break;
case ColorRed:
CelDrawLightTo(out, position, *fonts[size], nCel, fontColorTableRed);
break;
case ColorGold:
CelDrawLightTo(out, position, *fonts[size], nCel, fontColorTableGold);
break;
case ColorBlack:
LightTableIndex = 15;
CelDrawLightTo(out, position, *fonts[size], nCel, nullptr);
return;
if (translationFile != nullptr) {
std::array<uint8_t, 256> colorMapping;
LoadFileInMem(translationFile, colorMapping);
LoadMaskedArt(path, font.get(), 256, 1, &colorMapping);
} else {
LoadMaskedArt(path, font.get(), 256, 1);
}
}
} // namespace
uint32_t fontId = (color << 24) | (size << 16);
Fonts.insert(make_pair(fontId, move(font)));
std::optional<CelSprite> pSPentSpn2Cels;
sprintf(path, "fonts\\%i-00.bin", FontSizes[size]);
LoadFileInMem(path, FontKerns[size]);
}
void InitText()
void UnloadFonts()
{
fonts[GameFontSmall] = LoadCel("CtrlPan\\SmalText.CEL", 13);
fonts[GameFontMed] = LoadCel("Data\\MedTextS.CEL", 22);
fonts[GameFontBig] = LoadCel("Data\\BigTGold.CEL", 46);
pSPentSpn2Cels = LoadCel("Data\\PentSpn2.CEL", 12);
for (int i = 0; i < 256; i++) {
uint8_t pix = i;
if (pix >= PAL16_GRAY + 14)
pix = PAL16_BLUE + 15;
else if (pix >= PAL16_GRAY)
pix -= PAL16_GRAY - (PAL16_BLUE + 2);
fontColorTableBlue[i] = pix;
}
for (int i = 0; i < 256; i++) {
uint8_t pix = i;
if (pix >= PAL16_GRAY)
pix -= PAL16_GRAY - PAL16_RED;
fontColorTableRed[i] = pix;
}
for (int i = 0; i < 256; i++) {
uint8_t pix = i;
if (pix >= PAL16_GRAY + 14)
pix = PAL16_YELLOW + 15;
else if (pix >= PAL16_GRAY)
pix -= PAL16_GRAY - (PAL16_YELLOW + 2);
fontColorTableGold[i] = pix;
}
Fonts.clear();
}
int GetLineWidth(string_view text, GameFontTables size, int spacing, int *charactersInLine)
@ -206,8 +70,8 @@ int GetLineWidth(string_view text, GameFontTables size, int spacing, int *charac
if (text[i] == '\n')
break;
uint8_t frame = FontFrame[size][FontIndex[static_cast<uint8_t>(text[i])]];
lineWidth += FontKern[size][frame] + spacing;
uint8_t frame = text[i] & 0xFF;
lineWidth += FontKerns[size][frame] + spacing;
}
if (charactersInLine != nullptr)
@ -227,7 +91,7 @@ int AdjustSpacingToFitHorizontally(int &lineWidth, int maxSpacing, int character
return maxSpacing - spacingRedux;
}
void WordWrapGameString(char *text, size_t width, GameFontTables size, int spacing)
void WordWrapString(char *text, size_t width, GameFontTables size, int spacing)
{
const size_t textLength = strlen(text);
size_t lineStart = 0;
@ -239,8 +103,8 @@ void WordWrapGameString(char *text, size_t width, GameFontTables size, int spaci
continue;
}
uint8_t frame = FontFrame[size][FontIndex[static_cast<uint8_t>(text[i])]];
lineWidth += FontKern[size][frame] + spacing;
uint8_t frame = text[i] & 0xFF;
lineWidth += FontKerns[size][frame] + spacing;
if (lineWidth - spacing <= width) {
continue; // String is still within the limit, continue to the next line
@ -270,17 +134,21 @@ void WordWrapGameString(char *text, size_t width, GameFontTables size, int spaci
/**
* @todo replace Rectangle with cropped Surface
*/
uint16_t DrawString(const Surface &out, string_view text, const Rectangle &rect, UiFlags flags, int spacing, int lineHeight, bool drawTextCursor)
uint32_t DrawString(const Surface &out, string_view text, const Rectangle &rect, UiFlags flags, int spacing, int lineHeight)
{
GameFontTables size = GameFontSmall;
if (HasAnyOf(flags, UiFlags::FontMedium))
size = GameFontMed;
else if (HasAnyOf(flags, UiFlags::FontHuge))
size = GameFontBig;
GameFontTables size = GameFont12;
if (HasAnyOf(flags, UiFlags::FontSize24))
size = GameFont24;
else if (HasAnyOf(flags, UiFlags::FontSize30))
size = GameFont30;
else if (HasAnyOf(flags, UiFlags::FontSize42))
size = GameFont42;
else if (HasAnyOf(flags, UiFlags::FontSize46))
size = GameFont46;
text_color color = ColorGold;
if (HasAnyOf(flags, UiFlags::ColorSilver))
color = ColorWhite;
color = ColorSilver;
else if (HasAnyOf(flags, UiFlags::ColorBlue))
color = ColorBlue;
else if (HasAnyOf(flags, UiFlags::ColorRed))
@ -303,17 +171,31 @@ uint16_t DrawString(const Surface &out, string_view text, const Rectangle &rect,
else if (HasAnyOf(flags, UiFlags::AlignRight))
characterPosition.x += rect.size.width - lineWidth;
int rightMargin = rect.position.x + rect.size.width;
int bottomMargin = rect.size.height != 0 ? rect.position.y + rect.size.height : out.h();
if (lineHeight == -1)
lineHeight = LineHeights[size];
uint16_t i = 0;
if (HasAnyOf(flags, UiFlags::VerticalCenter)) {
int textHeight = (std::count(text.cbegin(), text.cend(), '\n') + 1) * lineHeight;
characterPosition.y += (rect.size.height - textHeight) / 2;
}
characterPosition.y += BaseLineOffset[size];
uint32_t fontId = (color << 24) | (size << 16);
auto font = Fonts.find(fontId);
if (font == Fonts.end()) {
Log("Font: size {} and color {} not loaded ", size, color);
return 0;
}
const auto &activeFont = font->second;
uint32_t i = 0;
for (; i < text.length(); i++) {
uint8_t frame = FontFrame[size][FontIndex[static_cast<uint8_t>(text[i])]];
int symbolWidth = FontKern[size][frame];
if (text[i] == '\n' || characterPosition.x + symbolWidth > rightMargin) {
uint8_t frame = text[i] & 0xFF;
if (text[i] == '\n') {
if (characterPosition.y + lineHeight >= bottomMargin)
break;
characterPosition.y += lineHeight;
@ -330,14 +212,14 @@ uint16_t DrawString(const Surface &out, string_view text, const Rectangle &rect,
else if (HasAnyOf(flags, UiFlags::AlignRight))
characterPosition.x += rect.size.width - lineWidth;
}
if (frame != 0) {
DrawChar(out, characterPosition, size, frame, color);
}
DrawArt(out, characterPosition, activeFont.get(), frame);
if (text[i] != '\n')
characterPosition.x += symbolWidth + spacing;
characterPosition.x += FontKerns[size][frame] + spacing;
}
if (drawTextCursor) {
CelDrawTo(out, characterPosition, *pSPentSpn2Cels, PentSpn2Spin());
if (HasAnyOf(flags, UiFlags::PentaCursor)) {
CelDrawTo(out, characterPosition + Displacement { 0, lineHeight - BaseLineOffset[size] }, *pSPentSpn2Cels, PentSpn2Spin());
} else if (HasAnyOf(flags, UiFlags::TextCursor) && GetAnimationFrame(2, 500) != 0) {
DrawArt(out, characterPosition, activeFont.get(), '|');
}
return i;

33
Source/engine/render/text_render.hpp

@ -19,14 +19,24 @@
namespace devilution {
enum GameFontTables : uint8_t {
GameFontSmall,
GameFontMed,
GameFontBig,
GameFont12,
GameFont24,
GameFont30,
GameFont42,
GameFont46,
};
enum text_color : uint8_t {
ColorSilver,
ColorGold,
ColorRed,
ColorBlue,
ColorBlack,
};
extern std::optional<CelSprite> pSPentSpn2Cels;
void InitText();
void LoadFont(GameFontTables size, text_color color, const char *translationFile = nullptr);
/**
* @brief Calculate pixel width of first line of text, respecting kerning
@ -36,8 +46,8 @@ void InitText();
* @param charactersInLine Receives characters read until newline or terminator
* @return Line width in pixels
*/
int GetLineWidth(string_view text, GameFontTables size = GameFontSmall, int spacing = 1, int *charactersInLine = nullptr);
void WordWrapGameString(char *text, size_t width, GameFontTables size = GameFontSmall, int spacing = 1);
int GetLineWidth(string_view text, GameFontTables size = GameFont12, int spacing = 1, int *charactersInLine = nullptr);
void WordWrapString(char *text, size_t width, GameFontTables size = GameFont12, int spacing = 1);
/**
* @brief Draws a line of text within a clipping rectangle (positioned relative to the origin of the output buffer).
@ -56,16 +66,14 @@ void WordWrapGameString(char *text, size_t width, GameFontTables size = GameFont
* @param spacing Additional space to add between characters.
* This value may be adjusted if the flag UIS_FIT_SPACING is passed in the flags parameter.
* @param lineHeight Allows overriding the default line height, useful for multi-line strings.
* @param drawTextCursor Whether to draw an animated cursor sprite at the end of the text (default is to display nothing).
* @return The number of characters rendered, including characters "drawn" outside the buffer.
*/
uint16_t DrawString(const Surface &out, string_view text, const Rectangle &rect, UiFlags flags = UiFlags::None, int spacing = 1, int lineHeight = -1, bool drawTextCursor = false);
uint32_t DrawString(const Surface &out, string_view text, const Rectangle &rect, UiFlags flags = UiFlags::None, int spacing = 1, int lineHeight = -1);
/**
* @brief Draws a line of text at the given position relative to the origin of the output buffer.
*
* This method is provided as a convenience to pass through to DrawString(..., Rectangle, ...) when no explicit
* clipping/wrapping is requested. Note that this will still wrap the rendered string if it would end up being drawn
* beyond the right edge of the output buffer and clip it if it would extend beyond the bottom edge of the buffer.
*
@ -76,14 +84,13 @@ uint16_t DrawString(const Surface &out, string_view text, const Rectangle &rect,
* @param spacing Additional space to add between characters.
* This value may be adjusted if the flag UIS_FIT_SPACING is passed in the flags parameter.
* @param lineHeight Allows overriding the default line height, useful for multi-line strings.
* @param drawTextCursor Whether to draw an animated cursor sprite at the end of the text (default is to display nothing).
* @return The number of characters rendered (could be less than the string length if it wrapped past the bottom of the buffer).
*/
inline uint16_t DrawString(const Surface &out, string_view text, const Point &position, UiFlags flags = UiFlags::None, int spacing = 1, int lineHeight = -1, bool drawTextCursor = false)
inline void DrawString(const Surface &out, string_view text, const Point &position, UiFlags flags = UiFlags::None, int spacing = 1, int lineHeight = -1)
{
return DrawString(out, text, { position, { out.w() - position.x, 0 } }, flags, spacing, lineHeight, drawTextCursor);
DrawString(out, text, { position, { out.w() - position.x, 0 } }, flags, spacing, lineHeight);
}
uint8_t PentSpn2Spin();
void UnloadFonts();
} // namespace devilution

14
Source/engine/size.hpp

@ -16,6 +16,20 @@ struct Size {
return !(*this == other);
}
constexpr Size &operator*=(const int factor)
{
width *= factor;
height *= factor;
return *this;
}
constexpr Size &operator*=(const float factor)
{
width = static_cast<int>(width * factor);
height = static_cast<int>(height * factor);
return *this;
}
constexpr Size &operator/=(const int factor)
{
width /= factor;

4
Source/error.cpp

@ -35,7 +35,7 @@ void InitNextLines()
char tempstr[1536]; // Longest test is about 768 chars * 2 for unicode
strcpy(tempstr, message.data());
WordWrapGameString(tempstr, LineWidth, GameFontSmall, 1);
WordWrapString(tempstr, LineWidth, GameFont12, 1);
const string_view paragraphs = tempstr;
size_t previous = 0;
@ -172,7 +172,7 @@ void DrawDiabloMsg(const Surface &out)
auto message = DiabloMessages.front();
int lineNumber = 0;
for (auto &line : TextLines) {
DrawString(out, line.c_str(), { { PANEL_X + 109, dialogStartY + 24 + lineNumber * LineHeight }, { LineWidth, LineHeight } }, UiFlags::AlignCenter, 1, LineHeight);
DrawString(out, line.c_str(), { { PANEL_X + 109, dialogStartY + 12 + lineNumber * LineHeight }, { LineWidth, LineHeight } }, UiFlags::AlignCenter, 1, LineHeight);
lineNumber += 1;
}

20
Source/gmenu.cpp

@ -96,7 +96,7 @@ int GmenuGetLineWidth(TMenuItem *pItem)
if ((pItem->dwFlags & GMENU_SLIDER) != 0)
return 490;
return GetLineWidth(_(pItem->pszStr), GameFontBig, 2);
return GetLineWidth(_(pItem->pszStr), GameFont46, 2);
}
void GmenuDrawMenuItem(const Surface &out, TMenuItem *pItem, int y)
@ -104,20 +104,20 @@ void GmenuDrawMenuItem(const Surface &out, TMenuItem *pItem, int y)
int w = GmenuGetLineWidth(pItem);
if ((pItem->dwFlags & GMENU_SLIDER) != 0) {
int x = 16 + w / 2;
CelDrawTo(out, { x + PANEL_LEFT, y - 10 }, *optbar_cel, 1);
CelDrawTo(out, { x + PANEL_LEFT, y + 40 }, *optbar_cel, 1);
uint16_t step = pItem->dwFlags & 0xFFF;
uint16_t steps = std::max<uint16_t>((pItem->dwFlags & 0xFFF000) >> 12, 2);
uint16_t pos = step * 256 / steps;
GmenuClearBuffer(out, x + 2 + PANEL_LEFT, y - 12, pos + 13, 28);
CelDrawTo(out, { x + 2 + pos + PANEL_LEFT, y - 12 }, *option_cel, 1);
GmenuClearBuffer(out, x + 2 + PANEL_LEFT, y + 38, pos + 13, 28);
CelDrawTo(out, { x + 2 + pos + PANEL_LEFT, y + 38 }, *option_cel, 1);
}
int x = (gnScreenWidth - w) / 2;
UiFlags style = (pItem->dwFlags & GMENU_ENABLED) != 0 ? UiFlags::ColorSilver : UiFlags::ColorBlack;
DrawString(out, _(pItem->pszStr), Point { x, y }, style | UiFlags::FontHuge, 2);
UiFlags style = (pItem->dwFlags & GMENU_ENABLED) != 0 ? UiFlags::ColorGold : UiFlags::ColorBlack;
DrawString(out, _(pItem->pszStr), Point { x, y }, style | UiFlags::FontSize46, 2);
if (pItem == sgpCurrItem) {
CelDrawTo(out, { x - 54, y + 1 }, *PentSpin_cel, PentSpn2Spin());
CelDrawTo(out, { x + 4 + w, y + 1 }, *PentSpin_cel, PentSpn2Spin());
CelDrawTo(out, { x - 54, y + 51 }, *PentSpin_cel, PentSpn2Spin());
CelDrawTo(out, { x + 4 + w, y + 51 }, *PentSpin_cel, PentSpn2Spin());
}
}
@ -163,7 +163,7 @@ void gmenu_draw_pause(const Surface &out)
RedBack(out);
if (sgpCurrentMenu == nullptr) {
LightTableIndex = 0;
DrawString(out, _("Pause"), Point { 0, PANEL_TOP / 2 }, UiFlags::FontHuge | UiFlags::AlignCenter, 2);
DrawString(out, _("Pause"), { { 0, 0 }, { gnScreenWidth, PANEL_TOP } }, UiFlags::FontSize46 | UiFlags::AlignCenter | UiFlags::VerticalCenter, 2);
}
}
@ -233,7 +233,7 @@ void gmenu_draw(const Surface &out)
}
}
CelDrawTo(out, { (gnScreenWidth - sgpLogo->Width()) / 2, 102 + UI_OFFSET_Y }, *sgpLogo, LogoAnim_frame);
int y = 160 + UI_OFFSET_Y;
int y = 110 + UI_OFFSET_Y;
TMenuItem *i = sgpCurrentMenu;
if (sgpCurrentMenu->fnMenu != nullptr) {
while (i->fnMenu != nullptr) {

6
Source/help.cpp

@ -106,7 +106,7 @@ void InitHelp()
for (const auto *text : HelpText) {
strcpy(tempString, _(text));
WordWrapGameString(tempString, 577);
WordWrapString(tempString, 577);
const string_view paragraph = tempString;
size_t previous = 0;
@ -137,8 +137,8 @@ void DrawHelp(const Surface &out)
const int sx = PANEL_X + 32;
const int sy = UI_OFFSET_Y + 51;
for (int i = 7; i < 22; i++) {
const char *line = HelpTextLines[i - 7 + SkipLines].c_str();
for (int i = 6; i < 21; i++) {
const char *line = HelpTextLines[i - 6 + SkipLines].c_str();
if (line[0] == '\0') {
continue;
}

2
Source/inv.cpp

@ -1248,7 +1248,7 @@ void DrawInvBelt(const Surface &out)
&& myPlayer.SpdList[i]._iStatFlag
&& myPlayer.SpdList[i]._itype != ITYPE_GOLD) {
snprintf(tempstr, sizeof(tempstr) / sizeof(*tempstr), "%i", i + 1);
DrawString(out, tempstr, { position, InventorySlotSizeInPixels }, UiFlags::ColorSilver | UiFlags::AlignRight);
DrawString(out, tempstr, { position - Displacement { 0, 12 }, InventorySlotSizeInPixels }, UiFlags::ColorSilver | UiFlags::AlignRight);
}
}
}

4
Source/items.cpp

@ -1121,7 +1121,7 @@ int SaveItemPower(Item &item, const ItemPower &power)
bool StringInPanel(const char *str)
{
return GetLineWidth(str, GameFontSmall, 0) < 125;
return GetLineWidth(str, GameFont12, 0) < 125;
}
int PLVal(int pv, int p1, int p2, int minv, int maxv)
@ -4130,7 +4130,7 @@ void DrawUniqueInfo(const Surface &out)
DrawUniqueInfoWindow(GlobalBackBuffer());
Rectangle rect { { 32 + RightPanel.position.x - SPANEL_WIDTH, 44 + RightPanel.position.y + 2 * 12 }, { 257, 0 } };
Rectangle rect { { 32 + RightPanel.position.x - SPANEL_WIDTH, 44 + RightPanel.position.y + 12 }, { 257, 0 } };
const UniqueItem &uitem = UniqueItems[curruitem._iUid];
DrawString(out, _(uitem.UIName), rect, UiFlags::AlignCenter);

6
Source/minitext.cpp

@ -44,7 +44,7 @@ void LoadText(const char *text)
char tempstr[1536]; // Longest test is about 768 chars * 2 for unicode
strcpy(tempstr, text);
WordWrapGameString(tempstr, 543, GameFontMed, 2);
WordWrapString(tempstr, 543, GameFont30);
const string_view paragraphs = tempstr;
size_t previous = 0;
@ -102,7 +102,7 @@ void DrawQTextContent(const Surface &out)
int y = CalculateTextPosition();
const int sx = PANEL_X + 48;
const int sy = LineHeight / 2 - (y % LineHeight);
const int sy = 0 - (y % LineHeight);
const unsigned int skipLines = y / LineHeight;
@ -117,7 +117,7 @@ void DrawQTextContent(const Surface &out)
continue;
}
DrawString(out, line, { { sx, sy + i * LineHeight }, { 543, LineHeight } }, UiFlags::FontMedium, 2);
DrawString(out, line, { { sx, sy + i * LineHeight }, { 543, LineHeight } }, UiFlags::FontSize30);
}
}

12
Source/palette.cpp

@ -160,10 +160,10 @@ void CycleColorsReverse(int from, int to)
} // namespace
void palette_update()
void palette_update(int first, int ncolor)
{
assert(Palette);
if (SDLC_SetSurfaceAndPaletteColors(pal_surface, Palette, system_palette, 0, 256) < 0) {
if (SDLC_SetSurfaceAndPaletteColors(pal_surface, Palette, system_palette, first, ncolor) < 0) {
ErrSdl();
}
pal_surface_palette_version++;
@ -345,7 +345,7 @@ void PaletteFadeOut(int fr)
void palette_update_caves()
{
CycleColors(1, 31);
palette_update();
palette_update(1, 31);
}
void palette_update_crypt()
@ -361,7 +361,7 @@ void palette_update_crypt()
}
if (glowDelay > 0) {
CycleColorsReverse(16, 31);
palette_update();
palette_update(1, 31);
glowDelay++;
} else {
glowDelay = 1;
@ -381,7 +381,7 @@ void palette_update_hive()
}
if (bubbleDelay == 2) {
CycleColorsReverse(9, 15);
palette_update();
palette_update(1, 31);
bubbleDelay = 0;
} else {
bubbleDelay++;
@ -393,7 +393,7 @@ void palette_update_quest_palette(int n)
int i = 32 - n;
logical_palette[i] = orig_palette[i];
ApplyGamma(system_palette, logical_palette, 32);
palette_update();
palette_update(0, 31);
if (sgOptions.Graphics.bBlendedTransparancy) {
// Update blended transparency, but only for the color that was updated
for (int j = 0; j < 256; j++) {

2
Source/palette.h

@ -35,7 +35,7 @@ extern SDL_Color orig_palette[256];
/** Lookup table for transparency */
extern Uint8 paletteTransparencyLookup[256][256];
void palette_update();
void palette_update(int first = 0, int ncolor = 256);
void palette_init();
void LoadPalette(const char *pszFileName, bool blend = true);
void LoadRndLvlPal(dungeon_type l);

240
Source/panels/charpanel.cpp

@ -7,6 +7,7 @@
#include "DiabloUI/art_draw.h"
#include "control.h"
#include "utils/display.h"
#include "engine/render/cel_render.hpp"
#include "engine/render/text_render.hpp"
#include "utils/language.h"
@ -36,17 +37,8 @@ struct PanelEntry {
std::string label;
Point position;
int length;
Displacement labelOffset; // label's offset (end of the label vs the beginning of the stat box)
int labelLength; // max label's length - used for line wrapping
int labelSpacing;
int statSpacing;
bool centered;
/**
* Toggles whether the box should be using the 27px version or 26px.
* Must be set to true for stat boxes or they don't line up with the "spend stat" button
*/
bool high;
std::function<StyledText()> statDisplayFunc; // function responsible for displaying stat
int labelLength; // max label's length - used for line wrapping
std::function<StyledText()> statDisplayFunc = nullptr; // function responsible for displaying stat
};
Player *MyPlayer = &Players[MyPlayerId];
@ -120,112 +112,90 @@ StyledText GetResistInfo(int8_t resist)
}
PanelEntry panelEntries[] = {
{ "", { 13, 14 }, 134, { 0, 0 }, 0, 0, 1, false, false,
{ "", { 9, 14 }, 150, 0,
[]() { return StyledText { UiFlags::ColorSilver, MyPlayer->_pName }; } },
{ N_("Level"), { 57, 52 }, 45, { -3, 0 }, 0, 0, 1, false, false,
[]() { return StyledText { UiFlags::ColorSilver, fmt::format("{:d}", MyPlayer->_pLevel) }; } },
{ "", { 161, 14 }, 149, 0,
[]() { return StyledText { UiFlags::ColorSilver, _(ClassStrTbl[static_cast<std::size_t>(MyPlayer->_pClass)]) }; } },
{ N_("Base"), { 88, 118 }, 33, { 39, 0 }, 0, 0, 0, false, false,
nullptr },
{ N_("Now"), { 135, 118 }, 33, { 39, 0 }, 0, 0, 0, false, false,
nullptr },
{ N_("Level"), { 57, 52 }, 57, 45,
[]() { return StyledText { UiFlags::ColorSilver, fmt::format("{:d}", MyPlayer->_pLevel) }; } },
{ N_("Experience"), { 211, 52 }, 99, 91,
[]() { return StyledText { UiFlags::ColorSilver, fmt::format("{:d}", MyPlayer->_pExperience) }; } },
{ N_("Next level"), { 211, 80 }, 99, 198,
[]() {
if (MyPlayer->_pLevel == MAXCHARLEVEL - 1) {
return StyledText { UiFlags::ColorGold, _("None") };
} else {
return StyledText { UiFlags::ColorSilver, fmt::format("{:d}", MyPlayer->_pNextExper) };
}
} },
{ N_("Strength"), { 88, 137 }, 33, { -3, 0 }, 0, 0, 1, false, true,
{ N_("Base"), { 88, 115 }, 0, 44 },
{ N_("Now"), { 135, 115 }, 0, 44 },
{ N_("Strength"), { 88, 135 }, 45, 76,
[]() { return StyledText { GetBaseStatColor(CharacterAttribute::Strength), fmt::format("{:d}", MyPlayer->_pBaseStr) }; } },
{ N_("Magic"), { 88, 165 }, 33, { -3, 0 }, 0, 0, 1, false, true,
[]() { return StyledText { GetBaseStatColor(CharacterAttribute::Magic), fmt::format("{:d}", MyPlayer->_pBaseMag) }; } },
{ N_("Dexterity"), { 88, 193 }, 33, { -3, 0 }, 0, 0, 1, false, true,
[]() { return StyledText { GetBaseStatColor(CharacterAttribute::Dexterity), fmt::format("{:d}", MyPlayer->_pBaseDex) }; } },
{ N_("Vitality"), { 88, 221 }, 33, { -3, 0 }, 0, 0, 1, false, true,
[]() { return StyledText { GetBaseStatColor(CharacterAttribute::Vitality), fmt::format("{:d}", MyPlayer->_pBaseVit) }; } },
{ "", { 135, 137 }, 33, { 0, 0 }, 0, 0, 1, false, true,
{ "", { 135, 135 }, 45, 0,
[]() { return StyledText { GetCurrentStatColor(CharacterAttribute::Strength), fmt::format("{:d}", MyPlayer->_pStrength) }; } },
{ "", { 135, 165 }, 33, { 0, 0 }, 0, 0, 1, false, true,
{ N_("Magic"), { 88, 163 }, 45, 76,
[]() { return StyledText { GetBaseStatColor(CharacterAttribute::Magic), fmt::format("{:d}", MyPlayer->_pBaseMag) }; } },
{ "", { 135, 163 }, 45, 0,
[]() { return StyledText { GetCurrentStatColor(CharacterAttribute::Magic), fmt::format("{:d}", MyPlayer->_pMagic) }; } },
{ "", { 135, 193 }, 33, { 0, 0 }, 0, 0, 1, false, true,
{ N_("Dexterity"), { 88, 191 }, 45, 76, []() { return StyledText { GetBaseStatColor(CharacterAttribute::Dexterity), fmt::format("{:d}", MyPlayer->_pBaseDex) }; } },
{ "", { 135, 191 }, 45, 0,
[]() { return StyledText { GetCurrentStatColor(CharacterAttribute::Dexterity), fmt::format("{:d}", MyPlayer->_pDexterity) }; } },
{ "", { 135, 221 }, 33, { 0, 0 }, 0, 0, 1, false, true,
{ N_("Vitality"), { 88, 219 }, 45, 76, []() { return StyledText { GetBaseStatColor(CharacterAttribute::Vitality), fmt::format("{:d}", MyPlayer->_pBaseVit) }; } },
{ "", { 135, 219 }, 45, 0,
[]() { return StyledText { GetCurrentStatColor(CharacterAttribute::Vitality), fmt::format("{:d}", MyPlayer->_pVitality) }; } },
{ N_("Points to distribute"), { 88, 250 }, 33, { -3, -5 }, 120, 0, 1, false, false,
{ N_("Points to distribute"), { 88, 248 }, 45, 76,
[]() {
MyPlayer->_pStatPts = std::min(CalcStatDiff(*MyPlayer), MyPlayer->_pStatPts);
return StyledText { UiFlags::ColorRed, (MyPlayer->_pStatPts > 0 ? fmt::format("{:d}", MyPlayer->_pStatPts) : "") };
} },
{ N_("Life"), { 88, 287 }, 33, { -3, 0 }, 0, 0, 1, false, false,
[]() { return StyledText { GetMaxHealthColor(), fmt::format("{:d}", MyPlayer->_pMaxHP >> 6) }; } },
{ "", { 135, 287 }, 33, { 0, 0 }, 0, 0, 1, false, false,
[]() { return StyledText { (MyPlayer->_pHitPoints != MyPlayer->_pMaxHP ? UiFlags::ColorRed : GetMaxHealthColor()), fmt::format("{:d}", MyPlayer->_pHitPoints >> 6) }; } },
{ N_("Mana"), { 88, 315 }, 33, { -3, 0 }, 0, 0, 1, false, false,
[]() { return StyledText { GetMaxManaColor(), fmt::format("{:d}", MyPlayer->_pMaxMana >> 6) }; } },
{ "", { 135, 315 }, 33, { 0, 0 }, 0, 0, 1, false, false,
[]() { return StyledText { (MyPlayer->_pMana != MyPlayer->_pMaxMana ? UiFlags::ColorRed : GetMaxManaColor()), fmt::format("{:d}", MyPlayer->_pMana >> 6) }; } },
{ "", { 161, 14 }, 134, { 0, 0 }, 0, 0, 1, false, false,
[]() { return StyledText { UiFlags::ColorSilver, _(ClassStrTbl[static_cast<std::size_t>(MyPlayer->_pClass)]) }; } },
{ N_("Experience"), { 208, 52 }, 87, { -3, 0 }, 0, 0, 1, false, false,
[]() { return StyledText { UiFlags::ColorSilver, fmt::format("{:d}", MyPlayer->_pExperience) }; } },
{ N_("Next level"), { 208, 80 }, 87, { -3, 0 }, 0, 0, 1, false, false,
[]() {
if (MyPlayer->_pLevel == MAXCHARLEVEL - 1) {
return StyledText { UiFlags::ColorGold, _("None") };
} else {
return StyledText { UiFlags::ColorSilver, fmt::format("{:d}", MyPlayer->_pNextExper) };
}
} },
{ N_("Gold"), { 208, 129 }, 87, { 0, -20 }, 0, 0, 1, true, false,
{ N_("Gold"), { 211, 107 }, 0, 98 },
{ "", { 211, 127 }, 99, 0,
[]() { return StyledText { UiFlags::ColorSilver, fmt::format("{:d}", MyPlayer->_pGold) }; } },
{ N_("Armor class"), { 250, 166 }, 45, { -3, -5 }, 55, 0, 1, false, false,
{ N_("Armor class"), { 253, 163 }, 57, 67,
[]() { return StyledText { GetValueColor(MyPlayer->_pIBonusAC), fmt::format("{:d}", MyPlayer->GetArmor()) }; } },
{ N_("To hit"), { 250, 194 }, 45, { -3, 0 }, 0, 0, 1, false, false,
{ N_("To hit"), { 253, 191 }, 57, 67,
[]() { return StyledText { GetValueColor(MyPlayer->_pIBonusToHit), fmt::format("{:d}%", (MyPlayer->InvBody[INVLOC_HAND_LEFT]._itype == ITYPE_BOW ? MyPlayer->GetRangedToHit() : MyPlayer->GetMeleeToHit())) }; } },
{ N_("Damage"), { 250, 222 }, 45, { -3, 0 }, 0, 0, 0, false, false,
{ N_("Damage"), { 253, 219 }, 57, 67,
[]() {
std::pair<int, int> dmg = GetDamage();
return StyledText { GetValueColor(MyPlayer->_pIBonusDam), fmt::format("{:d}-{:d}", dmg.first, dmg.second) };
} },
{ N_("Resist magic"), { 250, 259 }, 45, { -3, -5 }, 46, 1, 1, false, false,
[]() { return GetResistInfo(MyPlayer->_pMagResist); } },
{ N_("Life"), { 88, 284 }, 45, 76,
[]() { return StyledText { GetMaxHealthColor(), fmt::format("{:d}", MyPlayer->_pMaxHP >> 6) }; } },
{ "", { 135, 284 }, 45, 0,
[]() { return StyledText { (MyPlayer->_pHitPoints != MyPlayer->_pMaxHP ? UiFlags::ColorRed : GetMaxHealthColor()), fmt::format("{:d}", MyPlayer->_pHitPoints >> 6) }; } },
{ N_("Mana"), { 88, 312 }, 45, 76,
[]() { return StyledText { GetMaxManaColor(), fmt::format("{:d}", MyPlayer->_pMaxMana >> 6) }; } },
{ "", { 135, 312 }, 45, 0,
[]() { return StyledText { (MyPlayer->_pMana != MyPlayer->_pMaxMana ? UiFlags::ColorRed : GetMaxManaColor()), fmt::format("{:d}", MyPlayer->_pMana >> 6) }; } },
{ N_("Resist fire"), { 250, 287 }, 45, { -3, -5 }, 46, 1, 1, false, false,
{ N_("Resist magic"), { 253, 256 }, 57, 67,
[]() { return GetResistInfo(MyPlayer->_pMagResist); } },
{ N_("Resist fire"), { 253, 284 }, 57, 67,
[]() { return GetResistInfo(MyPlayer->_pFireResist); } },
{ N_("Resist lightning"), { 250, 315 }, 45, { -3, -5 }, 76, 0, 1, false, false,
{ N_("Resist lightning"), { 253, 313 }, 57, 67,
[]() { return GetResistInfo(MyPlayer->_pLghtResist); } },
};
Art PanelParts[6];
Art PanelBoxLeft;
Art PanelBoxMiddle;
Art PanelBoxRight;
Art PanelFull;
void DrawPanelFieldLow(const Surface &out, Point pos, int len)
{
DrawArt(out, pos, &PanelParts[0]);
pos.x += PanelParts[0].w();
DrawArt(out, pos, &PanelParts[1], 0, len);
pos.x += len;
DrawArt(out, pos, &PanelParts[2]);
}
void DrawPanelFieldHigh(const Surface &out, Point pos, int len)
void DrawPanelField(const Surface &out, Point pos, int len)
{
DrawArt(out, pos, &PanelParts[3]);
pos.x += PanelParts[3].w();
DrawArt(out, pos, &PanelParts[4], 0, len);
DrawArt(out, pos, &PanelBoxLeft);
pos.x += PanelBoxLeft.w();
len -= PanelBoxLeft.w() + PanelBoxRight.w();
DrawArt(out, pos, &PanelBoxMiddle, 0, len);
pos.x += len;
DrawArt(out, pos, &PanelParts[5]);
DrawArt(out, pos, &PanelBoxRight);
}
void DrawShadowString(const Surface &out, const PanelEntry &entry)
@ -235,87 +205,83 @@ void DrawShadowString(const Surface &out, const PanelEntry &entry)
std::string text_tmp = _(entry.label.c_str());
char buffer[32];
int spacing = entry.labelSpacing;
int spacing = 0;
strcpy(buffer, text_tmp.c_str());
if (entry.labelLength > 0)
WordWrapGameString(buffer, entry.labelLength, GameFontSmall, spacing);
WordWrapString(buffer, entry.labelLength, GameFont12, spacing);
std::string text(buffer);
int width = GetLineWidth(text, GameFontSmall, spacing);
Point finalPos = { entry.position + Displacement { 0, 17 } + entry.labelOffset };
if (entry.centered)
width = entry.length;
else
finalPos.x -= width;
UiFlags style = UiFlags::AlignRight;
if (entry.centered) {
style = UiFlags::AlignCenter;
finalPos += Displacement { 7, 0 }; // left border
UiFlags style = UiFlags::VerticalCenter;
Point labelPosition = entry.position;
if (entry.length == 0) {
style |= UiFlags::AlignCenter;
} else {
style |= UiFlags::AlignRight;
labelPosition += Displacement { -entry.labelLength - 3, 0 };
}
DrawString(out, text, { finalPos + Displacement { -2, 2 }, { width, 0 } }, style | UiFlags::ColorBlack, spacing, 10);
DrawString(out, text, { finalPos, { width, 0 } }, style | UiFlags::ColorSilver, spacing, 10);
DrawString(out, text, { labelPosition + Displacement { -2, 2 }, { entry.labelLength, 20 } }, style | UiFlags::ColorBlack, spacing, 10);
DrawString(out, text, { labelPosition, { entry.labelLength, 20 } }, style | UiFlags::ColorSilver, spacing, 10);
}
void DrawStatButtons(const Surface &out)
{
if (MyPlayer->_pStatPts > 0) {
if (MyPlayer->_pBaseStr < MyPlayer->GetMaximumAttributeValue(CharacterAttribute::Strength))
CelDrawTo(out, GetPanelPosition(UiPanels::Character, { 137, 157 }), *pChrButtons, chrbtn[static_cast<size_t>(CharacterAttribute::Strength)] ? 3 : 2);
if (MyPlayer->_pBaseMag < MyPlayer->GetMaximumAttributeValue(CharacterAttribute::Magic))
CelDrawTo(out, GetPanelPosition(UiPanels::Character, { 137, 185 }), *pChrButtons, chrbtn[static_cast<size_t>(CharacterAttribute::Magic)] ? 5 : 4);
if (MyPlayer->_pBaseDex < MyPlayer->GetMaximumAttributeValue(CharacterAttribute::Dexterity))
CelDrawTo(out, GetPanelPosition(UiPanels::Character, { 137, 214 }), *pChrButtons, chrbtn[static_cast<size_t>(CharacterAttribute::Dexterity)] ? 7 : 6);
if (MyPlayer->_pBaseVit < MyPlayer->GetMaximumAttributeValue(CharacterAttribute::Vitality))
CelDrawTo(out, GetPanelPosition(UiPanels::Character, { 137, 242 }), *pChrButtons, chrbtn[static_cast<size_t>(CharacterAttribute::Vitality)] ? 9 : 8);
}
}
} // namespace
void LoadCharPanel()
{
LoadArt("data\\charbg.pcx", &PanelFull);
LoadArt("data\\boxleftend26.pcx", &PanelParts[0]);
LoadArt("data\\boxmiddle26.pcx", &PanelParts[1]);
LoadArt("data\\boxrightend26.pcx", &PanelParts[2]);
LoadArt("data\\boxleftend27.pcx", &PanelParts[3]);
LoadArt("data\\boxmiddle27.pcx", &PanelParts[4]);
LoadArt("data\\boxrightend27.pcx", &PanelParts[5]);
UpdatePalette(&PanelFull); // PanelFull is being used as a render target
LoadArt("data\\boxleftend.pcx", &PanelBoxLeft);
LoadArt("data\\boxmiddle.pcx", &PanelBoxMiddle);
LoadArt("data\\boxrightend.pcx", &PanelBoxRight);
const Surface out(PanelFull.surface.get());
for (auto &entry : panelEntries) {
if (entry.statDisplayFunc != nullptr) {
if (entry.high)
DrawPanelFieldHigh(out, entry.position, entry.length);
else
DrawPanelFieldLow(out, entry.position, entry.length);
DrawPanelField(out, entry.position, entry.length);
}
DrawShadowString(out, entry);
}
for (auto &gfx : PanelParts) {
gfx.Unload();
}
PanelBoxLeft.Unload();
PanelBoxMiddle.Unload();
PanelBoxRight.Unload();
}
bool CharPanelLoaded = false;
void DrawStatButtons(const Surface &out)
void FreeCharPanel()
{
if (MyPlayer->_pStatPts > 0) {
if (MyPlayer->_pBaseStr < MyPlayer->GetMaximumAttributeValue(CharacterAttribute::Strength))
CelDrawTo(out, GetPanelPosition(UiPanels::Character, { 137, 159 }), *pChrButtons, chrbtn[static_cast<size_t>(CharacterAttribute::Strength)] ? 3 : 2);
if (MyPlayer->_pBaseMag < MyPlayer->GetMaximumAttributeValue(CharacterAttribute::Magic))
CelDrawTo(out, GetPanelPosition(UiPanels::Character, { 137, 187 }), *pChrButtons, chrbtn[static_cast<size_t>(CharacterAttribute::Magic)] ? 5 : 4);
if (MyPlayer->_pBaseDex < MyPlayer->GetMaximumAttributeValue(CharacterAttribute::Dexterity))
CelDrawTo(out, GetPanelPosition(UiPanels::Character, { 137, 216 }), *pChrButtons, chrbtn[static_cast<size_t>(CharacterAttribute::Dexterity)] ? 7 : 6);
if (MyPlayer->_pBaseVit < MyPlayer->GetMaximumAttributeValue(CharacterAttribute::Vitality))
CelDrawTo(out, GetPanelPosition(UiPanels::Character, { 137, 244 }), *pChrButtons, chrbtn[static_cast<size_t>(CharacterAttribute::Vitality)] ? 9 : 8);
}
PanelFull.Unload();
}
} // namespace
void DrawChr(const Surface &out)
{
if (!CharPanelLoaded) {
LoadCharPanel();
CharPanelLoaded = true;
}
Point pos = GetPanelPosition(UiPanels::Character, { 0, 0 });
DrawArt(out, pos, &PanelFull);
for (auto &entry : panelEntries) {
if (entry.statDisplayFunc != nullptr) {
StyledText tmp = entry.statDisplayFunc();
Displacement displacement = Displacement { pos.x + 7, pos.y + 17 };
if (entry.high)
displacement += { 0, 1 };
DrawString(out, tmp.text.c_str(), { entry.position + displacement, { entry.length, 0 } }, UiFlags::AlignCenter | tmp.style, entry.statSpacing);
DrawString(
out,
tmp.text.c_str(),
{ entry.position + Displacement { pos.x, pos.y }, { entry.length, 27 } },
UiFlags::AlignCenter | UiFlags::VerticalCenter | tmp.style,
1);
}
}
DrawStatButtons(out);

2
Source/panels/charpanel.hpp

@ -10,5 +10,7 @@ extern std::optional<CelSprite> pChrButtons;
extern const char *const ClassStrTbl[];
void DrawChr(const Surface &);
void LoadCharPanel();
void FreeCharPanel();
} // namespace devilution

4
Source/plrmsg.cpp

@ -31,7 +31,7 @@ void PrintChatMessage(const Surface &out, int x, int y, int width, char *text, U
if (text[i] == '\n')
text[i] = ' ';
}
WordWrapGameString(text, width);
WordWrapString(text, width);
DrawString(out, text, { { x, y }, { width, 0 } }, style, 1, 10);
}
@ -109,7 +109,7 @@ void InitPlrMsg()
void DrawPlrMsg(const Surface &out)
{
DWORD x = 10;
DWORD y = 70;
DWORD y = 58;
DWORD width = gnScreenWidth - 20;
_plrmsg *pMsg;

8
Source/qol/itemlabels.cpp

@ -88,7 +88,7 @@ void AddItemToLabelQueue(int id, int x, int y)
y *= 2;
}
x -= nameWidth / 2;
labelQueue.push_back(ItemLabel { id, nameWidth, { x, y }, textOnGround });
labelQueue.push_back(ItemLabel { id, nameWidth, { x, y - Height }, textOnGround });
}
bool IsMouseOverGameArea()
@ -148,7 +148,7 @@ void DrawItemNameLabels(const Surface &out)
for (const ItemLabel &label : labelQueue) {
Item &item = Items[label.id];
if (MousePosition.x >= label.pos.x && MousePosition.x < label.pos.x + label.width && MousePosition.y >= label.pos.y - Height + MarginY && MousePosition.y < label.pos.y + MarginY) {
if (MousePosition.x >= label.pos.x && MousePosition.x < label.pos.x + label.width && MousePosition.y >= label.pos.y + MarginY && MousePosition.y < label.pos.y + MarginY + Height) {
if (!gmenu_is_active() && PauseMode == 0 && !MyPlayerIsDead && IsMouseOverGameArea()) {
isLabelHighlighted = true;
cursPosition = item.position;
@ -156,9 +156,9 @@ void DrawItemNameLabels(const Surface &out)
}
}
if (pcursitem == label.id)
FillRect(out, label.pos.x, label.pos.y - Height + MarginY, label.width, Height, PAL8_BLUE + 6);
FillRect(out, label.pos.x, label.pos.y + MarginY, label.width, Height, PAL8_BLUE + 6);
else
DrawHalfTransparentRectTo(out, label.pos.x, label.pos.y - Height + MarginY, label.width, Height);
DrawHalfTransparentRectTo(out, label.pos.x, label.pos.y + MarginY, label.width, Height);
DrawString(out, label.text, { { label.pos.x + MarginX, label.pos.y }, { label.width, Height } }, item.getTextColor());
}
labelQueue.clear();

14
Source/qol/monhealthbar.cpp

@ -109,14 +109,16 @@ void DrawMonsterHealthBar(const Surface &out)
UnsafeDrawVerticalLine(out, { position.x + width - border - 1, position.y + border + 1 }, borderHeight, borderColor);
}
int barLabelY = position.y + 10 + (height - 11) / 2;
DrawString(out, monster.mName, { position.x - 1, barLabelY + 1, width, height }, UiFlags::AlignCenter | UiFlags::ColorBlack);
UiFlags style = UiFlags::ColorSilver;
int barLabelY = position.y;
UiFlags style = UiFlags::AlignCenter | UiFlags::VerticalCenter;
DrawString(out, monster.mName, { position + Displacement { -1, 1 }, width, height }, style | UiFlags::ColorBlack);
if (monster._uniqtype != 0)
style = UiFlags::ColorGold;
style |= UiFlags::ColorGold;
else if (monster.leader != 0)
style = UiFlags::ColorBlue;
DrawString(out, monster.mName, { position.x, barLabelY, width, height }, UiFlags::AlignCenter | style);
style |= UiFlags::ColorBlue;
else
style |= UiFlags::ColorSilver;
DrawString(out, monster.mName, { position, width, height }, style);
if (monster._uniqtype != 0 || MonsterKillCounts[monster.MType->mtype] >= 15) {
monster_resistance immunes[] = { IMMUNE_MAGIC, IMMUNE_FIRE, IMMUNE_LIGHTNING };

9
Source/quests.cpp

@ -276,14 +276,13 @@ int QuestLogMouseToEntry()
void PrintQLString(const Surface &out, int x, int y, const char *str, bool marked, bool disabled = false)
{
int width = GetLineWidth(str);
int sx = x + std::max((257 - width) / 2, 0);
int sy = y + lineHeight; //seems that DrawString y is the text base line -> so add a lines height
x += std::max((257 - width) / 2, 0);
if (marked) {
CelDrawTo(out, GetPanelPosition(UiPanels::Quest, { sx - 20, sy + 1 }), *pSPentSpn2Cels, PentSpn2Spin());
CelDrawTo(out, GetPanelPosition(UiPanels::Quest, { x - 20, y + 13 }), *pSPentSpn2Cels, PentSpn2Spin());
}
DrawString(out, str, { GetPanelPosition(UiPanels::Quest, { sx, sy }), { 257, 0 } }, disabled ? UiFlags::ColorGold : UiFlags::ColorSilver);
DrawString(out, str, { GetPanelPosition(UiPanels::Quest, { x, y }), { 257, 0 } }, disabled ? UiFlags::ColorGold : UiFlags::ColorSilver);
if (marked) {
CelDrawTo(out, GetPanelPosition(UiPanels::Quest, { sx + width + 7, sy + 1 }), *pSPentSpn2Cels, PentSpn2Spin());
CelDrawTo(out, GetPanelPosition(UiPanels::Quest, { x + width + 7, y + 13 }), *pSPentSpn2Cels, PentSpn2Spin());
}
}

30
Source/scrollrt.cpp

@ -1206,21 +1206,15 @@ void DrawView(const Surface &out, Point startPosition)
for (auto m : DebugCoordsMap) {
Point dunCoords = { m.first % MAXDUNX, m.first / MAXDUNX };
Point pixelCoords = m.second;
Displacement ver = { 0, -TILE_HEIGHT / 2 };
Displacement hor = { TILE_WIDTH / 2, 0 };
if (!zoomflag) {
if (!zoomflag)
pixelCoords *= 2;
hor *= 2;
ver *= 2;
}
Point center = pixelCoords + hor + ver;
if (DebugCoords || (DebugCursorCoords && dunCoords == cursPosition)) {
char coordstr[10];
sprintf(coordstr, "%d:%d", dunCoords.x, dunCoords.y);
int textWidth = GetLineWidth(coordstr);
int textHeight = 12;
Point position = center + Displacement { -textWidth / 2, textHeight / 2 };
DrawString(out, coordstr, { position, { textWidth, textHeight } }, UiFlags::ColorRed);
Size tileSize = { TILE_WIDTH, TILE_HEIGHT };
if (!zoomflag)
tileSize *= 2;
DrawString(out, coordstr, { pixelCoords - Displacement { 0, tileSize.height }, tileSize }, UiFlags::ColorRed | UiFlags::AlignCenter | UiFlags::VerticalCenter);
}
if (DebugGrid) {
auto DrawLine = [&out](Point from, Point to, uint8_t col) {
@ -1236,11 +1230,19 @@ void DrawView(const Surface &out, Point startPosition)
out.SetPixel({ (int)sx, (int)sy }, col);
};
Displacement hor = { TILE_WIDTH / 2, 0 };
Displacement ver = { 0, TILE_HEIGHT / 2 };
if (!zoomflag) {
hor *= 2;
ver *= 2;
}
Point center = pixelCoords + hor - ver;
uint8_t col = PAL16_BEIGE;
DrawLine(center - hor, center - ver, col);
DrawLine(center + hor, center - ver, col);
DrawLine(center - hor, center + ver, col);
DrawLine(center + hor, center + ver, col);
DrawLine(center - hor, center - ver, col);
DrawLine(center + hor, center - ver, col);
}
}
}
@ -1321,7 +1323,7 @@ void DrawFPS(const Surface &out)
frameend = 0;
}
snprintf(string, 12, "%i FPS", framerate);
DrawString(out, string, Point { 8, 65 }, UiFlags::ColorRed);
DrawString(out, string, Point { 8, 53 }, UiFlags::ColorRed);
}
/**

8
Source/stores.cpp

@ -24,6 +24,7 @@ namespace devilution {
Item golditem;
std::optional<CelSprite> pSPentSpn2Cels;
std::optional<CelSprite> pSTextBoxCels;
std::optional<CelSprite> pSTextSlidCels;
@ -2163,13 +2164,13 @@ void DrawSelector(const Surface &out, const Rectangle &rect, const char *text, U
if (HasAnyOf(flags, UiFlags::AlignCenter))
x1 += (rect.size.width - lineWidth) / 2;
CelDrawTo(out, { x1, rect.position.y + 1 }, *pSPentSpn2Cels, PentSpn2Spin());
CelDrawTo(out, { x1, rect.position.y + 13 }, *pSPentSpn2Cels, PentSpn2Spin());
int x2 = rect.position.x + rect.size.width + 5;
if (HasAnyOf(flags, UiFlags::AlignCenter))
x2 = rect.position.x + (rect.size.width - lineWidth) / 2 + lineWidth + 5;
CelDrawTo(out, { x2, rect.position.y + 1 }, *pSPentSpn2Cels, PentSpn2Spin());
CelDrawTo(out, { x2, rect.position.y + 13 }, *pSPentSpn2Cels, PentSpn2Spin());
}
} // namespace
@ -2199,6 +2200,7 @@ void AddStoreHoldRepair(Item *itm, int8_t i)
void InitStores()
{
pSPentSpn2Cels = LoadCel("Data\\PentSpn2.CEL", 12);
pSTextBoxCels = LoadCel("Data\\TextBox2.CEL", 271);
pSTextSlidCels = LoadCel("Data\\TextSlid.CEL", 12);
ClearSText(0, STORE_LINES);
@ -2250,7 +2252,7 @@ void PrintSString(const Surface &out, int margin, int line, const char *text, Ui
sx += 320;
}
int sy = UI_OFFSET_Y + 44 + line * 12 + stext[line]._syoff;
int sy = UI_OFFSET_Y + 32 + line * 12 + stext[line]._syoff;
int width = stextsize ? 575 : 255;
if (stextscrl && line >= 4 && line <= 20) {

Loading…
Cancel
Save