Monopoly — Portage moderne 0.1.0
Portage moderne C/C++23 du Monopoly de 1999
Loading...
Searching...
No Matches
PieceIdleDisplay.cpp
Go to the documentation of this file.
2
3#include "PiecePlacement.hpp"
5
6namespace monopoly::pieces
7{
8 namespace
9 {
10 constexpr std::uint8_t StayAtEnd = 2;
11 constexpr std::uint8_t LoopToBeginning = 3;
12
13 [[nodiscard]] bool samePose(
14 const TokenPose& left, const TokenPose& right) noexcept
15 {
16 return left.x == right.x && left.y == right.y &&
17 left.z == right.z && left.yaw == right.yaw;
18 }
19
20 [[nodiscard]] bool excluded(
21 const PieceIdleDisplayContext& context,
22 rules::PlayerNumber player) noexcept
23 {
24 return context.movingPlayer == player ||
25 context.paddywagonPlayer == player ||
26 context.idleMovingOut == player ||
27 context.idleMovingIn == player;
28 }
29 }
30 std::expected<std::optional<TokenPose>, std::string>
31 PieceIdleDisplay::desiredPose(
32 const rules::GameState& state,
33 const PieceIdleState& idleState,
34 const PieceIdleDisplayContext& context,
35 rules::PlayerNumber player) const
36 {
37 if (player >= rules::MaxPlayers)
38 return std::unexpected("persistent idle player is out of range");
39 if (!context.boardVisible || player >= state.numberOfPlayers ||
40 excluded(context, player))
41 return std::optional<TokenPose>{};
42
43 const auto& source = state.players[player];
44 if (source.currentSquare >= 41)
45 return std::optional<TokenPose>{};
46 if (source.token >= rules::MaxTokens)
47 return std::unexpected("persistent idle token is out of range");
48 if (!idleState.initialized())
49 return std::unexpected("persistent idle occupancy is not initialized");
50
51 if (idleState.center() == player)
52 {
53 const auto pose = tokenOrientation(source.currentSquare);
54 if (!pose)
55 return std::unexpected("persistent center idle square is invalid");
56 return pose;
57 }
58 const auto square = source.currentSquare;
59 const auto& slots = idleState.occupancy()[square];
60 std::optional<std::uint8_t> restingSlot;
61 for (std::uint8_t slot = 0; slot < RestingPositionCount; ++slot)
62 {
63 if (slots[slot] && *slots[slot] == player)
64 restingSlot = slot;
65 }
66 if (!restingSlot)
67 return std::unexpected("persistent resting idle has no occupied slot");
68
69 const auto pose = tokenRestingOrientation(
70 square, *restingSlot, source.token);
71 if (!pose)
72 return std::unexpected("persistent resting idle pose is invalid");
73 return pose;
74 }
75
77 rules::PlayerNumber player) const noexcept
78 {
79 if (player >= rules::MaxPlayers) return data::EmptyDataId;
80 return shown_[player];
81 }
82
84 {
85 shown_.fill(data::EmptyDataId);
86 for (auto& pose : poses_) pose.reset();
87 }
88 std::expected<PieceIdleDisplayUpdate, std::string> PieceIdleDisplay::sync(
91 const PieceIdleDisplayContext& context,
93 {
95 for (rules::PlayerNumber player = 0;
96 player < rules::MaxPlayers; ++player)
97 {
98 const auto wanted = desiredPose(state, idleState, context, player);
99 if (!wanted) return std::unexpected(wanted.error());
100
101 const auto priority = static_cast<std::uint16_t>(
102 PersistentIdlePriority + player);
103 if (!*wanted)
104 {
105 if (shown_[player] != data::EmptyDataId)
106 {
107 const auto stopped = playback.stop(shown_[player], priority);
108 if (!stopped) return std::unexpected(stopped.error());
109 shown_[player] = data::EmptyDataId;
110 poses_[player].reset();
111 ++update.stopped;
112 }
113 continue;
114 }
115
116 const auto& source = state.players[player];
117 const auto tag = static_cast<std::uint32_t>(PersistentIdleBaseTag) +
118 static_cast<std::uint32_t>(IdleAnimationsPerToken) * source.token;
119 if (tag > 0xFFFFU)
120 return std::unexpected("persistent idle sequence tag overflow");
121 const auto sequenceId = data::packDataId(
122 data::LegacyGroupId::ThreeD, static_cast<data::DataTag>(tag));
123 const auto transform = sequence::moveRySTxzTransform(
124 (*wanted)->yaw, 1.0F, (*wanted)->x, (*wanted)->z);
125 if (shown_[player] != sequenceId)
126 {
127 const std::optional<data::DataId> previous =
128 shown_[player] == data::EmptyDataId ? std::nullopt :
129 std::optional<data::DataId>(shown_[player]);
130 const auto transitioned = playback.transitionMovedDrop(
131 previous, sequenceId, priority, transform,
132 context.animationsEnabled ? LoopToBeginning : StayAtEnd);
133 if (!transitioned) return std::unexpected(transitioned.error());
134 if (previous) ++update.stopped;
135 ++update.started;
136 shown_[player] = sequenceId;
137 poses_[player] = **wanted;
138 continue;
139 }
140
141 if (!poses_[player] || !samePose(*poses_[player], **wanted))
142 {
143 const auto moved = playback.move(sequenceId, priority, transform);
144 if (!moved) return std::unexpected(moved.error());
145 poses_[player] = **wanted;
146 ++update.moved;
147 }
148 }
149 return update;
150 }
151}
std::atomic< float > left
std::atomic< float > right
std::uint16_t priority
PlayerNumber slot
std::shared_ptr< const data::HmdTextureImage > source
unsigned state
unsigned index
data::DataId shownSequence(rules::PlayerNumber player) const noexcept
std::expected< PieceIdleDisplayUpdate, std::string > sync(const rules::GameState &state, const PieceIdleState &idleState, const PieceIdleDisplayContext &context, 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
constexpr std::uint8_t LoopToBeginning
std::optional< TokenPose > tokenOrientation(std::uint8_t boardSquare) noexcept
constexpr std::uint8_t RestingPositionCount
constexpr data::DataTag IdleAnimationsPerToken
constexpr std::uint16_t PersistentIdlePriority
constexpr data::DataTag PersistentIdleBaseTag
std::optional< TokenPose > tokenRestingOrientation(std::uint8_t boardSquare, std::uint8_t restingPosition, std::uint8_t token) noexcept
std::uint8_t PlayerNumber
Definition RuleTypes.hpp:12
constexpr std::size_t MaxTokens
Definition RuleTypes.hpp:30
constexpr PlayerNumber MaxPlayers
Definition RuleTypes.hpp:14
Matrix3D moveRySTxzTransform(float yaw, float scale, float x, float z) noexcept