Port to v17.0.0 (2025.9.9)

This commit is contained in:
Gurge44 committed 2025-09-10 12:17:58 +02:00
1 parent 088c218325
commit e3836c9d31
43 files changed
+531 -181

No files matched your search

+7 -3
View File
@@ -18,7 +18,7 @@ public enum CustomRoles
// Impostors
Abyssbringer,
Hacker, // Anonymous
Anonymous,
AntiAdminer,
Sans, // Arrogance
Assumer,
@@ -106,6 +106,7 @@ public enum CustomRoles
Twister,
Undertaker,
Vampire,
Venerer,
Ventriloquist,
Vindicator,
Visionary,
@@ -166,7 +167,6 @@ public enum CustomRoles
Dealer,
Demolitionist,
Deputy,
Detective,
Detour,
Dictator,
Doctor,
@@ -181,6 +181,7 @@ public enum CustomRoles
Express,
Farmer,
Farseer,
Forensic,
Divinator, // Fortune Teller
Gardener,
Gaulois,
@@ -189,6 +190,7 @@ public enum CustomRoles
Grenadier,
MeetingManager,
Guardian,
Hacker,
Helper,
Ignitor,
Imitator,
@@ -218,7 +220,6 @@ public enum CustomRoles
Mortician,
NiceEraser,
NiceGuesser,
NiceHacker,
NiceSwapper,
Nightmare,
Negotiator,
@@ -295,6 +296,7 @@ public enum CustomRoles
Enderman,
Evolver,
Executioner,
Explosivist,
Totocalcio, // Follower
Gaslighter,
Glitch,
@@ -366,6 +368,7 @@ public enum CustomRoles
Technician,
Tank,
Terrorist,
Thanos,
Tiger,
Traitor,
Tremor,
@@ -494,6 +497,7 @@ public enum CustomRoles
Energetic,
Entranced,
EvilSpirit,
Facilitator, // Ghost role
Finder,
Flashman,
Fragile,
+8 -1
View File
@@ -9,11 +9,13 @@ public enum CustomRoles
Impostor,
Phantom,
Shapeshifter,
Viper,
// Vanilla Remakes
ImpostorEHR,
PhantomEHR,
ShapeshifterEHR,
ViperEHR,
// Impostors
@@ -124,6 +126,7 @@ public enum CustomRoles
Noisemaker,
Scientist,
Tracker,
Detective,
// Vanilla Remakes
CrewmateEHR,
@@ -132,6 +135,7 @@ public enum CustomRoles
NoisemakerEHR,
ScientistEHR,
TrackerEHR,
DetectiveEHR,
// Crewmates
@@ -167,7 +171,6 @@ public enum CustomRoles
Dealer,
Demolitionist,
Deputy,
Detective,
Detour,
Dictator,
Doctor,
@@ -182,6 +185,7 @@ public enum CustomRoles
Express,
Farmer,
Farseer,
Forensic,
Divinator, // Fortune Teller
Gardener,
Gaulois,
@@ -296,6 +300,7 @@ public enum CustomRoles
Enderman,
Evolver,
Executioner,
Explosivist,
Totocalcio, // Follower
Gaslighter,
Glitch,
@@ -496,6 +501,7 @@ public enum CustomRoles
Energetic,
Entranced,
EvilSpirit,
Examiner,
Facilitator, // Ghost role
Finder,
Flashman,
@@ -556,6 +562,7 @@ public enum CustomRoles
Undead,
Underdog,
Unlucky,
Venom,
Warden, // Ghost role
Watcher,
Workhorse,
+2 -2
View File
@@ -27,11 +27,11 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="AmongUs.GameLibs.Steam" Version="2025.4.15" PrivateAssets="all" Condition="'$(Configuration)' == 'Release' Or '$(Configuration)' == 'Debug'"/>
<PackageReference Include="AmongUs.GameLibs.Steam" Version="2025.9.9" PrivateAssets="all" Condition="'$(Configuration)' == 'Release' Or '$(Configuration)' == 'Debug'" />
<PackageReference Include="AmongUs.GameLibs.Android" Version="2025.6.10" PrivateAssets="all" Condition="'$(Configuration)' == 'Android'"/>
<PackageReference Include="BepInEx.IL2CPP.MSBuild" Version="2.1.0-rc.1"/>
<PackageReference Include="BepInEx.Unity.IL2CPP" Version="6.0.0-be.735" Private="false" ExcludeAssets="runtime;native"/>
<PackageReference Include="JetBrains.Annotations" Version="2025.1.0-eap1"/>
<PackageReference Include="JetBrains.Annotations" Version="2025.2.2" />
<PackageReference Include="Samboy063.Cpp2IL.Core" Version="2022.1.0-pre-release.19"/>
</ItemGroup>
+12 -6
View File
@@ -58,7 +58,7 @@ public class Main : BasePlugin
public const string ModColor = "#00ffff";
public const bool AllowPublicRoom = true;
public const string ForkId = "EHR";
public const string SupportedAUVersion = "2025.4.15";
public const string SupportedAUVersion = "2025.9.9";
public static readonly string DataPath =
#if ANDROID
@@ -175,7 +175,7 @@ public class Main : BasePlugin
private Harmony Harmony { get; } = new(PluginGuid);
public static NormalGameOptionsV09 NormalOptions => GameOptionsManager.Instance != null ? GameOptionsManager.Instance.currentNormalGameOptions : null;
public static NormalGameOptionsV10 NormalOptions => GameOptionsManager.Instance != null ? GameOptionsManager.Instance.currentNormalGameOptions : null;
// Client Options
public static ConfigEntry<string> HideName { get; private set; }
@@ -356,6 +356,7 @@ public class Main : BasePlugin
{ CustomRoles.GuardianAngel, "#77e6d1" },
{ CustomRoles.Tracker, "#34ad50" },
{ CustomRoles.Noisemaker, "#ff4a62" },
{ CustomRoles.Detective, "#625EEE" },
// Vanilla Remakes
{ CustomRoles.CrewmateEHR, "#8cffff" },
{ CustomRoles.EngineerEHR, "#FF6A00" },
@@ -363,6 +364,7 @@ public class Main : BasePlugin
{ CustomRoles.GuardianAngelEHR, "#77e6d1" },
{ CustomRoles.TrackerEHR, "#34ad50" },
{ CustomRoles.NoisemakerEHR, "#ff4a62" },
{ CustomRoles.DetectiveEHR, "#625EEE" },
// Crewmates
{ CustomRoles.DoubleAgent, "#ff1919" },
{ CustomRoles.Luckey, "#b8d7a3" },
@@ -455,7 +457,7 @@ public class Main : BasePlugin
{ CustomRoles.SpeedBooster, "#00ffff" },
{ CustomRoles.Doctor, "#80ffdd" },
{ CustomRoles.Dictator, "#df9b00" },
{ CustomRoles.Detective, "#7160e8" },
{ CustomRoles.Forensic, "#7160e8" },
{ CustomRoles.NiceGuesser, "#f0e68c" },
{ CustomRoles.SwordsMan, "#7a7a7a" },
{ CustomRoles.Transporter, "#42D1FF" },
@@ -538,6 +540,7 @@ public class Main : BasePlugin
{ CustomRoles.Duality, "#8D6F64" },
{ CustomRoles.Thanos, "#F9D401" },
{ CustomRoles.SerialKiller, "#233fcc" },
{ CustomRoles.Explosivist, "#D20103" },
{ CustomRoles.Slenderman, "#2c2e00" },
{ CustomRoles.Amogus, "#ff0000" },
{ CustomRoles.Weatherman, "#347deb" },
@@ -668,6 +671,8 @@ public class Main : BasePlugin
{ CustomRoles.Physicist, "#87e9ff" },
{ CustomRoles.Finder, "#32a879" },
{ CustomRoles.Noisy, "#e34fb2" },
{ CustomRoles.Examiner, "#625EEE" },
{ CustomRoles.Venom, "#ff1919" },
{ CustomRoles.Torch, "#eee5be" },
{ CustomRoles.Seer, "#61b26c" },
{ CustomRoles.Brakar, "#1447af" },
@@ -793,9 +798,9 @@ public class Main : BasePlugin
ClassInjector.RegisterTypeInIl2Cpp<VitalsPagingBehaviour>();
#endif
NormalGameOptionsV09.RecommendedImpostors = NormalGameOptionsV09.MaxImpostors = Enumerable.Repeat(128, 128).ToArray();
NormalGameOptionsV09.MinPlayers = Enumerable.Repeat(4, 128).ToArray();
HideNSeekGameOptionsV09.MinPlayers = Enumerable.Repeat(4, 128).ToArray();
NormalGameOptionsV10.RecommendedImpostors = NormalGameOptionsV10.MaxImpostors = Enumerable.Repeat(128, 128).ToArray();
NormalGameOptionsV10.MinPlayers = Enumerable.Repeat(4, 128).ToArray();
HideNSeekGameOptionsV10.MinPlayers = Enumerable.Repeat(4, 128).ToArray();
PrivateTagManager.LoadTagsFromFile();
@@ -1017,6 +1022,7 @@ public enum CustomWinner
Necromancer = CustomRoles.Necromancer,
Wraith = CustomRoles.Wraith,
SerialKiller = CustomRoles.SerialKiller,
Explosivist = CustomRoles.Explosivist,
Thanos = CustomRoles.Thanos,
Duality = CustomRoles.Duality,
Slenderman = CustomRoles.Slenderman,
+12
View File
@@ -120,6 +120,18 @@ public static class AURoleOptions
set => Opt.SetFloat(FloatOptionNames.TrackerDelay, value);
}
public static float ViperDissolveTime
{
get => Opt.GetFloat(FloatOptionNames.ViperDissolveTime);
set => Opt.SetFloat(FloatOptionNames.ViperDissolveTime, value);
}
public static float DetectiveSuspectLimit
{
get => Opt.GetFloat(FloatOptionNames.DetectiveSuspectLimit);
set => Opt.SetFloat(FloatOptionNames.DetectiveSuspectLimit, value);
}
public static void SetOpt(IGameOptions opt)
{
Opt = opt;
+1
View File
@@ -624,6 +624,7 @@ namespace EHR
protected override void OnFixedUpdate()
{
base.OnFixedUpdate();
if (Options.CurrentGameMode != CustomGameMode.BedWars) return;
timer -= Time.fixedDeltaTime;
if (timer <= 0f)
+11 -1
View File
@@ -18,6 +18,8 @@ internal static class CustomRoleSelector
public static int AddNoisemakerNum;
public static int AddTrackerNum;
public static int AddPhantomNum;
public static int AddViperNum;
public static int AddDetectiveNum;
public static readonly Dictionary<CustomGameMode, CustomRoles> GameModeRoles = new()
{
@@ -905,6 +907,8 @@ internal static class CustomRoleSelector
AddNoisemakerNum = 0;
AddTrackerNum = 0;
AddPhantomNum = 0;
AddViperNum = 0;
AddDetectiveNum = 0;
foreach (CustomRoles role in RoleResult.Values)
{
@@ -930,6 +934,12 @@ internal static class CustomRoleSelector
case CustomRoles.Phantom:
AddPhantomNum++;
break;
case CustomRoles.Viper:
AddViperNum++;
break;
case CustomRoles.Detective:
AddDetectiveNum++;
break;
}
}
catch (Exception e) { Utils.ThrowException(e); }
@@ -955,7 +965,7 @@ internal static class CustomRoleSelector
case CustomRoles.Mare or CustomRoles.Glow or CustomRoles.Sleep when Main.CurrentMap == MapNames.Fungle:
case CustomRoles.Madmate when Options.MadmateSpawnMode.GetInt() != 0:
case CustomRoles.Lovers or CustomRoles.LastImpostor or CustomRoles.Workhorse or CustomRoles.Undead or CustomRoles.Insane:
case CustomRoles.Nimble or CustomRoles.Physicist or CustomRoles.Bloodlust or CustomRoles.Finder or CustomRoles.Noisy: // Assigned at a different function due to role base change
case CustomRoles.Nimble or CustomRoles.Physicist or CustomRoles.Bloodlust or CustomRoles.Finder or CustomRoles.Noisy or CustomRoles.Examiner or CustomRoles.Venom: // Assigned at a different function due to role base change
continue;
}
+31 -36
View File
@@ -39,6 +39,7 @@ internal static class CustomRolesHelper
CustomRoles.PortalMaker,
CustomRoles.Gardener,
CustomRoles.Farmer,
CustomRoles.Explosivist,
// Add-ons
CustomRoles.Energetic,
@@ -279,7 +280,7 @@ internal static class CustomRolesHelper
CustomRoles.Escapee => UsePets ? CustomRoles.Impostor : CustomRoles.Shapeshifter,
CustomRoles.NiceGuesser => CustomRoles.Crewmate,
CustomRoles.EvilGuesser => CustomRoles.Impostor,
CustomRoles.Detective => CustomRoles.Crewmate,
CustomRoles.Forensic => CustomRoles.Crewmate,
CustomRoles.God => CustomRoles.Crewmate,
CustomRoles.Tank => CustomRoles.Engineer,
CustomRoles.Technician => Technician.CanVent.GetBool() ? CustomRoles.Engineer : CustomRoles.Crewmate,
@@ -339,7 +340,7 @@ internal static class CustomRolesHelper
CustomRoles.Devourer => CustomRoles.Shapeshifter,
CustomRoles.Deathpact => CustomRoles.Shapeshifter,
CustomRoles.Bloodhound => CustomRoles.Crewmate,
CustomRoles.Tracker => CustomRoles.Crewmate,
CustomRoles.Scout => CustomRoles.Crewmate,
CustomRoles.Merchant => CustomRoles.Crewmate,
CustomRoles.Lookout => CustomRoles.Crewmate,
CustomRoles.Guardian => CustomRoles.Crewmate,
@@ -365,6 +366,8 @@ internal static class CustomRolesHelper
CustomRoles.ScientistEHR => CustomRoles.Scientist,
CustomRoles.TrackerEHR => CustomRoles.Tracker,
CustomRoles.NoisemakerEHR => CustomRoles.Noisemaker,
CustomRoles.DetectiveEHR => CustomRoles.Detective,
CustomRoles.ViperEHR => CustomRoles.Viper,
// Hide And Seek
CustomRoles.Hider => CustomRoles.Crewmate,
@@ -418,6 +421,8 @@ internal static class CustomRolesHelper
CustomRoles.Impostor => CustomRoles.ImpostorEHR,
CustomRoles.Phantom => CustomRoles.PhantomEHR,
CustomRoles.Shapeshifter => CustomRoles.ShapeshifterEHR,
CustomRoles.Detective => CustomRoles.DetectiveEHR,
CustomRoles.Viper => CustomRoles.ViperEHR,
_ => role.IsImpostor() ? CustomRoles.ImpostorEHR : CustomRoles.CrewmateEHR
};
}
@@ -482,6 +487,7 @@ internal static class CustomRolesHelper
CustomRoles.Poisoner => RoleTypes.Impostor,
CustomRoles.Duality => RoleTypes.Impostor,
CustomRoles.SerialKiller => RoleTypes.Impostor,
CustomRoles.Explosivist => RoleTypes.Impostor,
CustomRoles.Thanos => RoleTypes.Shapeshifter,
CustomRoles.Slenderman => RoleTypes.Impostor,
CustomRoles.Amogus => RoleTypes.Impostor,
@@ -611,6 +617,7 @@ internal static class CustomRolesHelper
CustomRoles.Rogue or
CustomRoles.Parasite or
CustomRoles.SerialKiller or
CustomRoles.Explosivist or
CustomRoles.Thanos or
CustomRoles.Duality or
CustomRoles.Slenderman or
@@ -673,6 +680,8 @@ internal static class CustomRolesHelper
CustomRoles.PhantomEHR or
CustomRoles.Shapeshifter or
CustomRoles.ShapeshifterEHR or
CustomRoles.Viper or
CustomRoles.ViperEHR or
CustomRoles.LovingImpostor or
CustomRoles.Godfather or
CustomRoles.EvilDiviner or
@@ -1029,6 +1038,7 @@ internal static class CustomRolesHelper
CustomRoles.Wraith or
CustomRoles.RouleteGrandeur or
CustomRoles.Enderman or
CustomRoles.Explosivist or
CustomRoles.Hookshot or
CustomRoles.Mycologist or
CustomRoles.Magician or
@@ -1052,12 +1062,12 @@ internal static class CustomRolesHelper
{
return role.IsAdditionRole() && (!Main.NeverSpawnTogetherCombos.TryGetValue(OptionItem.CurrentPreset, out Dictionary<CustomRoles, List<CustomRoles>> neverList) || !neverList.TryGetValue(pc.GetCustomRole(), out List<CustomRoles> bannedAddonList) || !bannedAddonList.Contains(role)) && pc.GetCustomRole() is not CustomRoles.GuardianAngelEHR and not CustomRoles.God && !pc.Is(CustomRoles.Madmate) && !pc.Is(CustomRoles.GM) && role is not CustomRoles.Lovers && !pc.Is(CustomRoles.Needy) && (!pc.HasSubRole() || pc.GetCustomSubRoles().Count < Options.NoLimitAddonsNumMax.GetInt()) && (!Options.AddonCanBeSettings.TryGetValue(role, out (OptionItem Imp, OptionItem Neutral, OptionItem Crew, OptionItem Coven) o) || ((o.Imp.GetBool() || !pc.GetCustomRole().IsImpostor()) && (o.Neutral.GetBool() || !pc.GetCustomRole().IsNeutral()) && (o.Crew.GetBool() || !pc.IsCrewmate()) && (o.Coven.GetBool() || !pc.Is(Team.Coven)))) && (!role.IsImpOnlyAddon() || (pc.IsImpostor() && !pc.Is(CustomRoles.DoubleAgent)) || (pc.Is(CustomRoles.Traitor) && Traitor.CanGetImpostorOnlyAddons.GetBool())) && role switch
{
CustomRoles.Commited when pc.GetRoleTypes() is not (RoleTypes.Impostor or RoleTypes.Phantom or RoleTypes.Shapeshifter) => false,
CustomRoles.Commited when pc.GetRoleTypes() is not (RoleTypes.Impostor or RoleTypes.Phantom or RoleTypes.Shapeshifter or RoleTypes.Viper) => false,
CustomRoles.Underdog when pc.Is(CustomRoles.Mare) => false,
CustomRoles.Shy when Options.DisableWhisperCommand.GetBool() => false,
CustomRoles.Blocked when !pc.CanUseVent() => false,
CustomRoles.Aide when pc.IsMadmate() || pc.Is(CustomRoles.Saboteur) => false,
CustomRoles.Sleuth when pc.GetCustomRole() is CustomRoles.NecroGuesser or CustomRoles.Imitator or CustomRoles.Detective => false,
CustomRoles.Sleuth when pc.GetCustomRole() is CustomRoles.NecroGuesser or CustomRoles.Imitator or CustomRoles.Forensic => false,
CustomRoles.Introvert when pc.GetCustomRole() is CustomRoles.Leery or CustomRoles.Samurai or CustomRoles.Arsonist or CustomRoles.Revolutionist or CustomRoles.Farseer or CustomRoles.Scavenger or CustomRoles.Analyst => false,
CustomRoles.Circumvent when pc.GetCustomRole() is CustomRoles.Swooper or CustomRoles.RiftMaker=> false,
CustomRoles.Oblivious when pc.Is(CustomRoles.Altruist) => false,
@@ -1070,7 +1080,7 @@ internal static class CustomRolesHelper
CustomRoles.Magnet when pc.Is(Team.Impostor) => false,
CustomRoles.Swift when pc.Is(CustomRoles.Magnet) => false,
CustomRoles.Oblivious when pc.Is(CustomRoles.Amnesiac) && Amnesiac.RememberMode.GetValue() == 0 => false,
CustomRoles.Rookie when pc.GetRoleTypes() is not (RoleTypes.Impostor or RoleTypes.Phantom or RoleTypes.Shapeshifter) => false,
CustomRoles.Rookie when pc.GetRoleTypes() is not (RoleTypes.Impostor or RoleTypes.Phantom or RoleTypes.Shapeshifter or RoleTypes.Viper) => false,
CustomRoles.Madmate when pc.Is(CustomRoles.Sidekick) => false,
CustomRoles.Autopsy when pc.Is(CustomRoles.Doctor) || pc.Is(CustomRoles.Tracefinder) || pc.Is(CustomRoles.Scientist) || pc.Is(CustomRoles.ScientistEHR) || pc.Is(CustomRoles.Sunnyboy) => false,
CustomRoles.Necroview when pc.Is(CustomRoles.Doctor) => false,
@@ -1088,11 +1098,11 @@ internal static class CustomRolesHelper
CustomRoles.Sunglasses when pc.Is(CustomRoles.Torch) || pc.Is(CustomRoles.GuardianAngelEHR) || pc.Is(CustomRoles.Bewilder) => false,
CustomRoles.Guesser when pc.GetCustomRole() is CustomRoles.EvilGuesser or CustomRoles.NiceGuesser or CustomRoles.Doomsayer or CustomRoles.CopyCat => false,
CustomRoles.Madmate when !pc.CanBeMadmate() || pc.Is(CustomRoles.Egoist) || pc.Is(CustomRoles.Rascal) => false,
CustomRoles.Oblivious when pc.Is(CustomRoles.Detective) || pc.Is(CustomRoles.Cleaner) || pc.Is(CustomRoles.Medusa) || pc.Is(CustomRoles.Mortician) || pc.Is(CustomRoles.Mediumshiper) || pc.Is(CustomRoles.GuardianAngelEHR) => false,
CustomRoles.Oblivious when pc.Is(CustomRoles.Forensic) || pc.Is(CustomRoles.Cleaner) || pc.Is(CustomRoles.Medusa) || pc.Is(CustomRoles.Mortician) || pc.Is(CustomRoles.Mediumshiper) || pc.Is(CustomRoles.GuardianAngelEHR) => false,
CustomRoles.Youtuber when !pc.IsCrewmate() || pc.Is(CustomRoles.Madmate) || pc.Is(CustomRoles.Sheriff) || pc.Is(CustomRoles.GuardianAngelEHR) => false,
CustomRoles.Egoist when !pc.IsImpostor() => false,
CustomRoles.Damocles when pc.GetCustomRole() is CustomRoles.Bomber or CustomRoles.Nuker or CustomRoles.Mercenary or CustomRoles.Cantankerous => false,
CustomRoles.Damocles when pc.GetRoleTypes() is not (RoleTypes.Impostor or RoleTypes.Phantom or RoleTypes.Shapeshifter) => false,
CustomRoles.Damocles when pc.GetRoleTypes() is not (RoleTypes.Impostor or RoleTypes.Phantom or RoleTypes.Shapeshifter or RoleTypes.Viper) => false,
CustomRoles.Flashman when pc.Is(CustomRoles.Swiftclaw) || pc.Is(CustomRoles.Giant) || pc.Is(CustomRoles.Spurt) || pc.GetCustomRole() is CustomRoles.Tank or CustomRoles.Zombie => false,
CustomRoles.Giant when pc.Is(CustomRoles.Flashman) || pc.Is(CustomRoles.Spurt) || pc.Is(CustomRoles.RoomRusher) => false,
CustomRoles.Necroview when pc.Is(CustomRoles.Visionary) => false,
@@ -1140,9 +1150,9 @@ internal static class CustomRolesHelper
CustomRoles.Swift when pc.Is(CustomRoles.Mafia) => false,
CustomRoles.Reach when pc.GetCustomRole() is CustomRoles.Mafioso or CustomRoles.Evolver => false,
CustomRoles.Trapper when pc.Is(CustomRoles.GuardianAngelEHR) => false,
CustomRoles.Reach when pc.GetRoleTypes() is not (RoleTypes.Impostor or RoleTypes.Phantom or RoleTypes.Shapeshifter) => false,
CustomRoles.Magnet when pc.GetRoleTypes() is not (RoleTypes.Impostor or RoleTypes.Phantom or RoleTypes.Shapeshifter) => false,
CustomRoles.Haste when pc.GetRoleTypes() is not (RoleTypes.Impostor or RoleTypes.Phantom or RoleTypes.Shapeshifter) || !pc.CanUseImpostorVentButton() => false,
CustomRoles.Reach when pc.GetRoleTypes() is not (RoleTypes.Impostor or RoleTypes.Phantom or RoleTypes.Shapeshifter or RoleTypes.Viper) => false,
CustomRoles.Magnet when pc.GetRoleTypes() is not (RoleTypes.Impostor or RoleTypes.Phantom or RoleTypes.Shapeshifter or RoleTypes.Viper) => false,
CustomRoles.Haste when pc.GetRoleTypes() is not (RoleTypes.Impostor or RoleTypes.Phantom or RoleTypes.Shapeshifter or RoleTypes.Viper) || !pc.CanUseImpostorVentButton() => false,
CustomRoles.Diseased when pc.Is(CustomRoles.Antidote) => false,
CustomRoles.Antidote when pc.Is(CustomRoles.Diseased) => false,
CustomRoles.Flashman or CustomRoles.Giant when pc.GetCustomRole() is CustomRoles.Swooper or CustomRoles.Wraith or CustomRoles.Chameleon or CustomRoles.Alchemist or CustomRoles.Ankylosaurus => false,
@@ -1153,6 +1163,8 @@ internal static class CustomRolesHelper
CustomRoles.Physicist when !pc.IsCrewmate() || pc.GetCustomRole().IsDesyncRole() || (pc.Is(CustomRoles.TimeMaster) && !TimeMaster.TimeMasterCanUseVitals.GetBool()) => false,
CustomRoles.Finder when !pc.IsCrewmate() || pc.GetCustomRole().IsDesyncRole() => false,
CustomRoles.Noisy when !pc.IsCrewmate() || pc.GetCustomRole().IsDesyncRole() => false,
CustomRoles.Examiner when !pc.IsCrewmate() || pc.GetCustomRole().IsDesyncRole() => false,
CustomRoles.Venom when !pc.IsImpostor() => false,
CustomRoles.Unreportable when pc.Is(CustomRoles.Bait) => false,
CustomRoles.Oblivious when pc.Is(CustomRoles.Bloodhound) => false,
CustomRoles.Oblivious when pc.Is(CustomRoles.Vulture) => false,
@@ -1284,6 +1296,8 @@ internal static class CustomRolesHelper
CustomRoles.Scientist or
CustomRoles.GuardianAngel or
CustomRoles.Impostor or
CustomRoles.Detective or
CustomRoles.Viper or
CustomRoles.Phantom or
CustomRoles.Shapeshifter;
}
@@ -1314,30 +1328,6 @@ internal static class CustomRolesHelper
return Options.GetRoleSpawnMode(role);
}
public static float GetChance(this CustomRoles role)
{
if (role.IsVanilla())
{
IRoleOptionsCollection roleOpt = Main.NormalOptions.RoleOptions;
return role switch
{
CustomRoles.Engineer => roleOpt.GetChancePerGame(RoleTypes.Engineer),
CustomRoles.Noisemaker => roleOpt.GetChancePerGame(RoleTypes.Noisemaker),
CustomRoles.Tracker => roleOpt.GetChancePerGame(RoleTypes.Tracker),
CustomRoles.Scientist => roleOpt.GetChancePerGame(RoleTypes.Scientist),
CustomRoles.Impostor => roleOpt.GetChancePerGame(RoleTypes.Impostor),
CustomRoles.Phantom => roleOpt.GetChancePerGame(RoleTypes.Phantom),
CustomRoles.Shapeshifter => roleOpt.GetChancePerGame(RoleTypes.Shapeshifter),
CustomRoles.GuardianAngel => roleOpt.GetChancePerGame(RoleTypes.GuardianAngel),
CustomRoles.Crewmate => roleOpt.GetChancePerGame(RoleTypes.Crewmate),
_ => 0
} / 100f;
}
return Options.GetRoleChance(role);
}
public static bool IsEnable(this CustomRoles role)
{
return role switch
@@ -1441,7 +1431,7 @@ internal static class CustomRolesHelper
RoleOptionType.Impostor_Concealing => Utils.GetRoleColor(CustomRoles.CopyCat),
RoleOptionType.Impostor_Miscellaneous => Palette.ImpostorRed,
RoleOptionType.Crewmate_Miscellaneous => Palette.CrewmateBlue,
RoleOptionType.Crewmate_Investigate => Utils.GetRoleColor(CustomRoles.Detective),
RoleOptionType.Crewmate_Investigate => Utils.GetRoleColor(CustomRoles.Forensic),
RoleOptionType.Crewmate_Support => Utils.GetRoleColor(CustomRoles.NiceEraser),
RoleOptionType.Crewmate_Killing => Utils.GetRoleColor(CustomRoles.Sheriff),
RoleOptionType.Crewmate_Power => Utils.GetRoleColor(CustomRoles.Electric),
@@ -1650,6 +1640,8 @@ internal static class CustomRolesHelper
CustomRoles.ShapeshifterEHR => RoleOptionType.Impostor_Miscellaneous,
CustomRoles.Phantom => RoleOptionType.Impostor_Miscellaneous,
CustomRoles.PhantomEHR => RoleOptionType.Impostor_Miscellaneous,
CustomRoles.Viper => RoleOptionType.Impostor_Miscellaneous,
CustomRoles.ViperEHR => RoleOptionType.Impostor_Miscellaneous,
CustomRoles.DoubleAgent => RoleOptionType.Crewmate_Investigate,
_ => role.IsCrewmate() ? RoleOptionType.Crewmate_Miscellaneous : RoleOptionType.Neutral_Benign
};
@@ -1669,6 +1661,8 @@ internal static class CustomRolesHelper
CustomRoles.TrackerEHR => RoleOptionType.Crewmate_Miscellaneous,
CustomRoles.Noisemaker => RoleOptionType.Crewmate_Miscellaneous,
CustomRoles.NoisemakerEHR => RoleOptionType.Crewmate_Miscellaneous,
CustomRoles.Detective => RoleOptionType.Crewmate_Miscellaneous,
CustomRoles.DetectiveEHR => RoleOptionType.Crewmate_Miscellaneous,
CustomRoles.Addict => RoleOptionType.Crewmate_Miscellaneous,
CustomRoles.CameraMan => RoleOptionType.Crewmate_Miscellaneous,
CustomRoles.Demolitionist => RoleOptionType.Crewmate_Miscellaneous,
@@ -1692,7 +1686,7 @@ internal static class CustomRolesHelper
CustomRoles.Chameleon => RoleOptionType.Crewmate_Investigate,
CustomRoles.Clairvoyant => RoleOptionType.Crewmate_Investigate,
CustomRoles.Bloodhound => RoleOptionType.Crewmate_Investigate,
CustomRoles.Detective => RoleOptionType.Crewmate_Investigate,
CustomRoles.Forensic => RoleOptionType.Crewmate_Investigate,
CustomRoles.Doctor => RoleOptionType.Crewmate_Investigate,
CustomRoles.DoubleAgent => RoleOptionType.Crewmate_Investigate,
CustomRoles.Druid => RoleOptionType.Crewmate_Investigate,
@@ -1863,6 +1857,7 @@ public enum CountTypes
HexMaster,
Wraith,
SerialKiller,
Explosivist,
Thanos,
Duality,
Slenderman,
+5 -1
View File
@@ -477,6 +477,8 @@ internal static class ExtendedPlayerControl
CustomRoles.Physicist when newRoleType == RoleTypes.Crewmate => RoleTypes.Scientist,
CustomRoles.Finder when newRoleType is RoleTypes.Crewmate or RoleTypes.Scientist or RoleTypes.Noisemaker => RoleTypes.Tracker,
CustomRoles.Noisy when newRoleType == RoleTypes.Crewmate => RoleTypes.Noisemaker,
CustomRoles.Examiner when newRoleType is RoleTypes.Crewmate or RoleTypes.Scientist or RoleTypes.Noisemaker => RoleTypes.Detective,
CustomRoles.Venom when newRoleType == RoleTypes.Impostor => RoleTypes.Viper,
_ => newRoleType
},
_ => newRoleType
@@ -1337,7 +1339,7 @@ internal static class ExtendedPlayerControl
{
CustomRoles role = pc.GetCustomRole();
if (pc.Data.Role.Role == RoleTypes.GuardianAngel) return false;
if (role.GetVNRole(true) is CustomRoles.Impostor or CustomRoles.ImpostorEHR or CustomRoles.Shapeshifter or CustomRoles.ShapeshifterEHR or CustomRoles.Phantom or CustomRoles.PhantomEHR) return true;
if (role.GetVNRole(true) is CustomRoles.Impostor or CustomRoles.ImpostorEHR or CustomRoles.Shapeshifter or CustomRoles.ShapeshifterEHR or CustomRoles.Phantom or CustomRoles.PhantomEHR or CustomRoles.Viper or CustomRoles.ViperEHR) return true;
if (pc.GetRoleTypes() is RoleTypes.Impostor or RoleTypes.Shapeshifter or RoleTypes.Phantom) return true;
if (pc.Is(CustomRoles.Bloodlust)) return true;
return !HasTasks(pc.Data, false);
@@ -2112,6 +2114,8 @@ internal static class ExtendedPlayerControl
{ } x when x.Contains(CustomRoles.Physicist) => RoleTypes.Scientist,
{ } x when x.Contains(CustomRoles.Finder) => RoleTypes.Tracker,
{ } x when x.Contains(CustomRoles.Noisy) => RoleTypes.Noisemaker,
{ } x when x.Contains(CustomRoles.Examiner) => RoleTypes.Detective,
{ } x when x.Contains(CustomRoles.Venom) => RoleTypes.Viper,
_ => pc.GetCustomRole().GetRoleTypes()
};
}
+10 -10
View File
@@ -9,13 +9,13 @@ public static class IGameManagerEx
opt.SetBool(name, value);
}
public static void Set(this BoolOptionNames name, bool value, NormalGameOptionsV09 opt)
public static void Set(this BoolOptionNames name, bool value, NormalGameOptionsV10 opt)
{
if (name is not BoolOptionNames.GhostsDoTasks and not BoolOptionNames.Roles)
opt.SetBool(name, value);
}
public static void Set(this BoolOptionNames name, bool value, HideNSeekGameOptionsV09 opt)
public static void Set(this BoolOptionNames name, bool value, HideNSeekGameOptionsV10 opt)
{
opt.SetBool(name, value);
}
@@ -25,12 +25,12 @@ public static class IGameManagerEx
opt.SetInt(name, value);
}
public static void Set(this Int32OptionNames name, int value, NormalGameOptionsV09 opt)
public static void Set(this Int32OptionNames name, int value, NormalGameOptionsV10 opt)
{
opt.SetInt(name, value);
}
public static void Set(this Int32OptionNames name, int value, HideNSeekGameOptionsV09 opt)
public static void Set(this Int32OptionNames name, int value, HideNSeekGameOptionsV10 opt)
{
opt.SetInt(name, value);
}
@@ -40,12 +40,12 @@ public static class IGameManagerEx
opt.SetFloat(name, value);
}
public static void Set(this FloatOptionNames name, float value, NormalGameOptionsV09 opt)
public static void Set(this FloatOptionNames name, float value, NormalGameOptionsV10 opt)
{
opt.SetFloat(name, value);
}
public static void Set(this FloatOptionNames name, float value, HideNSeekGameOptionsV09 opt)
public static void Set(this FloatOptionNames name, float value, HideNSeekGameOptionsV10 opt)
{
opt.SetFloat(name, value);
}
@@ -55,12 +55,12 @@ public static class IGameManagerEx
opt.SetByte(name, value);
}
public static void Set(this ByteOptionNames name, byte value, NormalGameOptionsV09 opt)
public static void Set(this ByteOptionNames name, byte value, NormalGameOptionsV10 opt)
{
opt.SetByte(name, value);
}
public static void Set(this ByteOptionNames name, byte value, HideNSeekGameOptionsV09 opt)
public static void Set(this ByteOptionNames name, byte value, HideNSeekGameOptionsV10 opt)
{
opt.SetByte(name, value);
}
@@ -70,12 +70,12 @@ public static class IGameManagerEx
opt.SetUInt(name, value);
}
public static void Set(this UInt32OptionNames name, uint value, NormalGameOptionsV09 opt)
public static void Set(this UInt32OptionNames name, uint value, NormalGameOptionsV10 opt)
{
opt.SetUInt(name, value);
}
public static void Set(this UInt32OptionNames name, uint value, HideNSeekGameOptionsV09 opt)
public static void Set(this UInt32OptionNames name, uint value, HideNSeekGameOptionsV10 opt)
{
opt.SetUInt(name, value);
}
@@ -24,10 +24,10 @@ public abstract class GameOptionsSender
writer.StartMessage(0);
writer.Write((byte)opt.GameMode);
if (opt.TryCast(out NormalGameOptionsV09 normalOpt))
NormalGameOptionsV09.Serialize(writer, normalOpt);
else if (opt.TryCast(out HideNSeekGameOptionsV09 hnsOpt))
HideNSeekGameOptionsV09.Serialize(writer, hnsOpt);
if (opt.TryCast(out NormalGameOptionsV10 normalOpt))
NormalGameOptionsV10.Serialize(writer, normalOpt);
else if (opt.TryCast(out HideNSeekGameOptionsV10 hnsOpt))
HideNSeekGameOptionsV10.Serialize(writer, hnsOpt);
else
{
writer.Recycle();
@@ -4,6 +4,7 @@ using AmongUs.GameOptions;
using EHR.AddOns.Common;
using EHR.AddOns.Crewmate;
using EHR.AddOns.GhostRoles;
using EHR.AddOns.Impostor;
using EHR.Coven;
using EHR.Crewmate;
using EHR.Impostor;
@@ -22,7 +23,7 @@ public sealed class PlayerGameOptionsSender(PlayerControl player) : GameOptionsS
public PlayerControl player = player;
private static IGameOptions BasedGameOptions =>
Main.RealOptionsData.Restore(new NormalGameOptionsV09(new UnityLogger().CastFast<ILogger>()).CastFast<IGameOptions>());
Main.RealOptionsData.Restore(new NormalGameOptionsV10(new UnityLogger().CastFast<ILogger>()).CastFast<IGameOptions>());
protected override bool IsDirty { get; set; }
@@ -254,6 +255,12 @@ public sealed class PlayerGameOptionsSender(PlayerControl player) : GameOptionsS
AURoleOptions.TrackerDuration = CrewmateVanillaRoles.TrackerDuration.GetFloat();
AURoleOptions.TrackerDelay = CrewmateVanillaRoles.TrackerDelay.GetFloat();
break;
case CustomRoles.DetectiveEHR:
AURoleOptions.DetectiveSuspectLimit = CrewmateVanillaRoles.DetectiveSuspectLimit.GetFloat();
break;
case CustomRoles.ViperEHR:
AURoleOptions.ViperDissolveTime = ImpostorVanillaRoles.ViperDissolveTime.GetFloat();
break;
}
// When impostor alert is off, and the player is a desync crewmate, set impostor alert as true
@@ -425,6 +432,12 @@ public sealed class PlayerGameOptionsSender(PlayerControl player) : GameOptionsS
AURoleOptions.NoisemakerImpostorAlert = Noisy.NoisyImpostorAlert.GetBool();
AURoleOptions.NoisemakerAlertDuration = Noisy.NoisyAlertDuration.GetFloat();
break;
case CustomRoles.Examiner when roleTypes == RoleTypes.Detective:
AURoleOptions.DetectiveSuspectLimit = Examiner.ExaminerSuspectLimit.GetFloat();
break;
case CustomRoles.Venom when roleTypes == RoleTypes.Viper:
AURoleOptions.ViperDissolveTime = Venom.VenomDissolveTime.GetFloat();
break;
}
}
@@ -458,6 +471,12 @@ public sealed class PlayerGameOptionsSender(PlayerControl player) : GameOptionsS
case RoleTypes.Tracker:
AURoleOptions.TrackerCooldown *= 0.75f;
break;
case RoleTypes.Viper:
AURoleOptions.ViperDissolveTime *= 0.75f;
break;
case RoleTypes.Detective:
AURoleOptions.DetectiveSuspectLimit *= 1.25f;
goto default;
case RoleTypes.CrewmateGhost:
case RoleTypes.ImpostorGhost:
break;
+1 -1
View File
@@ -42,7 +42,7 @@ public class OptionBackupData
// Since TryGetUInt is not implemented, get it separately
AllValues.Add(new UIntOptionBackupValue(UInt32OptionNames.Keywords, (uint)option.Keywords));
RoleTypes[] array = [RoleTypes.Scientist, RoleTypes.Engineer, RoleTypes.GuardianAngel, RoleTypes.Shapeshifter, RoleTypes.Noisemaker, RoleTypes.Phantom, RoleTypes.Tracker];
RoleTypes[] array = [RoleTypes.Scientist, RoleTypes.Engineer, RoleTypes.GuardianAngel, RoleTypes.Shapeshifter, RoleTypes.Noisemaker, RoleTypes.Phantom, RoleTypes.Tracker, RoleTypes.Viper, RoleTypes.Detective];
foreach (RoleTypes role in array) AllValues.Add(new RoleRateBackupValue(role, option.RoleOptions.GetNumPerGame(role), option.RoleOptions.GetChancePerGame(role)));
}
+3 -1
View File
@@ -839,6 +839,7 @@ public static class Utils
case CustomRoles.Eclipse:
case CustomRoles.Pyromaniac:
case CustomRoles.SerialKiller:
case CustomRoles.Explosivist:
case CustomRoles.Thanos:
case CustomRoles.Slenderman:
case CustomRoles.Amogus:
@@ -3269,6 +3270,7 @@ public static class Utils
CustomRoles.Tiger => Tiger.EnrageCooldown.GetInt() + (includeDuration ? Tiger.EnrageDuration.GetInt() : 0),
CustomRoles.Nonplus => Nonplus.BlindCooldown.GetInt() + (includeDuration ? Nonplus.BlindDuration.GetInt() : 0),
CustomRoles.Amogus => Amogus.AbilityCooldown.GetInt() + (includeDuration ? Amogus.AbilityDuration.GetInt() : 0),
CustomRoles.Explosivist => Explosivist.AbilityCooldown.GetInt() + (includeDuration ? Explosivist.ExplosionDelay.GetInt() : 0),
CustomRoles.Cherokious => Cherokious.KillCooldown.GetInt(),
CustomRoles.Shifter => Shifter.KillCooldown.GetInt(),
CustomRoles.NoteKiller => NoteKiller.AbilityCooldown.GetInt(),
@@ -4105,7 +4107,7 @@ public static class Utils
{
int baseColorId = deadBodyParent.Data.DefaultOutfit.ColorId;
deadBodyParent.Data.DefaultOutfit.ColorId = colorId;
DeadBody deadBody = Object.Instantiate(GameManager.Instance.DeadBodyPrefab);
DeadBody deadBody = Object.Instantiate(GameManager.Instance.deadBodyPrefab[0]);
deadBody.enabled = false;
deadBody.ParentId = deadBodyParent.PlayerId;
foreach (SpriteRenderer b in deadBody.bodyRenderers)
+2 -1
View File
@@ -23,7 +23,8 @@ internal static class ChatBubbleSetNamePatch
if (GameStates.IsInGame && !voted && seer.PlayerId == target.PlayerId) __instance.NameText.color = seer.GetRoleColor();
if (seer.GetCustomRole().GetDYRole() is RoleTypes.Shapeshifter or RoleTypes.Phantom) __instance.NameText.color = Color.white;
if (seer.GetCustomRole().GetDYRole() is RoleTypes.Shapeshifter or RoleTypes.Phantom or RoleTypes.Viper)
__instance.NameText.color = Color.white;
if (Main.DarkTheme.Value)
{
+25 -1
View File
@@ -3238,6 +3238,30 @@ internal static class ChatCommands
subArgs = args.Length < 3 ? "" : args[2];
GameOptionsManager.Instance.CurrentGameOptions.SetFloat(FloatOptionNames.TrackerDelay, float.Parse(subArgs));
break;
case "vipercount":
subArgs = args.Length < 3 ? "" : args[2];
GameOptionsManager.Instance.CurrentGameOptions.RoleOptions.SetRoleRate(RoleTypes.Viper, int.Parse(subArgs), GameOptionsManager.Instance.CurrentGameOptions.RoleOptions.GetChancePerGame(RoleTypes.Viper));
break;
case "viperchance":
subArgs = args.Length < 3 ? "" : args[2];
GameOptionsManager.Instance.CurrentGameOptions.RoleOptions.SetRoleRate(RoleTypes.Viper, GameOptionsManager.Instance.CurrentGameOptions.RoleOptions.GetNumPerGame(RoleTypes.Viper), int.Parse(subArgs));
break;
case "viperdissolvetime":
subArgs = args.Length < 3 ? "" : args[2];
GameOptionsManager.Instance.CurrentGameOptions.SetFloat(FloatOptionNames.ViperDissolveTime, float.Parse(subArgs));
break;
case "detectivecount":
subArgs = args.Length < 3 ? "" : args[2];
GameOptionsManager.Instance.CurrentGameOptions.RoleOptions.SetRoleRate(RoleTypes.Detective, int.Parse(subArgs), GameOptionsManager.Instance.CurrentGameOptions.RoleOptions.GetChancePerGame(RoleTypes.Detective));
break;
case "detectivechance":
subArgs = args.Length < 3 ? "" : args[2];
GameOptionsManager.Instance.CurrentGameOptions.RoleOptions.SetRoleRate(RoleTypes.Detective, GameOptionsManager.Instance.CurrentGameOptions.RoleOptions.GetNumPerGame(RoleTypes.Detective), int.Parse(subArgs));
break;
case "detectivesuspectlimit":
subArgs = args.Length < 3 ? "" : args[2];
GameOptionsManager.Instance.CurrentGameOptions.SetFloat(FloatOptionNames.DetectiveSuspectLimit, float.Parse(subArgs));
break;
default:
Utils.SendMessage(GetString("Commands.ChangeSettingHelp"), player.PlayerId);
break;
@@ -3328,7 +3352,7 @@ internal static class ChatCommands
"擺爛人" or "摆烂" => GetString("Needy"),
"獨裁者" or "独裁" or "dict" => GetString("Dictator"),
"法醫" or "doc" => GetString("Doctor"),
"偵探" or "det" => GetString("Detective"),
"偵探" or "det" => GetString("Forensic"),
"幸運兒" or "幸运" => GetString("Luckey"),
"大明星" or "明星" or "ss" => GetString("SuperStar"),
"demo" => GetString("Demolitionist"),
+1 -1
View File
@@ -1101,7 +1101,7 @@ internal static class GameEndChecker
if ((GameData.Instance.TotalTasks == 0 && GameData.Instance.CompletedTasks == 0) || !Main.PlayerStates.Values.Any(x => x.TaskState.HasTasks)) return false;
if (Options.DisableTaskWinIfAllCrewsAreDead.GetBool() && !Main.AllAlivePlayerControls.Any(x => x.Is(CustomRoleTypes.Crewmate))) return false;
if (Options.DisableTaskWinIfAllCrewsAreConverted.GetBool() && Main.AllAlivePlayerControls.Where(x => x.Is(Team.Crewmate) && x.GetRoleTypes() is RoleTypes.Crewmate or RoleTypes.Engineer or RoleTypes.Scientist or RoleTypes.Noisemaker or RoleTypes.Tracker or RoleTypes.CrewmateGhost or RoleTypes.GuardianAngel).All(x => x.IsConverted())) return false;
if (Options.DisableTaskWinIfAllCrewsAreConverted.GetBool() && Main.AllAlivePlayerControls.Where(x => x.Is(Team.Crewmate) && x.GetRoleTypes() is RoleTypes.Crewmate or RoleTypes.Engineer or RoleTypes.Scientist or RoleTypes.Noisemaker or RoleTypes.Tracker or RoleTypes.Detective or RoleTypes.CrewmateGhost or RoleTypes.GuardianAngel).All(x => x.IsConverted())) return false;
if (GameData.Instance.TotalTasks <= GameData.Instance.CompletedTasks)
{
+2 -2
View File
@@ -266,11 +266,11 @@ internal static class Crowded
}
}
[HarmonyPatch(typeof(NormalGameOptionsV09), nameof(NormalGameOptionsV09.AreInvalid))]
[HarmonyPatch(typeof(NormalGameOptionsV10), nameof(NormalGameOptionsV10.AreInvalid))]
public static class InvalidOptionsPatches
{
[SuppressMessage("ReSharper", "UnusedMember.Global")]
public static bool Prefix(NormalGameOptionsV09 __instance, [HarmonyArgument(0)] int maxExpectedPlayers)
public static bool Prefix(NormalGameOptionsV10 __instance, [HarmonyArgument(0)] int maxExpectedPlayers)
{
return __instance.MaxPlayers > maxExpectedPlayers ||
__instance.NumImpostors < 1 ||
+1
View File
@@ -219,6 +219,7 @@ internal static class HudManagerPatch
RoleTypes roleTypes = player.GetRoleTypes();
__instance.AbilityButton?.OverrideText(GetString($"AbilityButtonText.{roleTypes}"));
__instance.SecondaryAbilityButton?.OverrideText(GetString($"SecondaryAbilityButtonText.{roleTypes}"));
PlayerState state = Main.PlayerStates[player.PlayerId];
+9 -1
View File
@@ -711,6 +711,14 @@ internal static class BeginCrewmatePatch
or CustomRoles.EvilTracker
or CustomRoles.Scout
=> GetIntroSound(RoleTypes.Tracker),
CustomRoles.Viper
or CustomRoles.ViperEHR
=> GetIntroSound(RoleTypes.Viper),
CustomRoles.Detective
or CustomRoles.DetectiveEHR
=> GetIntroSound(RoleTypes.Detective),
CustomRoles.Noisemaker
or CustomRoles.NoisemakerEHR
@@ -921,7 +929,7 @@ internal static class BeginCrewmatePatch
private static AudioClip GetIntroSound(RoleTypes roleType)
{
return RoleManager.Instance.AllRoles.FirstOrDefault(role => role.Role == roleType)?.IntroSound;
return RoleManager.Instance.AllRoles.Find((Il2CppSystem.Predicate<RoleBehaviour>)(role => role.Role == roleType))?.IntroSound;
}
}
+2 -2
View File
@@ -776,7 +776,7 @@ internal static class MeetingHudStartPatch
AddMsg(string.Format(GetString("SilencerDead"), playername, pc.PlayerId, Utils.ColorString(Utils.GetRoleColor(CustomRoles.Silencer), GetString("SilencerKillTitle"))));
}
if (Detective.DetectiveNotify.TryGetValue(pc.PlayerId, out string value1)) AddMsg(value1, pc.PlayerId, Utils.ColorString(Utils.GetRoleColor(CustomRoles.Detective), GetString("DetectiveNoticeTitle")));
if (Forensic.ForensicNotify.TryGetValue(pc.PlayerId, out string value1)) AddMsg(value1, pc.PlayerId, Utils.ColorString(Utils.GetRoleColor(CustomRoles.Forensic), GetString("ForensicNoticeTitle")));
if (Main.SleuthMsgs.TryGetValue(pc.PlayerId, out string msg)) AddMsg(msg, pc.PlayerId, Utils.ColorString(Utils.GetRoleColor(CustomRoles.Sleuth), GetString("Sleuth")));
if (pc.Is(CustomRoles.Mimic) && !pc.IsAlive())
@@ -815,7 +815,7 @@ internal static class MeetingHudStartPatch
Main.SuperStarDead.Clear();
Express.SpeedNormal.Clear();
Express.SpeedUp.Clear();
Detective.DetectiveNotify.Clear();
Forensic.ForensicNotify.Clear();
Main.SleuthMsgs.Clear();
Virus.VirusNotify.Clear();
Mortician.MsgToSend.Clear();
+29 -10
View File
@@ -170,7 +170,9 @@ internal static class ChangeRoleSettings
RoleTypes.Shapeshifter,
RoleTypes.Noisemaker,
RoleTypes.Phantom,
RoleTypes.Tracker
RoleTypes.Tracker,
RoleTypes.Detective,
RoleTypes.Viper
}.Do(x => Main.NormalOptions.roleOptions.SetRoleRate(x, 0, 0));
if (Main.NormalOptions.MapId > 5 && !(Main.NormalOptions.MapId == 6 && SubmergedCompatibility.Loaded))
@@ -241,7 +243,7 @@ internal static class ChangeRoleSettings
Mafia.MafiaRevenged = [];
Warlock.IsCurseAndKill = [];
Warlock.IsCursed = false;
Detective.DetectiveNotify = [];
Forensic.ForensicNotify = [];
Provocateur.Provoked = [];
Crusader.ForCrusade = [];
Godfather.GodfatherTarget = byte.MaxValue;
@@ -472,7 +474,7 @@ internal static class StartGameHostPatch
public static readonly Dictionary<byte, bool> DataDisconnected = [];
private static RoleOptionsCollectionV09 RoleOpt => Main.NormalOptions.roleOptions;
private static RoleOptionsCollectionV10 RoleOpt => Main.NormalOptions.roleOptions;
private static void UpdateRoleTypeNums()
{
@@ -483,7 +485,9 @@ internal static class StartGameHostPatch
{ RoleTypes.Shapeshifter, AddShapeshifterNum },
{ RoleTypes.Noisemaker, AddNoisemakerNum },
{ RoleTypes.Phantom, AddPhantomNum },
{ RoleTypes.Tracker, AddTrackerNum }
{ RoleTypes.Tracker, AddTrackerNum },
{ RoleTypes.Detective, AddDetectiveNum },
{ RoleTypes.Viper, AddViperNum }
};
}
@@ -690,6 +694,8 @@ internal static class StartGameHostPatch
bool nimbleSpawn = random.Next(100) < (Options.CustomAdtRoleSpawnRate.TryGetValue(CustomRoles.Nimble, out IntegerOptionItem option2) ? option2.GetFloat() : 0) && CustomRoles.Nimble.IsEnable();
bool finderSpawn = random.Next(100) < (Options.CustomAdtRoleSpawnRate.TryGetValue(CustomRoles.Finder, out IntegerOptionItem option3) ? option3.GetFloat() : 0) && CustomRoles.Finder.IsEnable();
bool noisySpawn = random.Next(100) < (Options.CustomAdtRoleSpawnRate.TryGetValue(CustomRoles.Noisy, out IntegerOptionItem option4) ? option4.GetFloat() : 0) && CustomRoles.Noisy.IsEnable();
bool examinerSpawn = random.Next(100) < (Options.CustomAdtRoleSpawnRate.TryGetValue(CustomRoles.Examiner, out IntegerOptionItem option5) ? option5.GetFloat() : 0) && CustomRoles.Examiner.IsEnable();
bool venomSpawn = random.Next(100) < (Options.CustomAdtRoleSpawnRate.TryGetValue(CustomRoles.Venom, out IntegerOptionItem option6) ? option6.GetFloat() : 0) && CustomRoles.Venom.IsEnable();
if (Options.EveryoneCanVent.GetBool())
{
@@ -697,12 +703,13 @@ internal static class StartGameHostPatch
physicistSpawn = false;
finderSpawn = false;
noisySpawn = false;
examinerSpawn = false;
}
HashSet<byte> bloodlustList = [], nimbleList = [], physicistList = [], finderList = [], noisyList = [];
HashSet<byte> bloodlustList = [], nimbleList = [], physicistList = [], finderList = [], noisyList = [], examinerList = [], venomList = [];
bool hasBanned = Main.NeverSpawnTogetherCombos.TryGetValue(OptionItem.CurrentPreset, out Dictionary<CustomRoles, List<CustomRoles>> banned);
if (nimbleSpawn || physicistSpawn || finderSpawn || noisySpawn || bloodlustSpawn)
if (nimbleSpawn || physicistSpawn || finderSpawn || noisySpawn || bloodlustSpawn || examinerSpawn || venomSpawn)
{
foreach (PlayerControl player in Main.AllPlayerControls)
{
@@ -715,6 +722,8 @@ internal static class StartGameHostPatch
bool physicistBanned = hasBanned && banned.Any(x => x.Key == kp.Value && x.Value.Contains(CustomRoles.Physicist));
bool finderBanned = hasBanned && banned.Any(x => x.Key == kp.Value && x.Value.Contains(CustomRoles.Finder));
bool noisyBanned = hasBanned && banned.Any(x => x.Key == kp.Value && x.Value.Contains(CustomRoles.Noisy));
bool examinerBanned = hasBanned && banned.Any(x => x.Key == kp.Value && x.Value.Contains(CustomRoles.Examiner));
bool venomBanned = hasBanned && banned.Any(x => x.Key == kp.Value && x.Value.Contains(CustomRoles.Venom));
if (kp.Value.IsCrewmate())
{
@@ -726,8 +735,12 @@ internal static class StartGameHostPatch
if (!physicistBanned) physicistList.Add(player.PlayerId);
if (!finderBanned) finderList.Add(player.PlayerId);
if (!noisyBanned) noisyList.Add(player.PlayerId);
if (!examinerBanned) examinerList.Add(player.PlayerId);
}
}
if (kp.Value.IsImpostor() && kp.Value.GetRoleTypes() == RoleTypes.Impostor && !venomBanned)
venomList.Add(player.PlayerId);
}
}
@@ -737,7 +750,9 @@ internal static class StartGameHostPatch
{ CustomRoles.Nimble, (nimbleSpawn, nimbleList) },
{ CustomRoles.Physicist, (physicistSpawn, physicistList) },
{ CustomRoles.Finder, (finderSpawn, finderList) },
{ CustomRoles.Noisy, (noisySpawn, noisyList) }
{ CustomRoles.Noisy, (noisySpawn, noisyList) },
{ CustomRoles.Examiner, (examinerSpawn, examinerList) },
{ CustomRoles.Venom, (venomSpawn, venomList) }
};
for (var i = 0; i < roleSpawnMapping.Count; i++)
@@ -875,7 +890,7 @@ internal static class StartGameHostPatch
{
foreach (CustomRoles role in item.Value)
{
if (role is CustomRoles.Nimble or CustomRoles.Physicist or CustomRoles.Bloodlust or CustomRoles.Finder or CustomRoles.Noisy) continue;
if (role is CustomRoles.Nimble or CustomRoles.Physicist or CustomRoles.Bloodlust or CustomRoles.Finder or CustomRoles.Noisy or CustomRoles.Examiner or CustomRoles.Venom) continue;
state.SetSubRole(role);
if (overrideLovers && role == CustomRoles.Lovers) Main.LoversPlayers.Add(Utils.GetPlayerById(item.Key));
@@ -1238,10 +1253,10 @@ internal static class StartGameHostPatch
if (Options.CurrentGameMode == CustomGameMode.Standard)
{
if (target.Is(Team.Crewmate) && roleType is not (RoleTypes.Crewmate or RoleTypes.Scientist or RoleTypes.Engineer or RoleTypes.Noisemaker or RoleTypes.Tracker or RoleTypes.CrewmateGhost or RoleTypes.GuardianAngel))
if (target.Is(Team.Crewmate) && roleType is not (RoleTypes.Crewmate or RoleTypes.Scientist or RoleTypes.Engineer or RoleTypes.Noisemaker or RoleTypes.Tracker or RoleTypes.Detective or RoleTypes.CrewmateGhost or RoleTypes.GuardianAngel))
displayRole = RoleTypes.Crewmate;
if (target.Is(Team.Impostor) && roleType is not (RoleTypes.Impostor or RoleTypes.Shapeshifter or RoleTypes.Phantom or RoleTypes.ImpostorGhost))
if (target.Is(Team.Impostor) && roleType is not (RoleTypes.Impostor or RoleTypes.Shapeshifter or RoleTypes.Phantom or RoleTypes.Viper or RoleTypes.ImpostorGhost))
displayRole = RoleTypes.Impostor;
}
@@ -1399,6 +1414,8 @@ internal static class StartGameHostPatch
CustomRoles.Physicist => RoleTypes.Scientist,
CustomRoles.Finder => RoleTypes.Tracker,
CustomRoles.Noisy => RoleTypes.Noisemaker,
CustomRoles.Examiner => RoleTypes.Detective,
CustomRoles.Venom => RoleTypes.Viper,
_ => roleType
};
}
@@ -1536,6 +1553,8 @@ internal static class StartGameHostPatch
CustomRoles.Physicist when roleTypes == RoleTypes.Crewmate => RoleTypes.Scientist,
CustomRoles.Finder when roleTypes is RoleTypes.Crewmate or RoleTypes.Scientist or RoleTypes.Noisemaker => RoleTypes.Tracker,
CustomRoles.Noisy when roleTypes == RoleTypes.Crewmate => RoleTypes.Noisemaker,
CustomRoles.Examiner when roleTypes is RoleTypes.Crewmate or RoleTypes.Scientist or RoleTypes.Noisemaker => RoleTypes.Detective,
CustomRoles.Venom when roleTypes == RoleTypes.Impostor => RoleTypes.Viper,
_ => roleTypes
}
: roleTypes;
+1 -1
View File
@@ -326,7 +326,7 @@ public static class PhantomRoleUseAbilityPatch
FastDestroyableSingleton<HudManager>.Instance.AbilityButton.SetSecondImage(__instance.Ability);
FastDestroyableSingleton<HudManager>.Instance.AbilityButton.OverrideText(FastDestroyableSingleton<TranslationController>.Instance.GetString(StringNames.PhantomAbilityUndo, new Il2CppReferenceArray<Il2CppSystem.Object>(0)));
__instance.Player.CmdCheckVanish(GameManager.Instance.LogicOptions.GetPhantomDuration());
__instance.Player.CmdCheckVanish(GameManager.Instance.LogicOptions.GetRoleFloat(FloatOptionNames.PhantomDuration));
return false;
}
}
+4 -2
View File
@@ -1258,8 +1258,8 @@ internal static class ReportDeadBodyPatch
if (tpc != null && !tpc.IsAlive())
{
if (player.Is(CustomRoles.Detective) && player.PlayerId != target.PlayerId)
Detective.OnReportDeadBody(player, target.Object);
if (player.Is(CustomRoles.Forensic) && player.PlayerId != target.PlayerId)
Forensic.OnReportDeadBody(player, target.Object);
else if (player.Is(CustomRoles.Sleuth) && player.PlayerId != target.PlayerId)
{
string msg = string.Format(GetString("SleuthMsg"), tpc.GetRealName(), tpc.GetDisplayRoleName());
@@ -2444,6 +2444,8 @@ internal static class PlayerControlLocalSetRolePatch
RoleTypes.Noisemaker => CustomRoles.NoisemakerEHR,
RoleTypes.Scientist => CustomRoles.ScientistEHR,
RoleTypes.Tracker => CustomRoles.TrackerEHR,
RoleTypes.Detective => CustomRoles.DetectiveEHR,
RoleTypes.Viper => CustomRoles.ViperEHR,
_ => CustomRoles.NotAssigned
};
+34 -15
View File
@@ -165,6 +165,8 @@
"Noisemaker": "Noisemaker",
"Tracker": "Tracker",
"Phantom": "Phantom",
"Detective": "Detective",
"Viper": "Viper",
"EngineerEHR": "Engineer",
"ScientistEHR": "Scientist",
"ShapeshifterEHR": "Shapeshifter",
@@ -174,6 +176,8 @@
"NoisemakerEHR": "Noisemaker",
"TrackerEHR": "Tracker",
"PhantomEHR": "Phantom",
"DetectiveEHR": "Detective",
"ViperEHR": "Viper",
"BountyHunter": "Bounty Hunter",
"Mare": "Mare",
"FireWorks": "Fireworker",
@@ -249,7 +253,7 @@
"SpeedBooster": "Speed Booster",
"Doctor": "Doctor",
"Dictator": "Dictator",
"Detective": "Detective",
"Forensic": "Forensic",
"NiceGuesser": "Nice Guesser",
"Transporter": "Transporter",
"TimeManager": "Time Manager",
@@ -528,7 +532,7 @@
"SpeedBoosterInfo": "Boost your speed",
"DoctorInfo": "Know how each player died",
"DictatorInfo": "Exile a player based on your own judgment",
"DetectiveInfo": "Gain extra info from your body reports",
"ForensicInfo": "Gain extra info from your body reports",
"UndercoverInfo": "Impostors see you as their partner",
"SwordsManInfo": "You can kill 1 player",
"NiceGuesserInfo": "Guess <color=#ff1919>evil</color> roles in meetings to kill",
@@ -757,7 +761,7 @@
"SpeedBoosterInfoLong": "(Crewmates):\\nSpeed Booster increases a random player's movement speed every time they complete a task.",
"DoctorInfoLong": "(Crewmates):\\nThe Doctor can view players' cause of death and access their vitals as long as their battery is still operational.",
"DictatorInfoLong": "(Crewmates):\\nDictator can end the meeting by voting someone out, which will also result in their death.",
"DetectiveInfoLong": "(Crewmate):\\nAfter reporting the body, the Detective receives a clue about the victim's role. The host may reveal the murderer's role to the Detective based on the setting. Note: Detective won't be Oblivious.",
"ForensicInfoLong": "(Crewmate):\\nAfter reporting the body, the Forensic receives a clue about the victim's role. The host may reveal the murderer's role to the Forensic based on the setting. Note: Forensic won't be Oblivious.",
"UndercoverInfoLong": "(Crewmates):\\nThe Impostors knows who Undercover is and sees him as a teammate, but Undercover himself does not know who the Impostors are.",
"NiceGuesserInfoLong": "(Crewmates):\\nNice Guesser can guess a player's role during the meeting. Correct guess results in killing the target, while a wrong one leads to suicide. Use the command /bt [player id] [role] to guess. You can see player IDs before their names or use the /id command.",
"SwordsManInfoLong": "(Crewmates):\\nVigilante can kill anyone, but only once. After killing, Vigilante can do tasks. Depending on settings, Vigilante can vent.",
@@ -854,7 +858,7 @@
"TorchInfoLong": "(Add-ons):\\nOnly Crewmates will get Torch, who have increased vision and may not be affected by Lights Sabotage.",
"SeerInfoLong": "(Add-ons):\\nWhen a player dies, the Seer sees a red flash (with an alarm sound like sabotage).",
"BrakarInfoLong": "(Add-ons):\\nIn case of a tie, the target voted by the Tiebreaker has priority. However, if multiple Tiebreakers choose different targets simultaneously, their skills will not take effect.",
"ObliviousInfoLong": "(Add-ons):\\nDetective and Cleaners won't be Oblivious. Oblivious cannot report dead bodies. Note: Bait killed by Oblivious will still be reported automatically, and Oblivious can still be used as a scapegoat for Anonymous.",
"ObliviousInfoLong": "(Add-ons):\\nForensic and Cleaners won't be Oblivious. Oblivious cannot report dead bodies. Note: Bait killed by Oblivious will still be reported automatically, and Oblivious can still be used as a scapegoat for Anonymous.",
"BewilderInfoLong": "(Add-ons):\\nBewilder's vision changes killer's vision on death.",
"TruantInfoLong": "(Add-ons):\\nAfter each meeting, you freeze in place for a set amount of seconds.",
"WorkhorseInfoLong": "(Add-ons):\\nComplete all tasks to become Workhorse and get extra tasks set by the host.",
@@ -1524,10 +1528,10 @@
"CrewKillingRed": "<color=#8cffff>Crewmate</color> Killings can be red",
"PsychicCanSeeNum": "Max number of red names",
"PsychicFresh": "New red names every meeting",
"DetectiveCanknowKiller": "Can find the killer's role",
"DetectiveCanknowDeathReason": "Can find the cause of death",
"DetectiveCanknowAddons": "Can find the dead player's add-ons",
"DetectiveCanknowKillTime": "Can find how long ago the player died",
"ForensicCanknowKiller": "Can find the killer's role",
"ForensicCanknowDeathReason": "Can find the cause of death",
"ForensicCanknowAddons": "Can find the dead player's add-ons",
"ForensicCanknowKillTime": "Can find how long ago the player died",
"ParanoiaVentCooldown": "Vent Cooldown",
"ParanoiaNumOfUseButton": "Max number of portable buttons",
"EveryOneKnowSuperStar": "Everyone knows the <color=#f6f657>Super Star</color>",
@@ -2113,12 +2117,12 @@
"MafiaKillSucceed": "<b>{0}</b> was killed by the Nemesis!",
"MafiaKillDisable": "Sorry, but according to Host's settings, Nemesis revenge is prohibited in this game",
"SuperStarDead": "Shock! Super Star <b>{0}</b> has unfortunately been mercilessly killed in the recent period of time!",
"DetectiveNoticeVictim": "According to your investigation,\\nthe victim (<b>{0}</b>) had the role [{1}]",
"DetectiveNoticeKiller": "\\nThe killer's role is <b>{0}</b>",
"DetectiveNoticeKillerNotFound": "The Detective couldn't find evidence leading to a murderer, this is most likely suicide.",
"DetectiveNoticeDeathReason": "\\nThe victim's cause of death is <b>{0}</b>",
"DetectiveNoticeAddons": "\\nThe victim's add-ons are: <b>{0}</b>",
"DetectiveNoticeKillTime": "\\nThe victim died <b>{0}</b> seconds ago",
"ForensicNoticeVictim": "According to your investigation,\\nthe victim (<b>{0}</b>) had the role [{1}]",
"ForensicNoticeKiller": "\\nThe killer's role is <b>{0}</b>",
"ForensicNoticeKillerNotFound": "The Forensic couldn't find evidence leading to a murderer, this is most likely suicide.",
"ForensicNoticeDeathReason": "\\nThe victim's cause of death is <b>{0}</b>",
"ForensicNoticeAddons": "\\nThe victim's add-ons are: <b>{0}</b>",
"ForensicNoticeKillTime": "\\nThe victim died <b>{0}</b> seconds ago",
"SleuthMsg": "{0}'s role is: {1}",
"GodNoticeAlive": "During the meeting, each player felt a revelation from heaven, and it turned out that God is still alive!",
"WorkaholicAdviceAlive": "It's not recommended to kill or vote <b>{0}</b> out. Doing so will help them finish their tasks quicker.",
@@ -2934,7 +2938,7 @@
"MessageFromTheHost": "★ Host message ★",
"SayTitle": "★ Moderator message ★",
"MessageFromEAC": "★ EAC ★",
"DetectiveNoticeTitle": "★ Message for the Detective ★",
"ForensicNoticeTitle": "★ Message for the Forensic ★",
"GuessKillTitle": "★ Message about Guessing ★",
"SuperStarNewsTitle": "★ Urgent news ★",
"GodAliveTitle": "★ Message about God ★",
@@ -3022,6 +3026,8 @@
"EnterVentWinCountDown": "Enter vent within <b>{0}</b> seconds to win!",
"InvalidArgs": "Invalid Args",
"InvalidArguments": "Invalid Arguments",
"DetectiveSuspectLimit": "Suspects Per Case",
"ViperDissolveTime": "Body Dissolve Time",
"On": "Always",
"Off": "OFF",
"ColoredOn": "<color=#00fefe><b>✓</b></color>",
@@ -3123,6 +3129,9 @@
"AbilityButtonText.Impostor": "Haunt",
"AbilityButtonText.Shapeshifter": "Shift",
"AbilityButtonText.Phantom": "Vanish",
"AbilityButtonText.Viper": "Acid",
"AbilityButtonText.Detective": "Notes",
"SecondaryAbilityButtonText.Detective": "Interrogate",
"GauloisKillButtonText": "Speed Up",
"SniperSnipeButtonText": "Snipe",
"FireWorksExplosionButtonText": "Detonate",
@@ -9100,6 +9109,16 @@
"AntidoteCDOpt": "Decrease the cooldown by",
"AntidoteCDReset": "Cooldown returns to normal after a meeting",
"HackButtonText": "Mimic",
"DetectiveEHRInfo": "Gather Info, Solve Murders",
"DetectiveEHRInfoLong": "(Crewmates):\\nAs the Detective, you can write down notes about each crime scene and interrogate suspects.",
"ViperEHRInfo": "Kill to Dissolve Bodies",
"ViperEHRInfoLong": "(Impostors):\\nAs the Viper, the bodies you leave behind slowly dissolve due to your acid, making them disappear and unreportable.",
"Explosivist": "Explosivist",
"ExplosivistInfo": "Explode Time Bombs",
"ExplosivistInfoLong": "(Neutrals):\\nAs the Explosivist, you cannot kill normally. Instead, you can pet/vanish to develop a bomb and start carrying it. Others will only see the bomb itself, and you standing in place where you've started to use your ability. After a few seconds, the bomb explodes, killing everyone nearby, and you teleport back to where you started carrying the bomb.\\nKill everyone to win!",
"Explosivist.ExplosionDelay": "Explosion Delay",
"Explosivist.ExplosionRadius": "Explosion Radius",
"ExplosivistSuffix": "<size=80%>Carrying the bomb</size>\\n<#ffff00>Explodes in </color>{0}s",
"BomberCooldownsResetEachOther": "Kill Cooldown & Bomb Cooldown Reset Each Other When Used",
"BomberDiesInExplosion": "<color=#ff1919>Bomber</color> dies in their explosion",
"ImpostorsSurviveBombs": "<color=#ff1919>Impostors</color> survive bombs",
+17
View File
@@ -0,0 +1,17 @@
namespace EHR.AddOns.Crewmate;
public class Examiner : IAddon
{
public AddonTypes Type => AddonTypes.Helpful;
public static OptionItem ExaminerSuspectLimit;
public void SetupCustomOption()
{
Options.SetupAdtRoleOptions(654400, CustomRoles.Examiner, canSetNum: true);
ExaminerSuspectLimit = new FloatOptionItem(654410, "DetectiveSuspectLimit", new(1f, 30f, 1f), 4f, TabGroup.Addons)
.SetParent(Options.CustomRoleSpawnChances[CustomRoles.DetectiveEHR])
.SetValueFormat(OptionFormat.Players);
}
}
+1 -1
View File
@@ -68,7 +68,7 @@ public class Workhorse : IAddon
{
if (!pc.IsAlive() || IsThisRole(pc.PlayerId)) return false;
if (pc.Is(CustomRoles.Needy) || pc.Is(CustomRoles.Lazy) || pc.Is(CustomRoles.Bloodlust)) return false;
if (pc.GetCustomRole().GetVNRole(true) is CustomRoles.Impostor or CustomRoles.ImpostorEHR or CustomRoles.Shapeshifter or CustomRoles.ShapeshifterEHR or CustomRoles.Phantom or CustomRoles.PhantomEHR) return false;
if (pc.GetCustomRole().GetVNRole(true) is CustomRoles.Impostor or CustomRoles.ImpostorEHR or CustomRoles.Shapeshifter or CustomRoles.ShapeshifterEHR or CustomRoles.Phantom or CustomRoles.PhantomEHR or CustomRoles.Viper or CustomRoles.ViperEHR) return false;
TaskState taskState = pc.GetTaskState();
if (taskState.CompletedTasksCount + 1 < taskState.AllTasksCount) return false;
+17
View File
@@ -0,0 +1,17 @@
namespace EHR.AddOns.Impostor;
public class Venom : IAddon
{
public AddonTypes Type => AddonTypes.Helpful;
public static OptionItem VenomDissolveTime;
public void SetupCustomOption()
{
Options.SetupAdtRoleOptions(654500, CustomRoles.Venom, canSetNum: true);
VenomDissolveTime = new FloatOptionItem(654510, "ViperDissolveTime", new(0f, 60f, 0.5f), 10f, TabGroup.Addons)
.SetParent(Options.CustomRoleSpawnChances[CustomRoles.ViperEHR])
.SetValueFormat(OptionFormat.Seconds);
}
}
+2
View File
@@ -76,11 +76,13 @@ internal class Analyst : RoleBase
CustomRoles.Impostor or CustomRoles.ImpostorEHR => Utils.ColorString(Utils.GetRoleColor(CustomRoles.Impostor), GetString("Impostor")),
CustomRoles.Shapeshifter or CustomRoles.ShapeshifterEHR => Utils.ColorString(Utils.GetRoleColor(CustomRoles.Speedrunner), GetString("Shapeshifter")),
CustomRoles.Phantom or CustomRoles.PhantomEHR => Utils.ColorString(Utils.GetRoleColor(CustomRoles.Witness), GetString("Phantom")),
CustomRoles.Viper or CustomRoles.ViperEHR => Utils.ColorString(Utils.GetRoleColor(CustomRoles.Poisoner), GetString("Viper")),
CustomRoles.Crewmate or CustomRoles.CrewmateEHR => Utils.ColorString(Utils.GetRoleColor(CustomRoles.Crewmate), GetString("Crewmate")),
CustomRoles.Engineer or CustomRoles.EngineerEHR => Utils.ColorString(Utils.GetRoleColor(CustomRoles.Autocrat), GetString("Engineer")),
CustomRoles.Scientist or CustomRoles.ScientistEHR => Utils.ColorString(Utils.GetRoleColor(CustomRoles.Doctor), GetString("Scientist")),
CustomRoles.Noisemaker or CustomRoles.NoisemakerEHR => Utils.ColorString(Utils.GetRoleColor(CustomRoles.Bubble), GetString("Noisemaker")),
CustomRoles.Tracker or CustomRoles.TrackerEHR => Utils.ColorString(Utils.GetRoleColor(CustomRoles.Scout), GetString("Tracker")),
CustomRoles.Detective or CustomRoles.DetectiveEHR => Utils.ColorString(Utils.GetRoleColor(CustomRoles.Forensic), GetString("Detective")),
_ => string.Empty
}
: string.Empty;
+7
View File
@@ -14,6 +14,7 @@ internal class CrewmateVanillaRoles : IVanillaSettingHolder
public static OptionItem TrackerCooldown;
public static OptionItem TrackerDuration;
public static OptionItem TrackerDelay;
public static OptionItem DetectiveSuspectLimit;
public TabGroup Tab => TabGroup.CrewmateRoles;
public void SetupCustomOption()
@@ -65,5 +66,11 @@ internal class CrewmateVanillaRoles : IVanillaSettingHolder
TrackerDelay = new FloatOptionItem(5064, "TrackerDelay", new(1f, 250f, 1f), 5f, Tab)
.SetParent(CustomRoleSpawnChances[CustomRoles.TrackerEHR])
.SetValueFormat(OptionFormat.Seconds);
SetupRoleOptions(5080, Tab, CustomRoles.DetectiveEHR);
DetectiveSuspectLimit = new FloatOptionItem(5082, "DetectiveSuspectLimit", new(1f, 30f, 1f), 4f, Tab)
.SetParent(CustomRoleSpawnChances[CustomRoles.DetectiveEHR])
.SetValueFormat(OptionFormat.Players);
}
}
-67
View File
@@ -1,67 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace EHR.Crewmate;
internal class Detective : RoleBase
{
public static OptionItem DetectiveCanknowKiller;
public static OptionItem DetectiveCanknowDeathReason;
public static OptionItem DetectiveCanknowAddons;
public static OptionItem DetectiveCanknowKillTime;
public static Dictionary<byte, string> DetectiveNotify = [];
public override bool IsEnable => false;
public override void SetupCustomOption()
{
Options.SetupRoleOptions(6600, TabGroup.CrewmateRoles, CustomRoles.Detective);
DetectiveCanknowKiller = new BooleanOptionItem(6610, "DetectiveCanknowKiller", true, TabGroup.CrewmateRoles)
.SetParent(Options.CustomRoleSpawnChances[CustomRoles.Detective]);
DetectiveCanknowDeathReason = new BooleanOptionItem(6611, "DetectiveCanknowDeathReason", true, TabGroup.CrewmateRoles)
.SetParent(Options.CustomRoleSpawnChances[CustomRoles.Detective]);
DetectiveCanknowAddons = new BooleanOptionItem(6612, "DetectiveCanknowAddons", true, TabGroup.CrewmateRoles)
.SetParent(Options.CustomRoleSpawnChances[CustomRoles.Detective]);
DetectiveCanknowKillTime = new BooleanOptionItem(6613, "DetectiveCanknowKillTime", true, TabGroup.CrewmateRoles)
.SetParent(Options.CustomRoleSpawnChances[CustomRoles.Detective]);
}
public override void Init() { }
public override void Add(byte playerId) { }
public static void OnReportDeadBody(PlayerControl player, PlayerControl tpc)
{
string msg = string.Format(Translator.GetString("DetectiveNoticeVictim"), tpc.GetRealName(), tpc.GetCustomRole().ToColoredString());
if (DetectiveCanknowKiller.GetBool())
{
PlayerControl realKiller = tpc.GetRealKiller();
if (realKiller == null)
msg += ";" + Translator.GetString("DetectiveNoticeKillerNotFound");
else
msg += ";" + string.Format(Translator.GetString("DetectiveNoticeKiller"), realKiller.GetCustomRole().ToColoredString());
}
if (DetectiveCanknowDeathReason.GetBool()) msg += ";" + string.Format(Translator.GetString("DetectiveNoticeDeathReason"), Translator.GetString($"DeathReason.{Main.PlayerStates[tpc.PlayerId].deathReason}"));
if (DetectiveCanknowAddons.GetBool()) msg += ";" + string.Format(Translator.GetString("DetectiveNoticeAddons"), string.Join(", ", tpc.GetCustomSubRoles().Select(x => x.ToColoredString())));
if (DetectiveCanknowKillTime.GetBool())
{
DateTime deathTimeStamp = Main.PlayerStates[tpc.PlayerId].RealKiller.TimeStamp;
DateTime now = DateTime.Now;
double timeSpanSeconds = (now - deathTimeStamp).TotalSeconds;
msg += ";" + string.Format(Translator.GetString("DetectiveNoticeKillTime"), (int)timeSpanSeconds);
}
DetectiveNotify[player.PlayerId] = msg;
}
}
+1 -1
View File
@@ -128,7 +128,7 @@ public class Farseer : RoleBase
}
else
{
float range = NormalGameOptionsV09.KillDistances[Mathf.Clamp(player.Is(CustomRoles.Reach) ? 2 : Main.NormalOptions.KillDistance, 0, 2)] + 0.5f;
float range = NormalGameOptionsV10.KillDistances[Mathf.Clamp(player.Is(CustomRoles.Reach) ? 2 : Main.NormalOptions.KillDistance, 0, 2)] + 0.5f;
float dis = Vector2.Distance(player.Pos(), arTarget.Pos());
if (dis <= range)
+67
View File
@@ -0,0 +1,67 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace EHR.Crewmate;
internal class Forensic : RoleBase
{
public static OptionItem ForensicCanknowKiller;
public static OptionItem ForensicCanknowDeathReason;
public static OptionItem ForensicCanknowAddons;
public static OptionItem ForensicCanknowKillTime;
public static Dictionary<byte, string> ForensicNotify = [];
public override bool IsEnable => false;
public override void SetupCustomOption()
{
Options.SetupRoleOptions(6600, TabGroup.CrewmateRoles, CustomRoles.Forensic);
ForensicCanknowKiller = new BooleanOptionItem(6610, "ForensicCanknowKiller", true, TabGroup.CrewmateRoles)
.SetParent(Options.CustomRoleSpawnChances[CustomRoles.Forensic]);
ForensicCanknowDeathReason = new BooleanOptionItem(6611, "ForensicCanknowDeathReason", true, TabGroup.CrewmateRoles)
.SetParent(Options.CustomRoleSpawnChances[CustomRoles.Forensic]);
ForensicCanknowAddons = new BooleanOptionItem(6612, "ForensicCanknowAddons", true, TabGroup.CrewmateRoles)
.SetParent(Options.CustomRoleSpawnChances[CustomRoles.Forensic]);
ForensicCanknowKillTime = new BooleanOptionItem(6613, "ForensicCanknowKillTime", true, TabGroup.CrewmateRoles)
.SetParent(Options.CustomRoleSpawnChances[CustomRoles.Forensic]);
}
public override void Init() { }
public override void Add(byte playerId) { }
public static void OnReportDeadBody(PlayerControl player, PlayerControl tpc)
{
string msg = string.Format(Translator.GetString("ForensicNoticeVictim"), tpc.GetRealName(), tpc.GetCustomRole().ToColoredString());
if (ForensicCanknowKiller.GetBool())
{
PlayerControl realKiller = tpc.GetRealKiller();
if (realKiller == null)
msg += ";" + Translator.GetString("ForensicNoticeKillerNotFound");
else
msg += ";" + string.Format(Translator.GetString("ForensicNoticeKiller"), realKiller.GetCustomRole().ToColoredString());
}
if (ForensicCanknowDeathReason.GetBool()) msg += ";" + string.Format(Translator.GetString("ForensicNoticeDeathReason"), Translator.GetString($"DeathReason.{Main.PlayerStates[tpc.PlayerId].deathReason}"));
if (ForensicCanknowAddons.GetBool()) msg += ";" + string.Format(Translator.GetString("ForensicNoticeAddons"), string.Join(", ", tpc.GetCustomSubRoles().Select(x => x.ToColoredString())));
if (ForensicCanknowKillTime.GetBool())
{
DateTime deathTimeStamp = Main.PlayerStates[tpc.PlayerId].RealKiller.TimeStamp;
DateTime now = DateTime.Now;
double timeSpanSeconds = (now - deathTimeStamp).TotalSeconds;
msg += ";" + string.Format(Translator.GetString("ForensicNoticeKillTime"), (int)timeSpanSeconds);
}
ForensicNotify[player.PlayerId] = msg;
}
}
+2 -2
View File
@@ -18,7 +18,7 @@ public class Scout : RoleBase
private static OptionItem OptionCanSeeLastRoomInMeeting;
private static OptionItem CanGetColoredArrow;
public static OptionItem HideVote;
public static OptionItem TrackerAbilityUseGainWithEachTaskCompleted;
public static OptionItem ScoutAbilityUseGainWithEachTaskCompleted;
public static OptionItem AbilityChargesWhenFinishedTasks;
public static OptionItem CancelVote;
@@ -48,7 +48,7 @@ public class Scout : RoleBase
HideVote = new BooleanOptionItem(Id + 8, "TrackerHideVote", false, TabGroup.CrewmateRoles)
.SetParent(CustomRoleSpawnChances[CustomRoles.Scout]);
TrackerAbilityUseGainWithEachTaskCompleted = new FloatOptionItem(Id + 9, "AbilityUseGainWithEachTaskCompleted", new(0f, 5f, 0.05f), 1f, TabGroup.CrewmateRoles)
ScoutAbilityUseGainWithEachTaskCompleted = new FloatOptionItem(Id + 9, "AbilityUseGainWithEachTaskCompleted", new(0f, 5f, 0.05f), 1f, TabGroup.CrewmateRoles)
.SetParent(CustomRoleSpawnChances[CustomRoles.Scout])
.SetValueFormat(OptionFormat.Times);
+1 -1
View File
@@ -191,7 +191,7 @@ public class Deathpact : RoleBase
foreach (PlayerControl player in dp.PlayersInDeathpact)
{
float range = NormalGameOptionsV09.KillDistances[Mathf.Clamp(player.Is(CustomRoles.Reach) ? 2 : Main.NormalOptions.KillDistance, 0, 2)] + 0.5f;
float range = NormalGameOptionsV10.KillDistances[Mathf.Clamp(player.Is(CustomRoles.Reach) ? 2 : Main.NormalOptions.KillDistance, 0, 2)] + 0.5f;
cancelDeathpact = dp.PlayersInDeathpact.Where(a => a.PlayerId != player.PlayerId).Select(otherPlayerInPact => Vector2.Distance(player.Pos(), otherPlayerInPact.Pos())).Aggregate(cancelDeathpact, (current, dis) => current && dis <= range);
}
+7
View File
@@ -8,6 +8,7 @@ internal class ImpostorVanillaRoles : IVanillaSettingHolder
public static OptionItem PhantomDuration;
public static OptionItem ShapeshiftCD;
public static OptionItem ShapeshiftDur;
public static OptionItem ViperDissolveTime;
public TabGroup Tab => TabGroup.ImpostorRoles;
public void SetupCustomOption()
@@ -32,5 +33,11 @@ internal class ImpostorVanillaRoles : IVanillaSettingHolder
ShapeshiftDur = new FloatOptionItem(403, "ShapeshiftDuration", new(1f, 60f, 1f), 10f, Tab)
.SetParent(CustomRoleSpawnChances[CustomRoles.ShapeshifterEHR])
.SetValueFormat(OptionFormat.Seconds);
SetupRoleOptions(410, Tab, CustomRoles.ViperEHR);
ViperDissolveTime = new FloatOptionItem(412, "ViperDissolveTime", new(0f, 60f, 0.5f), 10f, Tab)
.SetParent(CustomRoleSpawnChances[CustomRoles.ViperEHR])
.SetValueFormat(OptionFormat.Seconds);
}
}
+1 -1
View File
@@ -35,7 +35,7 @@ public class Psychopath : RoleBase
{
if (!GameStates.IsInTask || ExileController.Instance || AntiBlackout.SkipTasks || Main.KillTimers[pc.PlayerId] > 0f || Count++ < 10) return;
var pos = pc.Pos();
var killRange = NormalGameOptionsV09.KillDistances[Mathf.Clamp(Main.NormalOptions.KillDistance, 0, 2)];
var killRange = NormalGameOptionsV10.KillDistances[Mathf.Clamp(Main.NormalOptions.KillDistance, 0, 2)];
var closestPlayer = Main.AllAlivePlayerControls.Select(x => (pc: x, distance: Vector2.Distance(x.Pos(), pos))).Where(x => x.distance <= killRange).MinBy(x => x.distance).pc;
if (closestPlayer == null) return;
Count = 0;
+1 -1
View File
@@ -202,7 +202,7 @@ internal class Puppeteer : RoleBase
{
KeyValuePair<byte, float> min = targetDistance.OrderBy(c => c.Value).FirstOrDefault();
PlayerControl target = Utils.GetPlayerById(min.Key);
float killRange = NormalGameOptionsV09.KillDistances[Mathf.Clamp(Main.NormalOptions.KillDistance, 0, 2)];
float killRange = NormalGameOptionsV10.KillDistances[Mathf.Clamp(Main.NormalOptions.KillDistance, 0, 2)];
if (min.Value <= killRange && player.CanMove && target.CanMove)
{
+1 -1
View File
@@ -199,7 +199,7 @@ public class Agitater : RoleBase
{
KeyValuePair<byte, float> min = targetDistance.OrderBy(c => c.Value).FirstOrDefault();
PlayerControl target = Utils.GetPlayerById(min.Key);
float KillRange = NormalGameOptionsV09.KillDistances[Mathf.Clamp(GameOptionsManager.Instance.currentNormalGameOptions.KillDistance, 0, 2)];
float KillRange = NormalGameOptionsV10.KillDistances[Mathf.Clamp(GameOptionsManager.Instance.currentNormalGameOptions.KillDistance, 0, 2)];
if (min.Value <= KillRange && player.CanMove && target.CanMove) PassBomb(player, target);
}
}
+1 -1
View File
@@ -201,7 +201,7 @@ internal class Arsonist : RoleBase
}
else
{
float range = NormalGameOptionsV09.KillDistances[Mathf.Clamp(player.Is(CustomRoles.Reach) ? 2 : Main.NormalOptions.KillDistance, 0, 2)] + 0.5f;
float range = NormalGameOptionsV10.KillDistances[Mathf.Clamp(player.Is(CustomRoles.Reach) ? 2 : Main.NormalOptions.KillDistance, 0, 2)] + 0.5f;
float dis = Vector2.Distance(player.Pos(), arTarget.Pos());
if (dis <= range)
+166
View File
@@ -0,0 +1,166 @@
using System.Linq;
using AmongUs.GameOptions;
using Hazel;
namespace EHR.Neutral;
public class Explosivist : RoleBase
{
public static bool On;
public static OptionItem AbilityCooldown;
private static OptionItem ImpostorVision;
public static OptionItem ExplosionDelay;
private static OptionItem ExplosionRadius;
public override bool IsEnable => On;
private TNT Explosive;
private Vector2 RealPosition;
private long ExplodeTS;
private byte ExplosivistId;
public override void SetupCustomOption()
{
StartSetup(654300)
.AutoSetupOption(ref AbilityCooldown, 22.5f, new FloatValueRule(0f, 180f, 0.5f), OptionFormat.Seconds)
.AutoSetupOption(ref ImpostorVision, true)
.AutoSetupOption(ref ExplosionDelay, 10, new IntegerValueRule(1, 60, 1), OptionFormat.Seconds)
.AutoSetupOption(ref ExplosionRadius, 4f, new FloatValueRule(0.25f, 10f, 0.25f), OptionFormat.Multiplier);
}
public override void Init()
{
On = false;
}
public override void Add(byte playerId)
{
On = true;
Explosive = null;
RealPosition = Vector2.zero;
ExplodeTS = 0;
ExplosivistId = playerId;
}
public override void SetKillCooldown(byte id)
{
Main.AllPlayerKillCooldown[id] = AbilityCooldown.GetFloat();
}
public override void ApplyGameOptions(IGameOptions opt, byte id)
{
opt.SetVision(ImpostorVision.GetBool());
if (Options.UsePhantomBasis.GetBool() && Options.UsePhantomBasisForNKs.GetBool())
{
AURoleOptions.PhantomCooldown = AbilityCooldown.GetFloat();
AURoleOptions.PhantomDuration = 1f;
}
}
public override bool CanUseKillButton(PlayerControl pc)
{
return false;
}
public override bool OnVanish(PlayerControl pc)
{
UseAbility(pc);
return false;
}
public override void OnPet(PlayerControl pc)
{
UseAbility(pc);
}
void UseAbility(PlayerControl player)
{
if (Explosive != null) return;
Vector2 pos = player.Pos();
Explosive = new TNT(pos);
RealPosition = pos;
// From https://github.com/Rabek009/MoreGamemodes/blob/master/Roles/Impostor/Concealing/Droner.cs
foreach (var pc in PlayerControl.AllPlayerControls)
{
if (pc == player || pc.AmOwner) continue;
CustomRpcSender sender = CustomRpcSender.Create("Explosivist", SendOption.Reliable);
sender.StartMessage(pc.GetClientId());
sender.StartRpc(player.NetTransform.NetId, (byte)RpcCalls.SnapTo)
.WriteVector2(player.transform.position)
.Write(player.NetTransform.lastSequenceId)
.EndRpc();
sender.StartRpc(player.NetTransform.NetId, (byte)RpcCalls.SnapTo)
.WriteVector2(player.transform.position)
.Write((ushort)(player.NetTransform.lastSequenceId + 16383))
.EndRpc();
sender.EndMessage();
sender.SendMessage();
Utils.NumSnapToCallsThisRound += 2;
}
if (player.AmOwner) player.Visible = false;
ExplodeTS = Utils.TimeStamp + ExplosionDelay.GetInt();
}
public override void OnFixedUpdate(PlayerControl pc)
{
if (!GameStates.IsInTask || ExileController.Instance || AntiBlackout.SkipTasks) return;
Explosive?.TP(pc.transform.position);
if (Explosive != null && ExplodeTS >= Utils.TimeStamp)
{
Utils.GetPlayersInRadius(ExplosionRadius.GetFloat(), Explosive.Position).Without(pc).Do(x => x.Suicide(PlayerState.DeathReason.Bombed, pc));
RevertFreeze(pc);
if (!Options.UsePets.GetBool()) pc.RpcResetAbilityCooldown();
Explosive.Despawn();
Explosive = null;
RealPosition = Vector2.zero;
ExplodeTS = 0;
}
}
public override void OnReportDeadBody()
{
if (Explosive != null)
{
PlayerControl pc = ExplosivistId.GetPlayer();
RevertFreeze(pc);
}
}
private void RevertFreeze(PlayerControl pc)
{
if (pc.AmOwner) pc.Visible = true;
pc.NetTransform.SnapTo(RealPosition, (ushort)(pc.NetTransform.lastSequenceId + 128));
CustomRpcSender sender = CustomRpcSender.Create("Explosivist Revert", SendOption.Reliable);
sender.StartMessage();
sender.StartRpc(pc.NetTransform.NetId, (byte)RpcCalls.SnapTo)
.WriteVector2(pc.transform.position)
.Write((ushort)(pc.NetTransform.lastSequenceId + 32767))
.EndRpc();
sender.StartRpc(pc.NetTransform.NetId, (byte)RpcCalls.SnapTo)
.WriteVector2(pc.transform.position)
.Write((ushort)(pc.NetTransform.lastSequenceId + 32767 + 16383))
.EndRpc();
sender.StartRpc(pc.NetTransform.NetId, (byte)RpcCalls.SnapTo)
.WriteVector2(pc.transform.position)
.Write(pc.NetTransform.lastSequenceId)
.EndRpc();
sender.EndMessage();
sender.SendMessage();
}
public override string GetSuffix(PlayerControl seer, PlayerControl target, bool hud = false, bool meeting = false)
{
if (seer.PlayerId != ExplosivistId || seer.PlayerId != target.PlayerId || (seer.IsModdedClient() && !hud) || meeting || ExplodeTS == 0) return string.Empty;
return string.Format(Translator.GetString("ExplosivistSuffix"), ExplodeTS - Utils.TimeStamp);
}
}
+1 -1
View File
@@ -176,7 +176,7 @@ internal class Revolutionist : RoleBase
}
else
{
float range = NormalGameOptionsV09.KillDistances[Mathf.Clamp(player.Is(CustomRoles.Reach) ? 2 : Main.NormalOptions.KillDistance, 0, 2)] + 0.5f;
float range = NormalGameOptionsV10.KillDistances[Mathf.Clamp(player.Is(CustomRoles.Reach) ? 2 : Main.NormalOptions.KillDistance, 0, 2)] + 0.5f;
float dis = Vector2.Distance(player.Pos(), rvTarget.Pos());
if (dis <= range)
+1 -1
View File
@@ -114,7 +114,7 @@ internal class Samurai : RoleBase
PlayerControl target = Utils.GetPlayerById(Target.Id);
if (target == null) return;
if (Vector2.Distance(target.Pos(), pc.Pos()) > NormalGameOptionsV09.KillDistances[Mathf.Clamp(pc.Is(CustomRoles.Reach) ? 2 : Main.NormalOptions.KillDistance, 0, 2)] + 0.5f)
if (Vector2.Distance(target.Pos(), pc.Pos()) > NormalGameOptionsV10.KillDistances[Mathf.Clamp(pc.Is(CustomRoles.Reach) ? 2 : Main.NormalOptions.KillDistance, 0, 2)] + 0.5f)
{
Target = (byte.MaxValue, 0);
pc.RpcCheckAndMurder(target);