mirror of
https://github.com/Gurge44/EndlessHostRoles.git
synced 2026-10-20 01:46:25 +00:00
Add Shifter, Fix bugs
This commit is contained in:
1 parent
f1b05d35b0
commit
20de8bd597
19 files changed
+212
-60
No files matched your search
@@ -280,6 +280,7 @@ public enum CustomRoles
|
||||
Samurai,
|
||||
SchrodingersCat,
|
||||
NSerialKiller, // Serial Killer
|
||||
Shifter,
|
||||
Sidekick,
|
||||
Simon,
|
||||
SoulHunter,
|
||||
|
||||
+28
-11
@@ -122,7 +122,7 @@ namespace EHR
|
||||
};
|
||||
memberNum[Team.Crewmate] = allPlayers.Count - memberNum.Values.Sum();
|
||||
|
||||
Logger.Warn($"Number of impostors: {memberNum[Team.Impostor]}", "debug");
|
||||
Logger.Warn($"Number of impostors: {memberNum[Team.Impostor]}", "HnsRoleAssigner");
|
||||
|
||||
foreach (var item in Main.SetRoles)
|
||||
{
|
||||
@@ -136,7 +136,7 @@ namespace EHR
|
||||
role.Value[item.Value]--;
|
||||
memberNum[role.Key]--;
|
||||
|
||||
Logger.Warn($"Pre-Set Role Assigned: {pc.GetRealName()} => {item.Value}", "CustomRoleSelector");
|
||||
Logger.Warn($"Pre-Set Role Assigned: {pc.GetRealName()} => {item.Value}", "HnsRoleAssigner");
|
||||
}
|
||||
|
||||
var playerTeams = Enum.GetValues<Team>()[1..]
|
||||
@@ -186,14 +186,14 @@ namespace EHR
|
||||
|
||||
foreach (PlayerControl pc in allPlayers.Except(result.Keys).ToArray())
|
||||
{
|
||||
Logger.Warn($"Unassigned, force Hider: {pc.GetRealName()} => {CustomRoles.Hider}", "debug");
|
||||
Logger.Warn($"Unassigned, force Hider: {pc.GetRealName()} => {CustomRoles.Hider}", "HnsRoleAssigner");
|
||||
result[pc] = CustomRoles.Hider;
|
||||
memberNum[Team.Crewmate]--;
|
||||
allPlayers.Remove(pc);
|
||||
}
|
||||
|
||||
if (allPlayers.Count > 0) Logger.Error($"Some players were not assigned a role: {allPlayers.Join(x => x.GetRealName())}", "CustomRoleSelector");
|
||||
Logger.Msg($"Roles: {result.Join(x => $"{x.Key.GetRealName()} => {x.Value}")}", "HideAndSeekRoleSelector");
|
||||
if (allPlayers.Count > 0) Logger.Error($"Some players were not assigned a role: {allPlayers.Join(x => x.GetRealName())}", "HnsRoleAssigner");
|
||||
Logger.Msg($"Roles: {result.Join(x => $"{x.Key.GetRealName()} => {x.Value}")}", "HnsRoleAssigner");
|
||||
|
||||
var roleInterfaces = Assembly.GetExecutingAssembly().GetTypes()
|
||||
.Where(x => typeof(IHideAndSeekRole).IsAssignableFrom(x) && !x.IsInterface)
|
||||
@@ -203,6 +203,14 @@ namespace EHR
|
||||
PlayerRoles = result.ToDictionary(x => x.Key.PlayerId, x => (roleInterfaces[x.Value.ToString()], x.Value));
|
||||
|
||||
result.IntersectBy(Main.PlayerStates.Keys, x => x.Key.PlayerId).Do(x => x.Key.RpcSetCustomRole(x.Value));
|
||||
|
||||
// ==================================================================================================================
|
||||
|
||||
if (result.ContainsValue(CustomRoles.Agent))
|
||||
{
|
||||
var agent = result.GetKeyByValue(CustomRoles.Agent).PlayerId;
|
||||
PlayerRoles.DoIf(x => x.Value.Interface.Team == Team.Impostor, x => TargetArrow.Add(x.Key, agent));
|
||||
}
|
||||
}
|
||||
|
||||
public static void ApplyGameOptions(IGameOptions opt, PlayerControl pc)
|
||||
@@ -248,6 +256,12 @@ namespace EHR
|
||||
|
||||
string dangerMeter = GetDangerMeter(seer);
|
||||
|
||||
if (PlayerRoles[seer.PlayerId].Interface.Team == Team.Impostor && PlayerRoles.Values.Any(x => x.Role == CustomRoles.Agent))
|
||||
{
|
||||
var agent = PlayerRoles.First(x => x.Value.Role == CustomRoles.Agent).Key;
|
||||
dangerMeter += TargetArrow.GetArrows(seer, agent);
|
||||
}
|
||||
|
||||
if (!isHUD && seer.IsModClient()) return string.Empty;
|
||||
if (TimeLeft <= 60)
|
||||
{
|
||||
@@ -304,9 +318,7 @@ namespace EHR
|
||||
// If there are no crew roles left, the game is over and only impostors win
|
||||
if (alivePlayers.All(x => PlayerRoles[x.PlayerId].Interface.Team != Team.Crewmate))
|
||||
{
|
||||
CustomWinnerHolder.ResetAndSetWinner(CustomWinner.Seeker);
|
||||
CustomWinnerHolder.WinnerIds.UnionWith(PlayerRoles.Where(x => x.Value.Interface.Team == Team.Impostor).Select(x => x.Key));
|
||||
AddFoxesToWinners();
|
||||
SetWinners(CustomWinner.Seeker, Team.Impostor);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -314,13 +326,18 @@ namespace EHR
|
||||
if (TimeLeft <= 0)
|
||||
{
|
||||
reason = GameOverReason.HumansByTask;
|
||||
CustomWinnerHolder.ResetAndSetWinner(CustomWinner.Hider);
|
||||
CustomWinnerHolder.WinnerIds.UnionWith(PlayerRoles.Where(x => x.Value.Interface.Team == Team.Crewmate).Select(x => x.Key));
|
||||
AddFoxesToWinners();
|
||||
SetWinners(CustomWinner.Hider, Team.Crewmate);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
static void SetWinners(CustomWinner winner, Team team)
|
||||
{
|
||||
CustomWinnerHolder.ResetAndSetWinner(winner);
|
||||
CustomWinnerHolder.WinnerIds.UnionWith(PlayerRoles.Where(x => x.Value.Interface.Team == team).Select(x => x.Key));
|
||||
AddFoxesToWinners();
|
||||
}
|
||||
}
|
||||
|
||||
public static void AddFoxesToWinners()
|
||||
|
||||
@@ -362,6 +362,7 @@ internal static class CustomRolesHelper
|
||||
CustomRoles.PlagueDoctor => RoleTypes.Impostor,
|
||||
CustomRoles.Postman => RoleTypes.Impostor,
|
||||
CustomRoles.SchrodingersCat => RoleTypes.Impostor,
|
||||
CustomRoles.Shifter => RoleTypes.Impostor,
|
||||
CustomRoles.Impartial => RoleTypes.Impostor,
|
||||
CustomRoles.Predator => RoleTypes.Impostor,
|
||||
CustomRoles.Reckless => RoleTypes.Impostor,
|
||||
@@ -400,6 +401,7 @@ internal static class CustomRolesHelper
|
||||
public static bool IsNonNK(this CustomRoles role, bool check = false) => (!check && role == CustomRoles.Arsonist && CanCheck && Options.IsLoaded && Options.ArsonistCanIgniteAnytime != null && !Options.ArsonistCanIgniteAnytime.GetBool()) || role is
|
||||
CustomRoles.Jester or
|
||||
CustomRoles.Postman or
|
||||
CustomRoles.Shifter or
|
||||
CustomRoles.SchrodingersCat or
|
||||
CustomRoles.Impartial or
|
||||
CustomRoles.Predator or
|
||||
@@ -515,6 +517,7 @@ internal static class CustomRolesHelper
|
||||
|
||||
public static bool IsNC(this CustomRoles role) => role is
|
||||
CustomRoles.Mario or
|
||||
CustomRoles.Shifter or
|
||||
CustomRoles.Terrorist or
|
||||
CustomRoles.Revolutionist or
|
||||
CustomRoles.Impartial or
|
||||
@@ -1021,9 +1024,10 @@ internal static class CustomRolesHelper
|
||||
CustomRoles.Parasite => CountTypes.Impostor,
|
||||
CustomRoles.Crewpostor => CountTypes.Impostor,
|
||||
CustomRoles.Refugee => CountTypes.Impostor,
|
||||
CustomRoles.DarkHide => DarkHide.SnatchesWin.GetBool() ? CountTypes.Crew : CountTypes.DarkHide,
|
||||
CustomRoles.Arsonist => !Options.ArsonistKeepsGameGoing.GetBool() ? CountTypes.Crew : CountTypes.Arsonist,
|
||||
CustomRoles.DarkHide when DarkHide.SnatchesWin.GetBool() => CountTypes.Crew,
|
||||
CustomRoles.Arsonist when !Options.ArsonistKeepsGameGoing.GetBool() => CountTypes.Crew,
|
||||
CustomRoles.SchrodingersCat => SchrodingersCat.WinsWithCrewIfNotAttacked.GetBool() ? CountTypes.Crew : CountTypes.OutOfGame,
|
||||
CustomRoles.Shifter => CountTypes.OutOfGame,
|
||||
|
||||
_ => Enum.TryParse(role.ToString(), true, out CountTypes type)
|
||||
? type
|
||||
|
||||
@@ -76,7 +76,7 @@ namespace EHR.Modules
|
||||
|
||||
foreach ((CustomTeam team, HashSet<byte> players) in CustomTeamPlayerIds)
|
||||
{
|
||||
if (!GetSettingForTeam(team, "Arrows")) continue;
|
||||
if (!IsSettingEnabledForTeam(team, "Arrows")) continue;
|
||||
|
||||
foreach (byte player in players)
|
||||
{
|
||||
@@ -91,7 +91,7 @@ namespace EHR.Modules
|
||||
|
||||
public static string GetSuffix(PlayerControl seer)
|
||||
{
|
||||
if (seer == null || EnabledCustomTeams.Count == 0 || !GetSettingForPlayerTeam(seer.PlayerId, "Arrows")) return string.Empty;
|
||||
if (seer == null || EnabledCustomTeams.Count == 0 || !IsSettingEnabledForPlayerTeam(seer.PlayerId, "Arrows")) return string.Empty;
|
||||
return CustomTeamPlayerIds[GetCustomTeam(seer.PlayerId)].Aggregate(string.Empty, (s, id) => s + Utils.ColorString(Main.PlayerColors.GetValueOrDefault(id, Color.white), TargetArrow.GetArrows(seer, id)));
|
||||
}
|
||||
|
||||
@@ -143,13 +143,13 @@ namespace EHR.Modules
|
||||
return team1 != null && team2 != null && team1.Equals(team2);
|
||||
}
|
||||
|
||||
public static bool GetSettingForPlayerTeam(byte id, string settingName)
|
||||
public static bool IsSettingEnabledForPlayerTeam(byte id, string settingName)
|
||||
{
|
||||
var team = GetCustomTeam(id);
|
||||
return team != null && GetSettingForTeam(team, settingName);
|
||||
return team != null && IsSettingEnabledForTeam(team, settingName);
|
||||
}
|
||||
|
||||
public static bool GetSettingForTeam(CustomTeam team, string settingName)
|
||||
public static bool IsSettingEnabledForTeam(CustomTeam team, string settingName)
|
||||
{
|
||||
var optionsGroup = CustomTeamOptions.First(x => x.Team.Equals(team));
|
||||
var setting = optionsGroup.GetType().GetFields().FirstOrDefault(x => x.Name.Contains(settingName));
|
||||
|
||||
@@ -24,7 +24,7 @@ static class ExtendedPlayerControl
|
||||
{
|
||||
public const MurderResultFlags ResultFlags = MurderResultFlags.Succeeded;
|
||||
|
||||
public static void RpcSetCustomRole(this PlayerControl player, CustomRoles role, bool isRoleForced = false)
|
||||
public static void RpcSetCustomRole(this PlayerControl player, CustomRoles role, bool isRoleForced = false, bool replaceAllAddons = false)
|
||||
{
|
||||
if (role < CustomRoles.NotAssigned || isRoleForced)
|
||||
{
|
||||
@@ -33,7 +33,7 @@ static class ExtendedPlayerControl
|
||||
else
|
||||
{
|
||||
if (!Cleanser.CleansedCanGetAddon.GetBool() && player.Is(CustomRoles.Cleansed)) return;
|
||||
Main.PlayerStates[player.PlayerId].SetSubRole(role);
|
||||
Main.PlayerStates[player.PlayerId].SetSubRole(role, replaceAllAddons);
|
||||
}
|
||||
|
||||
if (AmongUsClient.Instance.AmHost)
|
||||
@@ -41,6 +41,7 @@ static class ExtendedPlayerControl
|
||||
MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.SetCustomRole, SendOption.Reliable);
|
||||
writer.Write(player.PlayerId);
|
||||
writer.WritePacked((int)role);
|
||||
writer.Write(replaceAllAddons);
|
||||
AmongUsClient.Instance.FinishRpcImmediately(writer);
|
||||
}
|
||||
}
|
||||
@@ -869,6 +870,8 @@ static class ExtendedPlayerControl
|
||||
if (Options.CurrentGameMode == CustomGameMode.SoloKombat) return;
|
||||
if (target == null) target = killer;
|
||||
|
||||
CheckAndSpawnAdditionalRefugee(target.Data);
|
||||
|
||||
if (target.GetTeam() is Team.Impostor or Team.Neutral) Stressed.OnNonCrewmateDead();
|
||||
|
||||
if (killer.Is(CustomRoles.Damocles)) Damocles.OnMurder(killer.PlayerId);
|
||||
|
||||
@@ -132,7 +132,11 @@ public class PlayerState(byte playerId)
|
||||
{
|
||||
if (role == CustomRoles.Cleansed)
|
||||
AllReplace = true;
|
||||
if (AllReplace) SubRoles.Clear();
|
||||
if (AllReplace)
|
||||
{
|
||||
SubRoles.Clear();
|
||||
Utils.SendRPC(CustomRPC.RemoveSubRole, PlayerId, 2);
|
||||
}
|
||||
|
||||
if (!SubRoles.Contains(role))
|
||||
SubRoles.Add(role);
|
||||
@@ -229,7 +233,7 @@ public class PlayerState(byte playerId)
|
||||
if (SubRoles.Contains(role))
|
||||
SubRoles.Remove(role);
|
||||
|
||||
Utils.SendRPC(CustomRPC.RemoveSubRole, PlayerId, (int)role);
|
||||
Utils.SendRPC(CustomRPC.RemoveSubRole, PlayerId, 1, (int)role);
|
||||
}
|
||||
|
||||
public void SetDead()
|
||||
|
||||
@@ -35,6 +35,8 @@ namespace EHR.Modules
|
||||
IGhostRole instance = CreateGhostRoleInstance(suitableRole);
|
||||
instance.OnAssign(pc);
|
||||
AssignedGhostRoles[pc.PlayerId] = (suitableRole, instance);
|
||||
|
||||
if (suitableRole == CustomRoles.Haunter) GhostRoles.Remove(suitableRole);
|
||||
}
|
||||
|
||||
public static void SpecificAssignGhostRole(byte id, CustomRoles role, bool set)
|
||||
@@ -57,16 +59,11 @@ namespace EHR.Modules
|
||||
if (pc.IsAlive() || pc.GetCountTypes() is CountTypes.None or CountTypes.OutOfGame || pc.Is(CustomRoles.EvilSpirit)) return false;
|
||||
|
||||
var suitableRole = GetSuitableGhostRole(pc);
|
||||
switch (suitableRole)
|
||||
return suitableRole switch
|
||||
{
|
||||
case CustomRoles.Specter when IsPartnerPickedRole():
|
||||
return false;
|
||||
case CustomRoles.Haunter:
|
||||
GhostRoles.Remove(CustomRoles.Haunter);
|
||||
break;
|
||||
}
|
||||
|
||||
return suitableRole.IsGhostRole() && !AssignedGhostRoles.Any(x => x.Key == pc.PlayerId || x.Value.Role == suitableRole);
|
||||
CustomRoles.Specter when IsPartnerPickedRole() => false,
|
||||
_ => suitableRole.IsGhostRole() && !AssignedGhostRoles.Any(x => x.Key == pc.PlayerId || x.Value.Role == suitableRole)
|
||||
};
|
||||
|
||||
bool IsPartnerPickedRole() => Main.PlayerStates[pc.PlayerId].Role switch
|
||||
{
|
||||
|
||||
@@ -182,7 +182,7 @@ public static class GuessManager
|
||||
return true;
|
||||
}
|
||||
|
||||
if (CustomTeamManager.AreInSameCustomTeam(pc.PlayerId, targetId) && !CustomTeamManager.GetSettingForPlayerTeam(targetId, "GuessEachOther"))
|
||||
if (CustomTeamManager.AreInSameCustomTeam(pc.PlayerId, targetId) && !CustomTeamManager.IsSettingEnabledForPlayerTeam(targetId, "GuessEachOther"))
|
||||
{
|
||||
if (!isUI) Utils.SendMessage(GetString("GuessSameCTAPlayer"), pc.PlayerId);
|
||||
else pc.ShowPopUp(GetString("GuessSameCTAPlayer"));
|
||||
|
||||
@@ -71,7 +71,7 @@ public static class NameColorManager
|
||||
}
|
||||
|
||||
// Custom Teams
|
||||
if (CustomTeamManager.AreInSameCustomTeam(seer.PlayerId, target.PlayerId) && CustomTeamManager.GetSettingForPlayerTeam(seer.PlayerId, "KnowRoles")) color = Main.RoleColors[target.GetCustomRole()];
|
||||
if (CustomTeamManager.AreInSameCustomTeam(seer.PlayerId, target.PlayerId) && CustomTeamManager.IsSettingEnabledForPlayerTeam(seer.PlayerId, "KnowRoles")) color = Main.RoleColors[target.GetCustomRole()];
|
||||
|
||||
// Add-ons
|
||||
if (target.Is(CustomRoles.Glow) && Utils.IsActive(SystemTypes.Electrical)) color = Main.RoleColors[CustomRoles.Glow];
|
||||
|
||||
+14
-5
@@ -51,6 +51,7 @@ public enum CustomRPC
|
||||
ShowPopUp,
|
||||
KillFlash,
|
||||
SyncAbilityUseLimit,
|
||||
RemoveAbilityUseLimit,
|
||||
RemoveSubRole,
|
||||
Arrow,
|
||||
|
||||
@@ -338,15 +339,23 @@ internal class RPCHandlerPatch
|
||||
case CustomRPC.SetCustomRole:
|
||||
byte CustomRoleTargetId = reader.ReadByte();
|
||||
CustomRoles role = (CustomRoles)reader.ReadPackedInt32();
|
||||
RPC.SetCustomRole(CustomRoleTargetId, role);
|
||||
bool replaceAllAddons = reader.ReadBoolean();
|
||||
RPC.SetCustomRole(CustomRoleTargetId, role, replaceAllAddons);
|
||||
break;
|
||||
case CustomRPC.SyncAbilityUseLimit:
|
||||
var pc = Utils.GetPlayerById(reader.ReadByte());
|
||||
pc.SetAbilityUseLimit(reader.ReadSingle(), rpc: false);
|
||||
break;
|
||||
case CustomRPC.RemoveSubRole:
|
||||
Main.PlayerStates[reader.ReadByte()].RemoveSubRole((CustomRoles)reader.ReadPackedInt32());
|
||||
case CustomRPC.RemoveAbilityUseLimit:
|
||||
Main.AbilityUseLimit.Remove(reader.ReadByte());
|
||||
break;
|
||||
case CustomRPC.RemoveSubRole:
|
||||
{
|
||||
byte id = reader.ReadByte();
|
||||
if (reader.ReadPackedInt32() == 2) Main.PlayerStates[id].SubRoles.Clear();
|
||||
else Main.PlayerStates[id].RemoveSubRole((CustomRoles)reader.ReadPackedInt32());
|
||||
break;
|
||||
}
|
||||
case CustomRPC.Arrow:
|
||||
if (reader.ReadBoolean()) TargetArrow.ReceiveRPC(reader);
|
||||
else LocateArrow.ReceiveRPC(reader);
|
||||
@@ -989,7 +998,7 @@ internal static class RPC
|
||||
}
|
||||
}
|
||||
|
||||
public static void SetCustomRole(byte targetId, CustomRoles role)
|
||||
public static void SetCustomRole(byte targetId, CustomRoles role, bool replaceAllAddons = false)
|
||||
{
|
||||
if (role < CustomRoles.NotAssigned)
|
||||
{
|
||||
@@ -997,7 +1006,7 @@ internal static class RPC
|
||||
}
|
||||
else
|
||||
{
|
||||
Main.PlayerStates[targetId].SetSubRole(role);
|
||||
Main.PlayerStates[targetId].SetSubRole(role, replaceAllAddons);
|
||||
}
|
||||
|
||||
HudManager.Instance.SetHudActive(true);
|
||||
|
||||
+23
-4
@@ -600,6 +600,7 @@ public static class Utils
|
||||
case CustomRoles.PlagueDoctor:
|
||||
case CustomRoles.Postman:
|
||||
case CustomRoles.SchrodingersCat:
|
||||
case CustomRoles.Shifter:
|
||||
case CustomRoles.Impartial:
|
||||
case CustomRoles.Predator:
|
||||
case CustomRoles.Reckless:
|
||||
@@ -773,7 +774,7 @@ public static class Utils
|
||||
__instance.Is(CustomRoleTypes.Impostor) && PlayerControl.LocalPlayer.Is(CustomRoles.Crewpostor) && Options.AlliesKnowCrewpostor.GetBool() ||
|
||||
__instance.Is(CustomRoleTypes.Impostor) && PlayerControl.LocalPlayer.Is(CustomRoleTypes.Impostor) && Options.ImpKnowAlliesRole.GetBool() ||
|
||||
__instance.Is(CustomRoleTypes.Impostor) && PlayerControl.LocalPlayer.Is(CustomRoles.Madmate) && Options.MadmateKnowWhosImp.GetBool() ||
|
||||
CustomTeamManager.AreInSameCustomTeam(__instance.PlayerId, PlayerControl.LocalPlayer.PlayerId) && CustomTeamManager.GetSettingForPlayerTeam(__instance.PlayerId, "KnowRoles") ||
|
||||
CustomTeamManager.AreInSameCustomTeam(__instance.PlayerId, PlayerControl.LocalPlayer.PlayerId) && CustomTeamManager.IsSettingEnabledForPlayerTeam(__instance.PlayerId, "KnowRoles") ||
|
||||
Main.PlayerStates.Values.Any(x => x.Role.KnowRole(PlayerControl.LocalPlayer, __instance)) ||
|
||||
PlayerControl.LocalPlayer.IsRevealedPlayer(__instance) ||
|
||||
PlayerControl.LocalPlayer.Is(CustomRoles.God) ||
|
||||
@@ -1635,6 +1636,23 @@ public static class Utils
|
||||
}
|
||||
}
|
||||
|
||||
public static void CheckAndSpawnAdditionalRefugee(GameData.PlayerInfo deadPlayer)
|
||||
{
|
||||
if (deadPlayer != null && Options.SpawnAdditionalRefugeeOnImpsDead.GetBool() && Main.AllAlivePlayerControls.Length >= Options.SpawnAdditionalRefugeeMinAlivePlayers.GetInt() && !CustomRoles.Refugee.RoleExist(countDead: true) && !Main.AllAlivePlayerControls.Any(x => x.PlayerId != deadPlayer.PlayerId && (x.Is(CustomRoleTypes.Impostor) || (x.IsNeutralKiller() && Options.SpawnAdditionalRefugeeWhenNKAlive.GetBool()))))
|
||||
{
|
||||
PlayerControl[] ListToChooseFrom = Options.UsePets.GetBool() ? Main.AllAlivePlayerControls.Where(x => x.PlayerId != deadPlayer.PlayerId && x.Is(CustomRoleTypes.Crewmate)).ToArray() : Main.AllAlivePlayerControls.Where(x => x.PlayerId != deadPlayer.PlayerId && x.Is(CustomRoleTypes.Crewmate) && x.GetCustomRole().GetRoleTypes() == RoleTypes.Impostor).ToArray();
|
||||
|
||||
if (ListToChooseFrom.Length > 0)
|
||||
{
|
||||
var pc = ListToChooseFrom.RandomElement();
|
||||
pc.RpcSetCustomRole(CustomRoles.Refugee);
|
||||
pc.SetKillCooldown();
|
||||
Logger.Warn($"{pc.GetRealName()} is now a Refugee since all Impostors are dead", "Add Refugee");
|
||||
}
|
||||
else Logger.Msg("No Player to change to Refugee.", "Add Refugee");
|
||||
}
|
||||
}
|
||||
|
||||
public static void SendMessage(string text, byte sendTo = byte.MaxValue, string title = "")
|
||||
{
|
||||
if (!AmongUsClient.Instance.AmHost) return;
|
||||
@@ -1982,7 +2000,6 @@ public static class Utils
|
||||
|
||||
if (Pelican.IsEaten(seer.PlayerId)) SelfName = $"{ColorString(GetRoleColor(CustomRoles.Pelican), GetString("EatenByPelican"))}";
|
||||
if (Deathpact.IsInActiveDeathpact(seer)) SelfName = Deathpact.GetDeathpactString(seer);
|
||||
if (NameNotifyManager.GetNameNotify(seer, out var name)) SelfName = name;
|
||||
|
||||
// Devourer
|
||||
if (Devourer.HideNameOfConsumedPlayer.GetBool() && Devourer.playerIdList.Any(x => Main.PlayerStates[x].Role is Devourer { IsEnable: true } dv && dv.PlayerSkinsCosumed.Contains(seer.PlayerId)) && !CamouflageIsForMeeting)
|
||||
@@ -1993,6 +2010,8 @@ public static class Utils
|
||||
|
||||
GameMode2:
|
||||
|
||||
if (NameNotifyManager.GetNameNotify(seer, out var name)) SelfName = name;
|
||||
|
||||
switch (Options.CurrentGameMode)
|
||||
{
|
||||
case CustomGameMode.SoloKombat:
|
||||
@@ -2008,7 +2027,7 @@ public static class Utils
|
||||
break;
|
||||
}
|
||||
|
||||
SelfName += SelfSuffix.ToString() == string.Empty ? string.Empty : $"\r\n {SelfSuffix}";
|
||||
SelfName += SelfSuffix.ToString() == string.Empty ? string.Empty : $"\r\n{SelfSuffix}";
|
||||
if (!isForMeeting) SelfName += "\r\n";
|
||||
|
||||
seer.RpcSetNamePrivate(SelfName, true, force: NoCache);
|
||||
@@ -2128,7 +2147,7 @@ public static class Utils
|
||||
(target.Is(CustomRoles.Mayor) && Mayor.MayorRevealWhenDoneTasks.GetBool() && target.GetTaskState().IsTaskFinished) ||
|
||||
(seer.Is(CustomRoleTypes.Crewmate) && target.Is(CustomRoles.Marshall) && target.GetTaskState().IsTaskFinished) ||
|
||||
(Main.PlayerStates[target.PlayerId].deathReason == PlayerState.DeathReason.Vote && Options.SeeEjectedRolesInMeeting.GetBool()) ||
|
||||
CustomTeamManager.AreInSameCustomTeam(seer.PlayerId, target.PlayerId) && CustomTeamManager.GetSettingForPlayerTeam(seer.PlayerId, "KnowRoles") ||
|
||||
CustomTeamManager.AreInSameCustomTeam(seer.PlayerId, target.PlayerId) && CustomTeamManager.IsSettingEnabledForPlayerTeam(seer.PlayerId, "KnowRoles") ||
|
||||
Main.PlayerStates.Values.Any(x => x.Role.KnowRole(seer, target)) ||
|
||||
Markseeker.PlayerIdList.Any(x => Main.PlayerStates[x].Role is Markseeker { IsEnable: true, TargetRevealed: true } ms && ms.MarkedId == target.PlayerId) ||
|
||||
Options.CurrentGameMode is CustomGameMode.FFA or CustomGameMode.MoveAndStop or CustomGameMode.HotPotato ||
|
||||
|
||||
@@ -235,7 +235,7 @@ class GameEndChecker
|
||||
.Where(x => x.Team != null)
|
||||
.GroupBy(x => x.Team)
|
||||
.ToDictionary(x => x.Key, x => x.Select(y => y.Player.PlayerId))
|
||||
.DoIf(x => !CustomTeamManager.GetSettingForTeam(x.Key, "WinWithOriginalTeam"), x => WinnerIds.ExceptWith(x.Value));
|
||||
.DoIf(x => !CustomTeamManager.IsSettingEnabledForTeam(x.Key, "WinWithOriginalTeam"), x => WinnerIds.ExceptWith(x.Value));
|
||||
}
|
||||
|
||||
if ((WinnerTeam == CustomWinner.Lovers || WinnerIds.Any(x => Main.PlayerStates[x].SubRoles.Contains(CustomRoles.Lovers))) && Main.LoversPlayers.All(x => x.IsAlive()))
|
||||
@@ -267,6 +267,8 @@ class GameEndChecker
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
WinnerIds.RemoveWhere(x => Main.PlayerStates[x].MainRole == CustomRoles.Shifter);
|
||||
}
|
||||
|
||||
Camouflage.BlockCamouflage = true;
|
||||
|
||||
+1
-15
@@ -1,6 +1,5 @@
|
||||
using System.Linq;
|
||||
using AmongUs.Data;
|
||||
using AmongUs.GameOptions;
|
||||
using EHR.Roles.AddOns.Crewmate;
|
||||
using EHR.Roles.AddOns.Impostor;
|
||||
using EHR.Roles.Crewmate;
|
||||
@@ -134,20 +133,7 @@ class ExileControllerWrapUpPatch
|
||||
if (map != null) Main.AllAlivePlayerControls.Do(map.RandomTeleport);
|
||||
}
|
||||
|
||||
if (exiled != null && Options.SpawnAdditionalRefugeeOnImpsDead.GetBool() && Main.AllAlivePlayerControls.Length >= Options.SpawnAdditionalRefugeeMinAlivePlayers.GetInt() && !CustomRoles.Refugee.RoleExist(countDead: true) && !Main.AllAlivePlayerControls.Any(x => x.PlayerId != exiled.PlayerId && (x.Is(CustomRoleTypes.Impostor) || (x.IsNeutralKiller() && Options.SpawnAdditionalRefugeeWhenNKAlive.GetBool()))))
|
||||
{
|
||||
PlayerControl[] ListToChooseFrom = Options.UsePets.GetBool() ? Main.AllAlivePlayerControls.Where(x => x.PlayerId != exiled.PlayerId && x.Is(CustomRoleTypes.Crewmate)).ToArray() : Main.AllAlivePlayerControls.Where(x => x.PlayerId != exiled.PlayerId && x.Is(CustomRoleTypes.Crewmate) && x.GetCustomRole().GetRoleTypes() == RoleTypes.Impostor).ToArray();
|
||||
|
||||
if (ListToChooseFrom.Length > 0)
|
||||
{
|
||||
var index = IRandom.Instance.Next(0, ListToChooseFrom.Length);
|
||||
var pc = ListToChooseFrom[index];
|
||||
pc.RpcSetCustomRole(CustomRoles.Refugee);
|
||||
pc.SetKillCooldown();
|
||||
Logger.Warn($"{pc.GetRealName()} is now a Refugee since all Impostors are dead", "Add Refugee");
|
||||
}
|
||||
else Logger.Msg("No Player to change to Refugee.", "Add Refugee");
|
||||
}
|
||||
Utils.CheckAndSpawnAdditionalRefugee(exiled);
|
||||
|
||||
FallFromLadder.Reset();
|
||||
Utils.CountAlivePlayers(true);
|
||||
|
||||
@@ -58,6 +58,9 @@ public static class HudSpritePatch
|
||||
|
||||
switch (player.GetCustomRole())
|
||||
{
|
||||
case CustomRoles.Shifter:
|
||||
newKillButton = CustomButton.Get("Swap");
|
||||
break;
|
||||
case CustomRoles.Changeling:
|
||||
newAbilityButton = CustomButton.Get("GlitchMimic");
|
||||
break;
|
||||
|
||||
@@ -810,7 +810,7 @@ class MeetingHudStartPatch
|
||||
(pc.Is(CustomRoles.Mayor) && Mayor.MayorRevealWhenDoneTasks.GetBool() && pc.GetTaskState().IsTaskFinished) ||
|
||||
(pc.Is(CustomRoles.Marshall) && PlayerControl.LocalPlayer.Is(CustomRoleTypes.Crewmate) && pc.GetTaskState().IsTaskFinished) ||
|
||||
(Main.PlayerStates[pc.PlayerId].deathReason == PlayerState.DeathReason.Vote && Options.SeeEjectedRolesInMeeting.GetBool()) ||
|
||||
CustomTeamManager.AreInSameCustomTeam(pc.PlayerId, PlayerControl.LocalPlayer.PlayerId) && CustomTeamManager.GetSettingForPlayerTeam(pc.PlayerId, "KnowRoles") ||
|
||||
CustomTeamManager.AreInSameCustomTeam(pc.PlayerId, PlayerControl.LocalPlayer.PlayerId) && CustomTeamManager.IsSettingEnabledForPlayerTeam(pc.PlayerId, "KnowRoles") ||
|
||||
Main.PlayerStates.Values.Any(x => x.Role.KnowRole(PlayerControl.LocalPlayer, pc)) ||
|
||||
Markseeker.PlayerIdList.Any(x => Main.PlayerStates[x].Role is Markseeker { IsEnable: true, TargetRevealed: true } ms && ms.MarkedId == pc.PlayerId) ||
|
||||
PlayerControl.LocalPlayer.IsRevealedPlayer(pc) ||
|
||||
|
||||
@@ -299,7 +299,7 @@ class CheckMurderPatch
|
||||
if (!AmongUsClient.Instance.AmHost) return false;
|
||||
if (target == null) target = killer;
|
||||
|
||||
if (CustomTeamManager.AreInSameCustomTeam(killer.PlayerId, target.PlayerId) && !CustomTeamManager.GetSettingForPlayerTeam(killer.PlayerId, "KillEachOther")) return false;
|
||||
if (CustomTeamManager.AreInSameCustomTeam(killer.PlayerId, target.PlayerId) && !CustomTeamManager.IsSettingEnabledForPlayerTeam(killer.PlayerId, "KillEachOther")) return false;
|
||||
|
||||
if (killer.Is(CustomRoles.Jackal) && target.Is(CustomRoles.Sidekick) && !Options.JackalCanKillSidekick.GetBool()) return false;
|
||||
if (killer.Is(CustomRoles.Sidekick) && target.Is(CustomRoles.Jackal) && !Options.SidekickCanKillJackal.GetBool()) return false;
|
||||
|
||||
@@ -3410,6 +3410,11 @@
|
||||
"BenefactorTargetGotShieldNotify": "You got a temporary shield as the task\\nyou completed was marked by the Benefactor!",
|
||||
"BenefactorTaskMarked": "Task marked",
|
||||
"TaskMarkPerRound": "Maximum Number of Tasks Marked Each Round",
|
||||
"Shifter": "Shifter",
|
||||
"ShifterInfo": "Steal Someone's Role",
|
||||
"ShifterInfoLong": "(Neutrals):\\nAs the Shifter, you must steal someone's role by using your kill button on them. Depending on the settings, you may also steal their progress in their role and ability uses, and their add-ons.\\nIf you have this role when the game ends, you lose!",
|
||||
"Shifter.StealAddons": "Steal Add-ons",
|
||||
"Shifter.StealProgress": "Steal Progress",
|
||||
"Rogue": "Rogue",
|
||||
"RogueInfo": "Complete Objectives, Get Rewards",
|
||||
"RogueInfoLong": "(Neutral):\\nAs the Rogue, you get an objective with a reward each round. You can optionally complete the objective to get the reward.",
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
using System.Linq;
|
||||
using AmongUs.GameOptions;
|
||||
using EHR.Modules;
|
||||
using HarmonyLib;
|
||||
|
||||
namespace EHR.Neutral
|
||||
{
|
||||
public class Shifter : RoleBase
|
||||
{
|
||||
private const int Id = 644400;
|
||||
public static bool On;
|
||||
|
||||
private static OptionItem KillCooldown;
|
||||
private static OptionItem CanVent;
|
||||
private static OptionItem HasImpostorVision;
|
||||
private static OptionItem StealAddons;
|
||||
private static OptionItem StealProgress;
|
||||
|
||||
public override bool IsEnable => On;
|
||||
|
||||
public static void SetupCustomOption()
|
||||
{
|
||||
Options.SetupRoleOptions(Id, TabGroup.NeutralRoles, CustomRoles.Shifter);
|
||||
KillCooldown = FloatOptionItem.Create(Id + 2, "AbilityCooldown", new(0f, 180f, 0.5f), 15f, TabGroup.NeutralRoles)
|
||||
.SetParent(Options.CustomRoleSpawnChances[CustomRoles.Shifter])
|
||||
.SetValueFormat(OptionFormat.Seconds);
|
||||
CanVent = BooleanOptionItem.Create(Id + 3, "CanVent", true, TabGroup.NeutralRoles)
|
||||
.SetParent(Options.CustomRoleSpawnChances[CustomRoles.Shifter]);
|
||||
HasImpostorVision = BooleanOptionItem.Create(Id + 4, "ImpostorVision", true, TabGroup.NeutralRoles)
|
||||
.SetParent(Options.CustomRoleSpawnChances[CustomRoles.Shifter]);
|
||||
StealAddons = BooleanOptionItem.Create(Id + 5, "Shifter.StealAddons", true, TabGroup.NeutralRoles)
|
||||
.SetParent(Options.CustomRoleSpawnChances[CustomRoles.Shifter]);
|
||||
StealProgress = BooleanOptionItem.Create(Id + 6, "Shifter.StealProgress", true, TabGroup.NeutralRoles)
|
||||
.SetParent(Options.CustomRoleSpawnChances[CustomRoles.Shifter]);
|
||||
}
|
||||
|
||||
public override void Init()
|
||||
{
|
||||
On = false;
|
||||
}
|
||||
|
||||
public override void Add(byte playerId)
|
||||
{
|
||||
On = true;
|
||||
|
||||
if (!AmongUsClient.Instance.AmHost) return;
|
||||
if (!Main.ResetCamPlayerList.Contains(playerId))
|
||||
Main.ResetCamPlayerList.Add(playerId);
|
||||
}
|
||||
|
||||
public override void SetKillCooldown(byte id) => Main.AllPlayerKillCooldown[id] = KillCooldown.GetFloat();
|
||||
public override void ApplyGameOptions(IGameOptions opt, byte id) => opt.SetVision(HasImpostorVision.GetBool());
|
||||
public override bool CanUseImpostorVentButton(PlayerControl pc) => CanVent.GetBool();
|
||||
public override bool CanUseKillButton(PlayerControl pc) => true;
|
||||
|
||||
public override bool OnCheckMurder(PlayerControl killer, PlayerControl target)
|
||||
{
|
||||
if (!base.OnCheckMurder(killer, target)) return false;
|
||||
|
||||
killer.RpcSetCustomRole(target.GetCustomRole());
|
||||
|
||||
if (StealProgress.GetBool())
|
||||
{
|
||||
Main.PlayerStates[killer.PlayerId].Role = Main.PlayerStates[target.PlayerId].Role;
|
||||
killer.SetAbilityUseLimit(target.GetAbilityUseLimit());
|
||||
}
|
||||
|
||||
if (StealAddons.GetBool())
|
||||
{
|
||||
var killerSubRoles = killer.GetCustomSubRoles();
|
||||
var targetSubRoles = target.GetCustomSubRoles();
|
||||
if (targetSubRoles.Count > 0)
|
||||
{
|
||||
killer.RpcSetCustomRole(targetSubRoles[0], replaceAllAddons: true);
|
||||
targetSubRoles.Skip(1).Do(x => killer.RpcSetCustomRole(x));
|
||||
}
|
||||
|
||||
if (killerSubRoles.Count > 0)
|
||||
{
|
||||
target.RpcSetCustomRole(killerSubRoles[0], replaceAllAddons: true);
|
||||
killerSubRoles.Skip(1).Do(x => target.RpcSetCustomRole(x));
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------
|
||||
|
||||
target.RpcSetCustomRole(CustomRoles.Shifter);
|
||||
Main.AbilityUseLimit.Remove(target.PlayerId);
|
||||
Utils.SendRPC(CustomRPC.RemoveAbilityUseLimit, target.PlayerId);
|
||||
target.SyncSettings();
|
||||
target.SetKillCooldown();
|
||||
|
||||
// ------------------------------------------------------------------------------------------
|
||||
|
||||
Utils.NotifyRoles(SpecifyTarget: killer);
|
||||
Utils.NotifyRoles(SpecifyTarget: target);
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -445,6 +445,7 @@ public class Main : BasePlugin
|
||||
{ CustomRoles.PlagueDoctor, "#ff6633" },
|
||||
{ CustomRoles.Postman, "#00b893" },
|
||||
{ CustomRoles.SchrodingersCat, "#616161" },
|
||||
{ CustomRoles.Shifter, "#777777" },
|
||||
{ CustomRoles.Impartial, "#4287f5" },
|
||||
{ CustomRoles.Predator, "#c73906" },
|
||||
{ CustomRoles.Reckless, "#6e000d" },
|
||||
|
||||
Reference in new issue
Block a user