Index: ai/advdomestic.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/ai/advdomestic.c,v retrieving revision 1.90 diff -u -r1.90 advdomestic.c --- ai/advdomestic.c 2002/09/27 12:32:42 1.90 +++ ai/advdomestic.c 2002/09/27 14:48:34 @@ -403,6 +403,8 @@ int tprod, prod, sci, tax, t, val, wwtv; int j, k; int values[B_LAST]; + int nplayers = game.nplayers + - teams_count_members(teams_get_by_idx(pplayer->team)); /* --- initialize control parameters --- */ t = pcity->ai.trade_want; /* trade_weighting */ @@ -677,7 +679,7 @@ case B_GREAT: /* basically (100 - freecost)% of a free tech per 2 turns */ values[id] = (total_bulbs_required(pplayer) * (100 - game.freecost) * t - * (game.nplayers - 2)) / (game.nplayers * 2 * 100); + * (nplayers - 2)) / (nplayers * 2 * 100); break; case B_WALL: if (!city_got_citywalls(pcity)) { Index: ai/aihand.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/ai/aihand.c,v retrieving revision 1.70 diff -u -r1.70 aihand.c --- ai/aihand.c 2002/08/21 22:19:25 1.70 +++ ai/aihand.c 2002/09/27 14:48:34 @@ -16,6 +16,9 @@ #include #include "city.h" +#include "config.h" +#include "events.h" +#include "fcintl.h" #include "game.h" #include "government.h" #include "log.h" @@ -27,6 +30,7 @@ #include "citytools.h" #include "cityturn.h" +#include "plrhand.h" #include "spacerace.h" #include "unithand.h" @@ -355,11 +359,41 @@ } /************************************************************************** - Main AI routine. + AI players that are in a team will automatically give away techs. **************************************************************************/ +static void ai_team_share_techs(struct player *pplayer) +{ + int i; + + players_iterate(aplayer) { + if (pplayer->team == aplayer->team) { + for (i = 0; i < game.num_tech_types; i++) { + if (get_invention(pplayer, i) == TECH_KNOWN + && get_invention(aplayer, i) != TECH_KNOWN) { + notify_player_ex(aplayer, -1, -1, E_TECH_GAIN, + _("Game: %s gave you %s!"), + pplayer->name, advances[i].name); + notify_embassies(aplayer, aplayer, + _("Game: The %s have acquired %s" + " from the %s."), + get_nation_name_plural(aplayer->nation), + advances[i].name, + get_nation_name_plural(pplayer->nation)); + do_dipl_cost(aplayer); + found_new_tech(aplayer, i, FALSE, FALSE); + } + } + } + } players_iterate_end; +} + +/************************************************************************** + ... +**************************************************************************/ void ai_do_first_activities(struct player *pplayer) { - ai_manage_units(pplayer); /* STOP. Everything else is at end of turn. */ + ai_team_share_techs(pplayer); + ai_manage_units(pplayer); } /************************************************************************** @@ -369,7 +403,6 @@ { ai_manage_cities(pplayer); /* manage cities will establish our tech_wants. */ - /* if I were upgrading units, which I'm not, I would do it here -- Syela */ freelog(LOG_DEBUG, "Managing %s's taxes.", pplayer->name); ai_manage_taxes(pplayer); freelog(LOG_DEBUG, "Managing %s's government.", pplayer->name); Index: common/game.h =================================================================== RCS file: /home/freeciv/CVS/freeciv/common/game.h,v retrieving revision 1.114 diff -u -r1.114 game.h --- common/game.h 2002/09/25 00:58:11 1.114 +++ common/game.h 2002/09/27 14:48:34 @@ -153,6 +153,8 @@ int playable_nation_count; int styles_count; + int team_count; + int watchtower_extra_vision; int watchtower_vision; int allowed_city_names; Index: common/nation.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/common/nation.c,v retrieving revision 1.25 diff -u -r1.25 nation.c --- common/nation.c 2002/08/07 11:21:47 1.25 +++ common/nation.c 2002/09/27 14:48:34 @@ -12,7 +12,7 @@ ***********************************************************************/ /********************************************************************** - Functions for handling the nations. + Functions for handling the nations and teams. ***********************************************************************/ #include @@ -26,10 +26,13 @@ #include "player.h" #include "support.h" #include "tech.h" +#include "config.h" +#include "fcintl.h" #include "nation.h" static struct nation_type *nations = NULL; +static struct team_type teams[MAX_NUM_TEAMS]; /*************************************************************** Returns 1 if nid is a valid nation id, else 0. @@ -151,6 +154,9 @@ return &nations[plr->nation]; } +/*************************************************************** + ... +***************************************************************/ struct nation_type *get_nation_by_idx(Nation_Type_id nation) { if (!bounds_check_nation_id(nation, LOG_FATAL, "get_nation_by_idx")) { @@ -233,4 +239,147 @@ exit(EXIT_FAILURE); } return nations[nation].city_style; +} + +/*************************************************************** + Returns the id of a team given its name, or -1 if not found +***************************************************************/ +Team_Type_id teams_find_by_name(const char *name) +{ + int i; + + assert(name != NULL); + for(i = 0; i < game.team_count; i++) + if(mystrcasecmp(name, teams_get_name(i)) == 0) + return i; + + return TEAM_NONE; +} + +/*************************************************************** + Returns name of a team given its id +***************************************************************/ +char *teams_get_name(Team_Type_id team) +{ + assert((team < MAX_NUM_TEAMS) && (team > TEAM_NONE)); + if (game.team_count < team) { + return NULL; + } + + return teams[team].name; +} + +/*************************************************************** + Returns pointer to a team given a player, returns null if none +***************************************************************/ +struct team_type *teams_get_by_plr(struct player *plr) +{ + assert((plr != NULL) && (plr->team < game.team_count)); + if ((game.team_count == 0) || (plr->team == TEAM_NONE)) { + return NULL; + } + return &teams[plr->team]; +} + +/*************************************************************** + Returns point to a team given its id +***************************************************************/ +struct team_type *teams_get_by_idx(Team_Type_id team) +{ + assert((team < game.team_count) && (team > TEAM_NONE)); + return &teams[team]; +} + +/*************************************************************** + Count living members of given team +***************************************************************/ +int teams_count_members(struct team_type *team) +{ + int count = 0; + + assert((team != NULL) && (team->team_no < game.team_count) + && (team->team_no > TEAM_NONE)); + players_iterate(pplayer) { + if ((pplayer->is_alive) && (pplayer->team == team->team_no)) { + count++; + } + } players_iterate_end; + return count; +} + +/*************************************************************** + Set a player to a team. Removes previous team affiliation, + creates a new team if it does not exist. Returns true if + action successful, false if teams list full. +***************************************************************/ +void teams_add_player(struct player *plr, const char *name) +{ + Team_Type_id team_id, i; + + assert((plr != NULL) && (name != NULL)); + + /* find or create team */ + team_id = teams_find_by_name(name); + if (team_id == TEAM_NONE) { + /* see if we have another team available */ + for (i = 0; i < MAX_NUM_TEAMS; i++) { + if (teams[i].team_no == TEAM_NONE) { + team_id = i; + break; + } + } + /* check if too many teams */ + if (team_id == TEAM_NONE) { + assert(FALSE); + } + /* add another team */ + teams[team_id].team_no = team_id; + sz_strlcpy(teams[team_id].name, name); + plr->team = team_id; + game.team_count++; + } else { + plr->team = team_id; + } +} + +/*************************************************************** + Removes a player from a team, and removes the team if empty of + players +***************************************************************/ +void teams_remove_player(struct player *plr) +{ + Team_Type_id i; + int count=0; + + assert((plr != NULL) && (plr->team < MAX_NUM_TEAMS)); + + if (plr->team == TEAM_NONE) { + return; + } + /* anyone else using my team? */ + for (i = 0; i < MAX_NUM_TEAMS; i++) { + if ((teams[i].team_no == plr->team) + && (plr->team != i)) { + count++; + } + } + /* no other team members left? remove team */ + if (count == 0) { + teams[plr->team].team_no = TEAM_NONE; + game.team_count--; + } + plr->team = TEAM_NONE; +} + +/*************************************************************** + Initializes team structure +***************************************************************/ +void teams_init() +{ + Team_Type_id i; + + for (i = 0; i < MAX_NUM_TEAMS; i++) { + /* mark as unused */ + teams[i].team_no = TEAM_NONE; + } } Index: common/nation.h =================================================================== RCS file: /home/freeciv/CVS/freeciv/common/nation.h,v retrieving revision 1.16 diff -u -r1.16 nation.h --- common/nation.h 2002/08/07 11:21:47 1.16 +++ common/nation.h 2002/09/27 14:48:34 @@ -19,8 +19,11 @@ #define MAX_NUM_TECH_GOALS 10 #define MAX_NUM_NATIONS 63 #define MAX_NUM_LEADERS 16 +#define MAX_NUM_TEAMS MAX_NUM_PLAYERS +#define TEAM_NONE -1 typedef int Nation_Type_id; +typedef int Team_Type_id; struct Sprite; /* opaque; client-gui specific */ struct player; @@ -89,6 +92,11 @@ } goals; }; +struct team_type { + char name[MAX_LEN_NAME]; + Team_Type_id team_no; +}; + Nation_Type_id find_nation_by_name(const char *name); const char *get_nation_name(Nation_Type_id nation); const char *get_nation_name_plural(Nation_Type_id nation); @@ -102,5 +110,25 @@ void nation_free(Nation_Type_id nation); void nation_city_names_free(struct city_name *city_names); int get_nation_city_style(Nation_Type_id nation); + +Team_Type_id teams_find_by_name(const char *name); +char *teams_get_name(Team_Type_id team); +struct team_type *teams_get_by_plr(struct player *plr); +struct team_type *teams_get_by_idx(Team_Type_id team); +void teams_add_player(struct player *plr, const char *name); +void teams_remove_player(struct player *plr); +int teams_count_members(struct team_type *team); +void teams_init(void); + +#define teams_iterate(PI_team) \ +{ \ + struct team_type *PI_team; \ + Team_Type_id PI_p_itr; \ + for (PI_p_itr = 0; PI_p_itr < game.team_count; PI_p_itr++) { \ + PI_team = teams_get_by_idx(PI_p_itr); + +#define teams_iterate_end \ + } \ +} #endif /* FC__NATION_H */ Index: common/player.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/common/player.c,v retrieving revision 1.100 diff -u -r1.100 player.c --- common/player.c 2002/09/23 22:47:10 1.100 +++ common/player.c 2002/09/27 14:48:34 @@ -71,6 +71,7 @@ plr->is_male = TRUE; plr->government=game.default_government; plr->nation=MAX_NUM_NATIONS; + plr->team = TEAM_NONE; plr->capital = FALSE; unit_list_init(&plr->units); city_list_init(&plr->cities); Index: common/player.h =================================================================== RCS file: /home/freeciv/CVS/freeciv/common/player.h,v retrieving revision 1.82 diff -u -r1.82 player.h --- common/player.h 2002/09/23 22:47:10 1.82 +++ common/player.h 2002/09/27 14:48:34 @@ -160,6 +160,7 @@ bool is_male; int government; Nation_Type_id nation; + Team_Type_id team; bool turn_done; int nturns_idle; bool is_alive; Index: server/diplhand.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/server/diplhand.c,v retrieving revision 1.63 diff -u -r1.63 diplhand.c --- server/diplhand.c 2002/09/22 19:21:30 1.63 +++ server/diplhand.c 2002/09/27 14:48:35 @@ -393,7 +393,6 @@ } } - /************************************************************************** ... **************************************************************************/ @@ -531,6 +530,12 @@ if (plr0->ai.control || plr1->ai.control) { notify_player(plr0, _("AI controlled players cannot participate in " "diplomatic meetings.")); + return; + } + if (plr0->team != TEAM_NONE && plr1->team != TEAM_NONE + && plr0->team != plr1->team) { + notify_player(plr0, _("You cannot have diplomatic relations with " + "members of another team.")); return; } Index: server/gamelog.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/server/gamelog.c,v retrieving revision 1.19 diff -u -r1.19 gamelog.c --- server/gamelog.c 2002/02/21 09:44:53 1.19 +++ server/gamelog.c 2002/09/27 14:48:35 @@ -76,6 +76,8 @@ fprintf(fs,"*** %s\n",buf); } else if (level==GAMELOG_RANK){ fprintf(fs,"RANK %s\n",buf); + } else if (level == GAMELOG_TEAM){ + fprintf(fs,"%s\n", buf); } else { fprintf(fs,"%i %s\n", game.year,buf); } @@ -132,6 +134,35 @@ count++; } } players_iterate_end; + + /* average game scores for teams */ + teams_iterate(team) { + int numplayers = 0; + int count = 0; + int teamscore = 0; + int teamsize = 0; + /* sum team score */ + players_iterate(pplayer) { + if (pplayer->team == team->team_no) { + numplayers++; + teamscore += rank[count].value; + teamsize += size[count].value; + } + count++; + } players_iterate_end; + /* average them */ + teamscore = floor(teamscore / numplayers); + teamsize = floor(teamsize / numplayers); + /* set scores to average */ + count=0; + players_iterate(pplayer) { + if (pplayer->team == team->team_no) { + rank[count].value = teamscore; + size[count].value = teamsize; + } + count++; + } players_iterate_end; + } teams_iterate_end; qsort(size, count, sizeof(struct player_score_entry), secompare1); buffer[0]=0; Index: server/gamelog.h =================================================================== RCS file: /home/freeciv/CVS/freeciv/server/gamelog.h,v retrieving revision 1.5 diff -u -r1.5 gamelog.h --- server/gamelog.h 2001/01/15 00:30:24 1.5 +++ server/gamelog.h 2002/09/27 14:48:35 @@ -30,6 +30,7 @@ #define GAMELOG_REVOLT 11 #define GAMELOG_GENO 12 #define GAMELOG_TREATY 13 +#define GAMELOG_TEAM 16 #define GAMELOG_RANK 17 #define GAMELOG_LAST 18 #define GAMELOG_EOT 19 Index: server/maphand.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/server/maphand.c,v retrieving revision 1.107 diff -u -r1.107 maphand.c --- server/maphand.c 2002/09/23 22:47:11 1.107 +++ server/maphand.c 2002/09/27 14:48:35 @@ -20,6 +20,7 @@ #include "fcintl.h" #include "game.h" #include "log.h" +#include "nation.h" #include "map.h" #include "mem.h" #include "packets.h" @@ -1226,6 +1227,12 @@ pplayer2 = get_player(packet->value); if (pplayer == pplayer2 || !pplayer2->is_alive || !gives_shared_vision(pplayer, pplayer2)) { + return; + } + + /* Do not allow team mates to backstab */ + if (pplayer->team != TEAM_NONE && pplayer2->team != TEAM_NONE + && pplayer->team == pplayer2->team) { return; } Index: server/plrhand.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/server/plrhand.c,v retrieving revision 1.244 diff -u -r1.244 plrhand.c --- server/plrhand.c 2002/08/25 11:36:53 1.244 +++ server/plrhand.c 2002/09/27 14:48:35 @@ -797,7 +797,7 @@ struct player *pplayer2; int reppenalty = 0; bool has_senate; - + if (other_player < 0 || other_player >= game.nplayers) { return; } @@ -809,6 +809,12 @@ /* can't break a pact with yourself */ if (pplayer == pplayer2) return; + + /* can't break a pact with a team member */ + if (pplayer->team != TEAM_NONE && pplayer2->team != TEAM_NONE + && pplayer->team == pplayer2->team) { + return; + } /* check what the new status will be, and what will happen to our reputation */ Index: server/savegame.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/server/savegame.c,v retrieving revision 1.92 diff -u -r1.92 savegame.c --- server/savegame.c 2002/09/27 12:32:47 1.92 +++ server/savegame.c 2002/09/27 14:48:36 @@ -577,6 +577,15 @@ sz_strlcpy(plr->username, secfile_lookup_str_default(file, "", "player%d.username", plrno)); plr->nation=secfile_lookup_int(file, "player%d.race", plrno); + /* not all players have teams */ + if (section_file_lookup(file, "player%d.team", plrno)) { + char tmp[MAX_LEN_NAME]; + sz_strlcpy(tmp, secfile_lookup_str(file, "player%d.team", plrno)); + teams_add_player(plr, tmp); + plr->team = teams_find_by_name(tmp); + } else { + plr->team = TEAM_NONE; + } if (is_barbarian(plr)) { plr->nation=game.nation_count-1; } @@ -1223,6 +1232,9 @@ secfile_insert_str(file, plr->name, "player%d.name", plrno); secfile_insert_str(file, plr->username, "player%d.username", plrno); secfile_insert_int(file, plr->nation, "player%d.race", plrno); + if (teams_get_by_plr(plr) != NULL) { + secfile_insert_str(file, teams_get_name(plr->team), "player%d.team", plrno); + } secfile_insert_int(file, plr->government, "player%d.government", plrno); secfile_insert_int(file, plr->embassy, "player%d.embassy", plrno); Index: server/srv_main.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/server/srv_main.c,v retrieving revision 1.96 diff -u -r1.96 srv_main.c --- server/srv_main.c 2002/09/11 18:49:13 1.96 +++ server/srv_main.c 2002/09/27 14:48:36 @@ -176,6 +176,9 @@ srvarg.extra_metaserver_info[0] = '\0'; + /* initialize teams */ + teams_init(); + /* mark as initialized */ has_been_srv_init = TRUE; @@ -184,32 +187,80 @@ } /************************************************************************** -... + Returns TRUE if any one game end condition is fulfilled, FALSE otherwise **************************************************************************/ static bool is_game_over(void) { - int barbs = 0; - int alive = 0; - - if (game.year > game.end_year) + int barbs = 0, alive = 0; + bool all_allied; + struct player *victor; + + /* quit if we are past the year limit */ + if (game.year > game.end_year) { + notify_conn(&game.est_connections, + "Game ended in a draw as end year exceeded"); + gamelog(GAMELOG_NORMAL, _("Game ended in a draw as end year exceeded")); return TRUE; + } + /* count barbarians */ players_iterate(pplayer) { if (is_barbarian(pplayer)) { barbs++; } } players_iterate_end; - if (game.nplayers == (barbs + 1)) + /* the game does not quit if we are playing solo */ + if (game.nplayers == (barbs + 1)) { return FALSE; + } + /* count the living */ players_iterate(pplayer) { if (pplayer->is_alive && !is_barbarian(pplayer)) { alive++; + victor = pplayer; } } players_iterate_end; + + /* quit if we have team victory */ + teams_iterate(team) { + if (teams_count_members(team) == alive) { + notify_conn(&game.est_connections, + "Team victory to %s", team->name); + gamelog(GAMELOG_NORMAL, _("Team victory to %s"), team->name); + gamelog(GAMELOG_TEAM, "TEAMVICTORY %s", team->name); + return TRUE; + } + } teams_iterate_end; + + /* quit if only one player is left alive */ + if (alive <= 1) { + notify_conn(&game.est_connections, + "Game ended in victory for %s", victor->name); + gamelog(GAMELOG_NORMAL, _("Game ended in victory for %s"), + victor->name); + gamelog(GAMELOG_TEAM, "SINGLEWINNER %s", victor->name); + return TRUE; + } + + /* quit if all players are allied to each other */ + all_allied = TRUE; + players_iterate(pplayer) { + players_iterate(aplayer) { + if (!pplayers_allied(pplayer, aplayer)) { + all_allied = FALSE; + } + } players_iterate_end; + } players_iterate_end; + if (all_allied) { + notify_conn(&game.est_connections, _("Game ended in allied victory")); + gamelog(GAMELOG_NORMAL, _("Game ended in allied victory")); + gamelog(GAMELOG_TEAM, "ALLIEDVICTORY"); + return TRUE; + } - return (alive <= 1); + return FALSE; } /************************************************************************** @@ -1978,6 +2029,20 @@ if(map.num_start_positions==0) { create_start_positions(); } + } + + /* Set up alliances based on team selections */ + if ((game.is_new_game) && (game.team_count>0)) { + players_iterate(pplayer) { + players_iterate(pdest) { + if ((pplayer->team == pdest->team) + && (pplayer->player_no != pdest->player_no)) { + pplayer->diplstates[pdest->player_no].type=DS_ALLIANCE; + give_shared_vision(pplayer, pdest); + pplayer->embassy |= (1 << pdest->player_no); + } + } players_iterate_end + } players_iterate_end } initialize_move_costs(); /* this may be the wrong place to do this */ Index: server/stdinhand.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/server/stdinhand.c,v retrieving revision 1.249 diff -u -r1.249 stdinhand.c --- server/stdinhand.c 2002/09/27 12:32:47 1.249 +++ server/stdinhand.c 2002/09/27 14:48:37 @@ -944,6 +944,7 @@ /* mostly non-harmful: */ CMD_SET, + CMD_TEAM, CMD_FIX, CMD_UNFIX, CMD_RULESETDIR, @@ -1070,6 +1071,12 @@ N_("set "), N_("Set server option."), NULL }, + {"team", ALLOW_CTRL, + N_("team [team]"), + N_("Change, add or remove a player's team affiliation."), + N_("Sets a player as member of a team. If no team specified, the " + "player is set teamless. Use \"\" if names contain whitespace.") + }, {"fix", ALLOW_CTRL, N_("fix "), N_("Make server option unchangeable during game."), NULL @@ -1723,7 +1730,7 @@ { struct player *pplayer; PlayerNameStatus PNameStatus; - + if (server_state!=PRE_GAME_STATE) { cmd_reply(CMD_CREATE, caller, C_SYNTAX, @@ -2647,6 +2654,53 @@ /****************************************************************** ... ******************************************************************/ +static void team_command(struct connection *caller, char *str) +{ + struct player *pplayer; + enum m_pre_result match_result; + char buf[MAX_LEN_CONSOLE_LINE]; + char *arg[2]; + int ntokens = 0; + + if (server_state!=PRE_GAME_STATE) { + cmd_reply(CMD_TEAM, caller, C_SYNTAX, + _("Cannot change teams once game has begun.")); + return; + } + + if (str != NULL || strlen(str) > 0) { + sz_strlcpy(buf, str); + ntokens = get_tokens(buf, arg, 2, TOKEN_DELIMITERS); + } + if (ntokens > 2 || ntokens < 1) { + cmd_reply(CMD_TEAM, caller, C_SYNTAX, + _("Undefined argument. Usage: team [team].")); + return; + } + + pplayer = find_player_by_name_prefix(arg[0], &match_result); + if (pplayer == NULL) { + cmd_reply_no_such_player(CMD_TEAM, caller, arg[0], match_result); + return; + } + + teams_remove_player(pplayer); + + if (ntokens == 1) { + /* Remove from team */ + cmd_reply(CMD_TEAM, caller, C_OK, _("Player %s is made teamless"), + pplayer->name); + return; + } + + teams_add_player(pplayer, arg[1]); + cmd_reply(CMD_TEAM, caller, C_OK, _("Player %s set to team %s"), + pplayer->name, arg[1]); +} + +/****************************************************************** + ... +******************************************************************/ static void set_command(struct connection *caller, char *str) { char command[MAX_LEN_CONSOLE_LINE], arg[MAX_LEN_CONSOLE_LINE], *cptr_s, *cptr_d; @@ -3141,13 +3195,16 @@ break; case CMD_SET: set_command(caller,arg); + break; + case CMD_TEAM: + team_command(caller, arg); break; - case CMD_FIX: - fix_command(caller,arg, CMD_FIX); - break; - case CMD_UNFIX: - fix_command(caller, arg, CMD_UNFIX); - break; + case CMD_FIX: + fix_command(caller,arg, CMD_FIX); + break; + case CMD_UNFIX: + fix_command(caller, arg, CMD_UNFIX); + break; case CMD_RULESETDIR: set_rulesetdir(caller, arg); break; @@ -3582,6 +3639,10 @@ if (!game.is_new_game) { cat_snprintf(buf2, sizeof(buf2), _(", nation %s"), get_nation_name_plural(pplayer->nation)); + } + if (pplayer->team != TEAM_NONE) { + cat_snprintf(buf2, sizeof(buf2), (", team %s"), + teams_get_name(pplayer->team)); } my_snprintf(buf, sizeof(buf), "%s (%s)", pplayer->name, buf2);