ban-and-rename

This commit is contained in:
HyperAtill committed 2025-09-23 17:00:34 +03:00
1 parent e3752dac69
commit 6397b9846b
13 files changed
+375 -374

No files matched your search

+1 -1
View File
@@ -218,7 +218,7 @@ public enum CustomRoles
Marshall,
Mathematician,
Mayor,
SabotageMaster, // Mechanic
Mechanic,
Medic,
Mediumshiper,
Merchant,
+1 -1
View File
@@ -371,7 +371,7 @@ public class Main : BasePlugin
{ CustomRoles.DoubleAgent, "#ff1919" },
{ CustomRoles.Luckey, "#b8d7a3" },
{ CustomRoles.Needy, "#a4dffe" },
{ CustomRoles.SabotageMaster, "#3333ff" },
{ CustomRoles.Mechanic, "#3333ff" },
{ CustomRoles.Snitch, "#b8fb4f" },
{ CustomRoles.Marshall, "#5573aa" },
{ CustomRoles.Mayor, "#204d42" },
+4 -4
View File
@@ -124,7 +124,7 @@ internal static class CustomRolesHelper
CustomRoles.Snitch => CustomRoles.Crewmate,
CustomRoles.ParityCop => CustomRoles.Crewmate,
CustomRoles.Marshall => CustomRoles.Crewmate,
CustomRoles.SabotageMaster => SabotageMaster.CanVent.GetBool() ? CustomRoles.Engineer : CustomRoles.Crewmate,
CustomRoles.Mechanic => Mechanic.CanVent.GetBool() ? CustomRoles.Engineer : CustomRoles.Crewmate,
CustomRoles.Mafia => Options.LegacyMafia.GetBool() ? CustomRoles.Shapeshifter : CustomRoles.Impostor,
CustomRoles.Terrorist => CustomRoles.Engineer,
CustomRoles.Executioner => CustomRoles.Crewmate,
@@ -1096,7 +1096,7 @@ internal static class CustomRolesHelper
CustomRoles.BananaMan when pc.Is(CustomRoles.Disco) || pc.Is(CustomRoles.Doppelganger) => false,
CustomRoles.Disco when pc.GetCustomRole() is CustomRoles.Chameleon or CustomRoles.Swooper or CustomRoles.Wraith or CustomRoles.Alchemist or CustomRoles.Doppelganger => false,
CustomRoles.Egoist when pc.Is(CustomRoles.Gangster) => false,
CustomRoles.Nimble when pc.GetCustomRole() is CustomRoles.Oxyman or CustomRoles.EngineerEHR or CustomRoles.SabotageMaster => false,
CustomRoles.Nimble when pc.GetCustomRole() is CustomRoles.Oxyman or CustomRoles.EngineerEHR or CustomRoles.Mechanic => false,
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,
@@ -1194,7 +1194,7 @@ internal static class CustomRolesHelper
CustomRoles.Unlucky when pc.Is(CustomRoles.Luckey) => false,
CustomRoles.Unlucky when pc.Is(CustomRoles.Lucky) => false,
CustomRoles.Lucky when pc.Is(CustomRoles.Unlucky) => false,
CustomRoles.Fool when pc.GetCustomRole() is CustomRoles.SabotageMaster or CustomRoles.GuardianAngelEHR or CustomRoles.Technician => false,
CustomRoles.Fool when pc.GetCustomRole() is CustomRoles.Mechanic or CustomRoles.GuardianAngelEHR or CustomRoles.Technician => false,
CustomRoles.Bloodhound when pc.Is(CustomRoles.Oblivious) => false,
CustomRoles.DoubleShot when pc.GetCustomRole() is not CustomRoles.EvilGuesser and not CustomRoles.NiceGuesser and not CustomRoles.Augur && !Options.GuesserMode.GetBool() => false,
CustomRoles.DoubleShot when !pc.Is(CustomRoles.Guesser) && !pc.Is(CustomRoles.EvilGuesser) && pc.Is(CustomRoleTypes.Impostor) && !Options.ImpostorsCanGuess.GetBool() => false,
@@ -1807,7 +1807,7 @@ internal static class CustomRolesHelper
CustomRoles.Helper => RoleOptionType.Crewmate_Support,
CustomRoles.Jailor => RoleOptionType.Crewmate_Support,
CustomRoles.Mathematician => RoleOptionType.Crewmate_Support,
CustomRoles.SabotageMaster => RoleOptionType.Crewmate_Support,
CustomRoles.Mechanic => RoleOptionType.Crewmate_Support,
CustomRoles.Medic => RoleOptionType.Crewmate_Support,
CustomRoles.Merchant => RoleOptionType.Crewmate_Support,
CustomRoles.Monarch => RoleOptionType.Crewmate_Support,
+3 -3
View File
@@ -474,10 +474,10 @@ public class TaskState
{
switch (player.GetCustomRole())
{
case CustomRoles.SabotageMaster:
if (Main.PlayerStates[player.PlayerId].Role is not SabotageMaster sm) break;
case CustomRoles.Mechanic:
if (Main.PlayerStates[player.PlayerId].Role is not Mechanic sm) break;
sm.UsedSkillCount -= SabotageMaster.SmAbilityUseGainWithEachTaskCompleted.GetFloat();
sm.UsedSkillCount -= Mechanic.MechanicAbilityUseGainWithEachTaskCompleted.GetFloat();
sm.SendRPC();
break;
case CustomRoles.Hacker:
+3 -3
View File
@@ -102,7 +102,7 @@ public enum CustomRPC
SetWeaponMasterMode,
SyncGlitchTimers,
SyncSpy,
SetSabotageMasterLimit,
SetMechanicLimit,
SetHackerLimit,
SetCurrentDrawTarget,
SetCpTasksDone,
@@ -875,9 +875,9 @@ internal static class RPCHandlerPatch
Druid.ReceiveRPCAddTrigger(reader);
break;
}
case CustomRPC.SetSabotageMasterLimit:
case CustomRPC.SetMechanicLimit:
{
SabotageMaster.ReceiveRPC(reader);
Mechanic.ReceiveRPC(reader);
break;
}
case CustomRPC.SetHackerLimit:
+1 -1
View File
@@ -634,7 +634,7 @@ internal static class BeginCrewmatePatch
=> FastDestroyableSingleton<HudManager>.Instance.TaskUpdateSound,
CustomRoles.Inhibitor or
CustomRoles.SabotageMaster or
CustomRoles.Mechanic or
CustomRoles.Saboteur or
CustomRoles.SecurityGuard or
CustomRoles.Provocateur
+2 -2
View File
@@ -2072,9 +2072,9 @@ internal static class FixedUpdatePatch
{
if (Main.HasJustStarted || !player.IsAlive()) return;
if (Main.PlayerStates[player.PlayerId].Role is SabotageMaster sm)
if (Main.PlayerStates[player.PlayerId].Role is Mechanic sm)
{
sm.UsedSkillCount -= SabotageMaster.AbilityChargesWhenFinishedTasks.GetFloat();
sm.UsedSkillCount -= Mechanic.AbilityChargesWhenFinishedTasks.GetFloat();
sm.SendRPC();
}
else
+5 -5
View File
@@ -98,8 +98,8 @@ internal static class RepairSystemPatch
switch (player.GetCustomRole())
{
case CustomRoles.SabotageMaster:
SabotageMaster.RepairSystem(player.PlayerId, systemType, amount);
case CustomRoles.Mechanic:
Mechanic.RepairSystem(player.PlayerId, systemType, amount);
Utils.NotifyRoles(SpecifySeer: player, SpecifyTarget: player);
break;
case CustomRoles.Alchemist when systemType != SystemTypes.Electrical && Main.PlayerStates[player.PlayerId].Role is Alchemist { IsEnable: true, FixNextSabo: true }:
@@ -134,10 +134,10 @@ internal static class RepairSystemPatch
{
switch (Main.PlayerStates[player.PlayerId].Role)
{
case SabotageMaster:
case Mechanic:
{
Logger.Info($"{player.GetNameWithRole().RemoveHtmlTags()} instant-fix-lights", "SabotageMaster");
SabotageMaster.SwitchSystemRepair(player.PlayerId, switchSystem, amount);
Logger.Info($"{player.GetNameWithRole().RemoveHtmlTags()} instant-fix-lights", "Mechanic");
Mechanic.SwitchSystemRepair(player.PlayerId, switchSystem, amount);
Utils.NotifyRoles(SpecifySeer: player, SpecifyTarget: player);
break;
}
+1
View File
@@ -125,6 +125,7 @@ tidytrice#2024,Alisa?(either this or above one)
Foamcrisp#5124, e5be77e02, Barbie (aka princess, broadbarn alt)
rosefiscal#4338, Bagelz (suspected alt of broadbarn or tidytrice)
driedbreak#2568, 2f9986d9f, ASHHHOLE (toxic)
markedfee#5991, 10e7b3318, (name-not-known)(toxic)
## Racist/Homophobic
onwardhome#3591, MentoMan
+13 -13
View File
@@ -245,7 +245,7 @@
"Mayor": "Mayor",
"Paranoia": "Paranoid",
"Psychic": "Psychic",
"SabotageMaster": "Mechanic",
"Mechanic": "Mechanic",
"Sheriff": "Sheriff",
"CopyCat": "Copycat",
"Snitch": "Snitch",
@@ -524,7 +524,7 @@
"MayorInfo": "Your vote counts multiple times",
"ParanoiaInfo": "You have a portable meeting button",
"PsychicInfo": "One of the red names is <color=#ff1919>evil</color>",
"SabotageMasterInfo": "Vent and fix sabotages quickly",
"MechanicInfo": "Vent and fix sabotages quickly",
"SheriffInfo": "Kill <color=#ff1919>evil</color> players",
"CopyCatInfo": "Use kill button to copy target's role",
"SnitchInfo": "Finish your tasks to find the <color=#ff1919>Impostors</color>",
@@ -754,7 +754,7 @@
"MayorInfoLong": "(Crewmates):\\nMayor's vote counts as multiple votes and may have the ability to trigger an emergency meeting.",
"ParanoiaInfoLong": "(Crewmates):\\nParanoid can call a meeting by venting/petting. The report animation will show a dead body with Paranoid's color, but the Paranoid is not dead.",
"PsychicInfoLong": "(Crewmates):\\nThe Psychic sees red highlighted names during the meeting, indicating at least one evil player. All Neutrals and Killing Crewmates are displayed as red names when the Psychic becomes a Madmate.",
"SabotageMasterInfoLong": "(Crewmates):\\nMechanic can use vent anytime. Can fix Reactors, O2, and Comms using one side. Lights fixed with one switch. Opening one door opens all doors.",
"MechanicInfoLong": "(Crewmates):\\nMechanic can use vent anytime. Can fix Reactors, O2, and Comms using one side. Lights fixed with one switch. Opening one door opens all doors.",
"SheriffInfoLong": "(Crewmates):\\nSheriff has no tasks and can kill the Impostor (maybe also neutrals). If the Sheriff tries to kill a crewmate, they will suicide. They may be able to kill anyone as a madmate.",
"SnitchInfoLong": "(Crewmates):\\nAs the Snitch completes tasks, Impostors' names are displayed in red during meetings. When the Snitch has only one task left, the Snitch and Impostors are marked with a star. If the Snitch becomes a Madmate, the star turns red.",
"MarshallInfoLong": "(Crewmates):\\nAs the Marshall, complete your tasks to reveal yourself to the rest of the crew. Settings determine which teams can see you.",
@@ -1398,17 +1398,17 @@
"KillCooldownNormally": "Kill Cooldown Without Sabotage",
"MareHasIncreasedSpeed": "Increased Speed During Lights Sabotage",
"MareSpeedDuringLightsOut": "Speed During Lights Sabotage",
"SabotageMasterSkillLimit": "Max use of Abilities (Excluding Doors)",
"MechanicSkillLimit": "Max use of Abilities (Excluding Doors)",
"LuckeyProbability": "Probability of surviving a kill",
"SabotageMasterFixesDoors": "Can open all doors in the same building",
"SabotageMasterFixesReactors": "Can Fix Both Reactors Alone",
"SabotageMasterFixesOxygens": "Can Fix Both O2 Alone",
"SabotageMasterFixesCommunications": "Can Fix Both Comms Alone In <color=#e84b56>MIRA HQ</color>",
"SabotageMasterFixesElectrical": "Can Fix Lights With One Switch",
"SMUsesUsedWhenFixingReactorOrO2": "Uses it takes to fix Reactor/O2",
"SMUsesUsedWhenFixingLightsOrComms": "Uses it takes to fix Lights/Comms",
"SMCanFixSabotageFromAnywhereWithPet": "Can Fix Sabotages From Anywhere If Pets Are On",
"SMMaxFixedViaPet": "Max Sabotages Fixed Via Pet",
"MechanicFixesDoors": "Can open all doors in the same building",
"MechanicFixesReactors": "Can Fix Both Reactors Alone",
"MechanicFixesOxygens": "Can Fix Both O2 Alone",
"MechanicFixesCommunications": "Can Fix Both Comms Alone In <color=#e84b56>MIRA HQ</color>",
"MechanicFixesElectrical": "Can Fix Lights With One Switch",
"MechanicUsesUsedWhenFixingReactorOrO2": "Uses it takes to fix Reactor/O2",
"MechanicUsesUsedWhenFixingLightsOrComms": "Uses it takes to fix Lights/Comms",
"MechanicCanFixSabotageFromAnywhereWithPet": "Can Fix Sabotages From Anywhere If Pets Are On",
"MechanicMaxFixedViaPet": "Max Sabotages Fixed Via Pet",
"SheriffCanKill%role%": "Can Kill %role%",
"SheriffCanKillNeutrals": "Can Kill <color=#ffab1b>Neutrals</color>",
"SheriffCanKillNeutralsMode": "<color=#ffab1b>Neutral</color> Configuration",
@@ -1,336 +1,336 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using AmongUs.GameOptions;
using EHR.Modules;
using Hazel;
namespace EHR.Crewmate;
public class SabotageMaster : RoleBase
{
private const int Id = 7000;
private static List<byte> PlayerIdList = [];
private static OptionItem SkillLimit;
private static OptionItem FixesDoors;
private static OptionItem FixesReactors;
private static OptionItem FixesOxygens;
private static OptionItem FixesComms;
private static OptionItem FixesElectrical;
public static OptionItem SmAbilityUseGainWithEachTaskCompleted;
public static OptionItem AbilityChargesWhenFinishedTasks;
private static OptionItem UsesUsedWhenFixingReactorOrO2;
private static OptionItem UsesUsedWhenFixingLightsOrComms;
private static OptionItem CanFixSabotageFromAnywhereWithPet;
private static OptionItem MaxFixedViaPet;
public static OptionItem CanVent;
private static OptionItem VentCooldown;
private static OptionItem MaxInVentTime;
private static bool DoorsProgressing;
private bool fixedSabotage;
private int PetLimit;
private byte SMId;
public float UsedSkillCount;
public override bool IsEnable => PlayerIdList.Count > 0;
public override void SetupCustomOption()
{
Options.SetupRoleOptions(Id, TabGroup.CrewmateRoles, CustomRoles.SabotageMaster);
SkillLimit = new IntegerOptionItem(Id + 10, "SabotageMasterSkillLimit", new(0, 80, 1), 2, TabGroup.CrewmateRoles)
.SetParent(Options.CustomRoleSpawnChances[CustomRoles.SabotageMaster])
.SetValueFormat(OptionFormat.Times);
FixesDoors = new BooleanOptionItem(Id + 11, "SabotageMasterFixesDoors", true, TabGroup.CrewmateRoles)
.SetParent(Options.CustomRoleSpawnChances[CustomRoles.SabotageMaster]);
FixesReactors = new BooleanOptionItem(Id + 12, "SabotageMasterFixesReactors", true, TabGroup.CrewmateRoles)
.SetParent(Options.CustomRoleSpawnChances[CustomRoles.SabotageMaster]);
FixesOxygens = new BooleanOptionItem(Id + 13, "SabotageMasterFixesOxygens", true, TabGroup.CrewmateRoles)
.SetParent(Options.CustomRoleSpawnChances[CustomRoles.SabotageMaster]);
FixesComms = new BooleanOptionItem(Id + 14, "SabotageMasterFixesCommunications", true, TabGroup.CrewmateRoles)
.SetParent(Options.CustomRoleSpawnChances[CustomRoles.SabotageMaster]);
FixesElectrical = new BooleanOptionItem(Id + 15, "SabotageMasterFixesElectrical", true, TabGroup.CrewmateRoles)
.SetParent(Options.CustomRoleSpawnChances[CustomRoles.SabotageMaster]);
SmAbilityUseGainWithEachTaskCompleted = new FloatOptionItem(Id + 16, "AbilityUseGainWithEachTaskCompleted", new(0f, 5f, 0.05f), 3f, TabGroup.CrewmateRoles)
.SetParent(Options.CustomRoleSpawnChances[CustomRoles.SabotageMaster])
.SetValueFormat(OptionFormat.Times);
AbilityChargesWhenFinishedTasks = new FloatOptionItem(Id + 19, "AbilityChargesWhenFinishedTasks", new(0f, 5f, 0.05f), 0.2f, TabGroup.CrewmateRoles)
.SetParent(Options.CustomRoleSpawnChances[CustomRoles.SabotageMaster])
.SetValueFormat(OptionFormat.Times);
UsesUsedWhenFixingReactorOrO2 = new FloatOptionItem(Id + 17, "SMUsesUsedWhenFixingReactorOrO2", new(0f, 5f, 0.1f), 4f, TabGroup.CrewmateRoles)
.SetParent(Options.CustomRoleSpawnChances[CustomRoles.SabotageMaster])
.SetValueFormat(OptionFormat.Times);
UsesUsedWhenFixingLightsOrComms = new FloatOptionItem(Id + 18, "SMUsesUsedWhenFixingLightsOrComms", new(0f, 5f, 0.1f), 1f, TabGroup.CrewmateRoles)
.SetParent(Options.CustomRoleSpawnChances[CustomRoles.SabotageMaster])
.SetValueFormat(OptionFormat.Times);
CanFixSabotageFromAnywhereWithPet = new BooleanOptionItem(Id + 20, "SMCanFixSabotageFromAnywhereWithPet", true, TabGroup.CrewmateRoles)
.SetParent(Options.CustomRoleSpawnChances[CustomRoles.SabotageMaster]);
MaxFixedViaPet = new IntegerOptionItem(Id + 21, "SMMaxFixedViaPet", new(1, 30, 1), 1, TabGroup.CrewmateRoles)
.SetParent(CanFixSabotageFromAnywhereWithPet);
CanVent = new BooleanOptionItem(Id + 22, "CanVent", true, TabGroup.CrewmateRoles)
.SetParent(Options.CustomRoleSpawnChances[CustomRoles.SabotageMaster]);
VentCooldown = new FloatOptionItem(Id + 23, "VentCooldown", new(0f, 60f, 0.5f), 0f, TabGroup.CrewmateRoles)
.SetParent(CanVent)
.SetValueFormat(OptionFormat.Seconds);
MaxInVentTime = new FloatOptionItem(Id + 24, "MaxInVentTime", new(0f, 60f, 0.5f), 0f, TabGroup.CrewmateRoles)
.SetParent(CanVent)
.SetValueFormat(OptionFormat.Seconds);
}
public override void Init()
{
PlayerIdList = [];
UsedSkillCount = 0;
SMId = byte.MaxValue;
}
public override void Add(byte playerId)
{
PlayerIdList.Add(playerId);
PetLimit = MaxFixedViaPet.GetInt();
UsedSkillCount = 0;
SMId = playerId;
}
public override void Remove(byte playerId)
{
PlayerIdList.Remove(playerId);
}
public override void ApplyGameOptions(IGameOptions opt, byte playerId)
{
if (!CanVent.GetBool()) return;
AURoleOptions.EngineerCooldown = VentCooldown.GetFloat();
AURoleOptions.EngineerInVentMaxTime = MaxInVentTime.GetFloat();
}
public override string GetProgressText(byte playerId, bool comms)
{
double limit = Math.Round(SkillLimit.GetInt() - UsedSkillCount, 1);
string colored = Utils.ColorString(Utils.GetRoleColor(CustomRoles.SabotageMaster).ShadeColor(0.25f), limit.ToString(CultureInfo.CurrentCulture));
return $"({colored}){base.GetProgressText(playerId, comms)}";
}
public override void OnPet(PlayerControl pc)
{
SystemTypes[] systemTypes = [SystemTypes.Electrical, SystemTypes.Reactor, SystemTypes.Laboratory, SystemTypes.LifeSupp, SystemTypes.HeliSabotage, SystemTypes.Comms];
if (!CanFixSabotageFromAnywhereWithPet.GetBool() || !systemTypes.FindFirst(Utils.IsActive, out SystemTypes activeSystem) || PetLimit-- < 1) return;
switch (activeSystem)
{
case SystemTypes.Electrical:
var switchSystem = ShipStatus.Instance.Systems[SystemTypes.Electrical].CastFast<SwitchSystem>();
if (switchSystem == null) break;
switchSystem.ActualSwitches = switchSystem.ExpectedSwitches;
switchSystem.IsDirty = true;
break;
case SystemTypes.Reactor:
case SystemTypes.Laboratory:
case SystemTypes.LifeSupp:
ShipStatus.Instance.UpdateSystem(activeSystem, pc, 16);
break;
case SystemTypes.HeliSabotage:
ShipStatus.Instance.UpdateSystem(activeSystem, pc, 17);
goto case SystemTypes.Reactor;
case SystemTypes.Comms:
if (Main.NormalOptions.MapId is 1 or 5) ShipStatus.Instance.UpdateSystem(activeSystem, pc, 17);
goto case SystemTypes.Reactor;
}
}
public void SendRPC()
{
if (!IsEnable || !Utils.DoRPC) return;
MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.SetSabotageMasterLimit, SendOption.Reliable);
writer.Write(SMId);
writer.Write(UsedSkillCount);
AmongUsClient.Instance.FinishRpcImmediately(writer);
}
public static void ReceiveRPC(MessageReader reader)
{
byte id = reader.ReadByte();
if (Main.PlayerStates[id].Role is not SabotageMaster sm) return;
sm.UsedSkillCount = reader.ReadSingle();
}
public static void RepairSystem(byte playerId, SystemTypes systemType, byte amount)
{
if (Main.PlayerStates[playerId].Role is not SabotageMaster sm) return;
switch (systemType)
{
case SystemTypes.Reactor:
case SystemTypes.Laboratory:
{
if (!FixesReactors.GetBool()) break;
if (SkillLimit.GetFloat() > 0 && sm.UsedSkillCount + UsesUsedWhenFixingReactorOrO2.GetFloat() - 1 >= SkillLimit.GetFloat()) break;
if (amount.HasAnyBit(ReactorSystemType.AddUserOp))
{
ShipStatus.Instance.UpdateSystem(Main.CurrentMap == MapNames.Polus ? SystemTypes.Laboratory : SystemTypes.Reactor, playerId.GetPlayer(), ReactorSystemType.ClearCountdown);
sm.UsedSkillCount += UsesUsedWhenFixingReactorOrO2.GetFloat();
sm.SendRPC();
}
break;
}
case SystemTypes.HeliSabotage:
{
if (!FixesReactors.GetBool()) break;
if (SkillLimit.GetFloat() > 0 && sm.UsedSkillCount + UsesUsedWhenFixingReactorOrO2.GetFloat() - 1 >= SkillLimit.GetFloat()) break;
var tags = (HeliSabotageSystem.Tags)(amount & HeliSabotageSystem.TagMask);
if (tags == HeliSabotageSystem.Tags.ActiveBit) sm.fixedSabotage = false;
if (!sm.fixedSabotage && tags == HeliSabotageSystem.Tags.FixBit)
{
sm.fixedSabotage = true;
int consoleId = amount & HeliSabotageSystem.IdMask;
int otherConsoleId = (consoleId + 1) % 2;
ShipStatus.Instance.UpdateSystem(SystemTypes.HeliSabotage, playerId.GetPlayer(), (byte)(otherConsoleId | (int)HeliSabotageSystem.Tags.FixBit));
sm.UsedSkillCount += UsesUsedWhenFixingReactorOrO2.GetFloat();
sm.SendRPC();
}
break;
}
case SystemTypes.LifeSupp:
{
if (!FixesOxygens.GetBool()) break;
if (SkillLimit.GetFloat() > 0 && sm.UsedSkillCount + UsesUsedWhenFixingReactorOrO2.GetFloat() - 1 >= SkillLimit.GetFloat()) break;
if (amount.HasAnyBit(LifeSuppSystemType.AddUserOp))
{
ShipStatus.Instance.UpdateSystem(SystemTypes.LifeSupp, playerId.GetPlayer(), LifeSuppSystemType.ClearCountdown);
sm.UsedSkillCount += UsesUsedWhenFixingReactorOrO2.GetFloat();
sm.SendRPC();
}
break;
}
case SystemTypes.Comms when Main.CurrentMap == MapNames.MiraHQ:
{
if (!FixesComms.GetBool()) break;
if (SkillLimit.GetFloat() > 0 && sm.UsedSkillCount + UsesUsedWhenFixingLightsOrComms.GetFloat() - 1 >= SkillLimit.GetFloat()) break;
var tags = (HqHudSystemType.Tags)(amount & HqHudSystemType.TagMask);
if (tags == HqHudSystemType.Tags.ActiveBit) sm.fixedSabotage = false;
if (!sm.fixedSabotage && tags == HqHudSystemType.Tags.FixBit)
{
sm.fixedSabotage = true;
int consoleId = amount & HqHudSystemType.IdMask;
int otherConsoleId = (consoleId + 1) % 2;
ShipStatus.Instance.UpdateSystem(SystemTypes.Comms, playerId.GetPlayer(), (byte)(otherConsoleId | (int)HqHudSystemType.Tags.FixBit));
sm.UsedSkillCount += UsesUsedWhenFixingLightsOrComms.GetFloat();
sm.SendRPC();
}
break;
}
case SystemTypes.Doors:
{
if (!FixesDoors.GetBool()) break;
if (DoorsProgressing) break;
int mapId = Main.NormalOptions.MapId;
if (AmongUsClient.Instance.NetworkMode == NetworkModes.FreePlay) mapId = AmongUsClient.Instance.TutorialMapId;
var shipStatus = ShipStatus.Instance;
DoorsProgressing = true;
switch (mapId)
{
case 2: // Polus
{
RepairSystemPatch.CheckAndOpenDoorsRange(shipStatus, amount, 71, 72);
RepairSystemPatch.CheckAndOpenDoorsRange(shipStatus, amount, 67, 68);
RepairSystemPatch.CheckAndOpenDoorsRange(shipStatus, amount, 64, 66);
RepairSystemPatch.CheckAndOpenDoorsRange(shipStatus, amount, 73, 74);
break;
}
case 4: // Airship
{
RepairSystemPatch.CheckAndOpenDoorsRange(shipStatus, amount, 64, 67);
RepairSystemPatch.CheckAndOpenDoorsRange(shipStatus, amount, 71, 73);
RepairSystemPatch.CheckAndOpenDoorsRange(shipStatus, amount, 74, 75);
RepairSystemPatch.CheckAndOpenDoorsRange(shipStatus, amount, 76, 78);
RepairSystemPatch.CheckAndOpenDoorsRange(shipStatus, amount, 68, 70);
RepairSystemPatch.CheckAndOpenDoorsRange(shipStatus, amount, 83, 84);
break;
}
case 5: // Fungle
{
int openedDoorId = amount & DoorsSystemType.IdMask;
OpenableDoor openedDoor = shipStatus.AllDoors.FirstOrDefault(door => door.Id == openedDoorId);
if (openedDoor == null)
Logger.Warn($"An unknown door has been opened: {openedDoorId}", nameof(SabotageMaster));
else
{
SystemTypes room = openedDoor.Room;
foreach (OpenableDoor door in shipStatus.AllDoors)
{
if (door.Id != openedDoorId && door.Room == room)
door.SetDoorway(true);
}
}
break;
}
}
DoorsProgressing = false;
break;
}
}
}
public static void SwitchSystemRepair(byte playerId, SwitchSystem switchSystem, byte amount)
{
if (!FixesElectrical.GetBool() || Main.PlayerStates[playerId].Role is not SabotageMaster sm) return;
if (SkillLimit.GetFloat() > 0 && sm.UsedSkillCount + UsesUsedWhenFixingLightsOrComms.GetFloat() - 1 >= SkillLimit.GetFloat()) return;
if (amount.HasBit(SwitchSystem.DamageSystem)) return;
int fixbit = 1 << amount;
switchSystem.ActualSwitches = (byte)(switchSystem.ExpectedSwitches ^ fixbit);
sm.UsedSkillCount += UsesUsedWhenFixingLightsOrComms.GetFloat();
sm.SendRPC();
}
public override bool CanUseVent(PlayerControl pc, int ventId)
{
return !IsThisRole(pc) || pc.Is(CustomRoles.Nimble) || CanVent.GetBool();
}
}
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using AmongUs.GameOptions;
using EHR.Modules;
using Hazel;
namespace EHR.Crewmate;
public class Mechanic : RoleBase
{
private const int Id = 7000;
private static List<byte> PlayerIdList = [];
private static OptionItem SkillLimit;
private static OptionItem FixesDoors;
private static OptionItem FixesReactors;
private static OptionItem FixesOxygens;
private static OptionItem FixesComms;
private static OptionItem FixesElectrical;
public static OptionItem MechanicAbilityUseGainWithEachTaskCompleted;
public static OptionItem AbilityChargesWhenFinishedTasks;
private static OptionItem UsesUsedWhenFixingReactorOrO2;
private static OptionItem UsesUsedWhenFixingLightsOrComms;
private static OptionItem CanFixSabotageFromAnywhereWithPet;
private static OptionItem MaxFixedViaPet;
public static OptionItem CanVent;
private static OptionItem VentCooldown;
private static OptionItem MaxInVentTime;
private static bool DoorsProgressing;
private bool fixedSabotage;
private int PetLimit;
private byte MechanicId;
public float UsedSkillCount;
public override bool IsEnable => PlayerIdList.Count > 0;
public override void SetupCustomOption()
{
Options.SetupRoleOptions(Id, TabGroup.CrewmateRoles, CustomRoles.Mechanic);
SkillLimit = new IntegerOptionItem(Id + 10, "MechanicSkillLimit", new(0, 80, 1), 2, TabGroup.CrewmateRoles)
.SetParent(Options.CustomRoleSpawnChances[CustomRoles.Mechanic])
.SetValueFormat(OptionFormat.Times);
FixesDoors = new BooleanOptionItem(Id + 11, "MechanicFixesDoors", true, TabGroup.CrewmateRoles)
.SetParent(Options.CustomRoleSpawnChances[CustomRoles.Mechanic]);
FixesReactors = new BooleanOptionItem(Id + 12, "MechanicFixesReactors", true, TabGroup.CrewmateRoles)
.SetParent(Options.CustomRoleSpawnChances[CustomRoles.Mechanic]);
FixesOxygens = new BooleanOptionItem(Id + 13, "MechanicFixesOxygens", true, TabGroup.CrewmateRoles)
.SetParent(Options.CustomRoleSpawnChances[CustomRoles.Mechanic]);
FixesComms = new BooleanOptionItem(Id + 14, "MechanicFixesCommunications", true, TabGroup.CrewmateRoles)
.SetParent(Options.CustomRoleSpawnChances[CustomRoles.Mechanic]);
FixesElectrical = new BooleanOptionItem(Id + 15, "MechanicFixesElectrical", true, TabGroup.CrewmateRoles)
.SetParent(Options.CustomRoleSpawnChances[CustomRoles.Mechanic]);
MechanicAbilityUseGainWithEachTaskCompleted = new FloatOptionItem(Id + 16, "AbilityUseGainWithEachTaskCompleted", new(0f, 5f, 0.05f), 3f, TabGroup.CrewmateRoles)
.SetParent(Options.CustomRoleSpawnChances[CustomRoles.Mechanic])
.SetValueFormat(OptionFormat.Times);
AbilityChargesWhenFinishedTasks = new FloatOptionItem(Id + 19, "AbilityChargesWhenFinishedTasks", new(0f, 5f, 0.05f), 0.2f, TabGroup.CrewmateRoles)
.SetParent(Options.CustomRoleSpawnChances[CustomRoles.Mechanic])
.SetValueFormat(OptionFormat.Times);
UsesUsedWhenFixingReactorOrO2 = new FloatOptionItem(Id + 17, "MechanicUsesUsedWhenFixingReactorOrO2", new(0f, 5f, 0.1f), 4f, TabGroup.CrewmateRoles)
.SetParent(Options.CustomRoleSpawnChances[CustomRoles.Mechanic])
.SetValueFormat(OptionFormat.Times);
UsesUsedWhenFixingLightsOrComms = new FloatOptionItem(Id + 18, "MechanicUsesUsedWhenFixingLightsOrComms", new(0f, 5f, 0.1f), 1f, TabGroup.CrewmateRoles)
.SetParent(Options.CustomRoleSpawnChances[CustomRoles.Mechanic])
.SetValueFormat(OptionFormat.Times);
CanFixSabotageFromAnywhereWithPet = new BooleanOptionItem(Id + 20, "MechanicCanFixSabotageFromAnywhereWithPet", true, TabGroup.CrewmateRoles)
.SetParent(Options.CustomRoleSpawnChances[CustomRoles.Mechanic]);
MaxFixedViaPet = new IntegerOptionItem(Id + 21, "MechanicMaxFixedViaPet", new(1, 30, 1), 1, TabGroup.CrewmateRoles)
.SetParent(CanFixSabotageFromAnywhereWithPet);
CanVent = new BooleanOptionItem(Id + 22, "CanVent", true, TabGroup.CrewmateRoles)
.SetParent(Options.CustomRoleSpawnChances[CustomRoles.Mechanic]);
VentCooldown = new FloatOptionItem(Id + 23, "VentCooldown", new(0f, 60f, 0.5f), 0f, TabGroup.CrewmateRoles)
.SetParent(CanVent)
.SetValueFormat(OptionFormat.Seconds);
MaxInVentTime = new FloatOptionItem(Id + 24, "MaxInVentTime", new(0f, 60f, 0.5f), 0f, TabGroup.CrewmateRoles)
.SetParent(CanVent)
.SetValueFormat(OptionFormat.Seconds);
}
public override void Init()
{
PlayerIdList = [];
UsedSkillCount = 0;
MechanicId = byte.MaxValue;
}
public override void Add(byte playerId)
{
PlayerIdList.Add(playerId);
PetLimit = MaxFixedViaPet.GetInt();
UsedSkillCount = 0;
MechanicId = playerId;
}
public override void Remove(byte playerId)
{
PlayerIdList.Remove(playerId);
}
public override void ApplyGameOptions(IGameOptions opt, byte playerId)
{
if (!CanVent.GetBool()) return;
AURoleOptions.EngineerCooldown = VentCooldown.GetFloat();
AURoleOptions.EngineerInVentMaxTime = MaxInVentTime.GetFloat();
}
public override string GetProgressText(byte playerId, bool comms)
{
double limit = Math.Round(SkillLimit.GetInt() - UsedSkillCount, 1);
string colored = Utils.ColorString(Utils.GetRoleColor(CustomRoles.Mechanic).ShadeColor(0.25f), limit.ToString(CultureInfo.CurrentCulture));
return $"({colored}){base.GetProgressText(playerId, comms)}";
}
public override void OnPet(PlayerControl pc)
{
SystemTypes[] systemTypes = [SystemTypes.Electrical, SystemTypes.Reactor, SystemTypes.Laboratory, SystemTypes.LifeSupp, SystemTypes.HeliSabotage, SystemTypes.Comms];
if (!CanFixSabotageFromAnywhereWithPet.GetBool() || !systemTypes.FindFirst(Utils.IsActive, out SystemTypes activeSystem) || PetLimit-- < 1) return;
switch (activeSystem)
{
case SystemTypes.Electrical:
var switchSystem = ShipStatus.Instance.Systems[SystemTypes.Electrical].CastFast<SwitchSystem>();
if (switchSystem == null) break;
switchSystem.ActualSwitches = switchSystem.ExpectedSwitches;
switchSystem.IsDirty = true;
break;
case SystemTypes.Reactor:
case SystemTypes.Laboratory:
case SystemTypes.LifeSupp:
ShipStatus.Instance.UpdateSystem(activeSystem, pc, 16);
break;
case SystemTypes.HeliSabotage:
ShipStatus.Instance.UpdateSystem(activeSystem, pc, 17);
goto case SystemTypes.Reactor;
case SystemTypes.Comms:
if (Main.NormalOptions.MapId is 1 or 5) ShipStatus.Instance.UpdateSystem(activeSystem, pc, 17);
goto case SystemTypes.Reactor;
}
}
public void SendRPC()
{
if (!IsEnable || !Utils.DoRPC) return;
MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.SetMechanicLimit, SendOption.Reliable);
writer.Write(MechanicId);
writer.Write(UsedSkillCount);
AmongUsClient.Instance.FinishRpcImmediately(writer);
}
public static void ReceiveRPC(MessageReader reader)
{
byte id = reader.ReadByte();
if (Main.PlayerStates[id].Role is not Mechanic m) return;
m.UsedSkillCount = reader.ReadSingle();
}
public static void RepairSystem(byte playerId, SystemTypes systemType, byte amount)
{
if (Main.PlayerStates[playerId].Role is not Mechanic m) return;
switch (systemType)
{
case SystemTypes.Reactor:
case SystemTypes.Laboratory:
{
if (!FixesReactors.GetBool()) break;
if (SkillLimit.GetFloat() > 0 && m.UsedSkillCount + UsesUsedWhenFixingReactorOrO2.GetFloat() - 1 >= SkillLimit.GetFloat()) break;
if (amount.HasAnyBit(ReactorSystemType.AddUserOp))
{
ShipStatus.Instance.UpdateSystem(Main.CurrentMap == MapNames.Polus ? SystemTypes.Laboratory : SystemTypes.Reactor, playerId.GetPlayer(), ReactorSystemType.ClearCountdown);
m.UsedSkillCount += UsesUsedWhenFixingReactorOrO2.GetFloat();
m.SendRPC();
}
break;
}
case SystemTypes.HeliSabotage:
{
if (!FixesReactors.GetBool()) break;
if (SkillLimit.GetFloat() > 0 && m.UsedSkillCount + UsesUsedWhenFixingReactorOrO2.GetFloat() - 1 >= SkillLimit.GetFloat()) break;
var tags = (HeliSabotageSystem.Tags)(amount & HeliSabotageSystem.TagMask);
if (tags == HeliSabotageSystem.Tags.ActiveBit) m.fixedSabotage = false;
if (!m.fixedSabotage && tags == HeliSabotageSystem.Tags.FixBit)
{
m.fixedSabotage = true;
int consoleId = amount & HeliSabotageSystem.IdMask;
int otherConsoleId = (consoleId + 1) % 2;
ShipStatus.Instance.UpdateSystem(SystemTypes.HeliSabotage, playerId.GetPlayer(), (byte)(otherConsoleId | (int)HeliSabotageSystem.Tags.FixBit));
m.UsedSkillCount += UsesUsedWhenFixingReactorOrO2.GetFloat();
m.SendRPC();
}
break;
}
case SystemTypes.LifeSupp:
{
if (!FixesOxygens.GetBool()) break;
if (SkillLimit.GetFloat() > 0 && m.UsedSkillCount + UsesUsedWhenFixingReactorOrO2.GetFloat() - 1 >= SkillLimit.GetFloat()) break;
if (amount.HasAnyBit(LifeSuppSystemType.AddUserOp))
{
ShipStatus.Instance.UpdateSystem(SystemTypes.LifeSupp, playerId.GetPlayer(), LifeSuppSystemType.ClearCountdown);
m.UsedSkillCount += UsesUsedWhenFixingReactorOrO2.GetFloat();
m.SendRPC();
}
break;
}
case SystemTypes.Comms when Main.CurrentMap == MapNames.MiraHQ:
{
if (!FixesComms.GetBool()) break;
if (SkillLimit.GetFloat() > 0 && m.UsedSkillCount + UsesUsedWhenFixingLightsOrComms.GetFloat() - 1 >= SkillLimit.GetFloat()) break;
var tags = (HqHudSystemType.Tags)(amount & HqHudSystemType.TagMask);
if (tags == HqHudSystemType.Tags.ActiveBit) m.fixedSabotage = false;
if (!m.fixedSabotage && tags == HqHudSystemType.Tags.FixBit)
{
m.fixedSabotage = true;
int consoleId = amount & HqHudSystemType.IdMask;
int otherConsoleId = (consoleId + 1) % 2;
ShipStatus.Instance.UpdateSystem(SystemTypes.Comms, playerId.GetPlayer(), (byte)(otherConsoleId | (int)HqHudSystemType.Tags.FixBit));
m.UsedSkillCount += UsesUsedWhenFixingLightsOrComms.GetFloat();
m.SendRPC();
}
break;
}
case SystemTypes.Doors:
{
if (!FixesDoors.GetBool()) break;
if (DoorsProgressing) break;
int mapId = Main.NormalOptions.MapId;
if (AmongUsClient.Instance.NetworkMode == NetworkModes.FreePlay) mapId = AmongUsClient.Instance.TutorialMapId;
var shipStatus = ShipStatus.Instance;
DoorsProgressing = true;
switch (mapId)
{
case 2: // Polus
{
RepairSystemPatch.CheckAndOpenDoorsRange(shipStatus, amount, 71, 72);
RepairSystemPatch.CheckAndOpenDoorsRange(shipStatus, amount, 67, 68);
RepairSystemPatch.CheckAndOpenDoorsRange(shipStatus, amount, 64, 66);
RepairSystemPatch.CheckAndOpenDoorsRange(shipStatus, amount, 73, 74);
break;
}
case 4: // Airship
{
RepairSystemPatch.CheckAndOpenDoorsRange(shipStatus, amount, 64, 67);
RepairSystemPatch.CheckAndOpenDoorsRange(shipStatus, amount, 71, 73);
RepairSystemPatch.CheckAndOpenDoorsRange(shipStatus, amount, 74, 75);
RepairSystemPatch.CheckAndOpenDoorsRange(shipStatus, amount, 76, 78);
RepairSystemPatch.CheckAndOpenDoorsRange(shipStatus, amount, 68, 70);
RepairSystemPatch.CheckAndOpenDoorsRange(shipStatus, amount, 83, 84);
break;
}
case 5: // Fungle
{
int openedDoorId = amount & DoorsSystemType.IdMask;
OpenableDoor openedDoor = shipStatus.AllDoors.FirstOrDefault(door => door.Id == openedDoorId);
if (openedDoor == null)
Logger.Warn($"An unknown door has been opened: {openedDoorId}", nameof(Mechanic));
else
{
SystemTypes room = openedDoor.Room;
foreach (OpenableDoor door in shipStatus.AllDoors)
{
if (door.Id != openedDoorId && door.Room == room)
door.SetDoorway(true);
}
}
break;
}
}
DoorsProgressing = false;
break;
}
}
}
public static void SwitchSystemRepair(byte playerId, SwitchSystem switchSystem, byte amount)
{
if (!FixesElectrical.GetBool() || Main.PlayerStates[playerId].Role is not Mechanic m) return;
if (SkillLimit.GetFloat() > 0 && m.UsedSkillCount + UsesUsedWhenFixingLightsOrComms.GetFloat() - 1 >= SkillLimit.GetFloat()) return;
if (amount.HasBit(SwitchSystem.DamageSystem)) return;
int fixbit = 1 << amount;
switchSystem.ActualSwitches = (byte)(switchSystem.ExpectedSwitches ^ fixbit);
m.UsedSkillCount += UsesUsedWhenFixingLightsOrComms.GetFloat();
m.SendRPC();
}
public override bool CanUseVent(PlayerControl pc, int ventId)
{
return !IsThisRole(pc) || pc.Is(CustomRoles.Nimble) || CanVent.GetBool();
}
}
+1 -1
View File
@@ -187,7 +187,7 @@ public class President : RoleBase
switch (Main.PlayerStates[player.PlayerId].Role)
{
case SabotageMaster sm:
case Mechanic sm:
sm.UsedSkillCount--;
break;
case Hacker when Hacker.UseLimit.ContainsKey(player.PlayerId):
+4 -4
View File
@@ -81,11 +81,11 @@ internal class Nullifier : RoleBase
Hacker.UseLimit[target.PlayerId]--;
break;
case CustomRoles.SabotageMaster:
if (Main.PlayerStates[target.PlayerId].Role is not SabotageMaster { IsEnable: true } sm) return;
case CustomRoles.Mechanic:
if (Main.PlayerStates[target.PlayerId].Role is not Mechanic { IsEnable: true } m) return;
sm.UsedSkillCount++;
sm.SendRPC();
m.UsedSkillCount++;
m.SendRPC();
break;
case CustomRoles.SwordsMan:
SwordsMan.Killed.Add(target.PlayerId);