1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034
|
/* $Header: /home/jcb/newmj/RCS/protocol.h,v 11.6 2002/03/30 18:43:29 jcb Rel $
* protocol.h
* defines the messages passed between players and controller
*/
/****************** COPYRIGHT STATEMENT **********************
* This file is Copyright (c) 2000 by J. C. Bradfield. *
* Distribution and use is governed by the LICENCE file that *
* accompanies this file. *
* The moral rights of the author are asserted. *
* *
***************** DISCLAIMER OF WARRANTY ********************
* This code is not warranted fit for any purpose. See the *
* LICENCE file for further information. *
* *
*************************************************************/
#ifndef PROTOCOL_H_INCLUDED
#define PROTOCOL_H_INCLUDED
#include "tiles.h"
#include "player.h" /* required for ChowPosition */
/* some constants */
/* This is the largest wall that this level of the protocol supports */
#define MAX_WALL_SIZE 144
/* a bool is an integer constrained to be 0 or 1 */
typedef int bool;
/* a word16 is a word of at most 15 (to allow for final null) characters,
without white space */
typedef char word16[16];
/* First we have the definitions for options. These are logically
part of the game module, but they are also needed by the this
module. Unfortunately, protocol.h can't just include game.h,
since game.h depends on this, and I can't see how to remove
the circularity.
*/
/* here are the names of the options. Option 0 for unknown.
The End option also has special reserved meaning.
Names (omitting GO) shd be 15 chars or less */
typedef enum {
/* make-enums sub { $_[0] =~ s/^GO//; } */
GOUnknown=0,
GOTimeout, /* the timeout in seconds for claims. Default: 15 */
GOScoreLimit, /* limit for score. Default 1000 */
GONoLimit, /* true if no limit on scores. Then ScoreLimit is
notional value of limit hand */
GOMahJongScore, /* base points for going out */
GOSevenPairs, /* seven pairs hand allowed? */
GOSevenPairsVal, /* value of a seven pair hand */
/* the following group of options concerns flowers, by
which is meant flowers and seasons as in the classical
rules */
GOFlowers, /* are flowers to be dealt? */
GOFlowersLoose, /* flowers replaced from dead wall? */
GOFlowersOwnEach, /* score for each own flower or season */
GOFlowersOwnBoth, /* score for own flower and season. N.B.
In this case there will also be two
scores of FlowersOwnEach */
GOFlowersBouquet, /* all four flowers or all four seasons */
GODeadWall, /* is there a dead wall, or do we play to the end? */
GODeadWall16, /* is the dead wall 16 tiles unreplenished (per Millington)
or the normal 14 replenished. */
GOConcealedFully, /* score for a fully concealed hand */
GOConcealedAlmost, /* score for hand concealed up to mah jong,
or to end of game (if next option applies) */
GOLosersPurity, /* do losers score the doubles for pure and almost
concealed hand? */
GOKongHas3Types, /* do we use Millington's 3-way kong distinction? */
GOEnd } GameOption;
#define GONumOptions (GOEnd+1)
/* and the types of options: printed as bool, int, string etc.
The string option is limited to 127 characters, and may
not contain white space. (I can't
remember why I thought it might be wanted.) */
typedef enum {
/* make-enums sub { $_[0] =~ s/^GOT// ; $_[0] =~ y/A-Z/a-z/; } */
GOTBool,
GOTInt,
GOTNat, /* non-negative integer -- introduced at proto 1020 */
GOTScore, /* a score is an int, but with a special interpretation:
if < 10000, it's a number of points; if a multiple of
10000, it's that number of doubles (up to 100); and
a fractional (/100) multiple of 100000000 indicates so
many limits. It may combine a limit with a number
of doubles, in which case the number of doubles is
used only in a no limit game. */
GOTString } GameOptionType;
typedef struct _GameOptionEntry {
GameOption option; /* integer option number */
char name[16]; /* short name: shd be same as name of option number */
GameOptionType type; /* type of option value */
int protversion; /* least protocol version required to use this
option. N.B. This may well be before the introduction
of the option, as with many options clients do not
have to know about them, and can use the server provided
text to allow the user to set them. */
bool enabled; /* is this option understood in this game? */
union { bool optbool; int optint; unsigned int optnat; int optscore; char optstring[128]; } value;
char desc[128]; /* short description */
void *userdata; /* field for client use */
} GameOptionEntry;
/* The fundamental principle is that players cannot change the state
of the game---including their own hand. They send a message to
the controller declaring what they want to do; the controller then
issues the message implementing it.
These messages should NOT be seen as request and reply, but simply
as event deliveries.
*/
/* Protocol version is an integer of the form 1000*major+minor.
The protocol major version should be incremented only when
it is impossible for an earlier client to play with the new
protocol. Normally, servers and players should be able to
downgrade to the lowest common minor version.
Note: in the earlier versions, including the alpha binary release,
the version was just 1,2,3, corresponding to our current major.
However, we will view all those as major 0, and start again at 1000.
Note that this is not really just the protocol version; it's more
a version of the protocol plus options etc.
*/
#define PROTOCOL_VERSION 1034
/* These structures are the programmer's view of the messages.
The protocol is actually defined by the wire protocol, not by
these structs.
*/
/* NOTE: for bad reasons, these enums should always be less
than 1000000 (to allow space for flag bits) */
/* types of message from controller to player.
For convenience in debugging, the actual values are widely spaced.
*/
typedef enum {
CMsgError = 0,
CMsgInfoTiles = 1,
CMsgStateSaved = 2,
CMsgConnectReply = 10,
CMsgPlayer = 20,
CMsgNewRound = 29,
CMsgGame = 30,
CMsgNewHand = 31,
CMsgPlayerDeclaresSpecial = 34,
CMsgStartPlay = 35,
CMsgStopPlay = 36,
CMsgPause = 37,
CMsgPlayerReady = 38,
CMsgPlayerDraws = 40,
CMsgPlayerDrawsLoose = 41,
CMsgPlayerDiscards = 50,
CMsgClaimDenied = 51,
CMsgPlayerDoesntClaim = 52,
CMsgDangerousDiscard = 55,
CMsgPlayerClaimsPung = 60,
CMsgPlayerPungs = 61,
CMsgPlayerFormsClosedPung = 62,
CMsgPlayerClaimsKong = 70,
CMsgPlayerKongs = 71,
CMsgPlayerDeclaresClosedKong = 80,
CMsgPlayerAddsToPung = 81,
CMsgPlayerRobsKong = 85,
CMsgCanMahJong = 87,
CMsgPlayerClaimsChow = 90,
CMsgPlayerChows = 91,
CMsgPlayerFormsClosedChow = 92,
CMsgWashOut = 99,
CMsgPlayerClaimsMahJong = 100,
CMsgPlayerMahJongs = 101,
CMsgPlayerPairs = 102,
CMsgPlayerFormsClosedPair = 103,
CMsgPlayerShowsTiles = 105,
CMsgPlayerSpecialSet = 106,
CMsgPlayerFormsClosedSpecialSet = 107,
CMsgPlayerOptionSet = 110,
CMsgHandScore = 115,
CMsgSettlement = 120,
CMsgGameOver = 200,
CMsgGameOption = 300,
CMsgChangeManager = 310,
CMsgMessage = 400,
CMsgWall = 900,
CMsgComment = 999,
CMsgSwapTile = 1000,
} ControllerMsgType;
/* Types of message sent by player. The numbers more or less
match the corresponding controller messages.
*/
typedef enum {
PMsgSaveState = 1,
PMsgConnect = 10,
PMsgDeclareSpecial = 33,
PMsgRequestPause = 36,
PMsgReady = 37,
PMsgDiscard = 50,
PMsgNoClaim = 51,
PMsgPung = 60,
PMsgFormClosedPung = 62,
PMsgKong = 70,
PMsgDeclareClosedKong = 80,
PMsgAddToPung = 81,
PMsgQueryMahJong = 87,
PMsgChow = 90,
PMsgFormClosedChow = 92,
PMsgDeclareWashOut = 99,
PMsgMahJong = 100,
PMsgPair = 102,
PMsgFormClosedPair = 103,
PMsgShowTiles = 105,
PMsgSpecialSet = 106,
PMsgFormClosedSpecialSet = 107,
PMsgSetPlayerOption = 110,
PMsgSetGameOption = 300,
PMsgQueryGameOption = 301,
PMsgListGameOptions = 302,
PMsgChangeManager = 310,
PMsgSendMessage = 400,
PMsgSwapTile = 1000,
} PlayerMsgType;
#define DebugMsgsStart 1000
/* NOTE: it is currently assumed (by the wire protocol) that these
structures have at most one (char *) component, and if they do,
it's the final element in the structure.
If this assumption becomes invalid, work will have to be done on
the wire protocol code; especially since much of the conversion
routines is automatically generated from this file.
For the same reason, when adding new structures, the layout
and naming convention should be the same as the existing ones.
*/
/* message sent by controller to player to signal an error.
The string is a human readable description.
*/
typedef struct _CMsgErrorMsg {
ControllerMsgType type; /* CMsgError */
int seqno; /* sequence number of player message provoking error, or 0 */
char *error; /* human readable explanation */
} CMsgErrorMsg;
/* This message requests the controller to save the state
of the current game. */
/* Note: in protocol versions before 1025, the filename field
did not exist. This should require no special handling. */
typedef struct _PMsgSaveStateMsg {
PlayerMsgType type; /* PMsgSaveState */
char *filename; /* name of file to save in; subject to interpretation
and overriding by server. May be null. */
} PMsgSaveStateMsg;
/* This message informs players that the state of the game
has been saved. */
/* This message was introduced at pversion 1025. */
typedef struct _CMsgStateSavedMsg {
ControllerMsgType type; /* CMsgStateSaved */
int id; /* player who requested save */
char *filename; /* file in which saved. Server dependent.
May include full path information in
system dependent form */
} CMsgStateSavedMsg;
/* This message is purely informational, and is mainly useful
for debugging or for very dumb clients. It may be sent to
a player whenever its hand changes, and contains a human
readable presentation of the player's tiles.
*/
typedef struct _CMsgInfoTilesMsg {
ControllerMsgType type; /* CMsgInfoTiles */
int id; /* id of player---in teaching situation might send
info on other players too */
char *tileinfo;
} CMsgInfoTilesMsg;
/* Message sent by player after connecting to controller */
typedef struct _PMsgConnectMsg {
PlayerMsgType type; /* PMsgConnect */
int pvers; /* protocol version used by player */
int last_id; /* (if non-zero) identifier from last session;
controller is not bound to keep this, but will try */
char *name; /* player's name */
} PMsgConnectMsg;
/* Message sent by controller to player on receipt of ConnectMsg */
typedef struct _CMsgConnectReplyMsg {
ControllerMsgType type; /* CMsgConnectReply */
int pvers; /* protocol version of server */
int id; /* id assigned by controller, or zero if connection refused */
char *reason; /* human readable reason for refusal (if refused) */
} CMsgConnectReplyMsg;
/* Message sent by controller to inform players of each other's existence.
When a player connects, it receives one such message for every already
existing player; and each existing player receives a message for the
new player.
This message is also sent if a player changes its name.
*/
typedef struct _CMsgPlayerMsg {
ControllerMsgType type; /* CMsgPlayer */
int id; /* id of player */
char *name; /* name of player */
} CMsgPlayerMsg;
/* Message sent by controller to initiate a game (possibly continued
from a previous session). Contains the initial wind assignment.
*/
typedef struct _CMsgGameMsg {
ControllerMsgType type; /* CMsgGame */
int east; /* id of player in east */
int south; /* id of south */
int west; /* id of west */
int north; /* id of north */
TileWind round; /* wind of the current round */
int hands_as_east; /* number of hands completed with this dealer */
int firsteast; /* id of player who was east in first hand of game */
int east_score; /* east's score in game */
int south_score;
int west_score;
int north_score;
int protversion; /* protocol version to be used in this game */
int manager; /* id of player owning this game */
} CMsgGameMsg;
/* Message to say that the wind of the round has changed */
typedef struct _CMsgNewRoundMsg {
ControllerMsgType type; /* CMsgNewRound */
TileWind round; /* wind of the new round */
} CMsgNewRoundMsg;
/* Message sent by controller to start new hand.
It also tells where the live wall notionally starts;
this is completely irrelevant to the actual implementation,
but can be used to give players a consistent view of the wall.
*/
typedef struct _CMsgNewHandMsg {
ControllerMsgType type; /* CMsgNewHand */
int east; /* id of east player for this hand: just to check */
int start_wall; /* the wall (as a seat number) in which the live wall starts*/
int start_stack; /* the stack (from right) at which the live wall starts */
} CMsgNewHandMsg;
/* Message sent by controller to draw one tile for player.
Other players will receive this message with a blank tile.
*/
typedef struct _CMsgPlayerDrawsMsg {
ControllerMsgType type; /* CMsgPlayerDraws */
int id; /* player drawing tile */
Tile tile; /* tile drawn (HiddenTile if not known to us) */
} CMsgPlayerDrawsMsg;
/* Message sent by controller to draw a loose tile for player.
Other players will receive this message with a blank tile.
*/
typedef struct _CMsgPlayerDrawsLooseMsg {
ControllerMsgType type; /* CMsgPlayerDrawsLoose */
int id; /* player drawing tile */
Tile tile; /* tile drawn (HiddenTile if not known to us) */
} CMsgPlayerDrawsLooseMsg;
/* Message sent by the player to declare a special tile.
If the tile is blank, player has no more specials. (Of course,
the controller knows this anyway.)
This message is also used during play.
*/
typedef struct _PMsgDeclareSpecialMsg { /* alias ds */
PlayerMsgType type; /* PMsgDeclareSpecial */
Tile tile; /* tile being declared, or blank */
} PMsgDeclareSpecialMsg;
/* Message sent by controller to implement special declaration. */
typedef struct _CMsgPlayerDeclaresSpecialMsg {
ControllerMsgType type; /* CMsgPlayerDeclaresSpecial */
int id; /* player making declaration */
Tile tile; /* tile being declared (blank if player finished) */
} CMsgPlayerDeclaresSpecialMsg;
/* This message is sent to all players, to tell them they may
start normal play. This happens either when a game starts,
or to restart a game that was suspended. */
typedef struct _CMsgStartPlayMsg {
ControllerMsgType type; /* CMsgStartPlay */
int id; /* not strictly necessary: id of player due to do something */
} CMsgStartPlayMsg;
/* This message is sent to all players to stop play.
This may be (for example) because a player has lost its
connection.
*/
typedef struct _CMsgStopPlayMsg {
ControllerMsgType type; /* CMsgStopPlay */
char *reason; /* human readable explanation */
} CMsgStopPlayMsg;
/* This message is sent by a player to request a pause in play.
If granted, all players (including the pausing player) must
give permission to continue again. */
typedef struct _PMsgRequestPauseMsg {
PlayerMsgType type; /* PMsgRequestPause */
char *reason; /* reason for pause; will be passed to other players */
} PMsgRequestPauseMsg;
/* This message is sent by the controller when it wishes to gain
the permission of players to proceed. This happens typically at:
the end of declaring specials, before play proper starts;
at the end of a hand, before proceeding to the next hand. */
typedef struct _CMsgPauseMsg {
ControllerMsgType type; /* CMsgPause */
int exempt; /* 0, or the id of the one player who is NOT being asked
to confirm readiness (typically because it's them to proceed) */
int requestor; /* 0, or id of player who requested pause */
char *reason; /* reason for pause. This will (it happens) be phrased
as an infinitive, e.g. "to start play" */
} CMsgPauseMsg;
/* and this is the reply */
typedef struct _PMsgReadyMsg {
PlayerMsgType type; /* PMsgReady */
} PMsgReadyMsg;
/* and this tells other players who's ready (and bloody emacs gets
confused by that quote, so here's another) */
typedef struct _CMsgPlayerReadyMsg {
ControllerMsgType type; /* CMsgPlayerReady */
int id;
} CMsgPlayerReadyMsg;
/* Message sent by player to announce discard */
typedef struct _PMsgDiscardMsg { /* alias d */
PlayerMsgType type; /* PMsgDiscard */
Tile tile; /* tile to be discarded */
bool calling; /* player is making a Calling declaration */
} PMsgDiscardMsg;
/* Message sent by controller to implement discard */
typedef struct _CMsgPlayerDiscardsMsg {
ControllerMsgType type; /* CMsgPlayerDiscards */
int id; /* player discarding */
Tile tile; /* tile being discarded */
int discard; /* a serial number for this discard */
bool calling; /* player is making a Calling declaration */
} CMsgPlayerDiscardsMsg;
/* This message is sent by a player to say that it has no claim
on the current discard. It implies a request to draw a tile if
it's the player's turn.
*/
typedef struct _PMsgNoClaimMsg { /* alias n */
PlayerMsgType type; /* PMsgNoClaim */
int discard; /* serial number of discard */
} PMsgNoClaimMsg;
/* Message sent by controller to say that a player is making
no claim on the current discard. Usually this is sent
only to the player concerned.
*/
typedef struct _CMsgPlayerDoesntClaimMsg {
ControllerMsgType type; /* CMsgPlayerDoesntClaim */
int id; /* player */
int discard; /* current discard serial */
bool timeout; /* 1 if this is generated by timeout in controller */
} CMsgPlayerDoesntClaimMsg;
/* This message is informational, and is sent by the controller
after a claim has been implemented to announce that the discard
was dangerous.
*/
typedef struct _CMsgDangerousDiscardMsg {
ControllerMsgType type; /* CMsgDangerousDiscard */
int id; /* player who discarded */
int discard; /* serial number of the dangerous discard */
bool nochoice; /* discard was dangerous, but discarder had no choice */
} CMsgDangerousDiscardMsg;
/* Message sent by player to claim a pung.
In the usual rules, it is possible to claim a pung up to the time
the *next* tile is discarded. At the moment, we don't implement that,
but we should in due course. Hence a pung (etc.) claim includes
an integer identifying the discard that is being claimed---the integer
was assigned by the controller. This provides some protection against
delays.
*/
typedef struct _PMsgPungMsg { /* alias p */
PlayerMsgType type; /* PMsgPung */
int discard; /* id of discard being claimed */
} PMsgPungMsg;
/* Message sent by controller to other players to inform them of
a pung claim (NOT of its success).
*/
typedef struct _CMsgPlayerClaimsPungMsg {
ControllerMsgType type; /* CMsgPlayerClaimsPung */
int id; /* player claiming */
int discard; /* discard being claimed */
} CMsgPlayerClaimsPungMsg;
/* generic refusal message sent by controller to deny a claim. */
typedef struct _CMsgClaimDeniedMsg {
ControllerMsgType type; /* CMsgClaimDenied */
int id; /* player who made claim */
char *reason; /* if non-NULL, human readable explanation */
} CMsgClaimDeniedMsg;
/* Message sent by controller to implement a successful pung claim. */
typedef struct _CMsgPlayerPungsMsg {
ControllerMsgType type; /* CMsgPlayerPungs */
int id; /* player who made claim */
Tile tile; /* tile of pung---redundant, but included for safety */
} CMsgPlayerPungsMsg;
/* Message to declare a closed pung during scoring */
typedef struct _PMsgFormClosedPungMsg {
PlayerMsgType type; /* PMsgFormClosedPung */
Tile tile;
} PMsgFormClosedPungMsg;
typedef struct _CMsgPlayerFormsClosedPungMsg {
ControllerMsgType type; /* CMsgPlayerFormsClosedPung */
int id;
Tile tile;
} CMsgPlayerFormsClosedPungMsg;
/* now the same for kongs */
typedef struct _PMsgKongMsg { /* alias k */
PlayerMsgType type; /* PMsgKong */
int discard; /* id of discard being claimed */
} PMsgKongMsg;
/* Message sent by controller to other players to inform them of
a pung claim (NOT of its success).
*/
typedef struct _CMsgPlayerClaimsKongMsg {
ControllerMsgType type; /* CMsgPlayerClaimsKong */
int id; /* player claiming */
int discard; /* discard being claimed */
} CMsgPlayerClaimsKongMsg;
/* the generic refusal message applies */
/* Message sent by controller to implement a successful pung claim. */
typedef struct _CMsgPlayerKongsMsg {
ControllerMsgType type; /* CMsgPlayerKongs */
int id; /* player who made claim */
Tile tile; /* tile of kong---redundant, but included for safety */
} CMsgPlayerKongsMsg;
/* Message sent by player to announce a concealed kong. */
typedef struct _PMsgDeclareClosedKongMsg { /* alias ck */
PlayerMsgType type; /* PMsgDeclareClosedKong */
Tile tile; /* which kong */
} PMsgDeclareClosedKongMsg;
/* Message sent by controller to implement a concealed kong
Because the kong may possibly be robbed, it gets
a discard serial number. */
typedef struct _CMsgPlayerDeclaresClosedKongMsg {
ControllerMsgType type; /* CMsgPlayerDeclaresClosedKong */
int id; /* player declaring kong */
Tile tile; /* tile being konged */
int discard; /* serial */
} CMsgPlayerDeclaresClosedKongMsg;
/* Message sent by player to add drawn tile to exposed pung */
typedef struct _PMsgAddToPungMsg {
PlayerMsgType type; /* PMsgAddToPung */
Tile tile; /* which pung */
} PMsgAddToPungMsg;
/* Message sent by controller to implement adding to a pung
Because the kong may possibly be robbed, it gets
a discard serial number. */
typedef struct _CMsgPlayerAddsToPungMsg {
ControllerMsgType type; /* CMsgPlayerAddsToPung */
int id; /* player */
Tile tile; /* the tile being added */
int discard; /* serial */
} CMsgPlayerAddsToPungMsg;
/* Message sent by controller to say that the player has
robbed the just declared kong */
typedef struct _CMsgPlayerRobsKongMsg {
ControllerMsgType type; /* CMsgPlayerRobsKong */
int id; /* player */
Tile tile; /* tile being robbed (redundant) */
} CMsgPlayerRobsKongMsg;
/* Message sent by player to ask whether it has a mah-jong hand.
Needed because only the server knows fully what hands are allowed:
the client code might be an earlier version. */
typedef struct _PMsgQueryMahJongMsg {
PlayerMsgType type; /* PMsgQueryMahJong */
Tile tile; /* do I have mahjong with this tile added? HiddenTile means no tile */
} PMsgQueryMahJongMsg;
/* And the reply */
typedef struct _CMsgCanMahJongMsg {
ControllerMsgType type; /* CMsgCanMahJong */
Tile tile; /* the tile specified */
bool answer; /* yes or no */
} CMsgCanMahJongMsg;
/* Message sent by player to claim chow.
The player should specify where the chowed tile will go
(i.e. lower, upper, middle). However, for added realism,
it is permissible to specify "any" (AnyPos) for the position.
If this is done, and the chow claim is successful, then
the controller will send to the chowing player (and only to
the chowing player) a PlayerChows message with the cpos set
to AnyPos. The player must then send another Chow message with
the position specified.
*/
typedef struct _PMsgChowMsg { /* alias c */
PlayerMsgType type; /* PMsgChow */
int discard; /* discard being claimed */
ChowPosition cpos; /* where the discard will go */
} PMsgChowMsg;
/* Message sent by controller to announce a chow claim */
typedef struct _CMsgPlayerClaimsChowMsg {
ControllerMsgType type; /* CMsgPlayerClaimsChow */
int id; /* player claiming */
int discard; /* discard being claimed */
ChowPosition cpos; /* chowposition specified (may be AnyPos) */
} CMsgPlayerClaimsChowMsg;
/* the general refusal message applies */
/* Message sent by controller to implement a chow claim.
See above for meaning of this message with cpos == AnyPos.
*/
typedef struct _CMsgPlayerChowsMsg {
ControllerMsgType type; /* CMsgPlayerChows */
int id; /* player claiming */
Tile tile; /* tile being claimed (redundant, but...) */
ChowPosition cpos; /* position of claimed tile in chow */
} CMsgPlayerChowsMsg;
/* To form a closed chow during scoring.
As all tiles are in hand, we require that the chow
is specified by the lower tile.
*/
typedef struct _PMsgFormClosedChowMsg {
PlayerMsgType type; /* PMsgFormClosedChow */
Tile tile;
} PMsgFormClosedChowMsg;
typedef struct _CMsgPlayerFormsClosedChowMsg {
ControllerMsgType type; /* CMsgPlayerFormsClosedChow */
int id;
Tile tile;
} CMsgPlayerFormsClosedChowMsg;
/* some rules allow a player to declare a washout under certain
circumstances.
*/
typedef struct _PMsgDeclareWashOutMsg {
PlayerMsgType type; /* PMsgDeclareWashOut */
} PMsgDeclareWashOutMsg;
/* Message sent by controller to declare a dead hand */
typedef struct _CMsgWashOutMsg {
ControllerMsgType type; /* CMsgWashOut */
char *reason; /* reason for washout */
} CMsgWashOutMsg;
/* Message sent by player to claim Mah-Jong.
Applies to both claiming a discard and mah-jong from wall.
*/
typedef struct _PMsgMahJongMsg {
PlayerMsgType type; /* PMsgMahJong */
int discard; /* discard being claimed, or 0 if from wall */
} PMsgMahJongMsg;
/* Message sent by controller to announce mah-jong claim */
typedef struct _CMsgPlayerClaimsMahJongMsg {
ControllerMsgType type; /* CMsgPlayerClaimsMahJong */
int id; /* player claiming */
int discard; /* discard being claimed */
} CMsgPlayerClaimsMahJongMsg;
/* Message sent by controller to announce successful mah-jong */
typedef struct _CMsgPlayerMahJongsMsg {
ControllerMsgType type; /* CMsgPlayerMahJongs */
int id; /* player claiming */
Tile tile; /* If this is HiddenTile, then the mahjong is by claiming
the discard (the tile will be named in a later claim).
If the mahjong is from the wall, then this is the tile
that was drawn; this allows the other players to see
the legitimacy of scoring claims. */
} CMsgPlayerMahJongsMsg;
/* Take the mah-jonged discard for a pair. Since this can only
happen at mah-jong, there is no need to specify a tile or
discard number */
typedef struct _PMsgPairMsg {
PlayerMsgType type; /* PMsgPair */
} PMsgPairMsg;
typedef struct _CMsgPlayerPairsMsg {
ControllerMsgType type; /* CMsgPlayerPairs */
int id;
Tile tile; /* for convenience of other players */
} CMsgPlayerPairsMsg;
/* Form a closed pair during scoring */
typedef struct _PMsgFormClosedPairMsg {
PlayerMsgType type; /* PMsgFormClosedPair */
Tile tile;
} PMsgFormClosedPairMsg;
typedef struct _CMsgPlayerFormsClosedPairMsg {
ControllerMsgType type; /* CMsgPlayerFormsClosedPair */
int id;
Tile tile;
} CMsgPlayerFormsClosedPairMsg;
/* These messages handle the case of special hands such as
thirteen unique wonders */
/* Claim the discard (during scoring) to form a special hand */
typedef struct _PMsgSpecialSetMsg {
PlayerMsgType type; /* PMsgSpecialSet */
} PMsgSpecialSetMsg;
/* Player claims the discard to form a special set with all remaining tiles;
this is a ShowTiles as well */
typedef struct _CMsgPlayerSpecialSetMsg {
ControllerMsgType type ; /* CMsgPlayerSpecialSet */
int id;
Tile tile; /* the discard tile */
char *tiles; /* string repn of the concealed tiles */
} CMsgPlayerSpecialSetMsg;
/* Form a special set in hand */
typedef struct _PMsgFormClosedSpecialSetMsg {
PlayerMsgType type; /* PMsgFormClosedSpecialSet */
} PMsgFormClosedSpecialSetMsg;
/* Player forms a special set in hand from the concealed tiles */
typedef struct _CMsgPlayerFormsClosedSpecialSetMsg {
ControllerMsgType type ; /* CMsgPlayerFormsClosedSpecialSet */
int id;
char *tiles; /* string repn of concealed tiles */
} CMsgPlayerFormsClosedSpecialSetMsg;
/* This message is sent by a losing player after it has finished
making scoring combinations: it reveals the concealed tiles,
and triggers the calculation of a score. */
typedef struct _PMsgShowTilesMsg {
PlayerMsgType type; /* PMsgShowTiles */
} PMsgShowTilesMsg;
/* This message reveals a player's concealed tiles.
It currently just has a string repn, because I'm lazy.
This ought to be a variable array of tiles.
*/
typedef struct _CMsgPlayerShowsTilesMsg {
ControllerMsgType type; /* CMsgPlayerShowsTiles */
int id;
char *tiles; /* string repn of concealed tiles */
} CMsgPlayerShowsTilesMsg;
/* This message gives the calculated score for a hand.
*/
typedef struct _CMsgHandScoreMsg {
ControllerMsgType type; /* CMsgHandScore */
int id;
int score; /* score of this hand */
char *explanation; /* human readable calculation of the score */
} CMsgHandScoreMsg;
/* This message announces the change in cumulative score for each player.
The explanation is text, which should be interpreted cumulatively
with any previous settlement explanations.
*/
typedef struct _CMsgSettlementMsg {
ControllerMsgType type; /* CMsgSettlement */
int east;
int south;
int west;
int north;
char *explanation;
} CMsgSettlementMsg;
/* This message requests the controller to set a player option,
or acknowledges a server set. */
typedef struct _PMsgSetPlayerOptionMsg {
PlayerMsgType type; /* PMsgSetPlayerOption */
PlayerOption option; /* which option is being set */
bool ack; /* 1 if this is acknowledging a server request */
int value; /* value of option if int or bool */
char *text; /* value of option if string */
} PMsgSetPlayerOptionMsg;
/* This informs the player that an option has been set.
It may be a response to a request; it may also be autonomous,
in which case the player should send a SetPlayerOption with
the given value to acknowledge.*/
typedef struct _CMsgPlayerOptionSetMsg {
ControllerMsgType type; /* CMsgPlayerOptionSet */
PlayerOption option; /* which option is being set */
bool ack; /* 1 if acknowledging a client request */
int value; /* value of option if int */
char *text; /* value of option if string */
} CMsgPlayerOptionSetMsg;
/* Message to tell players game is over */
typedef struct _CMsgGameOverMsg {
ControllerMsgType type; /* CMsgGameOver */
} CMsgGameOverMsg;
/* Message to set a game option */
typedef struct _PMsgSetGameOptionMsg {
PlayerMsgType type; /* PMsgSetGameOption */
word16 optname;
char *optvalue;
} PMsgSetGameOptionMsg;
/* Message to inform players of a game option value */
typedef struct _CMsgGameOptionMsg {
ControllerMsgType type; /* CMsgGameOption */
int id; /* player who set it, if any */
GameOptionEntry optentry;
} CMsgGameOptionMsg;
/* Message to query a game option. Controller will reply
with a GameOptionMsg */
typedef struct _PMsgQueryGameOptionMsg {
PlayerMsgType type; /* PMsgQueryGameOption */
word16 optname; /* name of option to query */
} PMsgQueryGameOptionMsg;
/* Message to query all game options. Controller will reply
with a sequence of GameOptionMsgs, finishing with the End pseudo-option */
typedef struct _PMsgListGameOptionsMsg {
PlayerMsgType type; /* PMsgListGameOptions */
bool include_disabled; /* send even disabled options */
} PMsgListGameOptionsMsg;
/* Request new manager for the game. */
typedef struct _PMsgChangeManagerMsg {
PlayerMsgType type; /* PMsgChangeManager */
int manager; /* new manager, or 0 if none */
} PMsgChangeManagerMsg;
/* Give new manager for the game. */
typedef struct _CMsgChangeManagerMsg {
ControllerMsgType type; /* CMsgChangeManager */
int id; /* player requesting change */
int manager; /* new manager, or 0 if none */
} CMsgChangeManagerMsg;
/* Send a message to other player(s). */
typedef struct _PMsgSendMessageMsg {
PlayerMsgType type; /* PMsgSendMessage */
int addressee; /* id of addressee, or 0 for broadcast */
char *text;
} PMsgSendMessageMsg;
/* Message from controller or other player. */
typedef struct _CMsgMessageMsg {
ControllerMsgType type; /* CMsgMessage */
int sender; /* id of sender, or 0 for message from controller */
int addressee; /* 0 for broadcast, id of recipient otherwise */
char *text;
} CMsgMessageMsg;
/* This message is primarily used by the controller internally.
It sets up the wall with the given tiles */
typedef struct _CMsgWallMsg {
ControllerMsgType type; /* CMsgWall */
char *wall; /* wall as space separated tile codes */
} CMsgWallMsg;
/* This message serves no purpose in the protocol; it allows comments
to be included in files of protocol commands. It is specially
hacked in the proto-encode scripts so that the message name
is a hash sign # rather than the word Comment; for the decode
script, we use the undocumented alias capability.
Introduced at protocol 1030.
*/
typedef struct _CMsgCommentMsg { /* alias # */
ControllerMsgType type; /* CMsgComment */
char *comment;
} CMsgCommentMsg;
/* This message is for debugging and testing. It asks the controller
to swap the old tile for the new tile. This is implemented by
finding the new tile in the wall and swapping it with the old tile.
*/
typedef struct _PMsgSwapTileMsg { /* alias st */
PlayerMsgType type; /* PMsgSwapTile */
int id; /* player to be changed */
Tile oldtile;
Tile newtile;
} PMsgSwapTileMsg;
typedef struct _CMsgSwapTileMsg {
ControllerMsgType type; /* CMsgSwapTile */
int id; /* player to be changed */
Tile oldtile;
Tile newtile;
} CMsgSwapTileMsg;
/* dummy just to get the type field. This MUST come after all
the real types (for auto-generation of printing and parsing) */
typedef struct _CMsgMsg {
ControllerMsgType type;
} CMsgMsg;
typedef struct _PMsgMsg {
PlayerMsgType type;
} PMsgMsg;
/* Two humungous unions for when they're wanted. Auto generated. */
#include "cmsg_union.h"
#include "pmsg_union.h"
/* after all that, some functions to handle conversion from/to
the wire protocol */
/* The application programmer need only view the protocol as a sequence
of lines. Lines may be terminated by CRLF, or LF.
If the last character before the terminator is \ (backslash), then
a newline is to be included in the "line", and the following
wire line appended.
The protocol is in fact human readable; it is described in protocol.c
*/
/* This function takes a pointer to a controller message,
and returns a string (including terminating CRLF) encoding it.
The returned string is in static storage, and will be overwritten
the next time this function is called.
*/
char *encode_cmsg(CMsgMsg *msg);
/* This function takes a string, which is expected to be a complete
line (including terminators, although their absence is ignored).
It returns a pointer to a message structure.
Both the message structure and any strings it contains are malloc'd.
The argument string will be mutilated by this function.
*/
CMsgMsg *decode_cmsg(char *arg);
/* Text (that is, char *) elements of the protocol may contain
special sequences of the form
{CODE#TYPE...#TYPE:TEXT}{ARG}...{ARG}
These are macros, which can be used to provide marked-up, rather than
formatted messages.
The CODE identifies the function the text serves (e.g. Pung claim,
line of scoring details, etc.); each #TYPE notes an argument, with
its type; and then the arguments follow. The TEXT provides a default
text which can be used by a client that does not recognize the CODE;
any occurrences of #n, for n = 1..9, in the TEXT should be replaced
by the corresponding ARG, formatted according to its type; if the
client does not recognize the type, arguments should be substituted
as is.
Each CODE or TYPE should be alphanumeric; they need not start
with a letter. They may have a maximum length of 15 characters.
Code definitions and type definitions are not strictly
part of the protocol, and do not *require* protocol version changes.
However, as a convenience, this file includes a function to do
expansion with the currently defined codes and types, and the
protocol minor version will be incremented when new codes and
types are defined.
All participants are required always to provide suitable default
texts. However, the following function is provided to do basic
expansion of macros, recognizing no codes or types.
NOTE: currently, no types or codes are defined.
As a consequence of the above, any occurrence of {, }, # or \
in text must be escaped with \.
Note that substition is NOT recursive, nor are braces balanced:
"{CODE: one { two } three }" will expand to
" one { two three }", possibly with a warning about an unescaped }.
*/
/* basic_expand_protocol_text:
Perform text expansion as above, recognizing no codes or types.
dest is the destination string, n its length (including terminating
null).
Returns 1 on success, 0 on internal errors (e.g. missing arguments),
and -1 if dest is not long enough. dest will always be null-terminated.
*/
int basic_expand_protocol_text(char *dest,const char *src,int n);
/* expand_protocol_text:
Ditto, recognizing all currently defined codes and types.
*/
int expand_protocol_text(char *dest,const char *src,int n);
/* Similar functions for player messages */
char *encode_pmsg(PMsgMsg *msg);
PMsgMsg *decode_pmsg(char *arg);
/* functions given the size of a message type.
If the size is negative, the last field is a char*
*/
int cmsg_size_of(ControllerMsgType t);
int pmsg_size_of(PlayerMsgType t);
/* functions to copy messages, mallocing space and
also mallocing any internal char stars, and to free
*/
CMsgMsg *cmsg_deepcopy(CMsgMsg *m);
PMsgMsg *pmsg_deepcopy(PMsgMsg *m);
void cmsg_deepfree(CMsgMsg *m);
void pmsg_deepfree(PMsgMsg *m);
/* enum parsing and printing functions (mainly for game options) */
#include "protocol-enums.h"
#endif /* PROTOCOL_H_INCLUDED */
|