📄 controller.c
字号:
/* fill in basic fields of possible replies */ patpm.id = id; em.type = CMsgError ; em.seqno = connections[cnx].seqno; patpm.type = CMsgPlayerAddsToPung; em.error = NULL; patpm.tile = m->tile; patpm.discard = the_game->serial+1; if ( handle_cmsg(the_game,&patpm) < 0 ) { em.error = the_game->cmsg_err; send_id(id,&em); return; } check_min_time(1); send_all(the_game,&patpm); send_infotiles(p); /* now we need to wait for people to try to rob the kong */ timeout = 1000*timeout_time; return; assert(0); } /* end of case PMsgAddToPung */ case PMsgQueryMahJong: { PMsgQueryMahJongMsg *m = (PMsgQueryMahJongMsg *) pmp; PlayerP p; int id; seats seat; CMsgCanMahJongMsg cmjm; MJSpecialHandFlags mjf; id = cnx_to_id(cnx); p = id_to_player(id); seat = id_to_seat(id); cmjm.type = CMsgCanMahJong; cmjm.tile = m->tile; mjf = 0; if ( (int)game_get_option_value(the_game,GOSevenPairs,NULL) ) mjf |= MJSevenPairs; cmjm.answer = player_can_mah_jong(p,m->tile,mjf); send_id(id,&cmjm); return; } case PMsgShowTiles: { PlayerP p; int id; seats seat; CMsgErrorMsg em; CMsgPlayerShowsTilesMsg pstm; id = cnx_to_id(cnx); p = id_to_player(id); seat = id_to_seat(id); /* fill in basic fields of possible replies */ pstm.id = id; em.type = CMsgError ; em.seqno = connections[cnx].seqno; pstm.type = CMsgPlayerShowsTiles; em.error = NULL; /* if there are no concealed tiles, just ignore the message; this can only happen from the mahjonging player or by duplication */ if ( p->num_concealed > 0 ) { char tiles[100]; int i; tiles[0] = '\000'; for ( i = 0; i < p->num_concealed; i++ ) { if ( i > 0 ) strcat(tiles," "); strcat(tiles,tile_code(p->concealed[i])); } pstm.tiles = tiles; if ( handle_cmsg(the_game,&pstm) < 0 ) { em.error = the_game->cmsg_err; send_id(id,&em); return; } check_min_time(1); send_all(the_game,&pstm); score_hand(the_game,seat); return; } return; } /* end of case PMsgShowTiles */ case PMsgSetGameOption: { PMsgSetGameOptionMsg *m = (PMsgSetGameOptionMsg *)pmp; PlayerP p; int id; CMsgErrorMsg em; CMsgGameOptionMsg gom; GameOptionEntry *goe; id = cnx_to_id(cnx); /* fill in basic fields of possible replies */ gom.type = CMsgGameOption; gom.id = id; p = id_to_player(id); em.type = CMsgError ; em.seqno = connections[cnx].seqno; em.error = NULL; /* do we have the option ? */ goe = game_get_option_entry(the_game,GOUnknown,m->optname); if ( ! goe ) { em.error = "Trying to set unknown option"; send_id(id,&em); return; } /* if the option is actually unknown or end, ignore it */ if ( goe->option == GOUnknown || goe->option == GOEnd ) break; if ( goe->enabled == 0 ) { em.error = "Option not available in this game"; send_id(id,&em); return; } gom.optentry = *goe; switch ( goe->type ) { case GOTBool: if ( sscanf(m->optvalue,"%d",&gom.optentry.value.optbool) == 0 ) { em.error = "No boolean value found for option"; send_id(id,&em); return; } if ( gom.optentry.value.optbool != 0 && gom.optentry.value.optbool != 1 ) { em.error = "No boolean value found for option"; send_id(id,&em); return; } break; case GOTNat: if ( sscanf(m->optvalue,"%u",&gom.optentry.value.optnat) == 0 ) { em.error = "No integer value found for option"; send_id(id,&em); return; } break; case GOTInt: if ( sscanf(m->optvalue,"%d",&gom.optentry.value.optint) == 0 ) { em.error = "No integer value found for option"; send_id(id,&em); return; } break; case GOTScore: if ( sscanf(m->optvalue,"%d",&gom.optentry.value.optscore) == 0 ) { em.error = "No score value found for option"; send_id(id,&em); return; } break; case GOTString: strcpy(gom.optentry.value.optstring,m->optvalue); break; } /* specific validity checking not done by handle_cmsg */ if ( gom.optentry.option == GOTimeout && gom.optentry.value.optint < 0 ) { em.error = "Can't set negative timeout!"; send_id(id,&em); return; } if ( handle_cmsg(the_game,&gom) < 0 ) { em.error = the_game->cmsg_err; send_id(id,&em); } send_all(the_game,&gom); if ( gom.optentry.option == GOTimeout || gom.optentry.option == GOTimeoutGrace ) { timeout_time = get_timeout_time(the_game,localtimeouts); } break; } case PMsgQueryGameOption: { PMsgQueryGameOptionMsg *m = (PMsgQueryGameOptionMsg *)pmp; int id; CMsgErrorMsg em; CMsgGameOptionMsg gom; GameOptionEntry *goe; id = cnx_to_id(cnx); /* fill in basic fields of possible replies */ gom.type = CMsgGameOption; gom.id = 0; em.type = CMsgError ; em.seqno = connections[cnx].seqno; em.error = NULL; goe = game_get_option_entry(the_game,GOUnknown,m->optname); if ( goe == NULL ) { em.error = "Option not known"; send_id(id,&em); return; } gom.optentry = *goe; send_id(id,&gom); break; } case PMsgListGameOptions: { PMsgListGameOptionsMsg *m = (PMsgListGameOptionsMsg *)pmp; int id; CMsgGameOptionMsg gom; GameOptionEntry *goe; unsigned int i; id = cnx_to_id(cnx); /* fill in basic fields of possible replies */ gom.type = CMsgGameOption; gom.id = 0; /* this relies on the fact that we know our option table contains only known options in numerical order. This would not necessarily be the case for clients, but it is for us, since we don't allow unknown options to be set */ for ( i = 1 ; i <= GOEnd ; i++ ) { goe = &the_game->option_table.options[i]; if ( !goe->enabled && ! m->include_disabled ) continue; gom.optentry = *goe; send_id(id,&gom); } break; } case PMsgChangeManager: { PMsgChangeManagerMsg *m = (PMsgChangeManagerMsg *)pmp; int id; CMsgChangeManagerMsg cmm; CMsgErrorMsg em; id = cnx_to_id(cnx); /* fill in basic fields of possible replies */ cmm.type = CMsgChangeManager; cmm.id = id; cmm.manager = m->manager; em.type = CMsgError ; em.seqno = connections[cnx].seqno; em.error = NULL; if ( handle_cmsg(the_game,&cmm) < 0 ) { em.error = the_game->cmsg_err; send_id(id,&em); return; } send_all(the_game,&cmm); break; } case PMsgSendMessage: { PMsgSendMessageMsg *m = (PMsgSendMessageMsg *)pmp; int id; CMsgMessageMsg mm; CMsgErrorMsg em; id = cnx_to_id(cnx); mm.type = CMsgMessage; mm.sender = id; mm.addressee = m->addressee; mm.text = m->text; em.type = CMsgError; em.seqno = connections[cnx].seqno; em.error = NULL; if ( mm.addressee == 0 ) { send_all(the_game,&mm); } else { if ( id_to_cnx(mm.addressee) < 0 ) { em.error = "Addressee not found in game"; send_id(id,&em); return; } else { send_id(mm.addressee,&mm); } } break; } case PMsgSwapTile: { PMsgSwapTileMsg *m = (PMsgSwapTileMsg *) pmp; PlayerP p; int id; seats seat; CMsgErrorMsg em; CMsgSwapTileMsg stm; int i; id = cnx_to_id(cnx); /* fill in basic fields of possible replies */ stm.type = CMsgSwapTile; stm.id = m->id; stm.oldtile = m->oldtile; stm.newtile = m->newtile; p = id_to_player(stm.id); seat = id_to_seat(stm.id); em.type = CMsgError ; em.seqno = connections[cnx].seqno; em.error = NULL; if ( p == NULL ) { em.error = "SwapTile: no such player"; send_id(id,&em); return; } /* find the new tile in the wall. Because this is only used for debugging and testing, we don't care that we're diving inside the game structure! Look for the tile from the end, so as to avoid depleting the early wall. */ for ( i = the_game->wall.dead_end-1 ; the_game->wall.tiles[i] != m->newtile && i >= the_game->wall.live_used ; i-- ) ; if ( i < the_game->wall.live_used ) em.error = "No new tile in wall"; else { if ( handle_cmsg(the_game,&stm) < 0 ) { em.error = the_game->cmsg_err; } else { send_id(stm.id,&stm); the_game->wall.tiles[i] = stm.oldtile; } } if ( em.error ) send_id(id,&em); return; } /* end of case PMsgSwapTile */ }}/* setup_maps: we need to be able to map between connections, player structures, and player ids. player to id is in the player structure, so we need the others. It's a pity we can't declare private variables here.*//* set up data for a new connection */static int new_connection(SOCKET skt) { int i; for (i= 0; i < MAX_CONNECTIONS; i++) { if ( connections[i].inuse ) continue; connections[i].inuse = 1; connections[i].skt = skt; connections[i].player = NULL; connections[i].seqno = 0; /* add to the event set */ FD_SET(skt,&event_fds); return i; } warn("No space for new connection"); return -1;}/* close connection */static int close_connection(int cnx) { if ( connections[cnx].player ) { /* clear maps and decrement counter */ remove_from_maps(cnx); num_connected_players--; } FD_CLR(connections[cnx].skt,&event_fds); closesocket(connections[cnx].skt); connections[cnx].inuse = 0; return 1;}static int cnx_to_id(int cnx) { PlayerP p; p = connections[cnx].player; return p ? p->id : -1;}static int id_to_cnx(int id) { int i; i = 0; while ( i < MAX_CONNECTIONS ) { if ( connections[i].inuse && connections[i].player && connections[i].player->id == id ) return i; i++; } return -1;}static PlayerP id_to_player(int id) { int f; f = id_to_cnx(id); if ( f < 0 ) return NULL; return connections[f].player;}static void setup_maps(int cnx, PlayerP p) { connections[cnx].player = p;}static void remove_from_maps(int cnx) { connections[cnx].player = (PlayerP) 0;}/* send_packet: send the given packet out on the given cnx, perhaps logging */static void send_packet(int cnx,CMsgMsg *m, int logit) { char *l; if ( cnx < 0 ) return; l = encode_cmsg(m); if ( l == NULL ) { /* this shouldn't happen */ warn("send_packet: protocol conversion failed"); /* in fact, it so much shouldn't happen that we'll dump core */ assert(0); return; } if ( logit && logfile ) { fprintf(logfile,">cnx%d %s",cnx,l); fflush(logfile); } if ( put_line(connections[cnx].skt,l) < 0 ) { warn("send_packet: write on cnx %d failed",cnx); /* maybe we should shutdown the descriptor here? */ return; }}/* send player id a packet. Maybe log it. Enter the packet into the player's history, if appropriate */static void _send_id(int id,CMsgMsg *m,int logit) { int cnx = id_to_cnx
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -