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

📄 game.c

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