You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
186 lines
7.8 KiB
186 lines
7.8 KiB
/** |
|
* @file error.cpp |
|
* |
|
* Implementation of in-game message functions. |
|
*/ |
|
|
|
#include <cstdint> |
|
#include <deque> |
|
|
|
#include "error.h" |
|
|
|
#include "DiabloUI/ui_flags.hpp" |
|
#include "engine/render/clx_render.hpp" |
|
#include "engine/render/text_render.hpp" |
|
#include "panels/info_box.hpp" |
|
#include "stores.h" |
|
#include "utils/algorithm/container.hpp" |
|
#include "utils/language.h" |
|
#include "utils/timer.hpp" |
|
|
|
namespace devilution { |
|
|
|
namespace { |
|
|
|
std::deque<std::string> DiabloMessages; |
|
std::vector<std::string> TextLines; |
|
uint32_t msgdelay; |
|
int ErrorWindowHeight = 54; |
|
const int LineHeight = 12; |
|
const int LineWidth = 418; |
|
|
|
void InitNextLines() |
|
{ |
|
msgdelay = GetMillisecondsSinceStartup(); |
|
TextLines.clear(); |
|
|
|
const std::string paragraphs = WordWrapString(DiabloMessages.front(), LineWidth, GameFont12, 1); |
|
|
|
size_t previous = 0; |
|
while (true) { |
|
size_t next = paragraphs.find('\n', previous); |
|
TextLines.emplace_back(paragraphs.substr(previous, next - previous)); |
|
if (next == std::string::npos) |
|
break; |
|
previous = next + 1; |
|
} |
|
|
|
ErrorWindowHeight = std::max(54, static_cast<int>((TextLines.size() * LineHeight) + 42)); |
|
} |
|
|
|
} // namespace |
|
|
|
/** Maps from error_id to error message. */ |
|
const char *const MsgStrings[] = { |
|
"", |
|
N_("No automap available in town"), |
|
N_("No multiplayer functions in demo"), |
|
N_("Direct Sound Creation Failed"), |
|
N_("Not available in shareware version"), |
|
N_("Not enough space to save"), |
|
N_("No Pause in town"), |
|
N_("Copying to a hard disk is recommended"), |
|
N_("Multiplayer sync problem"), |
|
N_("No pause in multiplayer"), |
|
N_("Loading..."), |
|
N_("Saving..."), |
|
N_(/* TRANSLATORS: Shrine Text. Keep atmospheric. :) */ "Some are weakened as one grows strong"), |
|
N_(/* TRANSLATORS: Shrine Text. Keep atmospheric. :) */ "New strength is forged through destruction"), |
|
N_(/* TRANSLATORS: Shrine Text. Keep atmospheric. :) */ "Those who defend seldom attack"), |
|
N_(/* TRANSLATORS: Shrine Text. Keep atmospheric. :) */ "The sword of justice is swift and sharp"), |
|
N_(/* TRANSLATORS: Shrine Text. Keep atmospheric. :) */ "While the spirit is vigilant the body thrives"), |
|
N_(/* TRANSLATORS: Shrine Text. Keep atmospheric. :) */ "The powers of mana refocused renews"), |
|
N_(/* TRANSLATORS: Shrine Text. Keep atmospheric. :) */ "Time cannot diminish the power of steel"), |
|
N_(/* TRANSLATORS: Shrine Text. Keep atmospheric. :) */ "Magic is not always what it seems to be"), |
|
N_(/* TRANSLATORS: Shrine Text. Keep atmospheric. :) */ "What once was opened now is closed"), |
|
N_(/* TRANSLATORS: Shrine Text. Keep atmospheric. :) */ "Intensity comes at the cost of wisdom"), |
|
N_(/* TRANSLATORS: Shrine Text. Keep atmospheric. :) */ "Arcane power brings destruction"), |
|
N_(/* TRANSLATORS: Shrine Text. Keep atmospheric. :) */ "That which cannot be held cannot be harmed"), |
|
N_(/* TRANSLATORS: Shrine Text. Keep atmospheric. :) */ "Crimson and Azure become as the sun"), |
|
N_(/* TRANSLATORS: Shrine Text. Keep atmospheric. :) */ "Knowledge and wisdom at the cost of self"), |
|
N_(/* TRANSLATORS: Shrine Text. Keep atmospheric. :) */ "Drink and be refreshed"), |
|
N_(/* TRANSLATORS: Shrine Text. Keep atmospheric. :) */ "Wherever you go, there you are"), |
|
N_(/* TRANSLATORS: Shrine Text. Keep atmospheric. :) */ "Energy comes at the cost of wisdom"), |
|
N_(/* TRANSLATORS: Shrine Text. Keep atmospheric. :) */ "Riches abound when least expected"), |
|
N_(/* TRANSLATORS: Shrine Text. Keep atmospheric. :) */ "Where avarice fails, patience gains reward"), |
|
N_(/* TRANSLATORS: Shrine Text. Keep atmospheric. :) */ "Blessed by a benevolent companion!"), |
|
N_(/* TRANSLATORS: Shrine Text. Keep atmospheric. :) */ "The hands of men may be guided by fate"), |
|
N_(/* TRANSLATORS: Shrine Text. Keep atmospheric. :) */ "Strength is bolstered by heavenly faith"), |
|
N_(/* TRANSLATORS: Shrine Text. Keep atmospheric. :) */ "The essence of life flows from within"), |
|
N_(/* TRANSLATORS: Shrine Text. Keep atmospheric. :) */ "The way is made clear when viewed from above"), |
|
N_(/* TRANSLATORS: Shrine Text. Keep atmospheric. :) */ "Salvation comes at the cost of wisdom"), |
|
N_(/* TRANSLATORS: Shrine Text. Keep atmospheric. :) */ "Mysteries are revealed in the light of reason"), |
|
N_(/* TRANSLATORS: Shrine Text. Keep atmospheric. :) */ "Those who are last may yet be first"), |
|
N_(/* TRANSLATORS: Shrine Text. Keep atmospheric. :) */ "Generosity brings its own rewards"), |
|
N_("You must be at least level 8 to use this."), |
|
N_("You must be at least level 13 to use this."), |
|
N_("You must be at least level 17 to use this."), |
|
N_(/* TRANSLATORS: Shrine Text. Keep atmospheric. :) */ "Arcane knowledge gained!"), |
|
N_(/* TRANSLATORS: Shrine Text. Keep atmospheric. :) */ "That which does not kill you..."), |
|
N_(/* TRANSLATORS: Shrine Text. Keep atmospheric. :) */ "Knowledge is power."), |
|
N_(/* TRANSLATORS: Shrine Text. Keep atmospheric. :) */ "Give and you shall receive."), |
|
N_(/* TRANSLATORS: Shrine Text. Keep atmospheric. :) */ "Some experience is gained by touch."), |
|
N_(/* TRANSLATORS: Shrine Text. Keep atmospheric. :) */ "There's no place like home."), |
|
N_(/* TRANSLATORS: Shrine Text. Keep atmospheric. :) */ "Spiritual energy is restored."), |
|
N_(/* TRANSLATORS: Shrine Text. Keep atmospheric. :) */ "You feel more agile."), |
|
N_(/* TRANSLATORS: Shrine Text. Keep atmospheric. :) */ "You feel stronger."), |
|
N_(/* TRANSLATORS: Shrine Text. Keep atmospheric. :) */ "You feel wiser."), |
|
N_(/* TRANSLATORS: Shrine Text. Keep atmospheric. :) */ "You feel refreshed."), |
|
N_(/* TRANSLATORS: Shrine Text. Keep atmospheric. :) */ "That which can break will."), |
|
}; |
|
|
|
void InitDiabloMsg(diablo_message e) |
|
{ |
|
InitDiabloMsg(LanguageTranslate(MsgStrings[e])); |
|
} |
|
|
|
void InitDiabloMsg(std::string_view msg) |
|
{ |
|
if (DiabloMessages.size() >= MAX_SEND_STR_LEN) |
|
return; |
|
|
|
if (c_find(DiabloMessages, msg) != DiabloMessages.end()) |
|
return; |
|
|
|
DiabloMessages.push_back(std::string(msg)); |
|
if (DiabloMessages.size() == 1) |
|
InitNextLines(); |
|
} |
|
|
|
bool IsDiabloMsgAvailable() |
|
{ |
|
return !DiabloMessages.empty(); |
|
} |
|
|
|
void CancelCurrentDiabloMsg() |
|
{ |
|
msgdelay = 0; |
|
} |
|
|
|
void ClrDiabloMsg() |
|
{ |
|
DiabloMessages.clear(); |
|
} |
|
|
|
void DrawDiabloMsg(const Surface &out) |
|
{ |
|
auto &uiRectanglePosition = GetUIRectangle().position; |
|
int dialogStartY = ((gnScreenHeight - GetMainPanel().size.height) / 2) - (ErrorWindowHeight / 2) + 9; |
|
|
|
ClxDraw(out, { uiRectanglePosition.x + 101, dialogStartY }, (*pSTextSlidCels)[0]); |
|
ClxDraw(out, { uiRectanglePosition.x + 101, dialogStartY + ErrorWindowHeight - 6 }, (*pSTextSlidCels)[1]); |
|
ClxDraw(out, { uiRectanglePosition.x + 527, dialogStartY + ErrorWindowHeight - 6 }, (*pSTextSlidCels)[2]); |
|
ClxDraw(out, { uiRectanglePosition.x + 527, dialogStartY }, (*pSTextSlidCels)[3]); |
|
|
|
int sx = uiRectanglePosition.x + 109; |
|
for (int i = 0; i < 35; i++) { |
|
ClxDraw(out, { sx, dialogStartY }, (*pSTextSlidCels)[4]); |
|
ClxDraw(out, { sx, dialogStartY + ErrorWindowHeight - 6 }, (*pSTextSlidCels)[6]); |
|
sx += 12; |
|
} |
|
int drawnYborder = 12; |
|
while ((drawnYborder + 12) < ErrorWindowHeight) { |
|
ClxDraw(out, { uiRectanglePosition.x + 101, dialogStartY + drawnYborder }, (*pSTextSlidCels)[5]); |
|
ClxDraw(out, { uiRectanglePosition.x + 527, dialogStartY + drawnYborder }, (*pSTextSlidCels)[7]); |
|
drawnYborder += 12; |
|
} |
|
|
|
DrawHalfTransparentRectTo(out, uiRectanglePosition.x + 104, dialogStartY - 8, 432, ErrorWindowHeight); |
|
|
|
int lineNumber = 0; |
|
for (auto &line : TextLines) { |
|
DrawString(out, line, { { uiRectanglePosition.x + 109, dialogStartY + 12 + lineNumber * LineHeight }, { LineWidth, LineHeight } }, UiFlags::AlignCenter, 1, LineHeight); |
|
lineNumber += 1; |
|
} |
|
|
|
if (msgdelay > 0 && msgdelay <= GetMillisecondsSinceStartup() - 3500) { |
|
msgdelay = 0; |
|
} |
|
if (msgdelay == 0) { |
|
DiabloMessages.pop_front(); |
|
if (!DiabloMessages.empty()) |
|
InitNextLines(); |
|
} |
|
} |
|
|
|
} // namespace devilution
|
|
|