PRoConEvents.MULTIbalancer.ToTeamByDispersal C# (CSharp) Method

ToTeamByDispersal() private method

private ToTeamByDispersal ( String name, int fromTeam, List teamListsById ) : int
name String
fromTeam int
teamListsById List
return int
        private int ToTeamByDispersal(String name, int fromTeam, List<PlayerModel>[] teamListsById)
        {
            int targetTeam = 0;
            bool allEqual = false;
            int grandTotal = 0;

            if (teamListsById == null) return 0;

            /*
            Select a team that would disperse this player evenly with similar players,
            regardless of balance or stacking. Dispersal list takes priority over
            other dispersal types.
            */

            PlayerModel player = GetPlayer(name);
            if (player == null) return 0;

            PerModeSettings perMode = GetPerModeSettings();
            if (perMode.isDefault) return 0;

            bool isSQDM = IsSQDM();
            bool mostMoves = true;

            bool isDispersalByRank = IsRankDispersal(player);
            bool isDispersalByList = IsInDispersalList(player, false);
            /* DCE */
            bool isDispersalByClanPop = false;
            if (!isDispersalByList) isDispersalByClanPop = IsClanDispersal(player, false);

            /* By Dispersal List */

            if (isDispersalByList) {
            int[] usualSuspects = new int[5]{0,0,0,0,0};

            if (player.DispersalGroup >= 1 && player.DispersalGroup <= 4) {
            // Disperse by group
            if (!isSQDM && player.DispersalGroup > 2) {
                if (DebugLevel >= 7) ConsoleDebug("ToTeamByDispersal ignoring Group " + player.DispersalGroup + " for ^b" + player.FullName + "^n, not SQDM");
                // fall thru
            } else {
                if (perMode.EnableStrictDispersal) return fGroupAssignments[player.DispersalGroup];
                // Otherwise, don't allow server to become wildly unbalanced
                targetTeam = fGroupAssignments[player.DispersalGroup];
                int nTarget = GetTeam(targetTeam).Count;
                int nFrom = GetTeam(fromTeam).Count;
                // Always ok if target team is smaller than current team
                if (nTarget < nFrom) return targetTeam;
                // Might be okay if target team is within MaxDiff
                if ((nTarget - nFrom) <= MaxDiff()) return targetTeam;
                // Target team too big, don't move this player
                if (DebugLevel >= 7) ConsoleDebug("ToTeamByDispersal lenient mode, target team " + GetTeamName(targetTeam) + " has too many players " + nTarget + "/" + nFrom + ", skipping dispersal by group of ^b" + player.FullName);
                targetTeam = 0;
                goto clan;
            }
            }
            // Otherwise normal list dispersal
            mostMoves = true;

            for (int teamId = 1; teamId < teamListsById.Length; ++teamId) {
            foreach (PlayerModel p in teamListsById[teamId]) {
                if (p.Name == player.Name) continue; // don't count this player

                if (IsInDispersalList(p, true)) {
                    usualSuspects[teamId] = usualSuspects[teamId] + 1;
                    grandTotal = grandTotal + 1;

                    // Make sure this player hasn't been moved more than any other dispersal player
                    if (GetMovesThisRound(p) >= GetMovesThisRound(player)) {
                        mostMoves = false;
                    }
                }
            }
            }

            if (mostMoves && GetMovesThisRound(player) > 0) {
            ConsoleDebug("^9ToTeamByDispersal List: ^b" + player.Name + "^n moved more than other dispersals (" + GetMovesThisRound(player) + " times), skipping!");
            targetTeam = -1;
            goto clan;
            }

            String an = usualSuspects[1] + "/" + usualSuspects[2];
            if (isSQDM) an = an + "/" + usualSuspects[3] + "/" + usualSuspects[4];
            DebugWrite("^9(DEBUG) ToTeamByDispersal: analysis of ^b" + player.FullName + "^n dispersal by list: " + an, 5);

            // Pick smallest one
            targetTeam = 0;
            allEqual = true;
            int minSuspects = 70;
            for (int i = 1; i < usualSuspects.Length; ++i) {
            if (!isSQDM && i > 2) continue;
            if (allEqual && usualSuspects[i] == minSuspects) {
                allEqual = true;
            } else if (usualSuspects[i] < minSuspects) {
                minSuspects = usualSuspects[i];
                targetTeam = i;
                if (i != 1) allEqual = false;
            } else {
                if (i != 1) allEqual = false;
            }
            }

            if (grandTotal > 1 && !allEqual && targetTeam != 0 && targetTeam != fromTeam) {
            if (perMode.EnableStrictDispersal) return targetTeam;
            // Otherwise, don't allow server to become wildly unbalanced
            int nTarget = GetTeam(targetTeam).Count;
            int nFrom = GetTeam(fromTeam).Count;
            // Always ok if target team is smaller than current team
            if (nTarget < nFrom) return targetTeam;
            // Might be okay if target team is within MaxDiff
            if ((nTarget - nFrom) <= MaxDiff()) return targetTeam;
            // Target team too big, don't move this player
            if (DebugLevel >= 7) ConsoleDebug("ToTeamByDispersal lenient mode, target team " + GetTeamName(targetTeam) + " has too many players " + nTarget + "/" + nFrom + ", skipping dispersal by list of ^b" + player.FullName);
            targetTeam = 0;
            goto clan;
            }

            if (allEqual) DebugWrite("^9(DEBUG) ToTeamByDispersal: all equal list, skipping", 5);
            // otherwise fall through and try clan
            }

            clan:
            if (isDispersalByClanPop) {
            String tag = ExtractTag(player);
            int[] pops = new int[5]{0,0,0,0,0};
            grandTotal = 0;
            mostMoves = false;

            int n = GetClanPopulation(player, 1);
            pops[1] = n;
            grandTotal = grandTotal + n;
            n = GetClanPopulation(player, 2);
            pops[2] = n;
            grandTotal = grandTotal + n;
            if (isSQDM) {
            n = GetClanPopulation(player, 3);
            pops[3] = n;
            grandTotal = grandTotal + n;
            n = GetClanPopulation(player, 4);
            pops[4] = n;
            grandTotal = grandTotal + n;
            }

            if  (grandTotal >= perMode.DisperseEvenlyByClanPlayers) {
            if (GetMovesThisRound(player) > 0 && player.Team >= 1 && player.Team < teamListsById.Length) {
                mostMoves = true;
                foreach (PlayerModel p in teamListsById[player.Team]) {
                    if (p.Name == player.Name) continue; // don't count this player
                    // Make sure this player hasn't been moved more than any other dispersal player
                    if (GetMovesThisRound(p) >= GetMovesThisRound(player)) {
                        mostMoves = false;
                        break;
                    }
                }
            }
            if (mostMoves) {
                ConsoleDebug("^9ToTeamByDispersal Clan: ^b" + player.FullName + "^n moved more than other dispersals (" + GetMovesThisRound(player) + " times), skipping!");
                targetTeam = -1;
                goto rank;
            }

            String a = pops[1] + "/" + pops[2];
            if (isSQDM) a = a + "/" + pops[3] + "/" + pops[4];
            DebugWrite("^9(DEBUG) ToTeamByDispersal: analysis of ^b" + player.FullName + "^n dispersal of clan population >= " + perMode.DisperseEvenlyByClanPlayers + ": " + grandTotal  + " = " + a, 5);

            // Pick largest and smallest
            targetTeam = 0;
            int bigTeam = 0;
            allEqual = true;
            int minPop = 40;
            int maxPop = 0;
            for (int i = 1; i < pops.Length; ++i) {
                if (!isSQDM && i > 2) continue;
                if (allEqual && pops[i] == minPop) {
                    allEqual = true;
                } else if (pops[i] < minPop) {
                    minPop = pops[i];
                    targetTeam = i;
                    if (i != 1) allEqual = false;
                } else {
                    if (i != 1) allEqual = false;
                }
                if (pops[i] > maxPop) {
                    maxPop = pops[i];
                    bigTeam = i;
                }
            }

            if (allEqual) {
                DebugWrite("^9(DEBUG) ToTeamByDispersal: all equal by clan population, skipping", 5);
                targetTeam = 0; // don't disperse
                goto rank;
            } else if (Math.Abs(maxPop - minPop) < 2 || targetTeam == bigTeam) {
                DebugWrite("^9(DEBUG) ToTeamByDispersal: [" + tag + "] clan populations " + maxPop + "/" + minPop + " balanced or targetTeam same as bigTeam", 5);
                targetTeam = 0;
                goto rank;
            } else {
                return targetTeam;
            }
            }
            // fall through
            }

            /* By Rank? */
            rank:
            if (isDispersalByRank) {
            int[] rankers = new int[5]{0,0,0,0,0};
            grandTotal = 0;
            mostMoves = true;

            for (int i = 1; i < teamListsById.Length; ++i) {
            foreach (PlayerModel p in teamListsById[i]) {
                if (p.Name == player.Name) continue; // don't count this player
                if (p.Rank >= perMode.DisperseEvenlyByRank) {
                    rankers[i] = rankers[i] + 1;
                    grandTotal = grandTotal + 1;

                    // Make sure this player hasn't been moved more than any other dispersal player
                    if (GetMovesThisRound(p) >= GetMovesThisRound(player)) {
                        mostMoves = false;
                    }
                }
            }
            }

            if (mostMoves && GetMovesThisRound(player) > 0) {
            ConsoleDebug("^9ToTeamByDispersal Rank: ^b" + player.Name + "^n moved more than other dispersals (" + GetMovesThisRound(player) + " times), skipping!");
            return -1;
            }

            String a = rankers[1] + "/" + rankers[2];
            if (isSQDM) a = a + "/" + rankers[3] + "/" + rankers[4];
            DebugWrite("^9(DEBUG) ToTeamByDispersal: analysis of ^b" + name + "^n dispersal of rank >= " + perMode.DisperseEvenlyByRank + ": " + a, 5);

            // Pick smallest one
            targetTeam = 0;
            allEqual = true;
            int minRanks = 70;
            for (int i = 1; i < rankers.Length; ++i) {
            if (!isSQDM && i > 2) continue;
            if (allEqual && rankers[i] == minRanks) {
                allEqual = true;
            } else if (rankers[i] < minRanks) {
                minRanks = rankers[i];
                targetTeam = i;
                if (i != 1) allEqual = false;
            } else {
                if (i != 1) allEqual = false;
            }
            }

            if (allEqual || grandTotal < 2) {
            DebugWrite("^9(DEBUG) ToTeamByDispersal: all equal by rank, skipping", 5);
            return 0; // don't disperse
            }
            // fall through
            }

            return targetTeam; // ok if 0 or same as fromTeam, caller checks
        }
MULTIbalancer