⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 game.c

📁 支持网络和单机的麻将游戏
💻 C
📖 第 1 页 / 共 5 页
字号:
      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 + -