Merge branch 'button-drawer' into 'master'

Embed button prompts in string drawers (ACS Dialogue support)

Closes #943

See merge request KartKrew/Kart!1847
This commit is contained in:
James R. 2024-01-18 23:03:12 +00:00
commit d20ef561b9
5 changed files with 235 additions and 10 deletions

View file

@ -218,18 +218,20 @@ void Dialogue::SetSpeaker(std::string name, patch_t *patch, UINT8 *colormap, sfx
typewriter.voiceSfx = voice;
}
void Dialogue::NewText(std::string newText)
void Dialogue::NewText(std::string_view rawText)
{
Init();
newText = V_ScaledWordWrap(
char* newText = V_ScaledWordWrap(
290 << FRACBITS,
FRACUNIT, FRACUNIT, FRACUNIT,
0, HU_FONT,
newText.c_str()
srb2::Draw::TextElement().parse(rawText).string().c_str() // parse special characters
);
typewriter.NewText(newText);
Z_Free(newText);
}
bool Dialogue::Active(void)

View file

@ -15,6 +15,7 @@
#define __K_DIALOGUE_HPP__
#include <string>
#include <string_view>
#include "doomdef.h"
#include "doomtype.h"
@ -34,7 +35,7 @@ public:
void SetSpeaker(std::string skinName, int portraitID);
void SetSpeaker(std::string name, patch_t *patch, UINT8 *colormap, sfxenum_t voice);
void NewText(std::string newText);
void NewText(std::string_view newText);
bool Active(void);
bool TextDone(void);

View file

@ -7,6 +7,8 @@
// See the 'LICENSE' file for more details.
//-----------------------------------------------------------------------------
#include <unordered_map>
#include "doomdef.h" // skincolornum_t
#include "doomtype.h"
#include "hu_stuff.h"
@ -27,6 +29,96 @@ int Draw::TextElement::width() const
return font_ ? font_width(*font_, default_font_flags(*font_) | flags_.value_or(0), string_.c_str()) / FRACUNIT : 0;
}
Draw::TextElement& Draw::TextElement::parse(std::string_view raw)
{
static const std::unordered_map<std::string_view, char> translation = {
#define BUTTON(str, lower_bits) \
{str, 0xB0 | lower_bits},\
{str "_animated", 0xA0 | lower_bits},\
{str "_pressed", 0x90 | lower_bits}
BUTTON("up", 0x00),
BUTTON("down", 0x01),
BUTTON("right", 0x02),
BUTTON("left", 0x03),
BUTTON("r", 0x07),
BUTTON("l", 0x08),
BUTTON("start", 0x09),
BUTTON("a", 0x0A),
BUTTON("b", 0x0B),
BUTTON("c", 0x0C),
BUTTON("x", 0x0D),
BUTTON("y", 0x0E),
BUTTON("z", 0x0F),
#undef BUTTON
{"white", 0x80},
{"purple", 0x81},
{"yellow", 0x82},
{"green", 0x83},
{"blue", 0x84},
{"red", 0x85},
{"gray", 0x86},
{"orange", 0x87},
{"sky", 0x88},
{"lavender", 0x89},
{"gold", 0x8A},
{"aqua", 0x8B},
{"magenta", 0x8C},
{"pink", 0x8D},
{"brown", 0x8E},
{"tan", 0x8F},
};
string_.clear();
string_.reserve(raw.size());
using std::size_t;
using std::string_view;
for (;;)
{
size_t p = raw.find('<');
// Copy characters until the start tag
string_.append(raw.substr(0, p));
if (p == raw.npos)
{
break; // end of string
}
raw.remove_prefix(p);
// Find end tag
p = raw.find('>');
if (p == raw.npos)
{
break; // no end tag
}
string_view code = raw.substr(1, p - 1);
if (auto it = translation.find(code); it != translation.end())
{
string_.push_back(it->second); // replace with character code
}
else
{
string_.append(raw.substr(0, p + 1)); // code not found, leave text verbatim
}
raw.remove_prefix(p + 1); // past end of tag
}
return *this;
}
void Chain::patch(patch_t* patch) const
{
const auto _ = Clipper(*this);

View file

@ -11,6 +11,7 @@
#define __V_DRAW_HPP__
#include <string>
#include <string_view>
#include <optional>
#include <utility>
@ -75,6 +76,8 @@ public:
class TextElement
{
public:
explicit TextElement() {}
explicit TextElement(std::string string) : string_(string) {}
template <class... Args>
@ -95,6 +98,14 @@ public:
return *this;
}
TextElement& parse(std::string_view string);
template <class... Args>
TextElement& parse(fmt::format_string<Args...> format, Args&&... args)
{
return parse(fmt::format(format, args...));
}
TextElement& font(Font font)
{
font_ = font;
@ -157,6 +168,8 @@ public:
template <class... Args>
void text(fmt::format_string<Args...> format, Args&&... args) const { text(fmt::format(format, args...)); }
TextElement text() const { return TextElement().font(font_).flags(flags_); }
void patch(patch_t* patch) const;
void patch(const char* name) const;
@ -238,13 +251,14 @@ public:
#define VOID_METHOD(Name) \
template <typename... Args>\
void Name (Args&&... args) const { return chain_.Name(std::forward<Args>(args)...); }
auto Name (Args&&... args) const { return chain_.Name(std::forward<Args>(args)...); }
VOID_METHOD(text);
VOID_METHOD(patch);
VOID_METHOD(thumbnail);
VOID_METHOD(fill);
VOID_METHOD(button);
VOID_METHOD(small_button);
#undef VOID_METHOD

View file

@ -14,6 +14,7 @@
/// Functions to blit a block to the screen.
#include <cmath>
#include <optional>
#include <tracy/tracy/Tracy.hpp>
@ -45,6 +46,7 @@
#include "k_hud.h"
#include "k_boss.h"
#include "i_time.h"
#include "v_draw.hpp"
using namespace srb2;
@ -1796,7 +1798,7 @@ void V_DrawCharacterScaled(
if (notColored == true)
{
if (( c & 0x80 ))
if (( c & 0xF0 ) == 0x80)
{
colormap = V_GetStringColormap(
( ( c & 0x7f ) << V_CHARCOLORSHIFT ) & V_CHARCOLORMASK
@ -2413,6 +2415,41 @@ static void V_GetFontSpecification(int fontno, INT32 flags, fontspec_t *result)
}
}
static UINT8 V_GetButtonCodeWidth(UINT8 c)
{
UINT8 x = 0;
switch (c & 0x0F)
{
case 0x00:
case 0x01:
case 0x02:
case 0x03:
// arrows
x = 12;
break;
case 0x07:
case 0x08:
case 0x09:
// shoulders, start
x = 14;
break;
case 0x0A:
case 0x0B:
case 0x0C:
case 0x0D:
case 0x0E:
case 0x0F:
// faces
x = 10;
break;
}
return x + 2;
}
void V_DrawStringScaled(
fixed_t x,
fixed_t y,
@ -2427,6 +2464,7 @@ void V_DrawStringScaled(
INT32 hchw;/* half-width for centering */
INT32 dupx;
INT32 dupy;
fixed_t right;
fixed_t bot;
@ -2491,18 +2529,20 @@ void V_DrawStringScaled(
if (( flags & V_NOSCALESTART ))
{
dupx = vid.dupx;
dupy = vid.dupy;
hchw *= dupx;
fontspec.chw *= dupx;
fontspec.spacew *= dupx;
fontspec.lfh *= vid.dupy;
fontspec.lfh *= dupy;
right = vid.width;
}
else
{
dupx = 1;
dupy = 1;
right = ( vid.width / vid.dupx );
if (!( flags & V_SNAPTOLEFT ))
@ -2530,7 +2570,7 @@ void V_DrawStringScaled(
cx = x;
break;
default:
if (( c & 0x80 ))
if (( c & 0xF0 ) == 0x80)
{
if (notcolored)
{
@ -2572,6 +2612,68 @@ void V_DrawStringScaled(
cyoff = V_DanceYOffset(dancecounter) * FRACUNIT;
}
if (( c & 0xB0 ) & 0x80) // button prompts
{
using srb2::Draw;
struct BtConf
{
UINT8 x, y;
Draw::Button type;
};
auto bt_inst = [c]() -> std::optional<BtConf>
{
switch (c & 0x0F)
{
case 0x00: return {{0, 3, Draw::Button::up}};
case 0x01: return {{0, 3, Draw::Button::down}};
case 0x02: return {{0, 3, Draw::Button::right}};
case 0x03: return {{0, 3, Draw::Button::left}};
case 0x07: return {{0, 1, Draw::Button::r}};
case 0x08: return {{0, 1, Draw::Button::l}};
case 0x09: return {{0, 1, Draw::Button::start}};
case 0x0A: return {{2, 1, Draw::Button::a}};
case 0x0B: return {{2, 1, Draw::Button::b}};
case 0x0C: return {{2, 1, Draw::Button::c}};
case 0x0D: return {{2, 1, Draw::Button::x}};
case 0x0E: return {{2, 1, Draw::Button::y}};
case 0x0F: return {{2, 1, Draw::Button::z}};
default: return {};
}
}();
if (bt_inst)
{
auto bt_translate_press = [c]() -> std::optional<bool>
{
switch (c & 0xB0)
{
default:
case 0x90: return true;
case 0xA0: return {};
case 0xB0: return false;
}
};
Draw(
FixedToFloat(cx) - (bt_inst->x * dupx),
FixedToFloat(cy + cyoff) - (bt_inst->y * dupy))
.flags(flags)
.small_button(bt_inst->type, bt_translate_press());
}
cw = V_GetButtonCodeWidth(c) * dupx;
cx += cw * scale;
break;
}
c -= font->start;
if (V_CharacterValid(font, c) == true)
{
@ -2662,9 +2764,17 @@ fixed_t V_StringScaledWidth(
cx = 0;
break;
default:
if (( c & 0x80 ))
if (( c & 0xF0 ) == 0x80 || c == V_STRINGDANCE)
continue;
if (( c & 0xB0 ) & 0x80)
{
cw = V_GetButtonCodeWidth(c) * dupx;
cx += cw * scale;
right = cx;
break;
}
if (uppercase)
{
c = toupper(c);
@ -2794,8 +2904,14 @@ char * V_ScaledWordWrap(
startwriter = 0;
break;
default:
if (( c & 0x80 ))
if (( c & 0xF0 ) == 0x80 || c == V_STRINGDANCE)
;
else if (( c & 0xB0 ) & 0x80) // button prompts
{
cw = V_GetButtonCodeWidth(c) * dupx;
cx += cw * scale;
right = cx;
}
else
{
if (uppercase)