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

📄 game.c

📁 支持网络和单机的麻将游戏
💻 C
📖 第 1 页 / 共 5 页
字号:
    return affected_id;  case CMsgInfoTiles:    /* Note that this always forces the player into compliance.       It's up to the client not to call this routine when       it's not wanted */    {      CMsgInfoTilesMsg *m = (CMsgInfoTilesMsg *)cm;      setups;      set_player_tiles(p,m->tileinfo);    }    return affected_id;  case CMsgNewRound:    {      CMsgNewRoundMsg *m = (CMsgNewRoundMsg *)cm;      g->round = m->round;      g->hands_as_east = 0; /* superfluous */    }    return affected_id;  case CMsgPause:    {      CMsgPauseMsg *m = (CMsgPauseMsg *)cm;      int i;      seats s;            if ( g->paused ) {	/* it is legitimate to start a new pause before one is complete */	free(g->paused);      }      g->paused = (char *)malloc(strlen(m->reason)+1);      if ( g->paused == NULL ) {	warn("unable to malloc space for pause reason");	return -2;      }      strcpy(g->paused,m->reason);      for ( i=0; i < NUM_SEATS; i++) g->ready[i] = 0;      s = game_id_to_seat(g,m->exempt);      if ( s != noseat ) g->ready[s] = 1;      affected_id = 0; /* affects everybody, really */    }    return affected_id;  case CMsgPlayerReady:    {      CMsgPlayerReadyMsg *m = (CMsgPlayerReadyMsg *)cm;      int i,ready;      setups;      affected_id = m->id;      if ( g->paused ) {	g->ready[s] = 1;	ready = 1;	for ( i=0 ; i < NUM_SEATS; i++ ) ready = (ready && g->ready[i]);	if ( ready ) {	  free(g->paused);	  g->paused = NULL;	}      }    }    return affected_id;  case CMsgNewHand:    {      CMsgNewHandMsg *m = (CMsgNewHandMsg *)cm;      PlayerP players[NUM_SEATS];      int n;      if ( chk ) {	if ( g->state != HandComplete ) {	  g->cmsg_err = "Still playing current hand";	  return -1;	}      }      /* If east has changed, reset hands_as_east */      if ( m->east != g->players[east]->id )	g->hands_as_east = 0;      /* first we have to rotate the players so that the current	 east is correct. */      for (i=0; i < NUM_SEATS; i++) players[i] = g->players[i];      n = game_id_to_seat(g,m->east);      for (i=0; i < NUM_SEATS; i++) g->players[i] = players[(i+n)%NUM_SEATS];      /* game state */      g->state = Dealing;      /* reset the hand scores and clear the flags */      for ( i = 0 ; i < NUM_SEATS ; i++ ) {	/* Warning: this knows TileWind = seats+1 */	player_newhand(g->players[i],i+1);      }      /* clear game flags */      g->flags = 0;      g->konging = NotKonging;      g->wall.live_used = 0;      g->wall.size = game_get_option_value(g,GOFlowers,NULL) ? 144 : 136;      g->wall.dead_end = g->wall.size;      g->wall.live_end = g->wall.dead_end - 	(game_get_option_value(g,GODeadWall,NULL) ? (game_get_option_value(g,GODeadWall16,NULL) ? 16 : 14) : 0) ;      g->serial = 0; /* must be initialized */      for ( i = 0 ; i < MaxTile ; i++ ) {	g->exposed_tile_count[i] = 0;	g->discarded_tile_count[i] = 0;      }    }    return affected_id;  case CMsgPlayerDraws:    {      CMsgPlayerDrawsMsg *m = (CMsgPlayerDrawsMsg *)cm;      Tile t;      setups;      affected_id = m->id;      if ( chk ) {	/* can this player draw? */	if ( g->state == Dealing ) {	  /* ought to check, but currently don't */	} else if ( g->state == Discarded ) {	  seats i;	  seats ds = g->player;	  /* legal if it's our turn and all claims have	     been received */	  if ( s != nextseat(ds) ) {	    g->cmsg_err = "Drawing out of turn";	    return -1;	  }	  for ( i = 0 ; i < NUM_SEATS ; i++ )	    if ( i != ds && g->claims[i] == UnknownClaim ) {	      g->cmsg_err = "Drawing before all claims received";	      return -1;	    }	  /* better not be a claim */	  for ( i = 0 ; i < NUM_SEATS ; i++ )	    if ( i != ds && g->claims[i] > NoClaim ) {	      g->cmsg_err = "Somebody has claimed the discard";	      return -1;	    }	} else if ( g->state == DeclaringSpecials ) {	  /* legal if it's our turn and we need a tile */	  if ( s != g->player ) {	    g->cmsg_err = "Can't draw out of turn";	    return -1;	  }	  if ( g->needs != FromWall ) {	    g->cmsg_err = "Don't need a tile now";	    return -1;	  }	} else if ( g->state == Discarding ) {	  /* only legal if we're drawing a replacement for	     a special under the rules where this comes	     from the live wall */	  if ( g->needs != FromWall ) {	    g->cmsg_err = "Already drawn or claimed a tile";	    return -1;	  }	} else {	  /* In any other state */	  g->cmsg_err = "Can't draw a tile now";	  return -1;	}      } /* end of legality checking */	        t = game_draw_tile(g);      if ( t == ErrorTile ) {	g->cmsg_err = "Wall exhausted";	return -1;      }      if ( chk && !teq(t,m->tile) ) {	g->cmsg_err = "Drawing tile not the first in wall";	warn(g->cmsg_err);	return -2;      }      /* if this fails, we're in a mess */      if ( ! player_draws_tile(p,m->tile) ) {	g->cmsg_err = "Unexpected failure drawing tile (player)";	warn(g->cmsg_err);	return -2;      }      /* next state of game */      if ( g->state == Dealing ) {	/* if this is east, store the tile */	if ( s == east ) g->tile = m->tile;	/* if deal is complete ... */	if ( g->players[east]->num_concealed == MAX_CONCEALED	     && g->players[south]->num_concealed == MAX_CONCEALED-1	     && g->players[west]->num_concealed == MAX_CONCEALED-1	     && g->players[north]->num_concealed == MAX_CONCEALED-1 ) {	  g->state = DeclaringSpecials;	  /* g->tile   was set before if nec */	  g->needs = FromNone;	  g->player = east;	  g->whence = FromWall;	}      } else {	if ( g->state == Discarded ) {	  g->state = Discarding;	}	g->tile = m->tile;	g->needs = FromNone;	g->player = s; 	g->whence = FromWall;	g->konging = NotKonging;      }    }    return affected_id;  case CMsgPlayerDrawsLoose:    {      CMsgPlayerDrawsLooseMsg *m = (CMsgPlayerDrawsLooseMsg *)cm;      Tile t;      setups;      affected_id = m->id;      if ( chk ) {	/* can this player draw a loose tile? */	/* can only happen when it's currently our turn */	if ( s != g->player ) {	  g->cmsg_err = "Can't draw a loose tile out of turn";	  return -1;	} else if ( (g->state == Discarding || g->state == DeclaringSpecials)		    && g->needs == FromLoose ) {	  /* OK */	} else {	  /* In any other state */	  g->cmsg_err = "Can't draw a tile now";	  return -1;	}      } /* end of legality checking */	        t = game_draw_loose_tile(g);      if ( t == ErrorTile ) {	g->cmsg_err = "Dead wall exhausted";	return -1;      }      if ( chk && !teq(t,m->tile) ) {	g->cmsg_err = "Drawing tile not the first loose tile";	warn(g->cmsg_err);	return -2;      }      /* if this fails, we're in a mess */      if ( ! player_draws_loose_tile(p,m->tile) ) {	g->cmsg_err = "Unexpected failure drawing tile (player)";	warn(g->cmsg_err);	return -2;      }      /* next state of game is unchanged apart from tile info */      g->needs = FromNone;      g->whence = FromLoose;      g->tile = m->tile;      g->konging = NotKonging;    }    return affected_id;  case CMsgPlayerDeclaresSpecial:    {      CMsgPlayerDeclaresSpecialMsg *m = (CMsgPlayerDeclaresSpecialMsg *)cm;      setups;      affected_id = m->id;      if ( chk ) {	/* Specials may be declared during the initial phase,	 or if it is the player's turn to discard, and at	 no other time.	 Morever, all rules I've seen say that specials can	 only be declared after drawing from the wall. Silly,	 but there it is.	 Pre-release version didn't have this, so we need	 to keep it for compatability.	*/	if ( g->state == DeclaringSpecials 	     || (g->state == Discarding		 && (g->protversion < 1010 		     || g->whence != FromDiscard) ) ) {	  if ( g->player != s ) {	    g->cmsg_err = "Can only declare in turn";	    return -1;	  }	} else {	  g->cmsg_err = "Can't discard specials now";	  return -1;	}      }      if ( m->tile == HiddenTile ) {	if ( chk && g->state == Discarding ) {	  /* this shouldn't happen. Although it's harmless,	     we will nonetheless return an error */	  g->cmsg_err = "Can't declare blank special now";	  return -1;	}	if ( s == north ) {	  g->state = Discarding;	  g->konging = NotKonging;	  g->needs = FromNone;	  /* we need to set whence. It could be from loose or wall,	     according to what happened during declaring specials. 	     However, if east is going to go out immediately, it doesn't	     matter, since that's a limit anyway. So we just set it to	     FromWall.	     FIXME: in fact the only reason we need to do this is	     because the controller deals itself, rather than passing	     cmsgs to the game. Sometime we should fix the controller.	     But that probably means making this routine fill in 	     details of cmsgs: which seems right anyway.	  */	  g->whence = FromWall;	  g->player = east;	} else {	  /* why do we set the state? So that resumption works:	     otherwise, there's no cue to enter the ds state */	  g->state = DeclaringSpecials;	  g->player = nextseat(s);	}      } else {	if ( ! player_declares_special(p,m->tile) ) {	  /* This can only fail if the player doesn't	     hold the tile */	  /* Actually, that's not true. It can also fail	     if the "hiddenness" is inconsistent. In this	     case, player will scream anyway. */	  g->cmsg_err = "Don't have that special";	  return -1;	}	if ( game_get_option_value(g,GOFlowersLoose,NULL) )	  g->needs = FromLoose;	else	  g->needs = FromWall;	g->exposed_tile_count[m->tile]++; /* who's counting specials ? */      }    }    return affected_id;  case CMsgStartPlay:    affected_id = ((CMsgStartPlayMsg *)cm)->id;    g->active = 1;    return affected_id;  case CMsgStopPlay:    g->active = 0;    return affected_id;  case CMsgPlayerDiscards:    {      CMsgPlayerDiscardsMsg *m = (CMsgPlayerDiscardsMsg *)cm;      int nodiscard;      setups;      affected_id = m->id;      if ( chk ) {	/* if it's not time to discard, return error */	if ( ! (g->state == Discarding	      && g->player == s) ) {	  g->cmsg_err = "Can't discard now";	  return -1;	}	/* give a more helpful error message when the player	   is waiting for a tile */	if ( g->needs ) {	  g->cmsg_err = "Need to draw a tile before discarding";	  return -1;	}	/* players aren't allowed to discard if the game is paused */	if ( g->paused ) {	  g->cmsg_err = "Can't discard until everybody's ready";	  return -1;	}	/* check legitimacy of calling declaration */	/* must be no sets declared */	if ( m->calling && p->num_concealed < 14 ) {	  g->cmsg_err = "Must have concealed hand to declare calling";	  return -1;	}	/* multiple calling declarations are silly */	if ( m->calling && pflag(p,Calling) ) {	  g->cmsg_err = "Already calling";	  return -1;	}	/* at present, only original call allowed */	if ( m->calling && ! pflag(p,NoDiscard) ) {	  g->cmsg_err = "Only Original Call declaration allowed";	  return -1;	}	/* if player is calling, can only discard the tile drawn.	   It is supposed to be impossible for a calling player	   to have claimed from a discard; but just as a precaution	   we'll check for it and panic. */	if ( pflag(p,Calling) ) {	  if ( g->whence == FromDiscard ) {	    g->cmsg_err = "Calling player discarding after claim??";	    warn("Calling player discarding after claim");	    return -2;	  }	  if ( m->tile != g->tile ) {	    g->cmsg_err = "Calling: can't discard that tile";	    return -1;	  }	}      }      nodiscard = pflag(p,NoDiscard); /* save as will be cleared by this */      if ( ! player_discards(p,m->tile) ) {	g->cmsg_err = "You can't discard that tile";	return -1;      }      g->state = Discarded;      g->player = s;      g->tile = m->tile;      g->serial = m->discard;      for ( i = 0 ; i < NUM_SEATS ; i++ )	g->claims[i] = UnknownClaim;      g->chowpending = 0;      game_clearflag(g,GFKong);      game_clearflag(g,GFKongUponKong);      game_clearflag(g,GFDangerousDiscard);      game_clearflag(g,GFNoChoice);      if ( m->calling ) {	psetflag(p,Calling);	if ( nodiscard ) { psetflag(p,OriginalCall); }      }      g->exposed_tile_count[m->tile]++;      g->discarded_tile_count[m->tile]++;      return affected_id;    }  case CMsgPlayerDoesntClaim:

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -