Monopoly — Portage moderne 0.1.0
Portage moderne C/C++23 du Monopoly de 1999
Loading...
Searching...
No Matches
OptionsCustomBoardPlayback.cpp
Go to the documentation of this file.
2#include "FontRuntime.hpp"
5#include <algorithm>
6#include <memory>
7#include <utility>
9{
10 namespace
11 {
13 {
15 image.pixels.assign(496U * 34U * 4U, 0);
16 return image;
17 }
18 struct RestoreFont
19 {
20 fonts::Runtime& font;
21 ~RestoreFont() { (void)font.restoreSettings(0); }
22 };
23 }
24 std::expected<void, std::string> CustomBoardPlayback::sync(CustomBoardState& state,
26 {
27 const bool visible = state.active && view == display::Screen2D::Options;
28 if (!visible && published_.empty()) return {};
29 if (visible && revision_ == state.revision) return {};
30 const std::size_t desiredCount = visible ? 13U + (customBoardHasPrevious(state) ? 1U : 0U) +
31 (customBoardHasNext(state) ? 1U : 0U) : 0U;
32 if (desiredCount + published_.size() > sequence::SequenceCommandQueue::Capacity - playback.commands().pendingCount())
33 return std::unexpected("sequence command queue cannot fit custom-board dialog transition");
34 std::vector<Object> desired;
35 std::vector<std::shared_ptr<const sequence::SequenceProgram>> programs;
36 std::array<Rect, 4> buttonRects{};
37 if (visible)
38 {
39 if (!font || !font->ready()) return std::unexpected("custom-board dialog font runtime is unavailable");
40 const auto resources = playback.resources();
41 if (!resources || !resources->language() || !resources->language()->catalog)
42 return std::unexpected("custom-board dialog language resources are unavailable");
43 const auto title = customBoardTitle(resources->context().board);
44 desired.push_back({title,100,70,0});
45 const auto loadedTitle = sequence::SequenceProgram::load(resources,title);
46 if (!loadedTitle) return std::unexpected(loadedTitle.error().detail);
47 programs.push_back(*loadedTitle);
48 // Preflight every stock asset before publishing any runtime text.
49 for (std::size_t slot = 0; slot < CustomBoardPageSize; ++slot)
50 {
51 const bool selected = state.selectedIndex >= 0 &&
52 static_cast<std::size_t>(state.selectedIndex) == state.pageOffset + slot &&
53 state.pageOffset + slot < state.entries.size();
54 const auto id = data::packDataId(data::LegacyGroupId::Main, selected ? 0x006C : 0x006B);
55 const auto program = sequence::SequenceProgram::load(resources,id);
56 if (!program) return std::unexpected(program.error().detail);
57 desired.push_back({id,static_cast<std::uint16_t>(100 + slot),100,100 + static_cast<int>(slot) * 68});
58 programs.push_back(*program);
59 }
60 std::array<data::LegacyBitmapRGBA8, 9> images{};
61 if (const auto restored = font->restoreSettings(0); !restored) return std::unexpected(restored.error().detail);
62 RestoreFont restore{*font};
63 // UDStats initializes saved slot 3 as Arial10/700; source board names use it.
64 if (const auto sized = font->setSize(10); !sized) return std::unexpected(sized.error().detail);
65 font->setWeight(700);
66 for (std::size_t slot = 0; slot < CustomBoardPageSize; ++slot)
67 {
69 const auto index = state.pageOffset + slot;
70 if (index >= state.entries.size()) continue;
71 const auto copied = font->blitText(
72 images[slot], state.entries[index].displayName,
73 13, 8, 0x00FFFFFFU);
74 if (!copied) return std::unexpected(copied.error().detail);
75 }
76 if (const auto restored = font->restoreSettings(0); !restored) return std::unexpected(restored.error().detail);
77 constexpr std::array<std::uint32_t, 4> ids{933,932,3170,3169};
78 constexpr std::array<int, 4> xs{500,600,100,700};
79 for (std::size_t index = 0; index < ids.size(); ++index)
80 {
81 const auto text = resources->language()->catalog->message(ids[index]);
82 if (!text) return std::unexpected(text.error().detail);
83 auto rendered = font->render(std::u16string_view(**text),0x00FFFFFFU);
84 if (!rendered) return std::unexpected(rendered.error().detail);
85 images[5 + index] = std::move(*rendered);
87 if (enabled) buttonRects[index] = {xs[index],430,xs[index]+static_cast<int>(images[5+index].width),
88 430+static_cast<int>(images[5+index].height)};
89 }
90 // All fallible resource/font reads have succeeded before surfaces are updated.
91 for (std::size_t index = 0; index < images.size(); ++index)
92 {
93 if (!textSurfaces_[index])
94 {
95 const auto created = playback.runtimeBitmaps().create(images[index].width,images[index].height,true);
96 if (!created) return std::unexpected(created.error());
97 textSurfaces_[index] = *created;
98 }
99 if (const auto updated = playback.runtimeBitmaps().update(*textSurfaces_[index],std::move(images[index])); !updated) return updated;
100 if (index >= 5 && buttonRects[index-5].right == 0) continue;
101 const auto program = sequence::SequenceProgram::rawBitmap(*textSurfaces_[index],data::LegacyDataType::Native);
102 if (!program) return std::unexpected(program.error().detail);
103 programs.push_back(*program);
104 if (index < 5)
105 desired.push_back({*textSurfaces_[index],static_cast<std::uint16_t>(101+index),152,112+static_cast<int>(index)*68});
106 else desired.push_back({*textSurfaces_[index],150,xs[index-5],430});
107 }
108 }
109 for (const auto& object : published_)
110 if (!playback.commands().enqueue(sequence::StopSequenceCommand{object.id,object.priority,false}))
111 return std::unexpected("validated custom-board dialog stop rejected");
112 for (std::size_t index = 0; index < desired.size(); ++index)
113 {
114 const auto& object = desired[index];
115 if (!playback.commands().enqueue(sequence::StartSequenceCommand{programs[index],object.priority,{},
116 sequence::moveXYTransform(object.x,object.y)}))
117 return std::unexpected("validated custom-board dialog start rejected");
118 }
119 published_ = std::move(desired);
120 revision_ = visible ? std::optional<std::uint64_t>{state.revision} : std::nullopt;
121 state.buttonRects = buttonRects;
122 return {};
123 }
124 void CustomBoardPlayback::reset() noexcept
125 {
126 textSurfaces_.fill(std::nullopt);
127 published_.clear();
128 revision_.reset();
129 }
130}
std::string_view text
std::atomic< float > right
LegacyBitmapRGBA8 image
fonts::Runtime & font
bool enabled
Definition Engine.cpp:170
data::DataId id
PlayerNumber slot
std::uint32_t height
std::uint32_t width
unsigned state
unsigned index
std::expected< void, std::string > sync(CustomBoardState &state, display::Screen2D view, fonts::Runtime *fontRuntime, engine::SequencePlayback &playback)
static std::expected< std::shared_ptr< const SequenceProgram >, RuntimeError > rawBitmap(data::DataId id, data::LegacyDataType sourceType, DescriptionLimits limits={})
static std::expected< std::shared_ptr< const SequenceProgram >, RuntimeError > load(const data::DataSource &source, data::DataId id, std::size_t offset=0, DescriptionLimits limits={})
constexpr DataId packDataId(std::uint16_t group, DataTag tag) noexcept
Definition DataBanks.hpp:39
constexpr std::size_t CustomBoardPageSize
bool customBoardHasNext(const CustomBoardState &state) noexcept
bool customBoardHasPrevious(const CustomBoardState &state) noexcept
constexpr data::DataId customBoardTitle(data::BoardEdition edition) noexcept
SequenceTransform moveXYTransform(std::int32_t x, std::int32_t y) noexcept
std::vector< std::uint8_t > pixels