Browse Source

Improve DiabloMsg handling

1. Simplified implementation.
2. Now adjusts the box size to fit the content (e.g. when wrapping
   failed or when there are too many lines).
pull/6701/head
Gleb Mazovetskiy 3 years ago
parent
commit
88bbf4f913
  1. 2
      Source/control.cpp
  2. 2
      Source/debug.cpp
  3. 2
      Source/diablo.cpp
  4. 76
      Source/diablo_msg.cpp
  5. 4
      Source/engine/render/scrollrt.cpp
  6. 2
      Source/gamemenu.cpp
  7. 2
      Source/objects.cpp
  8. 4
      Source/panels/info_box.hpp
  9. 2
      Source/qol/chatlog.cpp

2
Source/control.cpp

@ -18,13 +18,13 @@
#include "controls/modifier_hints.h" #include "controls/modifier_hints.h"
#include "controls/plrctrls.h" #include "controls/plrctrls.h"
#include "cursor.h" #include "cursor.h"
#include "diablo_msg.hpp"
#include "engine/backbuffer_state.hpp" #include "engine/backbuffer_state.hpp"
#include "engine/clx_sprite.hpp" #include "engine/clx_sprite.hpp"
#include "engine/load_cel.hpp" #include "engine/load_cel.hpp"
#include "engine/render/clx_render.hpp" #include "engine/render/clx_render.hpp"
#include "engine/render/text_render.hpp" #include "engine/render/text_render.hpp"
#include "engine/trn.hpp" #include "engine/trn.hpp"
#include "diablo_msg.hpp"
#include "gamemenu.h" #include "gamemenu.h"
#include "init.h" #include "init.h"
#include "inv.h" #include "inv.h"

2
Source/debug.cpp

@ -15,11 +15,11 @@
#include "automap.h" #include "automap.h"
#include "control.h" #include "control.h"
#include "cursor.h" #include "cursor.h"
#include "diablo_msg.hpp"
#include "engine/backbuffer_state.hpp" #include "engine/backbuffer_state.hpp"
#include "engine/events.hpp" #include "engine/events.hpp"
#include "engine/load_cel.hpp" #include "engine/load_cel.hpp"
#include "engine/point.hpp" #include "engine/point.hpp"
#include "diablo_msg.hpp"
#include "inv.h" #include "inv.h"
#include "levels/setmaps.h" #include "levels/setmaps.h"
#include "lighting.h" #include "lighting.h"

2
Source/diablo.cpp

@ -23,6 +23,7 @@
#include "controls/plrctrls.h" #include "controls/plrctrls.h"
#include "controls/remap_keyboard.h" #include "controls/remap_keyboard.h"
#include "diablo.h" #include "diablo.h"
#include "diablo_msg.hpp"
#include "discord/discord.h" #include "discord/discord.h"
#include "doom.h" #include "doom.h"
#include "encrypt.h" #include "encrypt.h"
@ -35,7 +36,6 @@
#include "engine/load_file.hpp" #include "engine/load_file.hpp"
#include "engine/random.hpp" #include "engine/random.hpp"
#include "engine/sound.h" #include "engine/sound.h"
#include "diablo_msg.hpp"
#include "gamemenu.h" #include "gamemenu.h"
#include "gmenu.h" #include "gmenu.h"
#include "help.h" #include "help.h"

76
Source/diablo_msg.cpp

@ -11,14 +11,13 @@
#include "diablo_msg.hpp" #include "diablo_msg.hpp"
#include "DiabloUI/ui_flags.hpp" #include "DiabloUI/ui_flags.hpp"
#include "control.h"
#include "engine/clx_sprite.hpp" #include "engine/clx_sprite.hpp"
#include "engine/render/clx_render.hpp" #include "engine/render/clx_render.hpp"
#include "engine/render/text_render.hpp" #include "engine/render/text_render.hpp"
#include "panels/info_box.hpp" #include "panels/info_box.hpp"
#include "utils/algorithm/container.hpp" #include "utils/algorithm/container.hpp"
#include "utils/language.h" #include "utils/language.h"
#include "utils/timer.hpp" #include "utils/str_split.hpp"
namespace devilution { namespace devilution {
@ -30,32 +29,29 @@ struct MessageEntry {
}; };
std::deque<MessageEntry> DiabloMessages; std::deque<MessageEntry> DiabloMessages;
uint32_t msgStartTime = 0; uint32_t msgStartTime;
std::vector<std::string> TextLines; std::vector<std::string> TextLines;
int OuterHeight = 54; int OuterHeight;
const int LineWidth = 418; int LineWidth;
int LineHeight;
int LineHeight() void InitDiabloMsg()
{
return IsSmallFontTall() ? 18 : 12;
}
void InitNextLines()
{ {
TextLines.clear(); TextLines.clear();
if (DiabloMessages.empty())
return;
const std::string paragraphs = WordWrapString(DiabloMessages.front().text, LineWidth, GameFont12, 1); LineWidth = 418;
const std::string_view text = DiabloMessages.front().text;
size_t previous = 0; const std::string wrapped = WordWrapString(text, LineWidth, GameFont12);
while (true) { for (const std::string_view line : SplitByChar(wrapped, '\n')) {
const size_t next = paragraphs.find('\n', previous); LineWidth = std::max(LineWidth, GetLineWidth(text, GameFont12));
TextLines.emplace_back(paragraphs.substr(previous, next - previous)); TextLines.emplace_back(line);
if (next == std::string::npos)
break;
previous = next + 1;
} }
OuterHeight = std::max(54, static_cast<int>((TextLines.size() * LineHeight()) + 42)); msgStartTime = SDL_GetTicks();
LineHeight = GetLineHeight(text, GameFont12);
OuterHeight = static_cast<int>((TextLines.size()) * LineHeight) + 42;
} }
} // namespace } // namespace
@ -126,17 +122,13 @@ void InitDiabloMsg(diablo_message e, uint32_t duration /*= 3500*/)
void InitDiabloMsg(std::string_view msg, uint32_t duration /*= 3500*/) void InitDiabloMsg(std::string_view msg, uint32_t duration /*= 3500*/)
{ {
if (DiabloMessages.size() >= MAX_SEND_STR_LEN)
return;
if (c_find_if(DiabloMessages, [&msg](const MessageEntry &entry) { return entry.text == msg; }) if (c_find_if(DiabloMessages, [&msg](const MessageEntry &entry) { return entry.text == msg; })
!= DiabloMessages.end()) != DiabloMessages.end())
return; return;
DiabloMessages.push_back({ std::string(msg), duration }); DiabloMessages.push_back({ std::string(msg), duration });
if (DiabloMessages.size() == 1) { if (DiabloMessages.size() == 1) {
InitNextLines(); InitDiabloMsg();
msgStartTime = SDL_GetTicks();
} }
} }
@ -149,10 +141,7 @@ void CancelCurrentDiabloMsg()
{ {
if (!DiabloMessages.empty()) { if (!DiabloMessages.empty()) {
DiabloMessages.pop_front(); DiabloMessages.pop_front();
if (!DiabloMessages.empty()) { InitDiabloMsg();
InitNextLines();
msgStartTime = SDL_GetTicks();
}
} }
} }
@ -176,14 +165,16 @@ void DrawDiabloMsg(const Surface &out)
const int borderPartWidth = 12; const int borderPartWidth = 12;
const int borderPartHeight = 12; const int borderPartHeight = 12;
const int outerHeight = OuterHeight; const int textPaddingX = 5;
const int outerWidth = 429;
const int borderThickness = 3; const int borderThickness = 3;
const int outerHeight = std::min<int>(out.h(), OuterHeight);
const int outerWidth = std::min<int>(out.w(), LineWidth + 2 * borderThickness + textPaddingX);
const int innerWidth = outerWidth - 2 * borderThickness; const int innerWidth = outerWidth - 2 * borderThickness;
const int lineWidth = innerWidth - textPaddingX;
const int innerHeight = outerHeight - 2 * borderThickness; const int innerHeight = outerHeight - 2 * borderThickness;
const Point uiRectanglePosition = GetUIRectangle().position; const Point topLeft { (out.w() - outerWidth) / 2, (out.h() - outerHeight) / 2 };
const Point topLeft { uiRectanglePosition.x + 101, ((gnScreenHeight - GetMainPanel().size.height - outerHeight) / 2) - borderThickness };
const int innerXBegin = topLeft.x + borderThickness; const int innerXBegin = topLeft.x + borderThickness;
const int innerXEnd = innerXBegin + innerWidth; const int innerXEnd = innerXBegin + innerWidth;
@ -210,25 +201,20 @@ void DrawDiabloMsg(const Surface &out)
} }
DrawHalfTransparentRectTo(out, innerXBegin, innerYBegin, innerWidth, innerHeight); DrawHalfTransparentRectTo(out, innerXBegin, innerYBegin, innerWidth, innerHeight);
const int lineHeight = LineHeight(); const int textX = innerXBegin + textPaddingX;
const int textX = innerXBegin + 5; int textY = innerYBegin + (innerHeight - LineHeight * static_cast<int>(TextLines.size())) / 2;
int textY = innerYBegin + (innerHeight - lineHeight * static_cast<int>(TextLines.size())) / 2;
for (const std::string &line : TextLines) { for (const std::string &line : TextLines) {
DrawString(out, line, { { textX, textY }, { LineWidth, lineHeight } }, UiFlags::AlignCenter, 1, lineHeight); DrawString(out, line, { { textX, textY }, { lineWidth, LineHeight } }, UiFlags::AlignCenter, 1, LineHeight);
textY += lineHeight; textY += LineHeight;
} }
// Calculate the time the current message has been displayed // Calculate the time the current message has been displayed
const uint32_t currentTime = SDL_GetTicks(); const uint32_t messageElapsedTime = SDL_GetTicks() - msgStartTime;
const uint32_t messageElapsedTime = currentTime - msgStartTime;
// Check if the current message's duration has passed // Check if the current message's duration has passed
if (!DiabloMessages.empty() && messageElapsedTime >= DiabloMessages.front().duration) { if (!DiabloMessages.empty() && messageElapsedTime >= DiabloMessages.front().duration) {
DiabloMessages.pop_front(); DiabloMessages.pop_front();
if (!DiabloMessages.empty()) { InitDiabloMsg();
InitNextLines();
msgStartTime = currentTime;
}
} }
} }

4
Source/engine/render/scrollrt.cpp

@ -13,6 +13,7 @@
#include "controls/plrctrls.h" #include "controls/plrctrls.h"
#include "cursor.h" #include "cursor.h"
#include "dead.h" #include "dead.h"
#include "diablo_msg.hpp"
#include "doom.h" #include "doom.h"
#include "engine/backbuffer_state.hpp" #include "engine/backbuffer_state.hpp"
#include "engine/dx.h" #include "engine/dx.h"
@ -21,7 +22,6 @@
#include "engine/render/text_render.hpp" #include "engine/render/text_render.hpp"
#include "engine/trn.hpp" #include "engine/trn.hpp"
#include "engine/world_tile.hpp" #include "engine/world_tile.hpp"
#include "diablo_msg.hpp"
#include "gmenu.h" #include "gmenu.h"
#include "help.h" #include "help.h"
#include "hwcursor.hpp" #include "hwcursor.hpp"
@ -1194,7 +1194,7 @@ void DrawView(const Surface &out, Point startPosition)
DrawChatLog(out); DrawChatLog(out);
} }
if (IsDiabloMsgAvailable()) { if (IsDiabloMsgAvailable()) {
DrawDiabloMsg(out); DrawDiabloMsg(out.subregionY(0, out.h() - GetMainPanel().size.height));
} }
if (MyPlayerIsDead) { if (MyPlayerIsDead) {
RedBack(out); RedBack(out);

2
Source/gamemenu.cpp

@ -6,11 +6,11 @@
#include "gamemenu.h" #include "gamemenu.h"
#include "cursor.h" #include "cursor.h"
#include "diablo_msg.hpp"
#include "engine/backbuffer_state.hpp" #include "engine/backbuffer_state.hpp"
#include "engine/events.hpp" #include "engine/events.hpp"
#include "engine/sound.h" #include "engine/sound.h"
#include "engine/sound_defs.hpp" #include "engine/sound_defs.hpp"
#include "diablo_msg.hpp"
#include "gmenu.h" #include "gmenu.h"
#include "init.h" #include "init.h"
#include "loadsave.h" #include "loadsave.h"

2
Source/objects.cpp

@ -18,12 +18,12 @@
#ifdef _DEBUG #ifdef _DEBUG
#include "debug.h" #include "debug.h"
#endif #endif
#include "diablo_msg.hpp"
#include "engine/backbuffer_state.hpp" #include "engine/backbuffer_state.hpp"
#include "engine/load_cel.hpp" #include "engine/load_cel.hpp"
#include "engine/load_file.hpp" #include "engine/load_file.hpp"
#include "engine/points_in_rectangle_range.hpp" #include "engine/points_in_rectangle_range.hpp"
#include "engine/random.hpp" #include "engine/random.hpp"
#include "diablo_msg.hpp"
#include "init.h" #include "init.h"
#include "inv.h" #include "inv.h"
#include "inv_iterators.hpp" #include "inv_iterators.hpp"

4
Source/panels/info_box.hpp

@ -5,14 +5,14 @@
namespace devilution { namespace devilution {
/** /**
* @brief Info box frame * @brief Fixed size info box frame
* *
* Used in stores, the quest log, the help window, and the unique item info window. * Used in stores, the quest log, the help window, and the unique item info window.
*/ */
extern OptionalOwnedClxSpriteList pSTextBoxCels; extern OptionalOwnedClxSpriteList pSTextBoxCels;
/** /**
* @brief Info box scrollbar graphics. * @brief Dynamic size info box frame and scrollbar graphics.
* *
* Used in stores and `DrawDiabloMsg`. * Used in stores and `DrawDiabloMsg`.
*/ */

2
Source/qol/chatlog.cpp

@ -14,9 +14,9 @@
#include "automap.h" #include "automap.h"
#include "chatlog.h" #include "chatlog.h"
#include "control.h" #include "control.h"
#include "diablo_msg.hpp"
#include "doom.h" #include "doom.h"
#include "engine/render/text_render.hpp" #include "engine/render/text_render.hpp"
#include "diablo_msg.hpp"
#include "gamemenu.h" #include "gamemenu.h"
#include "help.h" #include "help.h"
#include "init.h" #include "init.h"

Loading…
Cancel
Save