Monopoly — Portage moderne 0.1.0
Portage moderne C/C++23 du Monopoly de 1999
Loading...
Searching...
No Matches
PlayerSetupFlow.cpp
Go to the documentation of this file.
1#include "PlayerSetupFlow.hpp"
2
3#include <algorithm>
4#include <array>
5#include <cstddef>
6#include <cstdint>
7#include <string>
8#include <string_view>
9#include <utility>
10
12{
13 namespace
14 {
15 using rules::GameState;
17 using rules::MaxTokens;
18
19
20 struct ButtonRect
21 {
24
25 Rect rect{};
26 };
27
28
29 // ----------------------------------------------------
30 // Coordonnées exactes du UDPsel.cpp 800x600.
31 // ----------------------------------------------------
32
33 constexpr Rect EnterNameNextRect{
34 341,
35 434,
36 468,
37 470
38 };
39
40
41 constexpr std::array<ButtonRect, 10> SelectPlayerButtons{{
42 { Button::SelectPlayerNew, { 547, 241, 676, 388 } },
43 { Button::SelectPlayerMore, { 506, 400, 726, 462 } },
44 { Button::SelectPlayerCard1, { 35, 253, 132, 363 } },
45 { Button::SelectPlayerCard2, { 141, 253, 238, 363 } },
46 { Button::SelectPlayerCard3, { 241, 253, 338, 363 } },
47 { Button::SelectPlayerCard4, { 344, 253, 441, 363 } },
48 { Button::SelectPlayerCard5, { 36, 370, 133, 480 } },
49 { Button::SelectPlayerCard6, { 141, 371, 238, 481 } },
50 { Button::SelectPlayerCard7, { 242, 371, 339, 481 } },
51 { Button::SelectPlayerCard8, { 345, 372, 442, 482 } }
52 }};
53
54
55 constexpr std::array<
56 ButtonRect,
57 12
58 > TokenButtons{{
59 {
61 { 77, 252, 177, 293 }
62 },
63
64 {
66 { 225, 252, 325, 293 }
67 },
68
69 {
71 { 376, 252, 476, 293 }
72 },
73
74 {
76 { 77, 311, 177, 352 }
77 },
78
79 {
81 { 225, 311, 325, 352 }
82 },
83
84 {
86 { 376, 311, 476, 352 }
87 },
88
89 {
91 { 77, 371, 177, 412 }
92 },
93
94 {
96 { 225, 371, 325, 412 }
97 },
98
99 {
101 { 376, 371, 476, 412 }
102 },
103
104 {
106 { 77, 432, 177, 473 }
107 },
108
109 {
111 { 225, 432, 325, 473 }
112 },
113
114 {
116 { 362, 434, 489, 470 }
117 }
118 }};
119
120
121 constexpr std::array<
122 ButtonRect,
123 4
124 > StartButtons{{
125 {
127 { 40, 254, 260, 316 }
128 },
129
130 {
132 { 545, 255, 765, 317 }
133 },
134
135 {
137 { 290, 255, 510, 317 }
138 },
139
140 {
142 { 290, 328, 510, 390 }
143 }
144 }};
145
146
147 constexpr Rect RemoveCancelRect{
148 291,
149 401,
150 511,
151 463
152 };
153
154
155 constexpr std::array<
156 ButtonRect,
157 3
158 > AIButtons{{
159 {
161 { 52, 254, 272, 316 }
162 },
163
164 {
166 { 291, 254, 511, 316 }
167 },
168
169 {
171 { 532, 254, 752, 316 }
172 }
173 }};
174
175
176 inline constexpr int UsaCityCount = 11;
177 inline constexpr int EuropeCountryCount = 12;
178
179 constexpr std::array<
180 ButtonRect,
181 5
182 > CityButtons{{
183 { Button::CityClassic, { 73, 214, 293, 276 } },
184 { Button::CityLoadBoard, { 507, 214, 727, 276 } },
185 { Button::CityLeft, { 320, 408, 343, 421 } },
186 { Button::CityRight, { 458, 408, 481, 421 } },
187 { Button::CityNext, { 341, 434, 468, 470 } }
188 }};
189
190 constexpr std::array<ButtonRect, 7> EuropeCityButtons{{
191 { Button::CityClassic, { 73, 214, 293, 276 } },
192 { Button::CityLoadBoard, { 507, 214, 727, 276 } },
193 { Button::CountryLeft, { 145, 442, 168, 455 } },
194 { Button::CountryRight, { 281, 442, 305, 455 } },
195 { Button::CurrencyLeft, { 485, 442, 508, 455 } },
196 { Button::CurrencyRight, { 663, 442, 687, 455 } },
197 { Button::CityNext, { 341, 434, 468, 470 } }
198 }};
199
200 constexpr std::array<
201 ButtonRect,
202 2
204 { Button::RulesStandard, { 75, 254, 295, 316 } },
205 { Button::RulesCustom, { 507, 254, 727, 316 } }
206 }};
207
208 // Fixed retail rectangle. The remaining CustomizeRules controls are
209 // positioned from localized font metrics and stay abstract until that
210 // backend exists.
211 constexpr Rect RulesOkayRect{ 337, 450, 464, 486 };
212
213
214 int languageCountry(data::LanguageId language) noexcept
215 {
216 const int raw = static_cast<int>(language);
217 return raw >= 2 && raw <= 10 ? raw - 2 : 0;
218 }
219
220 void validateEuropeCurrencies(State& state) noexcept
221 {
222 state.currencySelection[0] = state.citySelected;
223 state.currencySelection[1] = languageCountry(state.language);
224 state.currencySelection[2] = MonetarySystemEuro;
225 }
226
227 void cycleEuropeCurrency(State& state, int direction) noexcept
228 {
229 const int previous = state.currencySelection[state.currencySelectionIndex];
230 do
231 {
232 state.currencySelectionIndex =
233 (state.currencySelectionIndex + direction + 3) % 3;
234 }
235 while (previous == state.currencySelection[state.currencySelectionIndex]);
236 }
237
238 std::uint8_t tokenForButton(
240 {
241 switch (button)
242 {
243 case Button::TokenGun:
244 return TokenGun;
245
246 case Button::TokenCar:
247 return TokenCar;
248
249 case Button::TokenDog:
250 return TokenDog;
251
252 case Button::TokenHat:
253 return TokenHat;
254
256 return TokenIron;
257
259 return TokenHorse;
260
262 return TokenShip;
263
265 return TokenShoe;
266
268 return TokenThimble;
269
271 return TokenBarrow;
272
274 return TokenMoneyBag;
275
276 default:
277 return 0;
278 }
279 }
280
281
282 bool isTokenButton(
284 {
285 return
288 }
289
290
293 std::size_t& slot)
294 {
297 {
298 return false;
299 }
300
301 slot = static_cast<std::size_t>(
302 static_cast<std::uint8_t>(button) -
303 static_cast<std::uint8_t>(Button::SelectPlayerCard1));
304 return true;
305 }
306
307
308 void startPhase(
309 State& state,
310 const GameState& uiState,
311 Phase phase)
312 {
313 // udpsel_StartPhase().
314
315 state.phase =
316 phase;
317
318
319 switch (phase)
320 {
321 case Phase::EnterName:
322 {
323 state.aiLevel = 0;
324
325 // Le jeu affichait immédiatement "_"
326 // pour permettre de taper sans attendre
327 // la fin des animations.
328 state.name = L"_";
329
330 break;
331 }
332
333
335 {
336 if (state.boardEdition == data::BoardEdition::Europe)
337 {
338 state.citySelected = languageCountry(state.language);
340 state.currencySelectionIndex = 0;
341 }
342 break;
343 }
344
346 {
347 if (state.aiLevel > 0)
348 {
349 state.token =
351 uiState,
352 state.token
353 );
354 }
355 else
356 {
357 state.token =
359 state,
360 uiState,
361 state.name
362 );
363 }
364
365 break;
366 }
367
368
369 default:
370 break;
371 }
372 }
373
374
375 std::wstring cleanedEnteredName(
376 std::wstring name)
377 {
378 if (
379 !name.empty() &&
380 name.back() == L'_')
381 {
382 name.pop_back();
383 }
384
385 return name;
386 }
387
388
389 std::wstring aiTokenName(
390 const State& state)
391 {
392 if (state.token >=
393 state.tokenNames.size())
394 {
395 return {};
396 }
397
398
399 std::wstring result =
400 state.tokenNames[
401 state.token
402 ];
403
404
405 // UDPsel.cpp :
406 // 10 caractères normalement.
407 // Le dé à coudre dispose de 11 caractères
408 // pour sa traduction française.
409 const std::size_t maximum =
410 state.token ==
414
415
416 if (result.size() > maximum)
417 {
418 result.resize(maximum);
419 }
420
421
422 return result;
423 }
424 }
425
426
428 State& state,
429 bool serverMode)
430 {
431 state = {};
432
433 state.phase =
435
436 state.desiredPhase =
438
439 state.name =
440 L"_";
441
442 state.token =
443 TokenGun;
444
445 state.aiLevel = 0;
446
447 state.serverMode =
448 serverMode;
449 }
450
451
453 State& state,
454 std::uint8_t token,
455 std::wstring_view name)
456 {
457 if (token >=
458 state.tokenNames.size())
459 {
460 return;
461 }
462
463
464 state.tokenNames[token] =
465 name;
466 }
467
468
470 State& state,
471 bool available)
472 {
473 state.hasPlayerLogEntries = available;
474
475 if (!available)
476 {
477 state.playerLogCount = 0;
478 state.playerLogPageStart = 0;
479 state.playerLog = {};
480 }
481 }
482
483
485 State& state,
487 std::span<const std::wstring> entries)
488 {
489 state.playerLog = {};
490 state.playerLogCount = 0;
491 state.playerLogPageStart = 0;
492
493 for (const auto& sourceName : entries)
494 {
495 if (sourceName.empty() ||
496 state.playerLogCount >= state.playerLog.size())
497 {
498 continue;
499 }
500
501 std::wstring candidate = sourceName;
504
505 bool alreadySelected = false;
506 for (rules::PlayerNumber player = 0;
507 player < uiState.numberOfPlayers;
508 ++player)
509 {
510 if (uiState.players[player].name == candidate)
511 {
512 alreadySelected = true;
513 break;
514 }
515 }
516
517 if (!alreadySelected)
518 state.playerLog[state.playerLogCount++] = std::move(candidate);
519 }
520
521 state.hasPlayerLogEntries = state.playerLogCount != 0;
522 }
523
524
526 State& state,
527 std::wstring_view name)
528 {
529 std::wstring result(name);
530
531
532 if (
533 result.size() >
535 {
536 result.resize(
538 );
539 }
540
541
542 state.name =
543 std::move(result);
544 }
545
546
548 State& state,
549 const GameState& uiState,
551 {
552 // UDPSEL_SwitchPhase().
553
554 if (requested == state.phase)
555 {
556 return;
557 }
558
559
560 Phase actual =
561 requested;
562
563
564 switch (requested)
565 {
567 {
568 // Si aucun historique n'existe, le jeu
569 // passe directement à ENTERNAME.
570 if (!state.hasPlayerLogEntries)
571 {
572 actual =
574 }
575
576 break;
577 }
578
579
580 default:
581 break;
582 }
583
584
585 state.desiredPhase =
586 actual;
587
588
589 // Le moteur moderne n'a pas encore les anim-outs
590 // LED/Sequencer : le passage logique peut donc être
591 // commité immédiatement.
592 startPhase(
593 state,
594 uiState,
595 actual
596 );
597 }
598
599
601 const GameState& uiState,
602 std::uint8_t token)
603 {
604 for (
605 rules::PlayerNumber player = 0;
606 player < uiState.numberOfPlayers;
607 ++player)
608 {
609 if (
610 uiState.players[player].token ==
611 token)
612 {
613 return false;
614 }
615 }
616
617
618 return true;
619 }
620
621
622 std::uint8_t nextAvailableToken(
623 const GameState& uiState,
624 std::uint8_t currentToken)
625 {
626 // udpsel_DetermineNextAvailableToken() exact.
627
628 const std::uint8_t original =
629 static_cast<std::uint8_t>(
630 currentToken %
631 MaxTokens
632 );
633
634
635 std::uint8_t token =
636 static_cast<std::uint8_t>(
637 (
638 original + 1
639 ) %
640 MaxTokens
641 );
642
643
644 // Comportement original :
645 // aucun joueur => renvoyer immédiatement
646 // le token SUIVANT.
647 if (uiState.numberOfPlayers == 0)
648 {
649 return token;
650 }
651
652
653 while (true)
654 {
655 if (
657 uiState,
658 token
659 ))
660 {
661 return token;
662 }
663
664
665 token =
666 static_cast<std::uint8_t>(
667 (
668 token + 1
669 ) %
670 MaxTokens
671 );
672
673
674 if (token == original)
675 {
676 return original;
677 }
678 }
679 }
680
681
682 std::uint8_t tokenFromName(
683 const State& state,
684 const GameState& uiState,
685 std::wstring_view name)
686 {
687 // udpsel_GetTokenByName().
688
689 for (
690 std::uint8_t token = 0;
691 token < MaxTokens;
692 ++token)
693 {
694 if (
695 !state.tokenNames[token].empty() &&
696 state.tokenNames[token] == name)
697 {
698 return token;
699 }
700 }
701
702
703 return
705 uiState,
707 );
708 }
709
710
712 const GameState& uiState,
713 std::uint8_t currentColour)
714 {
715 // udpsel_DetermineNextAvailableColour() exact.
716
717 const std::uint8_t original =
718 static_cast<std::uint8_t>(
720 MaxPlayerColours
721 );
722
723
724 std::uint8_t colour =
725 original;
726
727
728 if (uiState.numberOfPlayers == 0)
729 {
730 return colour;
731 }
732
733
734 while (true)
735 {
736 bool available = true;
737
738
739 for (
740 rules::PlayerNumber player = 0;
741 player < uiState.numberOfPlayers;
742 ++player)
743 {
744 if (
745 uiState.players[player].colour ==
746 colour)
747 {
748 available = false;
749 break;
750 }
751 }
752
753
754 if (available)
755 {
756 return colour;
757 }
758
759
760 colour =
761 static_cast<std::uint8_t>(
762 (
763 colour + 1
764 ) %
765 MaxPlayerColours
766 );
767
768
769 if (colour == original)
770 {
771 return original;
772 }
773 }
774 }
775
776
778 Phase phase,
779 int x,
780 int y,
781 data::BoardEdition edition)
782 {
783 switch (phase)
784 {
786 {
787 for (const auto& entry : SelectPlayerButtons)
788 {
789 if (entry.rect.contains(x, y))
790 return entry.button;
791 }
792 break;
793 }
794
795
796 case Phase::EnterName:
797 {
798 if (
799 EnterNameNextRect.contains(
800 x,
801 y
802 ))
803 {
804 return
806 }
807
808 break;
809 }
810
811
813 {
814 for (
815 const auto& entry :
817 {
818 if (
819 entry.rect.contains(
820 x,
821 y
822 ))
823 {
824 return entry.button;
825 }
826 }
827
828 break;
829 }
830
831
833 {
834 for (
835 const auto& entry :
837 {
838 if (
839 entry.rect.contains(
840 x,
841 y
842 ))
843 {
844 return entry.button;
845 }
846 }
847
848 break;
849 }
850
851
853 {
854 if (
855 RemoveCancelRect.contains(
856 x,
857 y
858 ))
859 {
860 return
862 }
863
864 break;
865 }
866
867
869 {
870 for (
871 const auto& entry :
872 AIButtons)
873 {
874 if (
875 entry.rect.contains(
876 x,
877 y
878 ))
879 {
880 return entry.button;
881 }
882 }
883
884 break;
885 }
886
887
889 {
890 if (edition == data::BoardEdition::Europe)
891 {
892 for (const auto& entry : EuropeCityButtons)
893 if (entry.rect.contains(x, y)) return entry.button;
894 }
895 else
896 {
897 for (const auto& entry : CityButtons)
898 if (entry.rect.contains(x, y)) return entry.button;
899 }
900 break;
901 }
902
903
905 {
906 for (const auto& entry : RulesChoiceButtons)
907 {
908 if (entry.rect.contains(x, y))
909 return entry.button;
910 }
911 break;
912 }
913
914
916 {
917 if (RulesOkayRect.contains(x, y))
918 return Button::RulesOkay;
919 break;
920 }
921
922
923 default:
924 break;
925 }
926
927
928 return Button::None;
929 }
930
931
933 State& state,
934 const GameState& uiState,
936 {
937 Command command{};
938
939
940 if (button == Button::None)
941 {
942 return command;
943 }
944
945
946 // ----------------------------------------------------
947 // SELECT PLAYER
948 // ----------------------------------------------------
949
950 if (state.phase == Phase::SelectPlayer)
951 {
953 {
954 state.aiLevel = 0;
956 return command;
957 }
958
960 {
961 if (state.playerLogCount > PlayerHistoryPageSize)
962 {
963 state.playerLogPageStart += PlayerHistoryPageSize;
964 if (state.playerLogPageStart >= state.playerLogCount)
965 state.playerLogPageStart = 0;
966 }
967 return command;
968 }
969
970 std::size_t slot = 0;
972 {
973 const std::size_t entry = state.playerLogPageStart + slot;
974 if (entry < state.playerLogCount)
975 {
976 state.name = state.playerLog[entry];
977 state.aiLevel = 0;
979 }
980 return command;
981 }
982
983 return command;
984 }
985
986
987 // ----------------------------------------------------
988 // ENTER NAME
989 // ----------------------------------------------------
990
991 if (
992 state.phase ==
994 {
995 if (
996 button ==
998 {
1000 state,
1001 uiState,
1003 );
1004 }
1005
1006
1007 return command;
1008 }
1009
1010
1011 // ----------------------------------------------------
1012 // PICK TOKEN
1013 // ----------------------------------------------------
1014
1015 if (
1016 state.phase ==
1018 {
1019 if (isTokenButton(button))
1020 {
1021 state.token =
1023 button
1024 );
1025
1026 return command;
1027 }
1028
1029
1030 if (
1031 button ==
1033 {
1034 std::wstring finalName;
1035
1036
1037 if (state.aiLevel > 0)
1038 {
1039 finalName =
1041 state
1042 );
1043 }
1044 else
1045 {
1046 finalName =
1048 state.name
1049 );
1050 }
1051
1052
1053 if (finalName.empty())
1054 {
1055 return command;
1056 }
1057
1058
1059 command.type =
1062
1063
1064 command.name =
1065 finalName;
1066
1067
1068 command.token =
1069 state.token;
1070
1071
1072 // PC_RED = 0.
1073 command.colour =
1075 uiState,
1076 0
1077 );
1078
1079
1080 command.aiLevel =
1081 state.aiLevel;
1082
1083
1085 state,
1086 uiState,
1088 );
1089
1090
1091 // Original :
1092 // reset du nom après l'ajout.
1093 state.name =
1094 L"_";
1095
1096
1097 return command;
1098 }
1099
1100
1101 return command;
1102 }
1103
1104
1105 // ----------------------------------------------------
1106 // START / ADD / REMOVE
1107 // ----------------------------------------------------
1108
1109 if (
1110 state.phase ==
1112 {
1113 switch (button)
1114 {
1115 case Button::AddHuman:
1116 {
1117 state.aiLevel = 0;
1118
1119
1121 state,
1122 uiState,
1124 );
1125
1126 return command;
1127 }
1128
1129
1131 {
1133 state,
1134 uiState,
1136 );
1137
1138 return command;
1139 }
1140
1141
1143 {
1145 state,
1146 uiState,
1148 );
1149
1150 return command;
1151 }
1152
1153
1154 case Button::StartGame:
1155 {
1156 state.startButtonPressed =
1157 true;
1158
1159
1160 command.type =
1162
1163
1164 if (state.serverMode)
1165 {
1167 state,
1168 uiState,
1170 );
1171 }
1172 else
1173 {
1175 state,
1176 uiState,
1178 );
1179 }
1180
1181
1182 return command;
1183 }
1184
1185
1186 default:
1187 return command;
1188 }
1189 }
1190
1191
1192 // ----------------------------------------------------
1193 // REMOVE PLAYER
1194 // ----------------------------------------------------
1195
1196 if (
1197 state.phase ==
1199 {
1200 if (
1201 button ==
1203 {
1205 state,
1206 uiState,
1208 );
1209 }
1210
1211
1212 return command;
1213 }
1214
1215
1216 // ----------------------------------------------------
1217 // AI STRENGTH
1218 // ----------------------------------------------------
1219
1220 if (
1221 state.phase ==
1223 {
1224 switch (button)
1225 {
1226 case Button::AIEasy:
1227 state.aiLevel = 1;
1228 break;
1229
1230 case Button::AIMedium:
1231 state.aiLevel = 2;
1232 break;
1233
1234 case Button::AIHard:
1235 state.aiLevel = 3;
1236 break;
1237
1238 default:
1239 return command;
1240 }
1241
1242
1244 state,
1245 uiState,
1247 );
1248
1249
1250 return command;
1251 }
1252
1253
1254 if (
1255 state.phase ==
1257 {
1258 if (state.boardEdition == data::BoardEdition::Europe)
1259 {
1260 switch (button)
1261 {
1263 command.type = CommandType::RequestCustomBoard;
1264 return command;
1265
1267 state.citySelected = state.citySelected > 0
1268 ? state.citySelected - 1 : EuropeCountryCount - 1;
1270 return command;
1271
1273 state.citySelected = state.citySelected < EuropeCountryCount - 1
1274 ? state.citySelected + 1 : 0;
1276 return command;
1277
1280 return command;
1281
1284 return command;
1285
1287 state.citySelected = languageCountry(state.language);
1289 command.type = CommandType::CommitCity;
1290 command.city = state.citySelected;
1291 command.system = state.currencySelection[state.currencySelectionIndex];
1293 return command;
1294
1295 case Button::CityNext:
1296 command.type = CommandType::CommitCity;
1297 command.city = state.citySelected;
1298 command.system = state.currencySelection[state.currencySelectionIndex];
1300 return command;
1301
1302 default:
1303 return command;
1304 }
1305 }
1306
1307 switch (button)
1308 {
1310 command.type = CommandType::RequestCustomBoard;
1311 return command;
1312
1313 case Button::CityLeft:
1314 state.citySelected = state.citySelected > 0
1315 ? state.citySelected - 1 : UsaCityCount - 1;
1316 return command;
1317
1318 case Button::CityRight:
1319 state.citySelected = state.citySelected < UsaCityCount - 1
1320 ? state.citySelected + 1 : 0;
1321 return command;
1322
1324 state.citySelected = 0;
1325 command.type = CommandType::CommitCity;
1326 command.city = 0;
1327 command.system = MonetarySystemUs;
1329 return command;
1330
1331 case Button::CityNext:
1332 command.type = CommandType::CommitCity;
1333 command.city = state.citySelected;
1334 command.system = MonetarySystemUs;
1336 return command;
1337
1338 default:
1339 return command;
1340 }
1341 }
1342
1343
1345 {
1346 switch (button)
1347 {
1349 state.customRulesDesired = true;
1351 return command;
1352
1354 state.customRulesDesired = false;
1355 command.type = CommandType::AcceptStandardRules;
1356 return command;
1357
1358 default:
1359 return command;
1360 }
1361 }
1362
1363
1364 if (state.phase == Phase::CustomizeRules)
1365 {
1366 switch (button)
1367 {
1368 case Button::RulesOkay:
1369 if (state.serverMode)
1370 command.type = CommandType::AcceptCustomRules;
1371 return command;
1372
1374 command.type = CommandType::RestoreStandardRules;
1375 return command;
1376
1378 command.type = CommandType::ApplyShortGameRules;
1379 return command;
1380
1381 default:
1382 return command;
1383 }
1384 }
1385
1386
1387 return command;
1388 }
1389
1390
1392 State& state,
1393 const GameState& uiState,
1394 int x,
1395 int y)
1396 {
1397 return
1399 state,
1400 uiState,
1401 buttonAt(
1402 state.phase,
1403 x,
1404 y,
1405 state.boardEdition
1406 )
1407 );
1408 }
1409
1410
1412 State& state,
1413 const GameState&,
1415 std::uint8_t choice)
1416 {
1417 Command command{};
1418
1419 if (state.phase != Phase::CustomizeRules || !state.serverMode)
1420 return command;
1421
1422 if (choice >= rules::options::setupRuleChoiceCount(rule))
1423 return command;
1424
1426 command.setupRule = rule;
1427 command.ruleChoice = choice;
1428 return command;
1429 }
1430
1431
1433 State& state,
1434 rules::PlayerNumber player)
1435 {
1436 // UDPSEL_PlayerButtonClicked().
1437
1438 Command command{};
1439
1440
1441 if (
1442 state.phase !=
1444 {
1445 return command;
1446 }
1447
1448
1449 if (player >=
1451 {
1452 return command;
1453 }
1454
1455
1456 command.type =
1459
1460
1461 command.player =
1462 player;
1463
1464
1465 state.phase =
1467
1468
1469 state.desiredPhase =
1471
1472
1473 return command;
1474 }
1475}
const char * name
PlayerNumber slot
unsigned state
unsigned index
int token
int colour
Rect rect
Button button
constexpr std::uint32_t UsaCityCount
std::uint8_t setupRuleChoiceCount(SetupRule rule) noexcept
constexpr std::size_t MaxPlayerColours
Definition RuleTypes.hpp:33
std::uint8_t PlayerNumber
Definition RuleTypes.hpp:12
constexpr std::size_t MaxTokens
Definition RuleTypes.hpp:30
constexpr PlayerNumber MaxPlayers
Definition RuleTypes.hpp:14
constexpr std::uint8_t TokenCar
constexpr std::uint8_t TokenThimble
void setPlayerLogEntries(State &state, const rules::GameState &uiState, std::span< const std::wstring > entries)
constexpr std::uint8_t TokenHat
Command playerBarClicked(State &state, rules::PlayerNumber player)
std::uint8_t tokenFromName(const State &state, const GameState &uiState, std::wstring_view name)
constexpr std::uint8_t TokenShoe
void setPlayerLogAvailable(State &state, bool available)
Command clickButton(State &state, const GameState &uiState, Button button)
Command clickAt(State &state, const GameState &uiState, int x, int y)
std::uint8_t nextAvailableColour(const GameState &uiState, std::uint8_t currentColour)
constexpr std::uint8_t TokenIron
bool tokenAvailable(const GameState &uiState, std::uint8_t token)
constexpr std::uint8_t TokenGun
constexpr std::size_t PlayerHistoryPageSize
std::uint8_t nextAvailableToken(const GameState &uiState, std::uint8_t currentToken)
void setEnteredName(State &state, std::wstring_view name)
constexpr std::uint8_t TokenBarrow
void initialize(State &state, bool serverMode)
Command customRuleChoice(State &state, const GameState &, rules::options::SetupRule rule, std::uint8_t choice)
void requestPhase(State &state, const GameState &uiState, Phase requested)
constexpr std::uint8_t TokenHorse
constexpr std::size_t MaximumEnteredNameLength
constexpr std::uint8_t TokenShip
constexpr std::uint8_t TokenDog
void setTokenName(State &state, std::uint8_t token, std::wstring_view name)
constexpr std::uint8_t TokenMoneyBag
Button buttonAt(Phase phase, int x, int y, data::BoardEdition edition)
Update startPhase(State &state, display::PlayerSetupPhase phase, bool aiPlayer, std::uint8_t numberOfPlayers) noexcept