📄 game.c
字号:
/* This is a consistency error. */ } g->state = Discarding; g->needs = FromLoose; g->supplier = g->player; g->player = s; g->konging = NotKonging; /* yes! This is not robbable. */ if ( game_flag(g,GFKong) ) { game_setflag(g,GFKongUponKong); } game_setflag(g,GFKong); g->exposed_tile_count[m->tile] += 3; if ( chk ) set_danger_flags(g,p); /* the player may now be dangerous */ return affected_id; } case CMsgPlayerChows: { CMsgPlayerChowsMsg *m = (CMsgPlayerChowsMsg *)cm; setups; affected_id = m->id; if ( chk ) { /* sanity checking */ /* Note that normally we assume the legality of the chow was previously checked at claim time */ if ( ! (g->state == Discarded || (g->state == MahJonging && g->mjpending && g->player == s) ) ) { g->cmsg_err = "Nothing to chow"; return -1; } if ( m->tile != g->tile ) { g->cmsg_err = "Chowed tile isn't discard"; return -2; } } /* if the position is AnyPos, then this is addressed to a successful claimant to tell it to specify the position. There is therefore nothing to do here, except set the pending flag. Oops! Actually, if we're mah-jonging, we have to check that the player can actually go out by chowing the tile. */ if ( m->cpos == AnyPos ) { if ( chk && g->state == MahJonging ) { /* checking is more complex: not only must the player be able make the chow in some position, but it must then be able to complete the hand */ ChowPosition pos; int ok = 0; for ( pos = Lower; pos <= Upper; pos++ ) { Player cp; copy_player(&cp,p); if ( ! player_chows(&cp,m->tile,pos) ) { continue; } if ( player_can_mah_jong(&cp,HiddenTile,mjspecflags) ) { ok = 1; break; } } if ( ! ok ) { g->cmsg_err = "Can't go out by chowing"; return -1; } } g->chowpending = 1; return affected_id; } /* is there a Mah Jong pending? */ if ( g->state == Discarded ) { if ( ! player_chows(p,m->tile,m->cpos) ) { g->cmsg_err = "Can't chow that tile that way"; return -1; } g->state = Discarding; g->konging = NotKonging; g->tile = m->tile; g->needs = FromNone; g->supplier = g->player; g->player = s; g->whence = FromDiscard; /* g->exposed_tile_count[m->tile] is unchanged */ switch ( m->cpos ) { case Lower: g->exposed_tile_count[m->tile+1]++; g->exposed_tile_count[m->tile+2]++; break; case Middle: g->exposed_tile_count[m->tile+1]++; g->exposed_tile_count[m->tile-1]++; break; case Upper: g->exposed_tile_count[m->tile-1]++; g->exposed_tile_count[m->tile-2]++; break; default: warn(g->cmsg_err = "Impossible chowposition"); return -2; } } else if ( g->state == MahJonging ) { /* checking is more complex: not only must the player be able make the chow, but it must then be able to complete the hand */ Player cp; if ( chk ) copy_player(&cp,p); /* in case next fails */ if ( ! player_chows(p,m->tile,m->cpos) ) { g->cmsg_err = "Can't chow that tile that way"; return -1; } if ( chk && ! player_can_mah_jong(p,HiddenTile,mjspecflags) ) { g->cmsg_err = "Can't go out with that chow"; copy_player(p,&cp); /* restore status quo */ return -1; } g->chowpending = 0; g->mjpending = 0; } else { g->cmsg_err = "Nothing to chow"; return -1; } if ( chk ) { mark_dangerous_discards(g); set_danger_flags(g,p); /* the player may now be dangerous */ } return affected_id; } case CMsgWashOut: g->state = HandComplete; g->player = noseat; for (i=0;i<NUM_SEATS;i++) g->claims[i] = 0; return affected_id; case CMsgPlayerMahJongs: { CMsgPlayerMahJongsMsg *m = (CMsgPlayerMahJongsMsg *)cm; setups; affected_id = m->id; if ( m->tile != HiddenTile ) { /* should be currently in the Discarding state */ if ( chk ) { if ( ! (g->state == Discarding && g->player == s ) ) { g->cmsg_err = "Don't have a complete hand"; return -1; } if ( !player_can_mah_jong(p,HiddenTile,mjspecflags) ) { g->cmsg_err = "Don't have a Mah Jong"; return -1; } /* consistency check */ if ( g->tile != HiddenTile && m->tile != g->tile ) { g->cmsg_err = "Tile in mah-jong claim doesn't match drawn tile"; return -2; } } /* g->supplier is unchanged */ /* g->whence is unchanged */ /* g->player is unchanged */ /* g->tile is unchanged */ g->mjpending = 0; g->chowpending = 0; g->state = MahJonging; } else { /* We should be currently in the Discarded state */ if ( chk ) { if ( ! g->state == Discarded ) { g->cmsg_err = "No discard to use"; return -1; } } g->supplier = g->player; g->whence = FromDiscard; g->player = s; /* g->tile is unchanged */ g->mjpending = 1; g->chowpending = 0; g->state = MahJonging; } return affected_id; } case CMsgPlayerFormsClosedPair: { CMsgPlayerFormsClosedPairMsg *m = (CMsgPlayerFormsClosedPairMsg *)cm; setups; affected_id = m->id; if ( chk ) { if ( g->state != MahJonging ) { g->cmsg_err = "Not scoring now"; return -1; } } /* if this is a non-mah-jonging player, it's easy. */ if ( s != g->player ) { if ( ! player_forms_closed_pair(p,m->tile) ) { g->cmsg_err = "Don't have that pair" ; return -1; } } else { /* checking is complex: not only must the player be able make the pair, but it must then be able to complete the hand */ Player cp; if ( chk ) copy_player(&cp,p); /* in case next fails */ if ( ! player_forms_closed_pair(p,m->tile) ) { g->cmsg_err = "Don't have that pair"; return -1; } if ( chk && ! player_can_mah_jong(p,HiddenTile,mjspecflags) ) { g->cmsg_err = "Can't go out with that pair"; copy_player(p,&cp); /* restore status quo */ return -1; } if ( p->num_concealed == 0 ) psetflag(p,HandDeclared); } return affected_id; } case CMsgPlayerFormsClosedSpecialSet: { CMsgPlayerFormsClosedSpecialSetMsg *m = (CMsgPlayerFormsClosedSpecialSetMsg *)cm; setups; affected_id = m->id; if ( chk ) { /* sanity checking */ /* Note that normally we assume the legality of the set was previously checked at claim time */ if ( ! ( g->state == MahJonging && s == g->player ) ) { g->cmsg_err = "Not going out"; return -1; } } if ( g->state == MahJonging ) { /* It is a rule that the special set must be formed last, and use up all the remaining tiles */ Player cp; int res; if ( chk ) copy_player(&cp,p); /* in case next fails */ if ( chk ) { /* only currently recognized special hand is 13 wonders */ if ( ! player_can_thirteen_wonders(p,HiddenTile) ) { g->cmsg_err = "No special hand to form"; return -1; } } /* first we use the given tiles as in a ShowTiles */ res = player_shows_tiles(p,m->tiles); if ( ! res ) { /* we are in deep trouble */ g->cmsg_err = "player_shows_tiles failed"; return -2; } if ( chk ) { /* better be the same number of tiles before and after */ if ( p->num_concealed != cp.num_concealed ) { g->cmsg_err = "Wrong number of tiles in special set"; copy_player(p,&cp); /* restore status quo */ return -1; } } if ( chk && ! player_can_mah_jong(p,HiddenTile,mjspecflags) ) { g->cmsg_err = "No mah jong hand!"; copy_player(p,&cp); /* restore status quo */ return -1; } } else { g->cmsg_err = "Can't declare special set now"; return -1; } return affected_id; } case CMsgPlayerFormsClosedPung: { CMsgPlayerFormsClosedPungMsg *m = (CMsgPlayerFormsClosedPungMsg *)cm; setups; affected_id = m->id; if ( chk ) { if ( g->state != MahJonging ) { g->cmsg_err = "Not scoring now"; return -1; } } /* if this is a non-mah-jonging player, it's easy. */ if ( s != g->player ) { if ( ! player_forms_closed_pung(p,m->tile) ) { g->cmsg_err = "Don't have that pung" ; return -1; } } else { /* checking is complex: not only must the player be able make the pung, but it must then be able to complete the hand */ Player cp; if ( chk ) copy_player(&cp,p); /* in case next fails */ if ( ! player_forms_closed_pung(p,m->tile) ) { g->cmsg_err = "Don't have that pung"; return -1; } if ( chk && ! player_can_mah_jong(p,HiddenTile,mjspecflags) ) { g->cmsg_err = "Can't go out with that pung"; copy_player(p,&cp); /* restore status quo */ return -1; } if ( p->num_concealed == 0 ) psetflag(p,HandDeclared); } return affected_id; } case CMsgPlayerFormsClosedChow: { CMsgPlayerFormsClosedChowMsg *m = (CMsgPlayerFormsClosedChowMsg *)cm; setups; affected_id = m->id; if ( chk ) { if ( g->state != MahJonging ) { g->cmsg_err = "Not scoring now"; return -1; } } /* if this is a non-mah-jonging player, it's easy. */ if ( s != g->player ) { if ( ! player_forms_closed_chow(p,m->tile,Lower) ) { g->cmsg_err = "Don't have that chow" ; return -1; } } else { /* checking is complex: not only must the player be able make the chow, but it must then be able to complete the hand */ Player cp; if ( chk ) copy_player(&cp,p); /* in case next fails */ if ( ! player_forms_closed_chow(p,m->tile,Lower) ) { g->cmsg_err = "Don't have that chow"; return -1; } if ( chk && ! player_can_mah_jong(p,HiddenTile,mjspecflags) ) { g->cmsg_err = "Can't go out with that chow"; copy_player(p,&cp); /* restore status quo */ return -1; } if ( p->num_concealed == 0 ) psetflag(p,HandDeclared); } return affected_id; } case CMsgPlayerDeclaresClosedKong: { CMsgPlayerDeclaresClosedKongMsg *m = (CMsgPlayerDeclaresClosedKongMsg *)cm; setups; affected_id = m->id; if ( chk ) { if ( ! (((g->state == Discarding && (g->protversion < 1010 || g->whence != FromDiscard)) || g->state == DeclaringSpecials) && g->player == s ) ) { g->cmsg_err = "Can't declare a closed kong now"; return -1; } /* We have to use the test function here, because if either kong or tile drawing fails we must leave the game unchanged */ if ( !player_can_declare_closed_kong(p,m->tile) ) { g->cmsg_err = "Don't have that kong"; return -1; } } /* This can't fail in the chking case */ player_declares_closed_kong(p,m->tile); g->needs = FromLoose; g->konging = DeclaringKong; g->tile = m->tile; g->serial = m->discard; for (i=0;i<NUM_SEATS;i++) g->claims[i] = 0; g->exposed_tile_count[m->tile] += 4; if ( chk ) set_danger_flags(g,p); /* the player may now be dangerous */ return affected_id; } case CMsgPlayerAddsToPung: { CMsgPlayerAddsToPungMsg *m = (CMsgPlayerAddsToPungMsg *)cm; setups; affected_id = m->id; if ( chk ) { if ( ! (g->state == Discarding && (g->protversion < 1010 || g->whence != FromDiscard) && g->player == s ) ) { g->cmsg_err = "Can't make a kong now"; return -1; } /* We have to use the test function here, because if either kong or tile drawing fails we must leave the game unchanged */ if ( !player_can_add_to_pung(p,m->tile) ) { g->cmsg_err = "Don't have the tiles for that kong"; return -1; } } /* This can't fail in the chking case */ player_adds_to_pung(p,m->tile); g->needs = FromLoose; g->konging = AddingToPung; g->tile = m->tile; g->serial = m->discard; for (i=0;i<NUM_SEATS;i++) g->claims[i] = 0; if ( game_flag(g,GFKong) ) { game_setflag(g,GFKongUponKong); } game_setflag(g,GFKong);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -