Browse Source

Difficulty indicator improvements (#5224)

* Difficulty indicator improvements

1. Clean up positioning code.
2. Do not show for non-save portraits.
3. Remove `vecDifficultyIndicators` - render the items on the fly instead
pull/5226/head
Gleb Mazovetskiy 4 years ago committed by GitHub
parent
commit
b881468c04
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 12
      Source/DiabloUI/button.cpp
  2. 2
      Source/DiabloUI/button.h
  3. 168
      Source/DiabloUI/diabloui.cpp
  4. 1
      Source/DiabloUI/diabloui.h
  5. 73
      Source/DiabloUI/scrollbar.h
  6. 29
      Source/DiabloUI/selhero.cpp

12
Source/DiabloUI/button.cpp

@ -34,17 +34,17 @@ ClxSprite ButtonSprite(bool pressed)
return (*ButtonSprites)[pressed ? 1 : 0];
}
void RenderButton(UiButton *button)
void RenderButton(const UiButton &button)
{
const Surface &out = Surface(DiabloUiSurface()).subregion(button->m_rect.x, button->m_rect.y, button->m_rect.w, button->m_rect.h);
RenderClxSprite(out, ButtonSprite(button->IsPressed()), { 0, 0 });
const Surface &out = Surface(DiabloUiSurface()).subregion(button.m_rect.x, button.m_rect.y, button.m_rect.w, button.m_rect.h);
RenderClxSprite(out, ButtonSprite(button.IsPressed()), { 0, 0 });
Rectangle textRect { { 0, 0 }, { button->m_rect.w, button->m_rect.h } };
if (!button->IsPressed()) {
Rectangle textRect { { 0, 0 }, { button.m_rect.w, button.m_rect.h } };
if (!button.IsPressed()) {
--textRect.position.y;
}
DrawString(out, button->GetText(), textRect, UiFlags::AlignCenter | UiFlags::FontSizeDialog | UiFlags::ColorDialogWhite);
DrawString(out, button.GetText(), textRect, UiFlags::AlignCenter | UiFlags::FontSizeDialog | UiFlags::ColorDialogWhite);
}
bool HandleMouseEventButton(const SDL_Event &event, UiButton *button)

2
Source/DiabloUI/button.h

@ -11,7 +11,7 @@ const Uint16 DialogButtonHeight = 28;
void LoadDialogButtonGraphics();
void FreeDialogButtonGraphics();
ClxSprite ButtonSprite(bool pressed);
void RenderButton(UiButton *button);
void RenderButton(const UiButton &button);
bool HandleMouseEventButton(const SDL_Event &event, UiButton *button);
void HandleGlobalMouseUpButton(UiButton *button);

168
Source/DiabloUI/diabloui.cpp

@ -563,8 +563,8 @@ void LoadUiGFX()
} else {
ArtLogo = LoadPcxSpriteList("ui_art\\smlogo.pcx", /*numFrames=*/15, /*transparentColor=*/250);
}
DifficultyIndicator[0] = LoadPcx("ui_art\\radio1.pcx");
DifficultyIndicator[1] = LoadPcx("ui_art\\radio3.pcx");
DifficultyIndicator[0] = LoadPcx("ui_art\\radio1.pcx", /*transparentColor=*/0);
DifficultyIndicator[1] = LoadPcx("ui_art\\radio3.pcx", /*transparentColor=*/0);
ArtFocus[FOCUS_SMALL] = LoadPcxSpriteList("ui_art\\focus16.pcx", /*numFrames=*/8, /*transparentColor=*/250);
ArtFocus[FOCUS_MED] = LoadPcxSpriteList("ui_art\\focus.pcx", /*numFrames=*/8, /*transparentColor=*/250);
ArtFocus[FOCUS_BIG] = LoadPcxSpriteList("ui_art\\focus42.pcx", /*numFrames=*/8, /*transparentColor=*/250);
@ -793,75 +793,75 @@ void UiPollAndRender(std::function<bool(SDL_Event &)> eventHandler)
namespace {
void Render(const UiText *uiText)
void Render(const UiText &uiText)
{
const Surface &out = Surface(DiabloUiSurface());
DrawString(out, uiText->GetText(), MakeRectangle(uiText->m_rect), uiText->GetFlags() | UiFlags::FontSizeDialog);
DrawString(out, uiText.GetText(), MakeRectangle(uiText.m_rect), uiText.GetFlags() | UiFlags::FontSizeDialog);
}
void Render(const UiArtText *uiArtText)
void Render(const UiArtText &uiArtText)
{
const Surface &out = Surface(DiabloUiSurface());
DrawString(out, uiArtText->GetText(), MakeRectangle(uiArtText->m_rect), uiArtText->GetFlags(), uiArtText->GetSpacing(), uiArtText->GetLineHeight());
DrawString(out, uiArtText.GetText(), MakeRectangle(uiArtText.m_rect), uiArtText.GetFlags(), uiArtText.GetSpacing(), uiArtText.GetLineHeight());
}
void Render(const UiImageClx *uiImage)
void Render(const UiImageClx &uiImage)
{
ClxSprite sprite = uiImage->sprite();
int x = uiImage->m_rect.x;
if (uiImage->isCentered()) {
x += GetCenterOffset(sprite.width(), uiImage->m_rect.w);
ClxSprite sprite = uiImage.sprite();
int x = uiImage.m_rect.x;
if (uiImage.isCentered()) {
x += GetCenterOffset(sprite.width(), uiImage.m_rect.w);
}
RenderClxSprite(Surface(DiabloUiSurface()), sprite, { x, uiImage->m_rect.y });
RenderClxSprite(Surface(DiabloUiSurface()), sprite, { x, uiImage.m_rect.y });
}
void Render(const UiImageAnimatedClx *uiImage)
void Render(const UiImageAnimatedClx &uiImage)
{
ClxSprite sprite = uiImage->sprite(GetAnimationFrame(uiImage->numFrames()));
int x = uiImage->m_rect.x;
if (uiImage->isCentered()) {
x += GetCenterOffset(sprite.width(), uiImage->m_rect.w);
ClxSprite sprite = uiImage.sprite(GetAnimationFrame(uiImage.numFrames()));
int x = uiImage.m_rect.x;
if (uiImage.isCentered()) {
x += GetCenterOffset(sprite.width(), uiImage.m_rect.w);
}
RenderClxSprite(Surface(DiabloUiSurface()), sprite, { x, uiImage->m_rect.y });
RenderClxSprite(Surface(DiabloUiSurface()), sprite, { x, uiImage.m_rect.y });
}
void Render(const UiArtTextButton *uiButton)
void Render(const UiArtTextButton &uiButton)
{
const Surface &out = Surface(DiabloUiSurface());
DrawString(out, uiButton->GetText(), MakeRectangle(uiButton->m_rect), uiButton->GetFlags());
DrawString(out, uiButton.GetText(), MakeRectangle(uiButton.m_rect), uiButton.GetFlags());
}
void Render(const UiList *uiList)
void Render(const UiList &uiList)
{
const Surface &out = Surface(DiabloUiSurface());
for (std::size_t i = listOffset; i < uiList->m_vecItems.size() && (i - listOffset) < ListViewportSize; ++i) {
SDL_Rect rect = uiList->itemRect(i - listOffset);
const UiListItem *item = uiList->GetItem(i);
for (std::size_t i = listOffset; i < uiList.m_vecItems.size() && (i - listOffset) < ListViewportSize; ++i) {
SDL_Rect rect = uiList.itemRect(i - listOffset);
const UiListItem &item = *uiList.GetItem(i);
if (i == SelectedItem)
DrawSelector(rect);
Rectangle rectangle = MakeRectangle(rect);
if (item->args.empty())
DrawString(out, item->m_text, rectangle, uiList->GetFlags() | item->uiFlags, uiList->GetSpacing());
if (item.args.empty())
DrawString(out, item.m_text, rectangle, uiList.GetFlags() | item.uiFlags, uiList.GetSpacing());
else
DrawStringWithColors(out, item->m_text, item->args, rectangle, uiList->GetFlags() | item->uiFlags, uiList->GetSpacing());
DrawStringWithColors(out, item.m_text, item.args, rectangle, uiList.GetFlags() | item.uiFlags, uiList.GetSpacing());
}
}
void Render(const UiScrollbar *uiSb)
void Render(const UiScrollbar &uiSb)
{
const Surface out = Surface(DiabloUiSurface());
// Bar background (tiled):
{
const int bgY = uiSb->m_rect.y + uiSb->m_arrow[0].height();
const int bgY = uiSb.m_rect.y + uiSb.m_arrow[0].height();
const int bgH = DownArrowRect(uiSb).y - bgY;
const Surface backgroundOut = out.subregion(uiSb->m_rect.x, bgY, SCROLLBAR_BG_WIDTH, bgH);
const Surface backgroundOut = out.subregion(uiSb.m_rect.x, bgY, ScrollBarBgWidth, bgH);
int y = 0;
while (y < bgH) {
RenderClxSprite(backgroundOut, uiSb->m_bg, { 0, y });
y += uiSb->m_bg.height();
RenderClxSprite(backgroundOut, uiSb.m_bg, { 0, y });
y += uiSb.m_bg.height();
}
}
@ -869,65 +869,30 @@ void Render(const UiScrollbar *uiSb)
{
const SDL_Rect rect = UpArrowRect(uiSb);
const auto frame = static_cast<uint16_t>(scrollBarState.upArrowPressed ? ScrollBarArrowFrame_UP_ACTIVE : ScrollBarArrowFrame_UP);
RenderClxSprite(out.subregion(rect.x, 0, SCROLLBAR_ARROW_WIDTH, out.h()), uiSb->m_arrow[frame], { 0, rect.y });
RenderClxSprite(out.subregion(rect.x, 0, ScrollBarArrowWidth, out.h()), uiSb.m_arrow[frame], { 0, rect.y });
}
{
const SDL_Rect rect = DownArrowRect(uiSb);
const auto frame = static_cast<uint16_t>(scrollBarState.downArrowPressed ? ScrollBarArrowFrame_DOWN_ACTIVE : ScrollBarArrowFrame_DOWN);
RenderClxSprite(out.subregion(rect.x, 0, SCROLLBAR_ARROW_WIDTH, out.h()), uiSb->m_arrow[frame], { 0, rect.y });
RenderClxSprite(out.subregion(rect.x, 0, ScrollBarArrowWidth, out.h()), uiSb.m_arrow[frame], { 0, rect.y });
}
// Thumb:
if (SelectedItemMax > 0) {
const SDL_Rect rect = ThumbRect(uiSb, SelectedItem, SelectedItemMax + 1);
RenderClxSprite(out, uiSb->m_thumb, { rect.x, rect.y });
RenderClxSprite(out, uiSb.m_thumb, { rect.x, rect.y });
}
}
void Render(const UiEdit *uiEdit)
void Render(const UiEdit &uiEdit)
{
DrawSelector(uiEdit->m_rect);
DrawSelector(uiEdit.m_rect);
// To simulate padding we inset the region used to draw text in an edit control
Rectangle rect = MakeRectangle(uiEdit->m_rect).inset({ 43, 1 });
Rectangle rect = MakeRectangle(uiEdit.m_rect).inset({ 43, 1 });
const Surface &out = Surface(DiabloUiSurface());
DrawString(out, uiEdit->m_value, rect, uiEdit->GetFlags() | UiFlags::TextCursor);
}
void RenderItem(UiItemBase *item)
{
if (item->IsHidden())
return;
switch (item->GetType()) {
case UiType::Text:
Render(static_cast<UiText *>(item));
break;
case UiType::ArtText:
Render(static_cast<UiArtText *>(item));
break;
case UiType::ImageClx:
Render(static_cast<UiImageClx *>(item));
break;
case UiType::ImageAnimatedClx:
Render(static_cast<UiImageAnimatedClx *>(item));
break;
case UiType::ArtTextButton:
Render(static_cast<UiArtTextButton *>(item));
break;
case UiType::Button:
RenderButton(static_cast<UiButton *>(item));
break;
case UiType::List:
Render(static_cast<UiList *>(item));
break;
case UiType::Scrollbar:
Render(static_cast<UiScrollbar *>(item));
break;
case UiType::Edit:
Render(static_cast<UiEdit *>(item));
break;
}
DrawString(out, uiEdit.m_value, rect, uiEdit.GetFlags() | UiFlags::TextCursor);
}
bool HandleMouseEventArtTextButton(const SDL_Event &event, const UiArtTextButton *uiButton)
@ -989,18 +954,18 @@ bool HandleMouseEventScrollBar(const SDL_Event &event, const UiScrollbar *uiSb)
if (event.button.button != SDL_BUTTON_LEFT)
return false;
if (event.type == SDL_MOUSEBUTTONUP) {
if (scrollBarState.upArrowPressed && IsInsideRect(event, UpArrowRect(uiSb))) {
if (scrollBarState.upArrowPressed && IsInsideRect(event, UpArrowRect(*uiSb))) {
UiFocusUp();
return true;
}
if (scrollBarState.downArrowPressed && IsInsideRect(event, DownArrowRect(uiSb))) {
if (scrollBarState.downArrowPressed && IsInsideRect(event, DownArrowRect(*uiSb))) {
UiFocusDown();
return true;
}
} else if (event.type == SDL_MOUSEBUTTONDOWN) {
if (IsInsideRect(event, BarRect(uiSb))) {
if (IsInsideRect(event, BarRect(*uiSb))) {
// Scroll up or down based on thumb position.
const SDL_Rect thumbRect = ThumbRect(uiSb, SelectedItem, SelectedItemMax + 1);
const SDL_Rect thumbRect = ThumbRect(*uiSb, SelectedItem, SelectedItemMax + 1);
if (event.button.y < thumbRect.y) {
UiFocusPageUp();
} else if (event.button.y > thumbRect.y + thumbRect.h) {
@ -1008,11 +973,11 @@ bool HandleMouseEventScrollBar(const SDL_Event &event, const UiScrollbar *uiSb)
}
return true;
}
if (IsInsideRect(event, UpArrowRect(uiSb))) {
if (IsInsideRect(event, UpArrowRect(*uiSb))) {
scrollBarState.upArrowPressed = true;
return true;
}
if (IsInsideRect(event, DownArrowRect(uiSb))) {
if (IsInsideRect(event, DownArrowRect(*uiSb))) {
scrollBarState.downArrowPressed = true;
return true;
}
@ -1047,16 +1012,51 @@ void LoadPalInMem(const SDL_Color *pPal)
}
}
void UiRenderItem(const UiItemBase &item)
{
if (item.IsHidden())
return;
switch (item.GetType()) {
case UiType::Text:
Render(static_cast<const UiText &>(item));
break;
case UiType::ArtText:
Render(static_cast<const UiArtText &>(item));
break;
case UiType::ImageClx:
Render(static_cast<const UiImageClx &>(item));
break;
case UiType::ImageAnimatedClx:
Render(static_cast<const UiImageAnimatedClx &>(item));
break;
case UiType::ArtTextButton:
Render(static_cast<const UiArtTextButton &>(item));
break;
case UiType::Button:
RenderButton(static_cast<const UiButton &>(item));
break;
case UiType::List:
Render(static_cast<const UiList &>(item));
break;
case UiType::Scrollbar:
Render(static_cast<const UiScrollbar &>(item));
break;
case UiType::Edit:
Render(static_cast<const UiEdit &>(item));
break;
}
}
void UiRenderItems(const std::vector<UiItemBase *> &items)
{
for (const auto &item : items)
RenderItem(item);
for (const UiItemBase *item : items)
UiRenderItem(*item);
}
void UiRenderItems(const std::vector<std::unique_ptr<UiItemBase>> &items)
{
for (const auto &item : items)
RenderItem(item.get());
for (const std::unique_ptr<UiItemBase> &item : items)
UiRenderItem(*item);
}
bool UiItemMouseEvents(SDL_Event *event, const std::vector<UiItemBase *> &items)

1
Source/DiabloUI/diabloui.h

@ -104,6 +104,7 @@ void UiFocusNavigationYesNo();
void UiInitList(void (*fnFocus)(int value), void (*fnSelect)(int value), void (*fnEsc)(), const std::vector<std::unique_ptr<UiItemBase>> &items, bool wraps = false, void (*fnFullscreen)() = nullptr, bool (*fnYesNo)() = nullptr, size_t selectedItem = 0);
void UiClearScreen();
void UiPollAndRender(std::function<bool(SDL_Event &)> eventHandler = nullptr);
void UiRenderItem(const UiItemBase &item);
void UiRenderItems(const std::vector<UiItemBase *> &items);
void UiRenderItems(const std::vector<std::unique_ptr<UiItemBase>> &items);
void UiInitList_clear();

73
Source/DiabloUI/scrollbar.h

@ -4,13 +4,14 @@
#include "DiabloUI/ui_item.h"
#include "engine/clx_sprite.hpp"
#include "utils/sdl_geometry.h"
namespace devilution {
extern OptionalOwnedClxSpriteList ArtScrollBarBackground;
extern OptionalOwnedClxSpriteList ArtScrollBarThumb;
extern OptionalOwnedClxSpriteList ArtScrollBarArrow;
const Uint16 SCROLLBAR_BG_WIDTH = 25;
constexpr Uint16 ScrollBarBgWidth = 25;
enum ScrollBarArrowFrame : uint8_t {
ScrollBarArrowFrame_UP_ACTIVE,
@ -19,59 +20,51 @@ enum ScrollBarArrowFrame : uint8_t {
ScrollBarArrowFrame_DOWN,
};
const Uint16 SCROLLBAR_ARROW_WIDTH = 25;
constexpr Uint16 ScrollBarArrowWidth = 25;
inline SDL_Rect UpArrowRect(const UiScrollbar *sb)
inline SDL_Rect UpArrowRect(const UiScrollbar &bar)
{
SDL_Rect Tmp;
Tmp.x = sb->m_rect.x;
Tmp.y = sb->m_rect.y;
Tmp.w = SCROLLBAR_ARROW_WIDTH;
Tmp.h = static_cast<Uint16>(sb->m_arrow[0].height());
return Tmp;
return MakeSdlRect(
bar.m_rect.x,
bar.m_rect.y,
ScrollBarArrowWidth,
bar.m_arrow[0].height());
}
inline SDL_Rect DownArrowRect(const UiScrollbar *sb)
inline SDL_Rect DownArrowRect(const UiScrollbar &bar)
{
SDL_Rect Tmp;
Tmp.x = sb->m_rect.x;
Tmp.y = static_cast<Sint16>(sb->m_rect.y + sb->m_rect.h - sb->m_arrow[0].height());
Tmp.w = SCROLLBAR_ARROW_WIDTH,
Tmp.h = static_cast<Uint16>(sb->m_arrow[0].height());
return Tmp;
return MakeSdlRect(
bar.m_rect.x,
bar.m_rect.y + bar.m_rect.h - bar.m_arrow[0].height(),
ScrollBarArrowWidth,
bar.m_arrow[0].height());
}
inline Uint16 BarHeight(const UiScrollbar *sb)
inline Uint16 BarHeight(const UiScrollbar &bar)
{
return sb->m_rect.h - 2 * sb->m_arrow[0].height();
return bar.m_rect.h - 2 * bar.m_arrow[0].height();
}
inline SDL_Rect BarRect(const UiScrollbar *sb)
inline SDL_Rect BarRect(const UiScrollbar &bar)
{
SDL_Rect Tmp;
Tmp.x = sb->m_rect.x;
Tmp.y = static_cast<Sint16>(sb->m_rect.y + sb->m_arrow[0].height());
Tmp.w = SCROLLBAR_ARROW_WIDTH,
Tmp.h = BarHeight(sb);
return Tmp;
return MakeSdlRect(
bar.m_rect.x,
bar.m_rect.y + bar.m_arrow[0].height(),
ScrollBarArrowWidth,
BarHeight(bar));
}
inline SDL_Rect ThumbRect(const UiScrollbar *sb, std::size_t selected_index, std::size_t num_items)
inline SDL_Rect ThumbRect(const UiScrollbar &bar, size_t selectedIndex, size_t numItems)
{
const int THUMB_OFFSET_X = 3;
const int thumb_max_y = BarHeight(sb) - sb->m_thumb.height();
const int thumb_y = static_cast<int>(selected_index * thumb_max_y / (num_items - 1));
SDL_Rect Tmp;
Tmp.x = static_cast<Sint16>(sb->m_rect.x + THUMB_OFFSET_X);
Tmp.y = static_cast<Sint16>(sb->m_rect.y + sb->m_arrow[0].height() + thumb_y);
Tmp.w = static_cast<Uint16>(sb->m_rect.w - THUMB_OFFSET_X);
Tmp.h = static_cast<Uint16>(sb->m_thumb.height());
return Tmp;
constexpr int ThumbOffsetX = 3;
const int thumbMaxY = BarHeight(bar) - bar.m_thumb.height();
const int thumbY = static_cast<int>(selectedIndex * thumbMaxY / (numItems - 1));
return MakeSdlRect(
bar.m_rect.x + ThumbOffsetX,
bar.m_rect.y + bar.m_arrow[0].height() + thumbY,
bar.m_rect.w - ThumbOffsetX,
bar.m_thumb.height());
}
void LoadScrollBar();

29
Source/DiabloUI/selhero.cpp

@ -39,12 +39,11 @@ char textStats[6][4];
const char *title = "";
_selhero_selections selhero_result;
bool selhero_navigateYesNo;
bool selhero_deleteEnabled;
bool selhero_isSavegame;
std::vector<std::unique_ptr<UiItemBase>> vecSelHeroDialog;
std::vector<std::unique_ptr<UiListItem>> vecSelHeroDlgItems;
std::vector<std::unique_ptr<UiItemBase>> vecSelDlgItems;
std::vector<std::unique_ptr<UiItemBase>> vecDifficultyIndicators;
UiImageClx *SELHERO_DIALOG_HERO_IMG;
@ -62,7 +61,7 @@ const char *SelheroGenerateName(HeroClass heroClass);
void SelheroUiFocusNavigationYesNo()
{
if (selhero_deleteEnabled)
if (selhero_isSavegame)
UiFocusNavigationYesNo();
}
@ -71,7 +70,6 @@ void SelheroFree()
ArtBackground = std::nullopt;
vecSelHeroDialog.clear();
vecDifficultyIndicators.clear();
vecSelDlgItems.clear();
vecSelHeroDlgItems.clear();
@ -87,13 +85,18 @@ void SelheroSetStats()
CopyUtf8(textStats[3], StrCat(selhero_heroInfo.dexterity), sizeof(textStats[3]));
CopyUtf8(textStats[4], StrCat(selhero_heroInfo.vitality), sizeof(textStats[4]));
CopyUtf8(textStats[5], StrCat(selhero_heroInfo.saveNumber), sizeof(textStats[5]));
}
const Point uiPosition = GetUIRectangle().position;
vecDifficultyIndicators.clear();
SDL_Rect rect = MakeSdlRect(uiPosition.x + 28, uiPosition.y + 198, 12, 12);
void RenderDifficultyIndicators()
{
if (!selhero_isSavegame)
return;
const uint16_t width = (*DifficultyIndicator[0])[0].width();
const uint16_t height = (*DifficultyIndicator[0])[0].height();
SDL_Rect rect = MakeSdlRect(SELHERO_DIALOG_HERO_IMG->m_rect.x, SELHERO_DIALOG_HERO_IMG->m_rect.y - height - 2, width, height);
for (int i = 0; i <= DIFF_LAST; i++) {
vecDifficultyIndicators.push_back(std::make_unique<UiImageAnimatedClx>(*DifficultyIndicator[i < selhero_heroInfo.herorank ? 0 : 1], rect, UiFlags::None));
rect.x += 12;
UiRenderItem(UiImageClx((*DifficultyIndicator[i < selhero_heroInfo.herorank ? 0 : 1])[0], rect, UiFlags::None));
rect.x += width;
}
}
@ -116,7 +119,7 @@ void SelheroListFocus(int value)
memcpy(&selhero_heroInfo, &selhero_heros[index], sizeof(selhero_heroInfo));
SelheroSetStats();
SELLIST_DIALOG_DELETE_BUTTON->SetFlags(baseFlags | UiFlags::ColorUiGold);
selhero_deleteEnabled = true;
selhero_isSavegame = true;
return;
}
@ -124,12 +127,12 @@ void SelheroListFocus(int value)
for (char *textStat : textStats)
strcpy(textStat, "--");
SELLIST_DIALOG_DELETE_BUTTON->SetFlags(baseFlags | UiFlags::ColorUiSilver | UiFlags::ElementDisabled);
selhero_deleteEnabled = false;
selhero_isSavegame = false;
}
bool SelheroListDeleteYesNo()
{
selhero_navigateYesNo = selhero_deleteEnabled;
selhero_navigateYesNo = selhero_isSavegame;
return selhero_navigateYesNo;
}
@ -564,7 +567,7 @@ static void UiSelHeroDialog(
while (!selhero_endMenu && !selhero_navigateYesNo) {
UiClearScreen();
UiRenderItems(vecSelHeroDialog);
UiRenderItems(vecDifficultyIndicators);
RenderDifficultyIndicators();
UiPollAndRender();
}
SelheroFree();

Loading…
Cancel
Save