5#include <SDL3/SDL_scancode.h>
15 std::array<std::wstring, rules::MaxPlayers>
playerNames{};
38 [[
nodiscard]]
constexpr bool contains(
int x,
int y)
const noexcept
104 return {
state.windowX +
state.windowWidth - 20,
127 return {
state.windowX +
state.windowWidth - 18,
141 return {
state.fluffWindowX,
state.fluffWindowY,
142 state.fluffWindowX +
state.fluffWindowWidth - 1,
143 state.fluffWindowY + 18};
147 return {
state.fluffWindowX,
state.fluffWindowY + 18,
148 state.fluffWindowX +
state.fluffWindowWidth - 1,
149 state.fluffWindowY +
state.fluffWindowHeight - 1};
153 return {
state.fluffWindowX,
state.fluffWindowY,
154 state.fluffWindowX + 19,
state.fluffWindowY + 18};
158 return {
state.fluffWindowX +
state.fluffWindowWidth - 21,
159 state.fluffWindowY + 1,
160 state.fluffWindowX +
state.fluffWindowWidth - 1,
161 state.fluffWindowY + 18};
165 return {
state.fluffWindowX +
state.fluffWindowWidth - 20,
166 state.fluffWindowY +
state.fluffWindowHeight - 18,
167 state.fluffWindowX +
state.fluffWindowWidth - 1,
168 state.fluffWindowY +
state.fluffWindowHeight - 1};
172 return {
state.fluffWindowX +
state.fluffWindowWidth - 18,
173 state.fluffWindowY + 18,
174 state.fluffWindowX +
state.fluffWindowWidth - 1,
175 state.fluffWindowY + 35};
179 return {
state.fluffWindowX +
state.fluffWindowWidth - 18,
180 state.fluffWindowY +
state.fluffWindowHeight - 35,
181 state.fluffWindowX +
state.fluffWindowWidth - 1,
182 state.fluffWindowY +
state.fluffWindowHeight - 18};
186 return {
state.fluffWindowX +
state.fluffWindowWidth - 17,
187 state.fluffWindowY + 35,
188 state.fluffWindowX +
state.fluffWindowWidth - 2,
189 state.fluffWindowY +
state.fluffWindowHeight - 35};
195 143 +
static_cast<int>(
category) * 20;
203 (
static_cast<int>(
ordinal) + 5) * 19 + 3;
215 --
runtime.backgroundAlphaIndex;
217 ++
runtime.backgroundAlphaIndex;
228 if (!
runtime.fluffOpen)
return false;
229 const int x =
static_cast<int>(message.numberA);
230 const int y =
static_cast<int>(message.numberB);
273 runtime.fluffScrolling =
false;
279 return (!
runtime.fluffShaded &&
325 runtime.fluffScrolling =
false;
335 runtime.fluffSelectedLine = -1;
358 return (!
runtime.fluffShaded &&
364 int x,
int y, std::uint32_t
eligible)
noexcept
368 player >= 0; --player)
370 const auto bit = 1u <<
static_cast<unsigned>(player);
387 const std::vector<std::uint8_t>&
bytes)
390 if (
bytes.empty() || (
bytes.size() % 2u) != 0u)
397 const auto unit =
static_cast<char16_t>(
398 static_cast<std::uint16_t
>(
bytes[
index * 2u]) |
399 (
static_cast<std::uint16_t
>(
bytes[
index * 2u + 1u]) << 8u));
407 const std::array<wchar_t, 80>&
text)
409 std::u16string result;
414 const auto code =
static_cast<std::uint32_t
>(
value);
415 if constexpr (
sizeof(
wchar_t) == 2)
417 result.push_back(
static_cast<char16_t>(code));
419 else if (code <= 0xFFFFu)
421 result.push_back(
static_cast<char16_t>(code));
425 const auto adjusted = code - 0x10000u;
426 result.push_back(
static_cast<char16_t>(
427 0xD800u + ((
adjusted >> 10u) & 0x3FFu)));
428 result.push_back(
static_cast<char16_t>(
438 for (std::size_t
i = 0;
i <
utf8.size() &&
441 const auto first =
static_cast<std::uint8_t
>(
utf8[
i]);
442 std::uint32_t code{};
445 else if ((
first & 0xE0u) == 0xC0u) { code =
first & 0x1Fu;
count = 2; }
446 else if ((
first & 0xF0u) == 0xE0u) { code =
first & 0x0Fu;
count = 3; }
447 else if ((
first & 0xF8u) == 0xF0u) { code =
first & 0x07u;
count = 4; }
448 else { ++
i;
continue; }
451 for (std::size_t
j = 1;
j <
count; ++
j)
457 if (!
valid) { ++
i;
continue; }
459 (
count == 3 && code < 0x800u) || (
count == 4 && code < 0x10000u);
460 if (
overlong || code > 0x10FFFFu || (code >= 0xD800u && code <= 0xDFFFu))
464 runtime.draft.push_back(
static_cast<char16_t>(code));
470 runtime.draft.push_back(
static_cast<char16_t>(0xD800u + (code >> 10u)));
471 runtime.draft.push_back(
static_cast<char16_t>(0xDC00u + (code & 0x3FFu)));
480 std::size_t
category, std::size_t line)
noexcept
486 static_cast<std::int64_t
>(line);
491 std::int64_t cannedTextId, actions::Message& result)
495 actions::Message message{};
497 message.fromPlayer = from;
499 message.numberA = to;
500 message.numberC = cannedTextId;
501 result = std::move(message);
507 if (
text.empty())
return;
513 std::move(
runtime.inputHistory.begin() + 1,
523 entry.senderNameCaptured =
true;
540 runtime.inputHistoryOffset = 0;
545 for (std::size_t player = 0; player <
playerNames.size(); ++player)
556 runtime.outputLayoutReady =
true;
596 return runtime.eligibleRecipients;
601 if (
runtime.fluffSelectedLine < 0)
return 0;
603 static_cast<std::size_t
>(
runtime.fluffSelectedLine));
610 if (!networkMode || !
runtime.fluffOpen ||
612 line >=
static_cast<std::size_t
>(
639 runtime.fluffSelectedLine = -1;
645 std::array<actions::Message, rules::MaxPlayers>
batch{};
663 echo.cannedTextId = cannedTextId;
664 echo.privateMessage =
true;
667 runtime.fluffSelectedLine = -1;
685 if (networkMode)
toggle();
721 ?
static_cast<std::size_t
>(
757 const int x =
static_cast<int>(message.
numberA);
758 const int y =
static_cast<int>(message.
numberB);
771 ?
static_cast<std::size_t
>(
826 if (
runtime.shaded)
return false;
832 runtime.fluffSelectedLine = -1;
854 if (
runtime.fluffSelectedLine < 0)
861 if (
runtime.fluffSelectedLine >= 0)
863 static_cast<std::size_t
>(
runtime.fluffSelectedLine),
892 if (
runtime.inputHistoryOffset > 1)
927 std::array<actions::Message, rules::MaxPlayers>
batch{};
930 if ((selected & (1u << player)) != 0u &&
945 echo.privateMessage =
true;
967 if (
entry.text.empty())
978 std::u16string_view
text,
987 message.fromPlayer = from;
989 message.numberA = to;
991 message.binaryDataA.reserve((
text.size() + 1u) * 2u);
994 const auto value =
static_cast<std::uint16_t
>(
unit);
995 message.binaryDataA.push_back(
static_cast<std::uint8_t
>(
value & 0xFFu));
996 message.binaryDataA.push_back(
static_cast<std::uint8_t
>(
value >> 8u));
998 message.binaryDataA.push_back(0);
999 message.binaryDataA.push_back(0);
1000 result = std::move(message);
1007 std::u16string_view
text)
std::atomic< float > left
std::atomic< float > right
std::vector< std::byte > bytes
bool processInput(const uimsg::Message &message, rules::PlayerNumber sender, std::uint32_t eligibleRecipients, bool networkMode)
std::uint32_t recipientMask() noexcept
bool buildTextAction(rules::PlayerNumber from, rules::PlayerNumber to, std::u16string_view text, actions::Message &result)
constexpr std::size_t HistoryCapacity
std::uint32_t eligibleRecipients() noexcept
bool activateFluffLine(std::size_t line, rules::PlayerNumber sender, std::uint32_t eligibleRecipients, bool networkMode)
const State & stateReadOnly() noexcept
constexpr std::size_t MaxInputCharacters
std::int64_t selectedFluffMessageId() noexcept
void setPlayerNames(const rules::GameState &gameState)
constexpr std::array< int, 6 > FluffCategoryLineCounts
constexpr std::size_t InputHistoryCapacity
void setOutputLayoutMetrics(std::size_t wrappedLines, int height, std::size_t visibleLines) noexcept
void setRecipientMask(std::uint32_t mask) noexcept
const Entry * entryAt(std::size_t index) noexcept
void setFluffSelectionText(std::int64_t cannedTextId, std::u16string_view text)
bool sendText(rules::PlayerNumber from, rules::PlayerNumber to, std::u16string_view text)
constexpr std::array< std::int64_t, 6 > FluffCategoryMessageStarts
bool processRuleMessage(const actions::Message &message)
std::size_t queuedActionCount()
constexpr std::size_t MessageQueueCapacity
bool sendAction(const actions::Message &message)
constexpr PlayerNumber BankPlayer
std::uint8_t PlayerNumber
constexpr PlayerNumber SpectatorPlayer
constexpr PlayerNumber MaxPlayers
constexpr PlayerNumber AllPlayers
std::vector< std::uint8_t > binaryDataA
std::array< wchar_t, 80 > stringA