mirror of
https://github.com/libretro/devilutionX.git
synced 2026-11-11 02:41:35 -10:00
https://github.com/diasurgical/devilutionx-mpq-tools produces an unpacked MPQ with all the graphics converted to CLX and the unused files removed. This is primarily useful on RAM-constrained platforms, such as PS2, because it eliminates the MPQ overhead. Adds a build option to load from such unpacked directories instead of the MPQ. These directories are searched for in the same locations where the MPQs would be searched for otherwise. Example directory layout: * /usr/local/share/diasurgical/devilutionx/diabdat/ -- unpacked and converted diabdat.mpq * /usr/local/share/diasurgical/devilutionx/hellfire/ -- unpacked and converted hellfire MPQs (all of them merged into 1 directory) * /usr/local/share/diasurgical/devilutionx/fonts/ -- unpacked fonts.mpq * /usr/local/share/diasurgical/devilutionx/pl/ -- unpacked pl.mpq These directory structure is produced by calling `unpack_and_minify_mpq`
158 lines
3.6 KiB
C++
158 lines
3.6 KiB
C++
/**
|
|
* @file minitext.cpp
|
|
*
|
|
* Implementation of scrolling dialog text.
|
|
*/
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#include "DiabloUI/ui_flags.hpp"
|
|
#include "control.h"
|
|
#include "engine.h"
|
|
#include "engine/clx_sprite.hpp"
|
|
#include "engine/dx.h"
|
|
#include "engine/load_cel.hpp"
|
|
#include "engine/render/clx_render.hpp"
|
|
#include "engine/render/text_render.hpp"
|
|
#include "textdat.h"
|
|
#include "utils/language.h"
|
|
#include "utils/stdcompat/optional.hpp"
|
|
#include "utils/stdcompat/string_view.hpp"
|
|
|
|
namespace devilution {
|
|
|
|
bool qtextflag;
|
|
|
|
namespace {
|
|
|
|
/** Vertical speed of the scrolling text in ms/px */
|
|
int qtextSpd;
|
|
/** Start time of scrolling */
|
|
Uint32 ScrollStart;
|
|
/** Graphics for the window border */
|
|
OptionalOwnedClxSpriteList pTextBoxCels;
|
|
|
|
/** Pixels for a line of text and the empty space under it. */
|
|
const int LineHeight = 38;
|
|
|
|
std::vector<std::string> TextLines;
|
|
|
|
void LoadText(string_view text)
|
|
{
|
|
TextLines.clear();
|
|
|
|
const std::string paragraphs = WordWrapString(text, 543, GameFont30);
|
|
|
|
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;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Calculate the speed the current text should scroll to match the given audio
|
|
* @param nSFX The index of the sound in the sgSFX table
|
|
* @return ms/px
|
|
*/
|
|
uint32_t CalculateTextSpeed(int nSFX)
|
|
{
|
|
const int numLines = TextLines.size();
|
|
|
|
#ifndef NOSOUND
|
|
Uint32 sfxFrames = GetSFXLength(nSFX);
|
|
#else
|
|
// Sound is disabled -- estimate length from the number of lines.
|
|
Uint32 sfxFrames = numLines * 3000;
|
|
#endif
|
|
assert(sfxFrames != 0);
|
|
|
|
uint32_t textHeight = LineHeight * numLines;
|
|
textHeight += LineHeight * 5; // adjust so when speaker is done two line are left
|
|
assert(textHeight != 0);
|
|
|
|
return sfxFrames / textHeight;
|
|
}
|
|
|
|
int CalculateTextPosition()
|
|
{
|
|
uint32_t currTime = SDL_GetTicks();
|
|
|
|
int y = (currTime - ScrollStart) / qtextSpd - 260;
|
|
|
|
int textHeight = LineHeight * TextLines.size();
|
|
if (y >= textHeight)
|
|
qtextflag = false;
|
|
|
|
return y;
|
|
}
|
|
|
|
/**
|
|
* @brief Draw the current text in the quest dialog window
|
|
*/
|
|
void DrawQTextContent(const Surface &out)
|
|
{
|
|
int y = CalculateTextPosition();
|
|
|
|
const int sx = GetUIRectangle().position.x + 48;
|
|
const int sy = 0 - (y % LineHeight);
|
|
|
|
const unsigned int skipLines = y / LineHeight;
|
|
|
|
for (int i = 0; i < 8; i++) {
|
|
const unsigned int lineNumber = skipLines + i;
|
|
if (lineNumber >= TextLines.size()) {
|
|
continue;
|
|
}
|
|
|
|
const std::string &line = TextLines[lineNumber];
|
|
if (line.empty()) {
|
|
continue;
|
|
}
|
|
|
|
DrawString(out, line, { { sx, sy + i * LineHeight }, { 543, LineHeight } }, UiFlags::FontSize30 | UiFlags::ColorGold);
|
|
}
|
|
}
|
|
|
|
} // namespace
|
|
|
|
void FreeQuestText()
|
|
{
|
|
pTextBoxCels = std::nullopt;
|
|
}
|
|
|
|
void InitQuestText()
|
|
{
|
|
pTextBoxCels = LoadCel("data\\textbox", 591);
|
|
}
|
|
|
|
void InitQTextMsg(_speech_id m)
|
|
{
|
|
if (Speeches[m].scrlltxt) {
|
|
QuestLogIsOpen = false;
|
|
LoadText(_(Speeches[m].txtstr));
|
|
qtextflag = true;
|
|
qtextSpd = CalculateTextSpeed(Speeches[m].sfxnr);
|
|
ScrollStart = SDL_GetTicks();
|
|
}
|
|
PlaySFX(Speeches[m].sfxnr);
|
|
}
|
|
|
|
void DrawQTextBack(const Surface &out)
|
|
{
|
|
const Point uiPosition = GetUIRectangle().position;
|
|
ClxDraw(out, uiPosition + Displacement { 24, 327 }, (*pTextBoxCels)[0]);
|
|
DrawHalfTransparentRectTo(out, uiPosition.x + 27, uiPosition.y + 28, 585, 297);
|
|
}
|
|
|
|
void DrawQText(const Surface &out)
|
|
{
|
|
DrawQTextBack(out);
|
|
DrawQTextContent(out.subregionY(GetUIRectangle().position.y + 49, 260));
|
|
}
|
|
|
|
} // namespace devilution
|