#include #include #include "defs.h" #include "struct.h" #include "data.h" #include "gencmds.h" #include "proto.h" #include "util.h" #ifdef TRIPLE_PLANET_MAYHEM /* ** 16-Jul-1994 James Cameron ** ** Balances teams according to player statistics. ** Intended for use with Triple Planet Mayhem */ /* ** Tell all that player will be moved */ static void moveallmsg(int p_no, int ours, int theirs, int p_value) { struct player *k = &players[p_no]; pmessage(0, MALL, addr_mess(p_no, MALL), "Balance: %16s (slot %c, rating %.2f) is to join the %s", k->p_name, shipnos[p_no], (float) ( p_value / 100.0 ), team_name(ours)); } /* ** Move a player to the specified team, if they are not yet there. ** Make them peaceful with the new team, and hostile/at war with the ** other team. */ static void move(int p_no, int ours, int theirs) { struct player *k = &players[p_no]; if ( k->p_team != ours ) { pmessage(k->p_no, MINDIV, addr_mess(k->p_no,MINDIV), "%s: please SWAP SIDES to the --> %s <--", k->p_name, team_name(ours)); } else { pmessage(k->p_no, MINDIV, addr_mess(k->p_no,MINDIV), "%s: please remain with the --> %s <--", k->p_name, team_name(ours)); } printf("Balance: %16s (%s) is to join the %s\n", k->p_name, k->p_mapchars, team_name(ours)); change_team(p_no, ours, theirs); } /* ** Return two team masks corresponding to the teams of the first two ** teams found in the player list. */ static void sides (int *one, int *two) { struct player *k; int i; int unseen; unseen = (FED | ROM | ORI | KLI); *one = 0; *two = 0; k = &players[0]; for(i=0;ip_status != PFREE) && (!(k->p_flags & PFROBOT))) { if ( ( unseen & k->p_team ) != 0 ) { if ( *one == 0 ) { *one = k->p_team; unseen &= ~k->p_team; k++; continue; } *two = k->p_team; return; } } k++; } } /* ** Calculate a player value */ static int value (struct player *k) { return (int) ( (float) ( #ifdef LTD_STATS ltd_bombing_rating(k) * BALANCE_BOMBING + ltd_planet_rating(k) * BALANCE_PLANET + ltd_defense_rating(k) * BALANCE_DEFENSE + ltd_offense_rating(k) * BALANCE_OFFENSE #else bombingRating(k) * BALANCE_BOMBING + planetRating(k) * BALANCE_PLANET + defenseRating(k) * BALANCE_DEFENSE + offenseRating(k) * BALANCE_OFFENSE #endif /* LTD_STATS */ ) ); } /* ** Balance the teams ** ** Uses an exhaustive algorithm (I'm exhausted!) to find the best combination ** of the current players that balances the teams in terms of statistics. ** The algorithm will support only the number of players that fits into the ** number of bits in an int. ** ** If there are multiple "best" combinations, then the combination ** involving the least number of team swaps will be chosen. */ void do_balance(void) { int i, j; /* miscellaneous counters */ int records; /* number of players in game */ int one; /* team number one mask */ int two; /* team number two mask */ struct player *k; /* pointer to current player */ struct item { int p_no; /* player number */ int p_value; /* calculated player value */ int p_team; /* team player on previously */ } list[MAXPLAYER]; /* working array */ struct { int combination; /* combination number */ int value; /* team balance difference */ int one; /* team one total value */ int two; /* team two total value */ int swaps; /* number of swaps involved */ } best; /* best team combination */ /* which teams are playing? give up if only one found */ sides ( &one, &two ); if ( two == 0 ) { /* addr_mess shouldn't be called with 0 as first arg * for MALL, but we don't have a player numer here. * Let addr_mess catch it. -da */ pmessage ( 0, MALL, addr_mess(0 ,MALL), "Can't balance only one team!" ); pmessage ( 0, MALL, addr_mess(0 ,MALL), "Please could somebody move to another team, then all vote again?" ); return; } /* initialise best to worst case */ best.combination = -1; best.value = 1<<30; best.one = 0; best.two = 0; best.swaps = 1<<30; /* reset working array */ for(i=0;ip_status != PFREE) && (!(k->p_flags & PFROBOT))) { list[records].p_no = k->p_no; list[records].p_value = value ( k ); list[records].p_team = k->p_team; records++; } k++; } /* randomise the working array; may cause different team mixes */ for(i=0;i 1 ) continue; /* reset team total for attempt */ value_a = 0; value_b = 0; /* calculate team total stats */ for(j=0;j