📄 game.c
字号:
g->exposed_tile_count[m->tile]++ ; if ( chk ) set_danger_flags(g,p); /* the player may now be dangerous */ /* a kong can be robbed, so is like a discard */ game_clearflag(g,GFDangerousDiscard); game_clearflag(g,GFNoChoice); return affected_id; } case CMsgCanMahJong: /* this just a reply to a query, and requires no action */ return affected_id; case CMsgPlayerRobsKong: { CMsgPlayerRobsKongMsg *m = (CMsgPlayerRobsKongMsg *)cm; setups; affected_id = m->id; if ( chk ) { if ( ! ((g->state == Discarding || g->state == DeclaringSpecials) && g->konging ) ) { g->cmsg_err = "No kong to rob"; return -1; } if ( m->tile != g->tile ) { g->cmsg_err = "Claimed tile doesn't match that of kong"; return -1; } if ( ! player_can_mah_jong(p,m->tile,mjspecflags) ) { g->cmsg_err = "Can't mah-jong with that tile"; return -1; } } /* To rob a kong, we will rob the player, and then move into the MahJonging state with a pending "discard", since the winning player needs to say which set it's forming. */ if ( ! player_kong_is_robbed(g->players[g->player],m->tile) ) { g->cmsg_err = "Victim doesn't have that kong!"; return -1; } g->state = MahJonging; g->whence = FromRobbedKong; g->needs = FromNone; /* this was set by the AddToPung that we robbed */ g->supplier = g->player; g->player = s; g->tile = m->tile; g->mjpending = 1; g->chowpending = 0; g->konging = NotKonging; game_clearflag(g,GFKong); game_clearflag(g,GFKongUponKong); return affected_id; } case CMsgPlayerShowsTiles: { CMsgPlayerShowsTilesMsg *m = (CMsgPlayerShowsTilesMsg *)cm; setups; affected_id = m->id; if ( chk ) { /* it's not allowed to show tiles twice */ if ( pflag(p,HandDeclared) ) { g->cmsg_err = "Hand already declared"; return -1; } if ( p->num_concealed > 0 ) { if ( g->state != MahJonging ) { g->cmsg_err = "Can't reveal your tiles now!"; return -1; } if ( s == g->player ) { g->cmsg_err = "Must finish making your sets"; return -1; } } } if ( ! player_shows_tiles(p,m->tiles) && chk ) { g->cmsg_err = "Couldn't show those tiles"; return -1; } /* the player_shows_tiles fn already set the HandDeclared flag */ return affected_id; } case CMsgSwapTile: { CMsgSwapTileMsg *m = (CMsgSwapTileMsg *)cm; setups; affected_id = m->id; if ( ! player_swap_tile(p,m->oldtile,m->newtile) ) { g->cmsg_err = p->err; return -1; } return affected_id; } case CMsgHandScore: { CMsgHandScoreMsg *m = (CMsgHandScoreMsg *)cm; setups; affected_id = m->id; set_player_hand_score(p,m->score); return affected_id; } case CMsgSettlement: { CMsgSettlementMsg *m = (CMsgSettlementMsg *)cm; change_player_cumulative_score(g->players[east],m->east); change_player_cumulative_score(g->players[south],m->south); change_player_cumulative_score(g->players[west],m->west); change_player_cumulative_score(g->players[north],m->north); g->state = HandComplete; for ( i=0;i<NUM_SEATS;i++) g->claims[i] = 0; /* g->player is still correct */ if ( g->player == east ) g->hands_as_east++; return affected_id; } case CMsgError: /* it is an error to pass this function an error */ g->cmsg_err = "Game shouldn't be given error messages"; return -1; case CMsgGameOver: /* nothing to do: up to client */ return affected_id; case CMsgGameOption: { CMsgGameOptionMsg *m = (CMsgGameOptionMsg *)cm; setups; if ( chk && (g->manager != 0) && g->manager != m->id ) { g->cmsg_err = "Not authorized to set game options"; return -1; } if ( game_set_option(g,&m->optentry) == 0 && chk ) { return -1; } return affected_id; } case CMsgChangeManager: { CMsgChangeManagerMsg *m = (CMsgChangeManagerMsg *)cm; setups; if ( chk && (g->manager != 0) && g->manager != m->id ) { g->cmsg_err = "Not authorized to change the manager"; return -1; } g->manager = m->manager; return affected_id; } case CMsgWall: { CMsgWallMsg *m = (CMsgWallMsg *)cm; int i; int n; char tn[5]; char *tp; Tile t; if ( g->state != HandComplete ) { g->cmsg_err = "Can only set the wall between hands"; return -1; } for ( i = 0, tp = m->wall ; i < MAX_WALL_SIZE ; i++, tp += n ) { if ( sscanf(tp,"%2s%n",tn,&n) == 0 ) break; t = tile_decode(tn); if ( t == ErrorTile ) { g->cmsg_err = "bad wall in WallMsg"; return -1; } g->wall.tiles[i] = t; } return 0; } case CMsgMessage: /* nothing to do for us */ return ((CMsgMessageMsg *)cm)->addressee; case CMsgComment: return 0; case CMsgPlayerOptionSet: /* This should be dealt with by client code, not us */ g->cmsg_err = "Player options are not dealt with by the game"; return -1; } /* if we get to here, we were passed a bad CMsg type, which should be impossible */ warn("Unknown Controller message type %d",cm->type); return -2;}/* say whether a game has started or not */int game_has_started(Game *g) { if ( g == NULL ) return 0; if ( g->round == UnknownWind ) return 0; if ( g->round != EastWind ) return 1; /* this next one is tricky: if there's no player in east, we've already deleted it, so it must be OK to delete others */ if ( g->players[east]->id == 0 ) return 0; if ( g->players[east]->id != g->firsteast ) return 1; if ( g->hands_as_east > 0 ) return 1; if ( g->state != HandComplete ) return 1; return 0;}/* this internal function sets the danger signal flags for a player. It does NOT deal with the DangerEnd flag. The game argument is currently unused. It should be called whenever a player declares a set. */static void set_danger_flags(Game *g UNUSED, PlayerP p) { int i,s; int numchows,numpungs,numkongs,allhonours, allterminals,dragonsets,windsets, allgreen,allbamboo,allcharacter,allcircle, allbamboohonour,allcharacterhonour,allcirclehonour; numchows = 0; numkongs = 0; numpungs = 0; allterminals = 1; allhonours = 1; windsets = 0; dragonsets = 0; allgreen = 1; allbamboo = 1; allcharacter = 1; allcircle = 1; allbamboohonour = 1; allcharacterhonour = 1; allcirclehonour = 1; s = p->wind-1; /* player's seat */ presetdflags(p,s); /* clear all flags */ /* go through collecting information. This is distressingly similar to code in scoring.c */ for ( i = 0; i < MAX_TILESETS; i++ ) { TileSetP t = (TileSetP) &p->tilesets[i]; if ( t->type == Empty ) continue; if ( t->type == Chow ) numchows++,allterminals=allhonours=0; if ( t->type == Pung ) numpungs++; if ( t->type == Kong ) numkongs++; dragonsets += is_dragon(t->tile); windsets += is_wind(t->tile); switch ( suit_of(t->tile) ) { case BambooSuit: allcharacter = allcharacterhonour = 0; allcircle = allcirclehonour = 0; switch ( t->type ) { case Chow: if ( !is_green(t->tile) || !is_green(t->tile+1) || !is_green(t->tile+2) ) allgreen = 0; break; default: if ( !is_green(t->tile) ) allgreen = 0; } break; case CharacterSuit: allbamboo = allbamboohonour = 0; allcircle = allcirclehonour = 0; allgreen = 0; break; case CircleSuit: allbamboo = allbamboohonour = 0; allcharacter = allcharacterhonour = 0; allgreen = 0; break; case DragonSuit: allbamboo = allcharacter = allcircle = 0; if ( !is_green(t->tile) ) allgreen = 0; break; case WindSuit: allbamboo = allcharacter = allcircle = 0; allgreen = 0; break; default: warn("Strange suit seen in hand"); } if ( !is_honour(t->tile) ) allhonours = 0; if ( !is_terminal(t->tile) ) allterminals = 0; } /* now set the flags again */ if ( numpungs+numkongs+numchows >= 3 && allbamboo ) psetdflags(p,s,DangerBamboo); if ( numpungs+numkongs+numchows >= 3 && allcharacter ) psetdflags(p,s,DangerCharacter); if ( numpungs+numkongs+numchows >= 3 && allcircle ) psetdflags(p,s,DangerCircle); if ( windsets >= 3 ) psetdflags(p,s,DangerWind); if ( dragonsets >= 2 ) psetdflags(p,s,DangerDragon); if ( numpungs+numkongs+numchows >= 3 && allhonours ) psetdflags(p,s,DangerHonour); if ( numpungs+numkongs+numchows >= 3 && allgreen ) psetdflags(p,s,DangerGreen); if ( numpungs+numkongs+numchows >= 3 && allterminals ) psetdflags(p,s,DangerTerminal); /* This is always set (for convenience); it's not a property of the player, but of the game as a whole, and will only be applied if a dangerous discard is made. */ psetdflags(p,s,DangerEnd); }/* This internal function sets the flags for the supply of a dangerous discard. It is called (by handle_cmsg) after a claim has been implemented, but before the claiming player's danger flags are re-evaluated. */static void mark_dangerous_discards(Game *g) { PlayerP p; unsigned int i; seats s,sup; /* seat of player, seat of supplier */ Tile t; /* the discard claimed */ unsigned int danger; int nochoice; p = g->players[g->player]; s = p->wind-1; sup = g->supplier; t = g->tile; danger = 0; nochoice = 0; if ( pdflag(p,s,DangerBamboo) && suit_of(t) == BambooSuit ) danger |= DangerBamboo; if ( pdflag(p,s,DangerCharacter) && suit_of(t) == CharacterSuit ) danger |= DangerCharacter; if ( pdflag(p,s,DangerCircle) && suit_of(t) == CircleSuit ) danger |= DangerCircle; if ( pdflag(p,s,DangerWind) && suit_of(t) == WindSuit ) danger |= DangerWind; if ( pdflag(p,s,DangerDragon) && suit_of(t) == DragonSuit ) danger |= DangerDragon; if ( pdflag(p,s,DangerHonour) && is_honour(t) ) danger |= DangerHonour; if ( pdflag(p,s,DangerTerminal) && is_terminal(t) ) danger |= DangerTerminal; if ( pdflag(p,s,DangerGreen) && is_green(t) ) danger |= DangerGreen; /* End danger is special */ if ( g->wall.live_end - g->wall.live_used <= 4 && g->discarded_tile_count[t] <= 1 ) danger |= DangerEnd; /* if we've determined that the discard was dangerous, we now have to see whether the supplier had no choice */ if ( danger && !pflag(g->players[sup],Hidden) ) { seats i; int j; PlayerP psup = g->players[sup]; PlayerP pp; Tile t; int dangerous; nochoice = 1; for ( j = 0; j < psup->num_concealed ; j++ ) { t = psup->concealed[j]; dangerous = 0; for ( i = 0 ; i < NUM_SEATS; i++ ) { if ( i == sup ) continue; pp = g->players[i]; if ( ( pdflag(pp,i,DangerBamboo) && suit_of(t) == BambooSuit ) || ( pdflag(pp,i,DangerCharacter) && suit_of(t) == CharacterSuit ) || ( pdflag(pp,i,DangerCircle) && suit_of(t) == CircleSuit ) || ( pdflag(pp,i,DangerWind) && suit_of(t) == WindSuit ) || ( pdflag(pp,i,DangerDragon) && suit_of(t) == DragonSuit ) || ( pdflag(pp,i,DangerHonour) && is_honour(t) ) || ( pdflag(pp,i,DangerTerminal) && is_terminal(t) ) || ( pdflag(pp,i,DangerGreen) && is_green(t) ) || ( g->wall.live_end - g->wall.live_used <= 4 && g->discarded_tile_count[t] <= 1 ) ) dangerous = 1; } if ( ! dangerous ) { nochoice = 0; break; } } } if ( danger && ! nochoice ) { /* The supplier has supplied a dangerous discard without excuse */ psetdflags(p,sup,danger); /* and this discharges the liability of any other player that previously made a dangerous discard */ for ( i = 0 ; i < NUM_SEATS ; i++ ) { if ( i != s && i != sup ) presetdflags(p,i); } } /* set the game danger flag */ if ( danger ) game_setflag(g,GFDangerousDiscard); if ( danger && nochoice ) game_setflag(g,GFNoChoice);}#include "game-enums.c"
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -