Monopoly — Portage moderne 0.1.0
Portage moderne C/C++23 du Monopoly de 1999
Loading...
Searching...
No Matches
PieceIdleTransition.cpp
Go to the documentation of this file.
2
3#include <numbers>
4
5namespace monopoly::pieces
6{
7 namespace
8 {
9 [[nodiscard]] bool validPlayer(const rules::GameState& state,
10 rules::PlayerNumber player) noexcept
11 {
12 return player < state.numberOfPlayers && player < rules::MaxPlayers;
13 }
14
15 [[nodiscard]] std::optional<std::uint8_t> chooseSourceFreeSlot(
16 const PieceIdleState::SquareSlots& slots) noexcept
17 {
18 std::optional<std::uint8_t> selected;
19 for (int index = RestingPositionCount - 1; index >= 0; --index)
20 if (!slots[static_cast<std::size_t>(index)])
21 selected = static_cast<std::uint8_t>(index);
22 return selected;
23 }
24
25 [[nodiscard]] std::optional<std::uint8_t> findSourcePlayerSlot(
26 const PieceIdleState::SquareSlots& slots,
27 rules::PlayerNumber player) noexcept
28 {
29 std::optional<std::uint8_t> selected;
30 for (std::uint8_t index = 0; index < RestingPositionCount; ++index)
31 if (slots[index] && *slots[index] == player) selected = index;
32 return selected;
33 }
34
35 [[nodiscard]] std::expected<PieceIdleAnimation, PieceIdleTransitionError>
36 makeIdleAnimation(const rules::GameState& state,
37 rules::PlayerNumber player, std::uint8_t slot,
38 data::DataTag baseTag) noexcept
39 {
40 if (!validPlayer(state, player))
41 return std::unexpected(PieceIdleTransitionError::InvalidPlayer);
42 const auto& source = state.players[player];
43 if (source.currentSquare >= 41)
44 return std::unexpected(PieceIdleTransitionError::InvalidSquare);
45 if (source.token >= rules::MaxTokens)
46 return std::unexpected(PieceIdleTransitionError::InvalidToken);
47 const auto category = restingIdleCategory(source.currentSquare);
48 const auto pose = tokenOrientation(source.currentSquare);
49 if (!category || !pose)
50 return std::unexpected(PieceIdleTransitionError::InvalidSquare);
51
52 const auto categoryIndex = static_cast<std::uint32_t>(*category);
53 const auto tag = static_cast<std::uint32_t>(baseTag) +
54 static_cast<std::uint32_t>(IdleAnimationsPerToken) * source.token +
55 2U * slot + 12U * categoryIndex;
56 if (tag > 0xFFFFU)
57 return std::unexpected(PieceIdleTransitionError::InvalidToken);
58
59 auto adjusted = *pose;
63 adjusted.yaw -= std::numbers::pi_v<float> / 2.0F;
64 return PieceIdleAnimation{
65 player, slot,
67 static_cast<data::DataTag>(tag)),
68 adjusted};
69 }
70 }
71
73 {
74 for (auto& square : occupancy_)
75 for (auto& slot : square) slot.reset();
76 center_.reset();
77 initialized_ = false;
78 }
79
80 std::expected<void, PieceIdleTransitionError> PieceIdleState::initializeNewGame(
81 const rules::GameState& state) noexcept
82 {
83 reset();
84 if (state.numberOfPlayers > rules::MaxPlayers)
85 return std::unexpected(PieceIdleTransitionError::InvalidProjection);
87 slot < state.numberOfPlayers; ++slot)
88 {
89 const auto player = static_cast<rules::PlayerNumber>(
90 state.numberOfPlayers - slot - 1U);
91 occupancy_[0][slot] = player;
92 }
93 initialized_ = true;
94 return {};
95 }
96 std::expected<void, PieceIdleTransitionError> PieceIdleState::initialize(
98 std::optional<rules::PlayerNumber> center) noexcept
99 {
100 reset();
101 if (state.numberOfPlayers > rules::MaxPlayers)
102 return std::unexpected(PieceIdleTransitionError::InvalidProjection);
103 if (center && !validPlayer(state, *center))
104 return std::unexpected(PieceIdleTransitionError::InvalidPlayer);
105
106 for (rules::PlayerNumber player = 0;
107 player < state.numberOfPlayers; ++player)
108 {
109 const auto square = state.players[player].currentSquare;
110 if (square >= BoardSquareCountWithSpecials)
111 return std::unexpected(PieceIdleTransitionError::InvalidSquare);
112 auto& slots = occupancy_[square];
113 const auto selected = chooseSourceFreeSlot(slots);
114 if ((!center || player != *center) && !selected)
115 return std::unexpected(PieceIdleTransitionError::InvalidProjection);
116 if (!center || player != *center) slots[*selected] = player;
117 }
118 center_ = center;
119 initialized_ = true;
120 return {};
121 }
122
123 std::expected<PieceIdleTransitionPlan, PieceIdleTransitionError>
126 {
127 if (!initialized_)
128 return std::unexpected(PieceIdleTransitionError::InvalidProjection);
130 return std::unexpected(PieceIdleTransitionError::InvalidPlayer);
131
133 result.newCenter = newCurrent;
134 auto nextOccupancy = occupancy_;
135
136 if (center_)
137 {
138 if (!validPlayer(state, *center_))
139 return std::unexpected(PieceIdleTransitionError::InvalidPlayer);
140 const auto square = state.players[*center_].currentSquare;
141 if (square > 41)
142 return std::unexpected(PieceIdleTransitionError::InvalidSquare);
143 if (square < 41)
144 {
145 auto& slots = nextOccupancy[square];
146 const auto selected = chooseSourceFreeSlot(slots);
147 if (!selected)
148 return std::unexpected(PieceIdleTransitionError::InvalidProjection);
149 auto animation = makeIdleAnimation(state, *center_, *selected,
151 if (!animation) return std::unexpected(animation.error());
152 slots[*selected] = *center_;
153 result.movingOut = *animation;
154 }
155 }
156
157 const auto square = state.players[newCurrent].currentSquare;
158 if (square >= 41)
159 return std::unexpected(PieceIdleTransitionError::InvalidSquare);
160 auto& slots = nextOccupancy[square];
161 const auto selected = findSourcePlayerSlot(slots, newCurrent);
162 if (!selected)
163 return std::unexpected(PieceIdleTransitionError::InvalidProjection);
164 auto animation = makeIdleAnimation(state, newCurrent, *selected,
166 if (!animation) return std::unexpected(animation.error());
167 slots[*selected].reset();
168 result.movingIn = *animation;
169
170 occupancy_ = std::move(nextOccupancy);
171 center_ = newCurrent;
172 return result;
173 }
174}
PlayerNumber slot
std::shared_ptr< const data::HmdTextureImage > source
unsigned state
unsigned index
std::expected< void, PieceIdleTransitionError > initialize(const rules::GameState &state, std::optional< rules::PlayerNumber > center=std::nullopt) noexcept
std::array< Slot, RestingPositionCount > SquareSlots
std::expected< void, PieceIdleTransitionError > initializeNewGame(const rules::GameState &state) noexcept
std::expected< PieceIdleTransitionPlan, PieceIdleTransitionError > planTurnChange(const rules::GameState &state, rules::PlayerNumber newCurrent) noexcept
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 BoardSquareCountWithSpecials
std::optional< RestingIdleCategory > restingIdleCategory(std::uint8_t boardSquare) noexcept
std::optional< TokenPose > tokenOrientation(std::uint8_t boardSquare) noexcept
constexpr data::DataTag IdleToRestBaseTag
constexpr std::uint8_t RestingPositionCount
constexpr data::DataTag IdleAnimationsPerToken
constexpr data::DataTag RestToCenterBaseTag
std::uint8_t PlayerNumber
Definition RuleTypes.hpp:12
constexpr std::size_t MaxTokens
Definition RuleTypes.hpp:30
constexpr PlayerNumber MaxPlayers
Definition RuleTypes.hpp:14