Monopoly — Portage moderne 0.1.0
Portage moderne C/C++23 du Monopoly de 1999
Loading...
Searching...
No Matches
StatsPlayerPlayback.cpp
Go to the documentation of this file.
2
3#include <algorithm>
4#include <array>
5#include <map>
6#include <memory>
7#include <set>
8#include <utility>
9
10namespace monopoly::statsui
11{
12 namespace
13 {
14 using Objects = std::vector<PlayerPlayback::Published>;
15
16 [[nodiscard]] constexpr bool bssmMode(ibar::RuleMode mode) noexcept
17 {
18 return mode == ibar::RuleMode::Build ||
19 mode == ibar::RuleMode::Sell ||
22 }
23
24 [[nodiscard]] constexpr data::DataId mainId(data::DataTag tag) noexcept
25 {
27 }
28
30 int square, bool mortgaged) noexcept
31 {
32 const int property = ibar::layout::propertyIndex(square);
33 if (property < 0) return data::EmptyDataId;
34 const auto base = mortgaged
37 static_cast<data::DataTag>(base + property));
38 }
39
40 struct PlayerGeometry
41 {
42 int boxWidth{};
43 int boxHeight{};
45 int deedBoxX{};
46 int deedBoxY{};
48 };
49
50 [[nodiscard]] constexpr PlayerGeometry playerGeometry(
51 std::size_t playerCount) noexcept
52 {
53 if (playerCount > 4)
54 return {130, 226, 120, 5, 300, PlayerBoxSmallBaseTag};
55 return {198, 222, 130, 61, 275, PlayerBoxLargeBaseTag};
56 }
57
58 [[nodiscard]] bool deedVisible(
59 const rules::GameState& gameState, int square,
60 const PlayerPlaybackInputs& inputs) noexcept
61 {
62 const auto bit = ibar::layout::propertyBit(square);
63 switch (inputs.mode)
64 {
66 return bit != 0 && (inputs.mortgageProperties & bit) != 0;
68 return gameState.squares[static_cast<std::size_t>(square)].mortgaged;
70 return bit != 0 && (inputs.buildProperties & bit) != 0;
72 return bit != 0 && (inputs.sellProperties & bit) != 0;
73 default:
74 return true;
75 }
76 }
77
79 const rules::GameState& gameState, int square,
80 ibar::RuleMode mode) noexcept
81 {
82 if (mode == ibar::RuleMode::Mortgage ||
84 return false;
85 return gameState.squares[static_cast<std::size_t>(square)].mortgaged;
86 }
87
88 [[nodiscard]] std::expected<Objects, std::string> desiredObjects(
89 const State& state, const rules::GameState& gameState,
90 const PlayerPlaybackInputs& inputs)
91 {
92 Objects result;
93 const auto count = std::min<std::size_t>(
94 state.playerCount, std::min<std::size_t>(
95 gameState.numberOfPlayers, rules::MaxPlayers));
96 const auto geometry = playerGeometry(count);
97 const bool localBssm = bssmMode(inputs.mode) &&
98 inputs.iBarPlayerLocalHuman;
99
100 int boxGapOffset = 3;
101 for (std::size_t column = 0; column < count; ++column)
102 {
103 const auto player = state.playerOrder[column];
104 if (player >= gameState.numberOfPlayers || player >= rules::MaxPlayers)
105 return std::unexpected(
106 "UDStats Player sort references invalid player");
107 if (localBssm && player != inputs.iBarPlayer)
108 continue;
109
110 const auto colour = gameState.players[player].colour;
112 return std::unexpected(
113 "UDStats Player colour is out of range");
114 result.push_back({
115 mainId(static_cast<data::DataTag>(geometry.boxBaseTag + colour)),
117 static_cast<int>(column) * geometry.boxWidth + boxGapOffset,
118 224});
119 boxGapOffset += 3;
120
121 for (int square = 0; square < static_cast<int>(rules::SquareCount); ++square)
122 {
123 if (gameState.squares[static_cast<std::size_t>(square)].owner != player)
124 continue;
125 const int order = ibar::layout::propertyBarOrder(square);
126 if (order < 0 || !deedVisible(gameState, square, inputs))
127 continue;
128 const auto rect = playerPropertyRect(state, gameState, column, square);
129 if (!rect) return std::unexpected("UDStats Player deed geometry failed");
130 const int x = rect->left;
131 const int y = rect->top;
132 const auto id = deedId(square,
133 deedUsesMortgagedFace(gameState, square, inputs.mode));
134 if (id == data::EmptyDataId)
135 return std::unexpected(
136 "UDStats Player owned square has no deed sequence");
137 result.push_back({id,
138 static_cast<std::uint16_t>(PlayerDeedBasePriority + order),
139 x, y});
140 }
141 }
142 return result;
143 }
144 }
145
146 std::expected<void, std::string> PlayerPlayback::sync(
147 const State& state, const rules::GameState& gameState,
150 {
153 state.screen == Screen::Player)
154 {
156 if (!planned) return std::unexpected(planned.error());
157 desired = std::move(*planned);
158 }
159
160 if (desired == current_) return {};
161
162 std::map<data::DataId, std::shared_ptr<const sequence::SequenceProgram>> programs;
163 for (const auto& object : desired)
164 {
165 if (programs.contains(object.id)) continue;
166 auto loaded = sequence::SequenceProgram::load(playback.resources(), object.id);
167 if (!loaded)
168 return std::unexpected(
169 "UDStats Player overlay resource failed: " + loaded.error().detail);
170 programs.emplace(object.id, std::move(*loaded));
171 }
172 std::set<std::pair<data::DataId, std::uint16_t>> stops;
173 for (const auto& object : current_)
174 stops.emplace(object.id, object.priority);
175
176 const std::size_t required = stops.size() + desired.size();
178 playback.commands().pendingCount())
179 {
180 return std::unexpected(
181 "sequence command queue cannot fit UDStats Player overlay transition");
182 }
183
184 for (const auto& [id, priority] : stops)
185 {
186 if (!playback.commands().enqueue(
188 return std::unexpected("validated UDStats Player stop rejected");
189 }
190 for (const auto& object : desired)
191 {
192 if (!playback.commands().enqueue(sequence::StartSequenceCommand{
193 programs.at(object.id), object.priority, {},
194 sequence::moveXYTransform(object.x, object.y)}))
195 return std::unexpected("validated UDStats Player start rejected");
196 }
197
198 current_ = std::move(desired);
199 return {};
200 }
201}
std::size_t count
data::DataId id
std::uint16_t priority
unsigned state
unsigned index
int colour
Rect rect
int deedBoxX
int deedBoxWidth
data::DataTag boxBaseTag
int boxHeight
int boxWidth
int deedBoxY
static std::expected< std::shared_ptr< const SequenceProgram >, RuntimeError > load(const data::DataSource &source, data::DataId id, std::size_t offset=0, DescriptionLimits limits={})
std::expected< void, std::string > sync(const State &state, const rules::GameState &gameState, const PlayerPlaybackInputs &inputs, display::Screen2D desiredView, engine::SequencePlayback &playback)
std::uint32_t DataId
Definition DataBanks.hpp:10
constexpr DataId EmptyDataId
Definition DataBanks.hpp:13
std::uint16_t DataTag
Definition DataBanks.hpp:11
constexpr DataId packDataId(std::uint16_t group, DataTag tag) noexcept
Definition DataBanks.hpp:39
int propertyIndex(int square) noexcept
PropertyMask propertyBit(int square) noexcept
int propertyBarOrder(int square) noexcept
constexpr std::size_t MaxPlayerColours
Definition RuleTypes.hpp:33
constexpr std::size_t SquareCount
Definition RuleTypes.hpp:24
constexpr PlayerNumber MaxPlayers
Definition RuleTypes.hpp:14
SequenceTransform moveXYTransform(std::int32_t x, std::int32_t y) noexcept
constexpr std::uint16_t PlayerBoxPriority
constexpr data::DataTag PlayerBoxLargeBaseTag
constexpr data::DataTag PlayerDeedMortgagedBaseTag
constexpr data::DataTag PlayerDeedNormalBaseTag
constexpr std::uint16_t PlayerDeedBasePriority
std::optional< Rect > playerPropertyRect(const State &state, const rules::GameState &gameState, std::size_t column, int square) noexcept
Definition StatsUI.cpp:380
constexpr data::DataTag PlayerBoxSmallBaseTag