diff --git a/MiraAPI/Patches/Roles/LogicRoleSelectionNormalPatch.cs b/MiraAPI/Patches/Roles/LogicRoleSelectionNormalPatch.cs new file mode 100644 index 0000000..b0540bb --- /dev/null +++ b/MiraAPI/Patches/Roles/LogicRoleSelectionNormalPatch.cs @@ -0,0 +1,93 @@ +using AmongUs.GameOptions; +using HarmonyLib; +using Il2CppSystem.Collections.Generic; +using System.Linq; +using MiraAPI.Roles; + +namespace MiraAPI.Patches.Roles; + +[HarmonyPatch(typeof(LogicRoleSelectionNormal))] +public static class LogicRoleSelectionNormalPatch +{ + [HarmonyPrefix] + [HarmonyPatch(nameof(LogicRoleSelectionNormal.AssignRolesForTeam))] + public static bool AssignRolesForTeam( + LogicRoleSelectionNormal __instance, + List players, + IGameOptions opts, + RoleTeamTypes team, + int teamMax, + Il2CppSystem.Nullable defaultRole) + { + int num = 0; + var source = RoleManager.Instance.AllRoles.ToArray() + .Where(role => role.TeamType == team && !RoleManager.IsGhostRole(role.Role) && + CustomRoleUtils.CanSpawnOnCurrentMode(role)); + List list = new List(); + IRoleOptionsCollection roleOptions = opts.RoleOptions; + + var assignmentData = source.Where(x => !x.IsDead).Select(role => + new RoleManager.RoleAssignmentData( + role, + roleOptions.GetNumPerGame(role.Role), + roleOptions.GetChancePerGame(role.Role))).ToList(); + var source2 = CustomRoleUtils.GetPossibleRoles(assignmentData, x => x.Chance == 100); + var guaranteedRoles = source.Where(x => source2.Contains(((ushort)x.Role, 100))); + foreach (RoleManager.RoleAssignmentData roleAssignmentData in guaranteedRoles.Select((x) => + new RoleManager.RoleAssignmentData(x, roleOptions.GetNumPerGame(x.Role), 100))) + { + while (true) + { + RoleManager.RoleAssignmentData roleAssignmentData2 = roleAssignmentData; + int count = roleAssignmentData2.Count; + roleAssignmentData2.Count = count - 1; + if (count <= 0) + { + break; + } + + list.Add(roleAssignmentData.Role.Role); + } + } + + __instance.AssignRolesFromList(players, teamMax, list, ref num); + + var list2 = source.Where(x => !x.IsDead).Select(role => + new RoleManager.RoleAssignmentData( + role, + roleOptions.GetNumPerGame(role.Role), + roleOptions.GetChancePerGame(role.Role))).ToList(); + + list.Clear(); + foreach (RoleManager.RoleAssignmentData roleAssignmentData3 in list2) + { + for (int i = 0; i < roleAssignmentData3.Count; i++) + { + if (HashRandom.Next(101) < roleAssignmentData3.Chance) + { + list.Add(roleAssignmentData3.Role.Role); + } + } + } + + __instance.AssignRolesFromList(players, teamMax, list, ref num); + var defaultRole2 = team is RoleTeamTypes.Crewmate ? RoleTypes.Crewmate : RoleTypes.Impostor; + try + { + defaultRole2 = defaultRole.Value; + } + catch + { + // Ignored + } + + while (list.Count < players.Count && list.Count + num < teamMax) + { + list.Add(defaultRole2); + } + + __instance.AssignRolesFromList(players, teamMax, list, ref num); + + return false; + } +} diff --git a/MiraAPI/Patches/Roles/SelectRolesPatch.cs b/MiraAPI/Patches/Roles/SelectRolesPatch.cs deleted file mode 100644 index dc51f03..0000000 --- a/MiraAPI/Patches/Roles/SelectRolesPatch.cs +++ /dev/null @@ -1,111 +0,0 @@ -using System.Collections.Generic; -using AmongUs.GameOptions; -using HarmonyLib; -using System.Linq; -using InnerNet; -using MiraAPI.Roles; - -namespace MiraAPI.Patches.Roles; - -[HarmonyPatch(typeof(RoleManager))] -public static class SelectRolesPatch -{ - public static bool ApiHandlesRoleSelect = true; - [HarmonyPrefix] - [HarmonyPatch(nameof(RoleManager.SelectRoles))] - public static bool SelectRoles() - { - if (!ApiHandlesRoleSelect) - { - return true; - } - Il2CppSystem.Collections.Generic.List list = new(); - AmongUsClient.Instance.GetAllClients(list); - List list2 = list.ToArray() - .Where(c => c.Character != null && c.Character.Data != null && !c.Character.Data.Disconnected && - !c.Character.Data.IsDead).OrderBy(c => c.Id).Select(c => c.Character.Data) - .ToList(); - - foreach (NetworkedPlayerInfo networkedPlayerInfo in GameData.Instance.AllPlayers) - { - if (networkedPlayerInfo.Object != null && networkedPlayerInfo.Object.isDummy) - { - list2.Add(networkedPlayerInfo); - } - } - IGameOptions currentGameOptions = GameOptionsManager.Instance.CurrentGameOptions; - int adjustedNumImpostors = GameOptionsManager.Instance.CurrentGameOptions.GetAdjustedNumImpostors(list2.Count); - AssignRolesForTeam(list2, currentGameOptions, RoleTeamTypes.Impostor, adjustedNumImpostors, RoleTypes.Impostor); - AssignRolesForTeam(list2, currentGameOptions, RoleTeamTypes.Crewmate, int.MaxValue, RoleTypes.Crewmate); - return false; - } - - public static void AssignRolesForTeam( - List players, - IGameOptions opts, - RoleTeamTypes team, - int teamMax, - RoleTypes defaultRole) - { - int num = 0; - var source = RoleManager.Instance.AllRoles.ToArray() - .Where(role => role.TeamType == team && !RoleManager.IsGhostRole(role.Role) && - CustomRoleUtils.CanSpawnOnCurrentMode(role)); - List list = new List(); - IRoleOptionsCollection roleOptions = opts.RoleOptions; - - // Assign guaranteed roles first, just like the vanilla selector. This is - // important because the list of players is shared by both team passes. - foreach (var role in source.Where(x => roleOptions.GetChancePerGame(x.Role) == 100) - .Select(role => role.Role)) - { - for (var i = 0; i < roleOptions.GetNumPerGame(role); i++) - { - list.Add(role); - } - } - - AssignRolesFromList(players, teamMax, list, ref num); - - // A 100% role was already assigned above. Including it here can consume - // another player and, more importantly, leaves the fallback count wrong. - list.Clear(); - foreach (var role in source.Where(x => - roleOptions.GetChancePerGame(x.Role) > 0 && - roleOptions.GetChancePerGame(x.Role) < 100) - .Select(role => role.Role)) - { - for (var i = 0; i < roleOptions.GetNumPerGame(role); i++) - { - if (HashRandom.Next(101) < roleOptions.GetChancePerGame(role)) - { - list.Add(role); - } - } - } - - AssignRolesFromList(players, teamMax, list, ref num); - - // Assign the remaining players up to the requested team limit. The - // vanilla list has been consumed by AssignRolesFromList at this point, - // so checking list.Count can leave players unassigned. - while (players.Count > 0 && num < teamMax) - { - list.Add(defaultRole); - AssignRolesFromList(players, teamMax, list, ref num); - } - } - private static void AssignRolesFromList(List players, int teamMax, List roleList, ref int rolesAssigned) - { - while (roleList.Count > 0 && players.Count > 0 && rolesAssigned < teamMax) - { - int index = HashRandom.FastNext(roleList.Count); - RoleTypes roleType = roleList[index]; - roleList.RemoveAt(index); - int index2 = HashRandom.FastNext(players.Count); - players[index2].Object.RpcSetRole(roleType, false); - players.RemoveAt(index2); - rolesAssigned++; - } - } -}