/* To start the game */ TEG_STATUS token_start( int fd ) { char strout[PROT_MAX_LEN + PLAYERNAME_MAX_LEN * TEG_MAX_PLAYERS + 200]; PSPLAYER pJ; PLAY_DEBUG("token_start()\n"); if( JUEGO_EMPEZADO || g_game.players < 2 ) goto error; if( g_server.with_console && fd != CONSOLE_FD) { if( !SPLAYER_HABILITADO_P(fd,&pJ) || !pJ->is_player ) goto error; } JUEGO_EN_EMPEZAR; g_game.playing = g_game.players; con_text_out(M_INF,_("Starting game number: %d with seed: %u\n"),g_game.gamenumber,g_game.seed); player_all_set_status ( PLAYER_STATUS_START ); countries_repartir(); if(turno_init() != TEG_STATUS_SUCCESS ) { con_text_out(M_ERR,_("Error, can't initialize a new turn\n")); goto error; } JUEGO_EN_FICHAS; g_game.turno->estado = PLAYER_STATUS_FICHAS; aux_token_stasta(strout, sizeof(strout) -1 ); netall_printf( "%s=%s;%s=%d,%d;%s=%d,%d,%d,%d;%s=%d,%d\n" ,TOKEN_START ,strout /* available players */ ,TOKEN_NEW_ROUND ,g_game.turno->numjug /* who starts the new turn */ ,g_game.round_number /* the round number */ ,TOKEN_MODALIDAD ,g_game.mission /* play with missions ? */ ,g_game.cmission /* play with common mission */ ,g_game.fog_of_war /* play with fog of war */ ,g_game.reglas /* which rules ? */ ,TOKEN_FICHAS ,g_game.turno->numjug, /* who starts ? */ g_game.fichas ); /* how many armies to place */ return TEG_STATUS_SUCCESS; error: net_print(fd,TOKEN_ERROR"="TOKEN_START"\n"); return TEG_STATUS_PARSEERROR; }
/* Called when a player finish his turn */ STATIC TEG_STATUS token_turn( int fd, char *unused ) { PSPLAYER pJ; PLAY_DEBUG("token_turn()"); if( player_whoisfd( fd, &pJ ) != TEG_STATUS_SUCCESS ) { goto error; } if( pJ->estado < PLAYER_STATUS_TURNOSTART || pJ->estado > PLAYER_STATUS_TURNOEND ) goto error; if( pJ != g_game.turno ) { con_text_out(M_ERR,_("BUG: The server believes that player `%s' does not have the turn"),pJ->name); goto error; } pJ->estado = PLAYER_STATUS_IDLE; if( turno_end( pJ ) != TEG_STATUS_SUCCESS ) goto error; /* give turn to the next player */ if( turno_next() != TEG_STATUS_SUCCESS ) goto error; return TEG_STATUS_SUCCESS; error: net_print(fd,TOKEN_ERROR"="TOKEN_TURNO"\n"); return TEG_STATUS_PARSEERROR; }
/* Puts the player in Game Over state */ TEG_STATUS token_surrender( int fd, char *unused ) { PSPLAYER pJ; PLAY_DEBUG("token_surrender\n"); if( player_whoisfd( fd, &pJ ) != TEG_STATUS_SUCCESS ) goto error; if( !pJ->is_player ) goto error; if( pJ->estado < PLAYER_STATUS_HABILITADO ) goto error; con_text_out(M_INF,_("Player %s(%d) abandoned the game\n"),pJ->name,pJ->numjug); netall_printf("%s=%d\n", TOKEN_SURRENDER, pJ->numjug ); player_del_soft( pJ ); return TEG_STATUS_SUCCESS; error: net_print(fd,TOKEN_ERROR"="TOKEN_SURRENDER"\n"); return TEG_STATUS_PARSEERROR; }
/* adds a fd to the all_set descriptors */ void fd_add( int fd ) { if( g_server.debug ) con_text_out(M_INF,_("Accepting fd %d\n"),fd); FD_SET(fd, &all_set ); if( fd > max_fd ) max_fd = fd; }
/* Clears a fd from the all_set descriptors */ void fd_remove( int fd ) { if( g_server.debug ) con_text_out(M_INF,_("Removing fd %d\n"),fd); if( fd > 0 ) { net_close(fd); FD_CLR(fd,&all_set); } }
TEG_STATUS launch_robot( int *robot_socket, char *mode ) { pid_t pid; char *args[5]; int sockets[2]; // sockets[0] is the client side of the robot // sockets[1] is the server side sockets[0] = 0; while(sockets[0] < 3) { int r = socketpair(AF_LOCAL, SOCK_STREAM, 0, sockets ); if( r != 0 ) return TEG_STATUS_ERROR; } // launch the server connected if ( (pid = fork()) < 0) { perror("tegserver: launch_bot() "); return TEG_STATUS_ERROR; } else if (pid == 0) { close( sockets[1] ); args[0] = BINDIR"/tegrobot"; args[1] = mode; args[2] = NULL; if ( dup2( sockets[0], 3 ) == -1 ) return TEG_STATUS_ERROR; con_text_out(M_ERR, _("Launching robot with options: %s %s\n"),args[0],args[1]); if( execv(args[0], args) < 0) { fprintf(stderr,"Launching robot failed. Does the file `%s' exists ?",args[0]); perror("exe:"); } exit(1); } else { close( sockets[0] ); } // return the robot fd *robot_socket = sockets[1]; return TEG_STATUS_SUCCESS; }
/* Protocol version */ STATIC TEG_STATUS token_pversion( int fd, char *str ) { PSPLAYER pJ; PARSER p; DELIM igualador={ ':', ':', ':' }; DELIM separador={ ',', ',', ',' }; int hi,lo; PLAY_DEBUG("token_pversion()\n"); if( strlen(str)==0 ) goto error; p.igualador = &igualador; p.separador = &separador; p.data = str; if( parser_call( &p ) && p.hay_otro ) { hi = atoi( p.token ); } else goto error; if( parser_call( &p ) && !p.hay_otro ) { lo = atoi( p.token ); } else goto error; net_printf(fd,"%s=%i,%i\n", TOKEN_PVERSION, PROTOCOL_HIVER,PROTOCOL_LOVER); if( hi != PROTOCOL_HIVER ) { con_text_out(M_ERR,_("Client with incompatible protocol version (server:%d , client:%d)\n"),PROTOCOL_HIVER,hi); if( player_whoisfd( fd, &pJ ) == TEG_STATUS_SUCCESS ) player_del_hard( pJ ); else fd_remove(fd); return TEG_STATUS_CONNCLOSED; } return TEG_STATUS_SUCCESS; error: net_print(fd,TOKEN_ERROR"="TOKEN_PVERSION"\n"); return TEG_STATUS_PARSEERROR; }
/* Assigns the player a color */ STATIC TEG_STATUS token_color( int fd, char *str ) { int color; int a; PSPLAYER pJ; PLAY_DEBUG("token_color()"); if( player_whoisfd( fd, &pJ ) != TEG_STATUS_SUCCESS ) { goto error; } if(strlen(str)==0) goto error; if( pJ->estado != PLAYER_STATUS_CONNECTED ) goto error; if( pJ->is_player == FALSE ) goto error; a = atoi( str ); if (a < 0 || a >= TEG_MAX_PLAYERS ) goto error; color = a; if ( color_libre( &color ) == FALSE ) goto error; pJ->estado = PLAYER_STATUS_HABILITADO; pJ->color = color; con_text_out(M_INF,_("Player %s(%d) has color %s\n"),pJ->name,pJ->numjug,_(g_colores[color])); netall_printf( "%s=%s,%d,%d\n", TOKEN_NEWPLAYER, pJ->name, pJ->numjug, pJ->color ); return TEG_STATUS_SUCCESS; error: net_print(fd,TOKEN_ERROR"="TOKEN_COLOR"\n"); return TEG_STATUS_PARSEERROR; }
/* A player is attacking from src to dst */ STATIC TEG_STATUS token_attack( int fd, char *str ) { PARSER p; DELIM igualador={ ':', ':', ':' }; DELIM separador={ ',', ',', ',' }; int src,dst,src_lost,dst_lost; char d_src[3],d_dst[3]; PSPLAYER pJ_src, pJ_dst; int conq = 0; int tropas = 0; char buffer[4096]; PLAY_DEBUG("token_attack()\n"); if( strlen(str)==0) goto error; if( !SPLAYER_ATAQUE_P(fd,&pJ_src)) { if( SPLAYER_TROPAS_P(fd,&pJ_src)) { pJ_src->estado=PLAYER_STATUS_ATAQUE; pJ_src->country_src = pJ_src->country_dst = -1; } else goto error; } p.igualador = &igualador; p.separador = &separador; p.data = str; if( parser_call( &p ) && p.hay_otro ) { src = atoi( p.token ); } else goto error; if( parser_call( &p ) && !p.hay_otro ) { dst = atoi( p.token ); } else goto error; if( src >= COUNTRIES_CANT || src < 0 || dst >= COUNTRIES_CANT || dst < 0) { goto error; } if( pJ_src->numjug != g_countries[src].numjug || pJ_src->numjug == g_countries[dst].numjug ) { goto error; } if( g_countries[src].ejercitos < 2 || !countries_eslimitrofe( src, dst) ) { goto error; } if( player_whois( g_countries[dst].numjug, &pJ_dst ) != TEG_STATUS_SUCCESS ){ goto error; } if( pactos_attack( src, dst ) != TEG_STATUS_SUCCESS ) goto error; /* aviso a todos que hay un attack */ if( ! g_game.fog_of_war ) netall_printf( "%s=%d,%d\n",TOKEN_ATAQUE,src,dst ); else { fow_2_netall_printf( src, dst, "%s=%s,%s\n",TOKEN_ATAQUE,"%d","%d" ); } /* so far, attack... */ aux_token_attack( g_countries[src].ejercitos, g_countries[dst].ejercitos, &src_lost, &dst_lost, d_src, d_dst ); g_countries[src].ejercitos -= src_lost; g_countries[dst].ejercitos -= dst_lost; pJ_src->tot_armies -= src_lost; pJ_dst->tot_armies -= dst_lost; /* updated statistics */ pJ_src->player_stats.armies_killed += dst_lost; pJ_dst->player_stats.armies_killed += src_lost; pJ_dst->player_stats.armies_lost += dst_lost; pJ_src->player_stats.armies_lost += src_lost; /* conquisto el country | country was conquered */ if( g_countries[dst].ejercitos == 0) { PLIST_ENTRY l; conq = 1; pJ_src->turno_conq++; pJ_src->tot_countries++; g_countries[dst].numjug = pJ_src->numjug; g_countries[dst].ejercitos++; /* se pasa automaticamente */ g_countries[src].ejercitos--; /* un ejercito */ tropas = g_countries[src].ejercitos - 1; /* cantidad que se pueden pasar */ if( tropas > 2 ) /* En verdad son 3, pero ya se le paso 1 */ tropas =2; pJ_src->estado = PLAYER_STATUS_TROPAS; pJ_src->country_src = src; pJ_src->country_dst = dst; pJ_dst->tot_countries--; l= RemoveHeadList( g_countries[dst].next.Blink ); InsertTailList( &pJ_src->countries, l); /* updated statistics */ pJ_src->player_stats.countries_won ++; pJ_dst->player_stats.countries_lost ++; } /* update the scores */ stats_score( &pJ_src->player_stats ); stats_score( &pJ_dst->player_stats ); /* tell everybody the result of the attack */ memset( buffer, 0, sizeof(buffer) ); if( ! g_game.fog_of_war ) { netall_printf( "%s=%d,%d,%d,%d,%d,%d,%d,%d\n", TOKEN_DADOS, src,d_src[0],d_src[1],d_src[2], dst,d_dst[0],d_dst[1],d_dst[2] ); } else { fow_2_netall_printf( src, dst, "%s=%s,%d,%d,%d,%s,%d,%d,%d\n" , TOKEN_DADOS , "%d",d_src[0],d_src[1],d_src[2] , "%d",d_dst[0],d_dst[1],d_dst[2] ); } if( ! g_game.fog_of_war ) { netall_printf( "%s=%d,%d,%d;%s=%d,%d,%d\n", TOKEN_COUNTRY, src, g_countries[src].numjug, g_countries[src].ejercitos, TOKEN_COUNTRY, dst, g_countries[dst].numjug, g_countries[dst].ejercitos ); } else { fow_netall_printf( src, "%s=%d,%d,%d\n", TOKEN_COUNTRY, src, g_countries[src].numjug, g_countries[src].ejercitos ); fow_netall_printf( dst, "%s=%d,%d,%d\n", TOKEN_COUNTRY, dst, g_countries[dst].numjug, g_countries[dst].ejercitos ); } if( conq == 1 ) { /* Did 'dst' player lose the game ? */ if( player_is_lost( pJ_dst ) ) { con_text_out(M_INF,_("Player %s(%d) lost the game\n"),pJ_dst->name,pJ_dst->numjug); netall_printf( "%s=%d\n",TOKEN_LOST, pJ_dst->numjug ); player_poner_perdio(pJ_dst); } /* Did 'src' player win the game ? */ if( mission_chequear( pJ_src ) == TEG_STATUS_GAMEOVER || game_is_finished() ) { #ifdef WITH_GGZ ggz_server_gameover(pJ_src->fd); #endif con_text_out(M_INF,_("Player %s(%d) is the winner! Game Over\n"),pJ_src->name,pJ_src->numjug); pJ_src->estado = PLAYER_STATUS_GAMEOVER; game_end( pJ_src ); return TEG_STATUS_SUCCESS; } net_printf(fd,"%s=%d,%d,%d\n", TOKEN_TROPAS, src,dst,tropas); /* in FOW show the boundaries countries */ if( g_game.fog_of_war ) { char buffer[2048]; memset( buffer, 0, sizeof(buffer) ); if( fow_fill_with_boundaries( dst, buffer, sizeof(buffer) ) == TEG_STATUS_SUCCESS ) net_printf( fd, "%s\n", buffer ); } } return TEG_STATUS_SUCCESS; error: net_print(fd,TOKEN_ERROR"="TOKEN_ATAQUE"\n"); return TEG_STATUS_PARSEERROR; }
STATIC TEG_STATUS token_cversion( int fd, char *str ) { con_text_out(M_INF,_("Using client version: %s\n"),str); return TEG_STATUS_SUCCESS; }
/* Creates a Player */ STATIC TEG_STATUS token_playerid( int fd, char *str ) { PARSER p; DELIM igualador={ ':', ':', ':' }; DELIM separador={ ',', ',', ',' }; SPLAYER j, *pJ; char c[TEG_MAX_PLAYERS]; char colores[100]; int i; int reconnect = FALSE; PLAY_DEBUG("token_playerid( fd=%d)\n",fd); /* si existe entonces da error, porque no tiene que existir */ if( player_whoisfd(fd, &pJ ) == TEG_STATUS_SUCCESS ) goto error; if( strlen(str)==0 ) goto error; p.igualador = &igualador; p.separador = &separador; p.data = str; memset( &j, 0, sizeof(SPLAYER)); /* averigua el name */ if( parser_call( &p ) && p.hay_otro ) { #ifdef WITH_GGZ if(g_server.with_ggz) { if( ggz_server_find_ggzname(fd,j.name,sizeof(j.name)-1) != TEG_STATUS_SUCCESS ) { player_fillname( &j, p.token ); } } else #endif /* WITH_GGZ */ player_fillname( &j, p.token ); } else goto error; if( parser_call( &p ) && p.hay_otro ) { j.is_player = atoi( p.token ); } else goto error; if( parser_call( &p ) && !p.hay_otro ) { j.human = atoi( p.token ); } else goto error; if( j.is_player ) { if( JUEGO_EMPEZADO ) { if( ! (reconnect = player_is_disconnected(&j)) ) { net_print(fd,TOKEN_GAMEINPROGRESS"\n"); fd_remove(fd); return TEG_STATUS_CONNCLOSED; } } if( reconnect ) pJ = player_return_disconnected( &j ); else pJ = player_ins_player( &j ); } else pJ = player_ins_ro( &j ); if( pJ == NULL ) { net_print(fd,TOKEN_SERVERFULL "\n"); fd_remove(fd); return TEG_STATUS_CONNCLOSED; } pJ->fd = fd; aux_find_inaddr( pJ ); if( reconnect ) { pJ->estado = pJ->status_before_discon; net_printf(fd,"%s=%s,%d,%d\n", TOKEN_RECONNECT, pJ->name,pJ->numjug,pJ->color); con_text_out(M_INF,_("Player %s(%d) is re-connected from %s\n"),pJ->name,pJ->numjug,pJ->addr); } else { colores_libres( c ); memset(colores,0,sizeof(colores)); for(i=0;i<TEG_MAX_PLAYERS;i++) { char buf[100]; sprintf( buf, ",%d",c[i] ); strncat( colores, buf, sizeof(colores)-1 ); } net_printf(fd,"%s=%s,%d%s\n", TOKEN_PLAYERID, pJ->name,pJ->numjug,colores); con_text_out(M_INF,_("Player %s(%d) is connected from %s\n"),pJ->name,pJ->numjug,pJ->addr); } return TEG_STATUS_SUCCESS; error: net_print(fd,TOKEN_ERROR"="TOKEN_PLAYERID"\n"); return TEG_STATUS_PARSEERROR; }
/* find the internet address of a player */ TEG_STATUS aux_find_inaddr( PSPLAYER pJ ) { struct sockaddr *sa; socklen_t slen = 128; assert(pJ); strncpy(pJ->addr, _("Unknown"), sizeof(pJ->addr)-1); #ifdef WITH_GGZ if(g_server.with_ggz) { strncpy(pJ->addr, _("GGZ Client"), sizeof(pJ->addr)-1); return TEG_STATUS_SUCCESS; } #endif /* WITH_GGZ */ if( pJ->fd <= 0) return TEG_STATUS_ERROR; if( (sa=malloc(slen)) == NULL ) return TEG_STATUS_ERROR; if( getpeername( pJ->fd, sa, &slen ) == -1) { con_text_out(M_ERR,"Error in getpeername()\n"); pJ->addr[sizeof(pJ->addr)-1]=0; free(sa); return TEG_STATUS_ERROR; } switch(sa->sa_family) { case AF_INET: { struct sockaddr_in *sin = (struct sockaddr_in*) sa; my_inet_ntop( AF_INET, &sin->sin_addr,pJ->addr, sizeof(pJ->addr)-1); break; } case AF_INET6: { struct sockaddr_in6 *sin6 = (struct sockaddr_in6*) sa; my_inet_ntop( AF_INET6, &sin6->sin6_addr,pJ->addr, sizeof(pJ->addr)-1); break; } case AF_UNIX: strncpy(pJ->addr,"127.0.0.1",sizeof(pJ->addr)-1); break; #if 0 { struct sockaddr_un *unp = (struct sockaddr_un *) sa; if(unp->sun_path[0]==0) strncpy(pJ->addr,_("Unknown"),sizeof(pJ->addr)-1); else snprintf(pJ->addr, sizeof(pJ->addr)-1, "%s", unp->sun_path); break; } #endif default: break; } pJ->addr[sizeof(pJ->addr)-1]=0; strip_invalid(pJ->addr); free(sa); return TEG_STATUS_SUCCESS; }