Monopoly — Portage moderne 0.1.0
Portage moderne C/C++23 du Monopoly de 1999
Loading...
Searching...
No Matches
RulePlayers.cpp
Go to the documentation of this file.
1#include "RulePlayers.hpp"
2
3#include "LegacyTextIds.hpp"
4#include "Messaging.hpp"
5#include "PhaseStack.hpp"
6
7#include <algorithm>
8#include <cstddef>
9#include <cwctype>
10#include <string>
11#include <string_view>
12
14{
15 namespace
16 {
17 std::wstring messageString(
18 const actions::Message& message)
19 {
20 return
21 std::wstring(
22 message.stringA.data()
23 );
24 }
25
26
28 std::wstring_view lhs,
29 std::wstring_view rhs)
30 {
31 if (lhs.size() != rhs.size())
32 {
33 return false;
34 }
35
36
37 for (std::size_t i = 0;
38 i < lhs.size();
39 ++i)
40 {
41 if (
42 std::towlower(lhs[i]) !=
43 std::towlower(rhs[i]))
44 {
45 return false;
46 }
47 }
48
49
50 return true;
51 }
52
53
54 void sendRestart()
55 {
60 );
61 }
62
63
64 void notYourPlayer(
65 PlayerNumber player,
66 std::wstring_view requestedName)
67 {
73 0,
74 player,
75 0,
77 );
78 }
79
80
81 void nameInUse(
82 PlayerNumber player,
83 std::wstring_view requestedName)
84 {
90 0,
91 player,
92 0,
94 );
95 }
96 }
97
98
101 const actions::Message& message)
102 {
103 const std::wstring requestedName =
104 messageString(message);
105
106
107 // ====================================================
108 // RULE_NOBODY_PLAYER :
109 // ajouter un nouveau joueur.
110 // ====================================================
111
112 if (
113 message.numberA ==
115 {
116 if (
118 MaxPlayers ||
121 {
127 0,
128 0,
129 0,
131 );
132
133 return;
134 }
135
136
137 const bool badBasicRequest =
138 requestedName.empty() ||
139 requestedName.size() >
141 message.numberC < 0 ||
142 message.numberC >=
143 static_cast<std::int64_t>(
145 ) ||
146 message.numberD < 0 ||
147 message.numberD >=
148 static_cast<std::int64_t>(
150 );
151
152
155
156
157 bool badRequest =
159
160
161 for (PlayerNumber player = 0;
162 player <
164 !badRequest;
165 ++player)
166 {
167 if (
168 state.players[player].token ==
169 message.numberC ||
170 state.players[player].colour ==
171 message.numberD ||
173 state.players[player].name,
175 ))
176 {
177 badRequest = true;
178 conflictingPlayer = player;
179 }
180 }
181
182
183 if (badRequest)
184 {
185 nameInUse(
188 );
189
190 return;
191 }
192
193
194 const PlayerNumber player =
196
197
198 PlayerState& info =
199 state.players[player];
200
201
202 info.name =
203 requestedName.substr(
204 0,
206 );
207
208
209 info.token =
210 static_cast<std::uint8_t>(
211 message.numberC
212 );
213
214
215 info.colour =
216 static_cast<std::uint8_t>(
217 message.numberD
218 );
219
220
221 // ActionNamePlayer ne clampait pas ce champ.
222 info.aiPlayerLevel =
223 static_cast<std::uint8_t>(
224 message.numberB
225 );
226 messaging::setPlayerOwner(player, message.sourceId);
227
228
234 MaxPlayers -
236 0,
237 0
238 );
239
240
241 sendRestart();
242
243 return;
244 }
245
246
247 // ====================================================
248 // Slot existant.
249 // ====================================================
250
251 if (
252 message.numberA < 0 ||
253 message.numberA >=
255 {
257 static_cast<PlayerNumber>(
258 message.numberA
259 ),
261 );
262
263 return;
264 }
265
266
268 static_cast<PlayerNumber>(
269 message.numberA
270 );
271
272
273 // Source Rule.cpp: a remote human may rename/remove only itself;
274 // takeover of an AI follows the phase/option checks below.
275 if (message.sourceId != 0 &&
276 state.players[playerToReplace].aiPlayerLevel == 0 &&
277 message.fromPlayer != playerToReplace)
278 {
280 return;
281 }
282
283
284 // ====================================================
285 // Nom vide :
286 // supprimer le joueur.
287 // Uniquement GF_ADDING_NEW_PLAYERS.
288 // ====================================================
289
290 if (requestedName.empty())
291 {
292 if (
293 phases::current(state).phase !=
295 {
296 nameInUse(
299 );
300
301 return;
302 }
303
304
305 const PlayerState deleted =
308 ];
309
310
316 deleted.token,
317 deleted.colour,
318 deleted.aiPlayerLevel,
319 deleted.name
320 );
321
322
324 static_cast<PlayerNumber>(
326 );
327
328
329 if (
332 {
333 // Le source échange le joueur supprimé
334 // avec le dernier slot.
335
338 ] =
341 ];
342 }
343
344
347 ] = {};
348
349
353
354
360 MaxPlayers -
362 0,
363 0
364 );
365
366
367 sendRestart();
368
369 return;
370 }
371
372
373 // ====================================================
374 // Renommage / takeover IA.
375 // ====================================================
376
377 PlayerState& player =
380 ];
381
382
383 if (
385 player.aiPlayerLevel != 0)
386 {
390 );
391
392 return;
393 }
394
395
396 // Monopoly PC :
397 // RULE_TAKE_OVER_AI_ONLY_WHEN_SAFE = 1.
398 //
399 // Le #if englobe réellement tout le chemin rename,
400 // pas uniquement le cas AI.
401
402 if (
403 phases::current(state).phase !=
405 {
410 static_cast<std::int64_t>(
411 message.action
412 ),
413 0,
414 message.fromPlayer,
415 0
416 );
417
418
419 if (message.fromPlayer !=
421 {
423 message.fromPlayer <
425 ? message.fromPlayer
426 : AllPlayers;
427
428
434 static_cast<std::int64_t>(
435 message.action
436 ),
437 message.fromPlayer,
438 static_cast<std::int64_t>(
440 .phase
441 )
442 );
443
444
445 sendRestart();
446 }
447
448
449 return;
450 }
451
452
453 const std::wstring oldName =
454 player.name;
455
456
457 player.name =
458 requestedName.substr(
459 0,
461 );
462
463
464 player.aiPlayerLevel =
465 static_cast<std::uint8_t>(
466 message.numberB
467 );
468
469
471 // Token et couleur restent ceux du slot original.
472
473
479 player.token,
480 player.colour,
481 player.aiPlayerLevel,
482 player.name
483 );
484
485
491 0,
493 0,
494 oldName
495 );
496
497
498 sendRestart();
499 }
500}
unsigned index
constexpr std::int64_t ErrorWrongPhase
constexpr std::int64_t ErrorPlayerReplaced
constexpr std::int64_t ErrorNotYourPlayer
constexpr std::int64_t ErrorNoMorePlayers
constexpr std::int64_t ErrorNameInUse
constexpr std::int64_t AddingPlayers
std::uint32_t playerOwner(rules::PlayerNumber player)
Definition Messaging.cpp:83
bool sendAction(const actions::Message &message)
void setPlayerOwner(rules::PlayerNumber player, std::uint32_t source)
Definition Messaging.cpp:76
const PendingPhase & current(const GameState &state)
void actionNamePlayer(GameState &state, const actions::Message &message)
constexpr std::size_t MaxPlayerColours
Definition RuleTypes.hpp:33
constexpr PlayerNumber BankPlayer
Definition RuleTypes.hpp:15
std::uint8_t PlayerNumber
Definition RuleTypes.hpp:12
constexpr std::size_t MaxPlayerNameLength
Definition RuleTypes.hpp:26
constexpr std::size_t MaxTokens
Definition RuleTypes.hpp:30
const GameState & state()
constexpr PlayerNumber MaxPlayers
Definition RuleTypes.hpp:14
constexpr PlayerNumber NobodyPlayer
Definition RuleTypes.hpp:16
constexpr PlayerNumber AllPlayers
Definition RuleTypes.hpp:17
rules::PlayerNumber fromPlayer
Definition Actions.hpp:128
std::array< wchar_t, 80 > stringA
Definition Actions.hpp:140
std::array< PlayerState, MaxPlayers > players