mirror of
https://github.com/Gurge44/EndlessHostRoles.git
synced 2026-10-20 01:46:25 +00:00
Add Gaslighter & Technician, add more settings
This commit is contained in:
1 parent
3ecbbdd256
commit
ccd0d7a45d
28 files changed
+642
-138
No files matched your search
@@ -273,6 +273,7 @@ public enum CustomRoles
|
||||
Evolver,
|
||||
Executioner,
|
||||
Totocalcio, // Follower
|
||||
Gaslighter,
|
||||
Glitch,
|
||||
God,
|
||||
FFF, // Hater
|
||||
@@ -329,6 +330,7 @@ public enum CustomRoles
|
||||
DarkHide, // Stalker
|
||||
Succubus,
|
||||
Sunnyboy,
|
||||
Technician,
|
||||
Tank,
|
||||
Terrorist,
|
||||
Tiger,
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=GA/@EntryIndexedValue">GA</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=GM/@EntryIndexedValue">GM</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=HP/@EntryIndexedValue">HP</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=HQ/@EntryIndexedValue">HQ</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=HUD/@EntryIndexedValue">HUD</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=KC/@EntryIndexedValue">KC</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=KCD/@EntryIndexedValue">KCD</s:String>
|
||||
|
||||
@@ -125,7 +125,8 @@ namespace EHR
|
||||
if (LastUpdate == now) return;
|
||||
LastUpdate = now;
|
||||
|
||||
Timers.Keys.ToArray().Do(x => Timers[x]--);
|
||||
//Timers.Keys.ToArray().Do(x => Timers[x]--);
|
||||
Timers.AdjustAllValues(x => x - 1);
|
||||
Utils.NotifyRoles();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -248,6 +248,7 @@ internal static class CustomRolesHelper
|
||||
CustomRoles.Detective => CustomRoles.Crewmate,
|
||||
CustomRoles.God => CustomRoles.Crewmate,
|
||||
CustomRoles.Tank => CustomRoles.Engineer,
|
||||
CustomRoles.Technician => Technician.CanVent.GetBool() ? CustomRoles.Engineer : CustomRoles.Crewmate,
|
||||
CustomRoles.GuardianAngelEHR => CustomRoles.GuardianAngel,
|
||||
CustomRoles.Zombie => CustomRoles.Impostor,
|
||||
CustomRoles.Mario => CustomRoles.Engineer,
|
||||
@@ -445,6 +446,7 @@ internal static class CustomRolesHelper
|
||||
CustomRoles.SchrodingersCat => RoleTypes.Impostor,
|
||||
CustomRoles.Shifter => RoleTypes.Impostor,
|
||||
CustomRoles.Impartial => RoleTypes.Impostor,
|
||||
CustomRoles.Gaslighter => RoleTypes.Impostor,
|
||||
CustomRoles.Backstabber => RoleTypes.Impostor,
|
||||
CustomRoles.Predator => RoleTypes.Impostor,
|
||||
CustomRoles.Reckless => RoleTypes.Impostor,
|
||||
@@ -823,6 +825,7 @@ internal static class CustomRolesHelper
|
||||
|
||||
public static bool CheckAddonConflict(CustomRoles role, PlayerControl pc) => role.IsAdditionRole() && (!Main.NeverSpawnTogetherCombos.TryGetValue(OptionItem.CurrentPreset, out var neverList) || !neverList.TryGetValue(pc.GetCustomRole(), out var 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 var o) || ((o.Imp.GetBool() || !pc.GetCustomRole().IsImpostor()) && (o.Neutral.GetBool() || !pc.GetCustomRole().IsNeutral()) && (o.Crew.GetBool() || !pc.IsCrewmate()))) && (!role.IsImpOnlyAddon() || pc.IsImpostor()) && role switch
|
||||
{
|
||||
CustomRoles.Swift when pc.Is(CustomRoles.Stealth) => false,
|
||||
CustomRoles.Disco when pc.GetCustomRole() is CustomRoles.Chameleon or CustomRoles.Swooper or CustomRoles.Wraith or CustomRoles.Alchemist => false,
|
||||
CustomRoles.Egoist when pc.Is(CustomRoles.Gangster) => false,
|
||||
CustomRoles.Nimble when pc.Is(CustomRoles.Oxyman) => false,
|
||||
@@ -1063,6 +1066,7 @@ internal static class CustomRolesHelper
|
||||
CustomRoles.Parasite => CountTypes.Impostor,
|
||||
CustomRoles.Crewpostor => CountTypes.Impostor,
|
||||
CustomRoles.Refugee => CountTypes.Impostor,
|
||||
CustomRoles.Gaslighter => Gaslighter.WinCondition.GetValue() == 2 ? CountTypes.Gaslighter : CountTypes.Crew,
|
||||
CustomRoles.DarkHide when DarkHide.SnatchesWin.GetBool() => CountTypes.Crew,
|
||||
CustomRoles.Arsonist when !Options.ArsonistKeepsGameGoing.GetBool() => CountTypes.Crew,
|
||||
CustomRoles.SchrodingersCat => SchrodingersCat.WinsWithCrewIfNotAttacked.GetBool() ? CountTypes.Crew : CountTypes.OutOfGame,
|
||||
@@ -1166,9 +1170,11 @@ internal static class CustomRolesHelper
|
||||
CustomRoles.Phantasm => RoleOptionType.Neutral_Benign,
|
||||
CustomRoles.Provocateur => RoleOptionType.Neutral_Benign,
|
||||
CustomRoles.SoulHunter => RoleOptionType.Neutral_Benign,
|
||||
CustomRoles.Technician => RoleOptionType.Neutral_Benign,
|
||||
CustomRoles.Tank => RoleOptionType.Neutral_Benign,
|
||||
CustomRoles.Totocalcio => RoleOptionType.Neutral_Benign,
|
||||
CustomRoles.Jester => RoleOptionType.Neutral_Evil,
|
||||
CustomRoles.Gaslighter => RoleOptionType.Neutral_Evil,
|
||||
CustomRoles.God => RoleOptionType.Neutral_Evil,
|
||||
CustomRoles.Executioner => RoleOptionType.Neutral_Evil,
|
||||
CustomRoles.Doomsayer => RoleOptionType.Neutral_Evil,
|
||||
@@ -1493,6 +1499,7 @@ public enum CountTypes
|
||||
Eclipse,
|
||||
Vengeance,
|
||||
HeadHunter,
|
||||
Gaslighter,
|
||||
Imitator,
|
||||
Werewolf,
|
||||
Juggernaut,
|
||||
|
||||
@@ -30,6 +30,36 @@ namespace EHR
|
||||
return default;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the value for all existing keys in a dictionary to a specific value
|
||||
/// </summary>
|
||||
/// <param name="dictionary"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <typeparam name="TKey"></typeparam>
|
||||
/// <typeparam name="TValue"></typeparam>
|
||||
public static void SetAllValues<TKey, TValue>(this Dictionary<TKey, TValue> dictionary, TValue value)
|
||||
{
|
||||
foreach (TKey key in dictionary.Keys.ToArray())
|
||||
{
|
||||
dictionary[key] = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adjusts the value for all existing keys in a dictionary
|
||||
/// </summary>
|
||||
/// <param name="dictionary">The dictionary to adjust the values of</param>
|
||||
/// <param name="adjust">The function to adjust the values with</param>
|
||||
/// <typeparam name="TKey"></typeparam>
|
||||
/// <typeparam name="TValue"></typeparam>
|
||||
public static void AdjustAllValues<TKey, TValue>(this Dictionary<TKey, TValue> dictionary, Func<TValue, TValue> adjust)
|
||||
{
|
||||
foreach (TKey key in dictionary.Keys.ToArray())
|
||||
{
|
||||
dictionary[key] = adjust(dictionary[key]);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a random element from a collection
|
||||
/// </summary>
|
||||
|
||||
+10
-16
@@ -689,7 +689,9 @@ public static class Utils
|
||||
case CustomRoles.Postman:
|
||||
case CustomRoles.SchrodingersCat:
|
||||
case CustomRoles.Shifter:
|
||||
case CustomRoles.Technician:
|
||||
case CustomRoles.Tank:
|
||||
case CustomRoles.Gaslighter:
|
||||
case CustomRoles.Impartial:
|
||||
case CustomRoles.Backstabber:
|
||||
case CustomRoles.Predator:
|
||||
@@ -1873,6 +1875,7 @@ public static class Utils
|
||||
if (Main.LoversPlayers.Any(x => x.PlayerId == seer.PlayerId)) SelfMark.Append(ColorString(GetRoleColor(CustomRoles.Lovers), " ♥"));
|
||||
if (BallLightning.IsGhost(seer)) SelfMark.Append(ColorString(GetRoleColor(CustomRoles.BallLightning), "■"));
|
||||
SelfMark.Append(Medic.GetMark(seer, seer));
|
||||
SelfMark.Append(Gaslighter.GetMark(seer, seer));
|
||||
SelfMark.Append(Gamer.TargetMark(seer, seer));
|
||||
SelfMark.Append(Sniper.GetShotNotify(seer.PlayerId));
|
||||
if (Silencer.ForSilencer.Contains(seer.PlayerId)) SelfMark.Append(ColorString(GetRoleColor(CustomRoles.Silencer), "╳"));
|
||||
@@ -2262,6 +2265,7 @@ public static class Utils
|
||||
TargetMark.Append(Executioner.TargetMark(seer, target));
|
||||
TargetMark.Append(Gamer.TargetMark(seer, target));
|
||||
TargetMark.Append(Medic.GetMark(seer, target));
|
||||
TargetMark.Append(Gaslighter.GetMark(seer, target));
|
||||
TargetMark.Append(Totocalcio.TargetMark(seer, target));
|
||||
TargetMark.Append(Romantic.TargetMark(seer, target));
|
||||
TargetMark.Append(Lawyer.LawyerMark(seer, target));
|
||||
@@ -2289,7 +2293,7 @@ public static class Utils
|
||||
|
||||
Main.PlayerStates.Values.Do(x => TargetSuffix.Append(x.Role.GetSuffix(seer, target, isMeeting: isForMeeting)));
|
||||
|
||||
if (MeetingStates.FirstMeeting && Main.FirstDied != string.Empty && Main.FirstDied == target.FriendCode && Main.ShieldPlayer != string.Empty && Options.CurrentGameMode is CustomGameMode.Standard or CustomGameMode.SoloKombat or CustomGameMode.FFA)
|
||||
if (MeetingStates.FirstMeeting && Main.ShieldPlayer == target.FriendCode && !string.IsNullOrEmpty(target.FriendCode) && Options.CurrentGameMode is CustomGameMode.Standard or CustomGameMode.SoloKombat or CustomGameMode.FFA)
|
||||
TargetSuffix.Append(GetString("DiedR1Warning"));
|
||||
|
||||
TargetSuffix.Append(AFKDetector.GetSuffix(seer, target));
|
||||
@@ -2577,25 +2581,15 @@ public static class Utils
|
||||
|
||||
if (Options.DiseasedCDReset.GetBool())
|
||||
{
|
||||
var array = Main.KilledDiseased.Keys.ToArray();
|
||||
foreach (var pid in array)
|
||||
{
|
||||
Main.KilledDiseased[pid] = 0;
|
||||
GetPlayerById(pid)?.ResetKillCooldown();
|
||||
}
|
||||
|
||||
Main.KilledDiseased.SetAllValues(0);
|
||||
Main.KilledDiseased.Keys.Select(x => x.GetPlayer()).Do(x => x?.ResetKillCooldown());
|
||||
Main.KilledDiseased.Clear();
|
||||
}
|
||||
|
||||
if (Options.AntidoteCDReset.GetBool())
|
||||
{
|
||||
var array = Main.KilledAntidote.Keys.ToArray();
|
||||
foreach (var pid in array)
|
||||
{
|
||||
Main.KilledAntidote[pid] = 0;
|
||||
GetPlayerById(pid)?.ResetKillCooldown();
|
||||
}
|
||||
|
||||
Main.KilledAntidote.SetAllValues(0);
|
||||
Main.KilledAntidote.Keys.Select(x => x.GetPlayer()).Do(x => x?.ResetKillCooldown());
|
||||
Main.KilledAntidote.Clear();
|
||||
}
|
||||
|
||||
@@ -2717,7 +2711,7 @@ public static class Utils
|
||||
|
||||
if (QuizMaster.On) QuizMaster.Data.NumPlayersDeadThisRound++;
|
||||
|
||||
FixedUpdatePatch.LoversSuicide(target.PlayerId, onMeeting);
|
||||
FixedUpdatePatch.LoversSuicide(target.PlayerId, guess: onMeeting);
|
||||
if (!target.HasGhostRole())
|
||||
{
|
||||
Main.AllPlayerSpeed[target.PlayerId] = Main.RealOptionsData.GetFloat(FloatOptionNames.PlayerSpeedMod);
|
||||
|
||||
@@ -181,6 +181,10 @@ class GameEndChecker
|
||||
WinnerIds.Add(pc.PlayerId);
|
||||
AdditionalWinnerTeams.Add(AdditionalWinners.Tank);
|
||||
break;
|
||||
case CustomRoles.Technician when (Main.PlayerStates[pc.PlayerId].Role as Technician).IsWon:
|
||||
WinnerIds.Add(pc.PlayerId);
|
||||
AdditionalWinnerTeams.Add(AdditionalWinners.Technician);
|
||||
break;
|
||||
case CustomRoles.Backstabber when (Main.PlayerStates[pc.PlayerId].Role as Backstabber).CheckWin():
|
||||
WinnerIds.Add(pc.PlayerId);
|
||||
AdditionalWinnerTeams.Add(AdditionalWinners.Backstabber);
|
||||
@@ -189,6 +193,10 @@ class GameEndChecker
|
||||
WinnerIds.Add(pc.PlayerId);
|
||||
AdditionalWinnerTeams.Add(AdditionalWinners.Predator);
|
||||
break;
|
||||
case CustomRoles.Gaslighter when (Main.PlayerStates[pc.PlayerId].Role as Gaslighter).AddAsAdditionalWinner():
|
||||
WinnerIds.Add(pc.PlayerId);
|
||||
AdditionalWinnerTeams.Add(AdditionalWinners.Gaslighter);
|
||||
break;
|
||||
case CustomRoles.SoulHunter when (Main.PlayerStates[pc.PlayerId].Role as SoulHunter).Souls >= SoulHunter.NumOfSoulsToWin.GetInt():
|
||||
WinnerIds.Add(pc.PlayerId);
|
||||
AdditionalWinnerTeams.Add(AdditionalWinners.SoulHunter);
|
||||
@@ -410,7 +418,7 @@ class GameEndChecker
|
||||
|
||||
foreach (var role in Enum.GetValues<CustomRoles>())
|
||||
{
|
||||
if ((!role.IsNK() && role != CustomRoles.Bloodlust) || role.IsMadmate() || role is CustomRoles.Sidekick) continue;
|
||||
if ((!role.IsNK() && role is not CustomRoles.Bloodlust and not CustomRoles.Gaslighter) || role.IsMadmate() || role is CustomRoles.Sidekick) continue;
|
||||
|
||||
var countTypes = role.GetCountTypes();
|
||||
if (countTypes is CountTypes.Crew or CountTypes.Impostor or CountTypes.None or CountTypes.OutOfGame or CountTypes.CustomTeam) continue;
|
||||
|
||||
@@ -503,11 +503,12 @@ static class CheckForEndVotingPatch
|
||||
{
|
||||
Witch.OnCheckForEndVoting(deathReason, playerIds);
|
||||
Virus.OnCheckForEndVoting(deathReason, playerIds);
|
||||
if (deathReason == PlayerState.DeathReason.Vote) Gaslighter.OnExile(playerIds);
|
||||
foreach (var playerId in playerIds)
|
||||
{
|
||||
var id = playerId;
|
||||
if (CustomRoles.Lovers.IsEnable() && !Main.IsLoversDead && Main.LoversPlayers.Any(lp => lp.PlayerId == id))
|
||||
FixedUpdatePatch.LoversSuicide(playerId, true, true);
|
||||
FixedUpdatePatch.LoversSuicide(playerId, exile: true, force: true);
|
||||
if (Main.PlayerStates.TryGetValue(id, out var state) && state.SubRoles.Contains(CustomRoles.Avanger))
|
||||
RevengeOnExile(playerId /*, deathReason*/);
|
||||
}
|
||||
|
||||
@@ -372,6 +372,7 @@ class CheckMurderPatch
|
||||
Medic.OnAnyoneCheckMurder(killer, target) ||
|
||||
Randomizer.IsShielded(target) ||
|
||||
Aid.ShieldedPlayers.ContainsKey(target.PlayerId) ||
|
||||
!Gaslighter.IsShielded(target) ||
|
||||
!Grappler.OnAnyoneCheckMurder(target) ||
|
||||
!Adventurer.OnAnyoneCheckMurder(target) ||
|
||||
!Sentinel.OnAnyoneCheckMurder(killer) ||
|
||||
@@ -510,7 +511,7 @@ class CheckMurderPatch
|
||||
break;
|
||||
}
|
||||
|
||||
if (Main.ShieldPlayer != string.Empty && Main.ShieldPlayer == target.FriendCode && IsAllAlive)
|
||||
if (MeetingStates.FirstMeeting && Main.ShieldPlayer == target.FriendCode && !string.IsNullOrEmpty(target.FriendCode))
|
||||
{
|
||||
Main.ShieldPlayer = string.Empty;
|
||||
killer.SetKillCooldown(15f);
|
||||
@@ -1658,6 +1659,7 @@ static class FixedUpdatePatch
|
||||
if (BallLightning.IsGhost(target)) Mark.Append(ColorString(GetRoleColor(CustomRoles.BallLightning), "■"));
|
||||
|
||||
Mark.Append(Medic.GetMark(seer, target));
|
||||
Mark.Append(Gaslighter.GetMark(seer, target));
|
||||
Mark.Append(Snitch.GetWarningArrow(seer, target));
|
||||
Mark.Append(Snitch.GetWarningMark(seer, target));
|
||||
Mark.Append(Deathpact.GetDeathpactMark(seer, target));
|
||||
@@ -1704,7 +1706,7 @@ static class FixedUpdatePatch
|
||||
if (Options.CurrentGameMode == CustomGameMode.SoloKombat)
|
||||
Suffix.Append(SoloKombatManager.GetDisplayHealth(target));
|
||||
|
||||
if (MeetingStates.FirstMeeting && Main.FirstDied != string.Empty && Main.FirstDied == target.FriendCode && !self && Main.ShieldPlayer != string.Empty && Options.CurrentGameMode is CustomGameMode.Standard or CustomGameMode.SoloKombat or CustomGameMode.FFA)
|
||||
if (MeetingStates.FirstMeeting && Main.ShieldPlayer == target.FriendCode && !string.IsNullOrEmpty(target.FriendCode) && !self && Options.CurrentGameMode is CustomGameMode.Standard or CustomGameMode.SoloKombat or CustomGameMode.FFA)
|
||||
Suffix.Append(GetString("DiedR1Warning"));
|
||||
|
||||
// Devourer
|
||||
@@ -1777,7 +1779,7 @@ static class FixedUpdatePatch
|
||||
}
|
||||
}
|
||||
|
||||
public static void LoversSuicide(byte deathId = 0x7f, bool exile = false, bool force = false)
|
||||
public static void LoversSuicide(byte deathId = 0x7f, bool exile = false, bool force = false, bool guess = false)
|
||||
{
|
||||
if (Lovers.LoverDieConsequence.GetValue() == 0 || Main.IsLoversDead || (!Main.LoversPlayers.Any(player => player.Data.IsDead && player.PlayerId == deathId) && !force)) return;
|
||||
|
||||
@@ -1791,7 +1793,7 @@ static class FixedUpdatePatch
|
||||
return;
|
||||
}
|
||||
|
||||
if (Lovers.LoverSuicideTime.GetValue() != 0 && !exile) return;
|
||||
if (Lovers.LoverSuicideTime.GetValue() != 0 && !exile && !guess) return;
|
||||
|
||||
if (exile) CheckForEndVotingPatch.TryAddAfterMeetingDeathPlayers(PlayerState.DeathReason.FollowingSuicide, partnerPlayer.PlayerId);
|
||||
else partnerPlayer.Suicide(PlayerState.DeathReason.FollowingSuicide);
|
||||
|
||||
@@ -96,13 +96,17 @@ class RepairSystemPatch
|
||||
switch (player.GetCustomRole())
|
||||
{
|
||||
case CustomRoles.SabotageMaster:
|
||||
SabotageMaster.RepairSystem(player.PlayerId, __instance, systemType, amount);
|
||||
SabotageMaster.RepairSystem(player.PlayerId, systemType, amount);
|
||||
Utils.NotifyRoles(SpecifySeer: player, SpecifyTarget: player);
|
||||
break;
|
||||
case CustomRoles.Alchemist when Main.PlayerStates[player.PlayerId].Role is Alchemist { IsEnable: true, FixNextSabo: true }:
|
||||
Alchemist.RepairSystem(player, systemType, amount);
|
||||
Utils.NotifyRoles(SpecifySeer: player, SpecifyTarget: player);
|
||||
break;
|
||||
case CustomRoles.Technician:
|
||||
Technician.RepairSystem(player.PlayerId, systemType, amount);
|
||||
Utils.NotifyRoles(SpecifySeer: player, SpecifyTarget: player);
|
||||
break;
|
||||
}
|
||||
|
||||
switch (systemType)
|
||||
@@ -170,30 +174,44 @@ class RepairSystemPatch
|
||||
switch (systemType)
|
||||
{
|
||||
case SystemTypes.Electrical when amount <= 4:
|
||||
{
|
||||
var SwitchSystem = ShipStatus.Instance?.Systems?[SystemTypes.Electrical]?.Cast<SwitchSystem>();
|
||||
if (SwitchSystem is { IsActive: true })
|
||||
{
|
||||
switch (Main.PlayerStates[player.PlayerId].Role)
|
||||
{
|
||||
case SabotageMaster:
|
||||
{
|
||||
Logger.Info($"{player.GetNameWithRole().RemoveHtmlTags()} instant-fix-lights", "SwitchSystem");
|
||||
SabotageMaster.SwitchSystemRepair(player.PlayerId, SwitchSystem, amount);
|
||||
Utils.NotifyRoles(SpecifySeer: player, SpecifyTarget: player);
|
||||
break;
|
||||
}
|
||||
case Alchemist { FixNextSabo: true } am:
|
||||
{
|
||||
Logger.Info($"{player.GetNameWithRole().RemoveHtmlTags()} instant-fix-lights", "SwitchSystem");
|
||||
SwitchSystem.ActualSwitches = 0;
|
||||
SwitchSystem.ExpectedSwitches = 0;
|
||||
am.FixNextSabo = false;
|
||||
Utils.NotifyRoles(SpecifySeer: player, SpecifyTarget: player);
|
||||
break;
|
||||
}
|
||||
case Adventurer av:
|
||||
{
|
||||
Logger.Info($"{player.GetNameWithRole().RemoveHtmlTags()} instant-fix-lights", "SwitchSystem");
|
||||
SwitchSystem.ActualSwitches = 0;
|
||||
SwitchSystem.ExpectedSwitches = 0;
|
||||
av.OnLightsFix();
|
||||
Utils.NotifyRoles(SpecifySeer: player, SpecifyTarget: player);
|
||||
break;
|
||||
}
|
||||
case Technician:
|
||||
{
|
||||
Logger.Info($"{player.GetNameWithRole().RemoveHtmlTags()} instant-fix-lights", "SwitchSystem");
|
||||
Technician.SwitchSystemRepair(player.PlayerId, SwitchSystem, amount);
|
||||
Utils.NotifyRoles(SpecifySeer: player, SpecifyTarget: player);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (player.Is(CustomRoles.Damocles) && Damocles.countRepairSabotage) Damocles.OnRepairSabotage(player.PlayerId);
|
||||
@@ -201,16 +219,19 @@ class RepairSystemPatch
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case SystemTypes.Reactor:
|
||||
case SystemTypes.LifeSupp:
|
||||
case SystemTypes.Comms:
|
||||
case SystemTypes.Laboratory:
|
||||
case SystemTypes.HeliSabotage:
|
||||
case SystemTypes.Electrical:
|
||||
{
|
||||
if (player.Is(CustomRoles.Damocles) && Damocles.countRepairSabotage) Damocles.OnRepairSabotage(player.PlayerId);
|
||||
if (player.Is(CustomRoles.Stressed) && Stressed.countRepairSabotage) Stressed.OnRepairSabotage(player);
|
||||
if (Main.PlayerStates[player.PlayerId].Role is Rogue rg) rg.OnFixSabotage();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1846,8 +1846,21 @@
|
||||
"RomanticProtectDuration": "Protect Duration",
|
||||
"RomanticKnowTargetRole": "<color=#ff1493>Romantic</color> knows their target's role",
|
||||
"RomanticBetTargetKnowRomantic": "Target knows who the <color=#ff1493>Romantic</color> is",
|
||||
"RomanticGetsPartnerConvertedAddons": "<color=#ff1493>Romantic</color> gets the converted add-ons of their partner",
|
||||
"RomanticArrows": "<color=#ff1493>Romantic</color> has arrows pointing to their Partner",
|
||||
"RomanticPartnerHasArrows": "Partner has arrows pointing to the <color=#FF1493>Romantic</color>",
|
||||
"Gaslighter": "Gaslighter",
|
||||
"GaslighterInfo": "Make others doubt their own memory",
|
||||
"GaslighterInfoLong": "(Neutrals):\\nAs the Gaslighter, you do different actions through your kill button every round.<size=80%>\\n\\nRound 1: Normal kills\\nRound 2: Knight players\\nRound 3: Curse players (like Witch)\\nRound 4: Shield players\\n\\n</size><size=90%>Then the cycle repeats, or you stay on normally killing until the end of the game depending on the settings.\\nSettings determine your win condition.</size>",
|
||||
"Gaslighter.WinCondition": "Win Condition",
|
||||
"GaslighterWinCondition.CrewLoses": "<#8cffff>Crewmates</color> <#ff0000>lose</color>",
|
||||
"GaslighterWinCondition.IfAlive": "<#00ff00>Alive</color> at the end",
|
||||
"GaslighterWinCondition.LastStanding": "<#ffab1b>Last one standing</color>",
|
||||
"Gaslighter.CycleRepeats": "Kill Button Actions Cycle Repeats",
|
||||
"Gaslighter.Kill": "In this round, you <#ff1919>kill normally</color>",
|
||||
"Gaslighter.Knight": "In this round, you <#ffa500>knight players</color>",
|
||||
"Gaslighter.Curse": "In this round, you <#ff00ff>curse players</color>",
|
||||
"Gaslighter.Shield": "In this round, you <#00ff97>shield players</color>",
|
||||
"Speedrunner": "Speedrunner",
|
||||
"SpeedrunnerInfo": "Crew wins if you finish your tasks",
|
||||
"SpeedrunnerInfoLong": "(Crewmates):\\nWhen you complete all of your tasks (and you're still alive), the game instantly ends and everyone on the crewmate team will win.",
|
||||
@@ -2983,6 +2996,7 @@
|
||||
"Hypnotist": "Hypnotist",
|
||||
"HypnotistInfo": "Prevent Body Reports",
|
||||
"HypnotistInfoLong": "(Impostors):\\nAs the Hypnotist, you can prevent all players from reporting bodies by using your ability (shapeshift/pet).",
|
||||
"Hypnotist.DoReportAfterHypnosisEnds": "Process reports that were blocked during hypnosis after the hypnosis expires",
|
||||
"Altruist": "Altruist",
|
||||
"AltruistInfo": "Erase your killer's role",
|
||||
"AltruistInfoLong": "(Crewmates):\\nAs the Altruist, if an impostor kills you, they will lose their abilities and become a regular impostor or shapeshifter.",
|
||||
@@ -4473,6 +4487,7 @@
|
||||
"Bloodmoon.Duration": "Time After Target Dies",
|
||||
"Bloodmoon.Suffix": "<{1}>You will die in <{2}>{0}s</color></color>",
|
||||
"Bloodmoon.Speed": "<#ff1919>Bloodmoon</color> Speed",
|
||||
"Bloodmoon.DieOnMeetingCall": "Targets Die on Meeting Call",
|
||||
"Prefix.Bloodmoon": "Bloodmoon",
|
||||
"GA": "Guardian Angel",
|
||||
"GAInfo": "Protect Crewmates",
|
||||
@@ -4643,6 +4658,7 @@
|
||||
"President.UsedDecreeMessage.Everyone": "The <#30916f>President</color> has used the <#ffab1b>{0}</color>!",
|
||||
"President.DecreeAlreadyUsedMessage": "You have already used this decree or it isn't enabled!",
|
||||
"President.DecreeAlreadyChosenThisMeetingMessage": "You have already chosen a decree this meeting!",
|
||||
"President.UsedDecreeMessage.RevealMessage": "{0} is the <#30916f>President</color>!",
|
||||
"GuessPresident": "You cannot guess a revealed <#30916f>President</color>.",
|
||||
"GuessErased": "You cannot guess a player's role that has been erased.",
|
||||
"Alchemist": "Alchemist",
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using EHR.Modules;
|
||||
using Hazel;
|
||||
using static EHR.Options;
|
||||
@@ -205,10 +204,7 @@ namespace EHR.AddOns.Crewmate
|
||||
private static void AdjustTime(int change)
|
||||
{
|
||||
if (!IsEnable) return;
|
||||
foreach (var x in Timers.Keys.ToArray())
|
||||
{
|
||||
Timers[x] += change;
|
||||
}
|
||||
Timers.AdjustAllValues(x => x + change);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,7 @@ namespace EHR.AddOns.GhostRoles
|
||||
private static OptionItem CD;
|
||||
private static OptionItem Duration;
|
||||
private static OptionItem Speed;
|
||||
private static OptionItem DieOnMeetingCall;
|
||||
|
||||
private static readonly Dictionary<byte, long> ScheduledDeaths = [];
|
||||
public Team Team => Team.Impostor | Team.Neutral;
|
||||
@@ -36,6 +37,8 @@ namespace EHR.AddOns.GhostRoles
|
||||
Speed = new FloatOptionItem(649404, "Bloodmoon.Speed", new(0.05f, 5f, 0.05f), 1f, TabGroup.OtherRoles)
|
||||
.SetParent(Options.CustomRoleSpawnChances[CustomRoles.Bloodmoon])
|
||||
.SetValueFormat(OptionFormat.Multiplier);
|
||||
DieOnMeetingCall = new BooleanOptionItem(649405, "Bloodmoon.DieOnMeetingCall", true, TabGroup.OtherRoles)
|
||||
.SetParent(Options.CustomRoleSpawnChances[CustomRoles.Bloodmoon]);
|
||||
}
|
||||
|
||||
public static void Update(PlayerControl pc)
|
||||
@@ -59,12 +62,15 @@ namespace EHR.AddOns.GhostRoles
|
||||
|
||||
public static void OnMeetingStart()
|
||||
{
|
||||
foreach (var id in ScheduledDeaths.Keys)
|
||||
if (DieOnMeetingCall.GetBool())
|
||||
{
|
||||
var pc = Utils.GetPlayerById(id);
|
||||
if (pc == null || !pc.IsAlive()) continue;
|
||||
foreach (var id in ScheduledDeaths.Keys)
|
||||
{
|
||||
var pc = Utils.GetPlayerById(id);
|
||||
if (pc == null || !pc.IsAlive()) continue;
|
||||
|
||||
pc.Suicide();
|
||||
pc.Suicide();
|
||||
}
|
||||
}
|
||||
|
||||
ScheduledDeaths.Clear();
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace EHR.AddOns.Impostor
|
||||
{
|
||||
@@ -68,11 +67,7 @@ namespace EHR.AddOns.Impostor
|
||||
public static void AfterMeetingTasks()
|
||||
{
|
||||
if (VentPreventionMode.GetValue() != 2) return;
|
||||
|
||||
foreach (var playerId in Limits.Keys.ToArray())
|
||||
{
|
||||
Limits[playerId] = Limit.GetInt();
|
||||
}
|
||||
Limits.SetAllValues(Limit.GetInt());
|
||||
}
|
||||
|
||||
public static string GetProgressText(byte playerId)
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using EHR.Modules;
|
||||
using Hazel;
|
||||
using static EHR.Options;
|
||||
@@ -164,18 +163,12 @@ namespace EHR.AddOns.Impostor
|
||||
|
||||
private static void AdjustTime(int change)
|
||||
{
|
||||
foreach (var item in Timer.Keys.ToArray())
|
||||
{
|
||||
Timer[item] += change;
|
||||
}
|
||||
Timer.AdjustAllValues(x => x + change);
|
||||
}
|
||||
|
||||
private static void AdjustTimeByPercent(double percent)
|
||||
{
|
||||
foreach (var item in Timer.Keys.ToArray())
|
||||
{
|
||||
Timer[item] = (int)Math.Round(Timer[item] * percent);
|
||||
}
|
||||
Timer.AdjustAllValues(x => (int)Math.Round(x * percent));
|
||||
}
|
||||
|
||||
public static string GetProgressText(byte id) => string.Format(GetString("DamoclesTimeLeft"), Timer.GetValueOrDefault(id, StartingTime));
|
||||
|
||||
@@ -115,7 +115,7 @@ namespace EHR.Crewmate
|
||||
{
|
||||
if (!IsEnable) return;
|
||||
shieldedPlayers.Clear();
|
||||
foreach (var playerId in TaskMarkPerRound.Keys)
|
||||
foreach (var playerId in TaskMarkPerRound.Keys.ToArray())
|
||||
{
|
||||
TaskMarkPerRound[playerId] = 0;
|
||||
if (taskIndex.ContainsKey(playerId)) taskIndex[playerId].Clear();
|
||||
@@ -156,7 +156,7 @@ namespace EHR.Crewmate
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var benefactorId in taskIndex.Keys)
|
||||
foreach (var benefactorId in taskIndex.Keys.ToArray())
|
||||
{
|
||||
if (taskIndex[benefactorId].Contains(task.Index))
|
||||
{
|
||||
|
||||
@@ -111,7 +111,7 @@ namespace EHR.Crewmate
|
||||
}
|
||||
else if (arTime >= FarseerRevealTime.GetFloat())
|
||||
{
|
||||
if (UsePets.GetBool()) player.AddKCDAsAbilityCD();
|
||||
if (UsePets.GetBool() && UsePet.GetBool()) player.AddKCDAsAbilityCD();
|
||||
else player.SetKillCooldown();
|
||||
FarseerTimer.Remove(player.PlayerId);
|
||||
IsRevealed[(player.PlayerId, arTarget.PlayerId)] = true;
|
||||
|
||||
@@ -66,13 +66,13 @@ namespace EHR.Crewmate
|
||||
switch (decree)
|
||||
{
|
||||
case Decree.Reveal:
|
||||
DecreeSettings[decree].AddRange(new[]
|
||||
{
|
||||
DecreeSettings[decree].AddRange(
|
||||
[
|
||||
new BooleanOptionItem(++id, "President.Reveal.CanBeConvertedAfterRevealing", false, tab)
|
||||
.SetParent(DecreeSettings[decree][0]),
|
||||
new BooleanOptionItem(++id, "President.Reveal.ConvertedPresidentCanReveal", false, tab)
|
||||
.SetParent(DecreeSettings[decree][0])
|
||||
});
|
||||
]);
|
||||
break;
|
||||
case Decree.GovernmentRecruiting:
|
||||
DecreeSettings[decree].Add(new StringOptionItem(++id, "President.GovernmentRecruiting.RecruitedRole", GovernmentRecruitRoles.Select(x => x.ToColoredString()).ToArray(), 0, tab, noTranslation: true)
|
||||
@@ -145,8 +145,9 @@ namespace EHR.Crewmate
|
||||
{
|
||||
case Decree.Reveal:
|
||||
if (!DecreeSettings[decree][1].GetBool()) pc.RpcSetCustomRole(CustomRoles.Loyal);
|
||||
if (!DecreeSettings[decree][2].GetBool() && pc.GetCustomSubRoles().Any(x => x.IsConverted())) return;
|
||||
if (!DecreeSettings[decree][2].GetBool() && pc.IsConverted() || pc.Is(CustomRoles.Bloodlust)) return;
|
||||
Utils.SendMessage(string.Format(Translator.GetString("President.UsedDecreeMessage.Everyone"), Translator.GetString($"President.Decree.{decree}")));
|
||||
Utils.SendMessage(string.Format(Translator.GetString("President.UsedDecreeMessage.RevealMessage"), pc.PlayerId.ColoredPlayerName()));
|
||||
break;
|
||||
case Decree.Finish:
|
||||
MeetingHud.Instance?.RpcClose();
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using AmongUs.GameOptions;
|
||||
using EHR.Modules;
|
||||
using Hazel;
|
||||
@@ -24,6 +25,7 @@ public class SabotageMaster : RoleBase
|
||||
public static OptionItem UsesUsedWhenFixingLightsOrComms;
|
||||
|
||||
private static bool DoorsProgressing;
|
||||
private bool fixedSabotage;
|
||||
private byte SMId;
|
||||
|
||||
public float UsedSkillCount;
|
||||
@@ -97,106 +99,156 @@ public class SabotageMaster : RoleBase
|
||||
sm.UsedSkillCount = reader.ReadSingle();
|
||||
}
|
||||
|
||||
public static void RepairSystem(byte playerId, ShipStatus __instance, SystemTypes systemType, byte amount)
|
||||
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:
|
||||
if (!FixesReactors.GetBool()) break;
|
||||
if (SkillLimit.GetFloat() > 0 && sm.UsedSkillCount + UsesUsedWhenFixingReactorOrO2.GetFloat() - 1 >= SkillLimit.GetFloat()) break;
|
||||
if (amount is 64 or 65)
|
||||
{
|
||||
ShipStatus.Instance.RpcUpdateSystem(SystemTypes.Reactor, 16);
|
||||
ShipStatus.Instance.RpcUpdateSystem(SystemTypes.Reactor, 17);
|
||||
sm.UsedSkillCount += UsesUsedWhenFixingReactorOrO2.GetFloat();
|
||||
sm.SendRPC();
|
||||
}
|
||||
|
||||
break;
|
||||
case SystemTypes.Laboratory:
|
||||
{
|
||||
if (!FixesReactors.GetBool()) break;
|
||||
if (SkillLimit.GetFloat() > 0 && sm.UsedSkillCount + UsesUsedWhenFixingReactorOrO2.GetFloat() - 1 >= SkillLimit.GetFloat()) break;
|
||||
if (amount is 64 or 65)
|
||||
if (amount.HasAnyBit(ReactorSystemType.AddUserOp))
|
||||
{
|
||||
ShipStatus.Instance.RpcUpdateSystem(SystemTypes.Laboratory, 67);
|
||||
ShipStatus.Instance.RpcUpdateSystem(SystemTypes.Laboratory, 66);
|
||||
ShipStatus.Instance.UpdateSystem((MapNames)Main.NormalOptions.MapId == 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;
|
||||
var consoleId = amount & HeliSabotageSystem.IdMask;
|
||||
var 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 is 64 or 65)
|
||||
if (amount.HasAnyBit(LifeSuppSystemType.AddUserOp))
|
||||
{
|
||||
ShipStatus.Instance.RpcUpdateSystem(SystemTypes.LifeSupp, 67);
|
||||
ShipStatus.Instance.RpcUpdateSystem(SystemTypes.LifeSupp, 66);
|
||||
ShipStatus.Instance.UpdateSystem(SystemTypes.LifeSupp, playerId.GetPlayer(), LifeSuppSystemType.ClearCountdown);
|
||||
sm.UsedSkillCount += UsesUsedWhenFixingReactorOrO2.GetFloat();
|
||||
sm.SendRPC();
|
||||
}
|
||||
|
||||
break;
|
||||
case SystemTypes.Comms:
|
||||
}
|
||||
case SystemTypes.Comms when Main.CurrentMap == MapNames.Mira:
|
||||
{
|
||||
if (!FixesComms.GetBool()) break;
|
||||
if (SkillLimit.GetFloat() > 0 && sm.UsedSkillCount + UsesUsedWhenFixingLightsOrComms.GetFloat() - 1 >= SkillLimit.GetFloat()) break;
|
||||
if (amount is 64 or 65)
|
||||
|
||||
var tags = (HqHudSystemType.Tags)(amount & HqHudSystemType.TagMask);
|
||||
if (tags == HqHudSystemType.Tags.ActiveBit)
|
||||
{
|
||||
ShipStatus.Instance.RpcUpdateSystem(SystemTypes.Comms, 16);
|
||||
ShipStatus.Instance.RpcUpdateSystem(SystemTypes.Comms, 17);
|
||||
sm.fixedSabotage = false;
|
||||
}
|
||||
|
||||
if (!sm.fixedSabotage && tags == HqHudSystemType.Tags.FixBit)
|
||||
{
|
||||
sm.fixedSabotage = true;
|
||||
var consoleId = amount & HqHudSystemType.IdMask;
|
||||
var 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(__instance, amount, 71, 72);
|
||||
RepairSystemPatch.CheckAndOpenDoorsRange(__instance, amount, 67, 68);
|
||||
RepairSystemPatch.CheckAndOpenDoorsRange(__instance, amount, 64, 66);
|
||||
RepairSystemPatch.CheckAndOpenDoorsRange(__instance, amount, 73, 74);
|
||||
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(__instance, amount, 64, 67);
|
||||
RepairSystemPatch.CheckAndOpenDoorsRange(__instance, amount, 71, 73);
|
||||
RepairSystemPatch.CheckAndOpenDoorsRange(__instance, amount, 74, 75);
|
||||
RepairSystemPatch.CheckAndOpenDoorsRange(__instance, amount, 76, 78);
|
||||
RepairSystemPatch.CheckAndOpenDoorsRange(__instance, amount, 68, 70);
|
||||
RepairSystemPatch.CheckAndOpenDoorsRange(__instance, amount, 83, 84);
|
||||
}
|
||||
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
|
||||
{
|
||||
var openedDoorId = amount & DoorsSystemType.IdMask;
|
||||
var openedDoor = shipStatus.AllDoors.FirstOrDefault(door => door.Id == openedDoorId);
|
||||
if (openedDoor == null)
|
||||
{
|
||||
Logger.Warn($"An unknown door has been opened: {openedDoorId}", nameof(SabotageMaster));
|
||||
}
|
||||
else
|
||||
{
|
||||
var room = openedDoor.Room;
|
||||
foreach (var 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 __instance, byte amount)
|
||||
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 (SkillLimit.GetFloat() > 0 && sm.UsedSkillCount + UsesUsedWhenFixingLightsOrComms.GetFloat() - 1 >= SkillLimit.GetFloat()) return;
|
||||
|
||||
if (amount <= 4)
|
||||
{
|
||||
__instance.ActualSwitches = 0;
|
||||
__instance.ExpectedSwitches = 0;
|
||||
sm.UsedSkillCount += UsesUsedWhenFixingLightsOrComms.GetFloat();
|
||||
sm.SendRPC();
|
||||
}
|
||||
if (amount.HasBit(SwitchSystem.DamageSystem)) return;
|
||||
|
||||
var fixbit = 1 << amount;
|
||||
switchSystem.ActualSwitches = (byte)(switchSystem.ExpectedSwitches ^ fixbit);
|
||||
|
||||
sm.UsedSkillCount += UsesUsedWhenFixingLightsOrComms.GetFloat();
|
||||
sm.SendRPC();
|
||||
}
|
||||
}
|
||||
@@ -15,6 +15,7 @@ namespace EHR.Impostor
|
||||
public static OptionItem AbilityDuration;
|
||||
public static OptionItem AbilityUseLimit;
|
||||
public static OptionItem AbilityUseGainWithEachKill;
|
||||
private static OptionItem DoReportAfterHypnosisEnds;
|
||||
|
||||
private long ActivateTS;
|
||||
private int Count;
|
||||
@@ -28,7 +29,8 @@ namespace EHR.Impostor
|
||||
.AutoSetupOption(ref AbilityCooldown, 30, new IntegerValueRule(0, 60, 1), OptionFormat.Seconds)
|
||||
.AutoSetupOption(ref AbilityDuration, 15, new IntegerValueRule(0, 30, 1), OptionFormat.Seconds)
|
||||
.AutoSetupOption(ref AbilityUseLimit, 1, new IntegerValueRule(0, 5, 1), OptionFormat.Times)
|
||||
.AutoSetupOption(ref AbilityUseGainWithEachKill, 0.5f, new FloatValueRule(0f, 5f, 0.1f), OptionFormat.Times);
|
||||
.AutoSetupOption(ref AbilityUseGainWithEachKill, 0.5f, new FloatValueRule(0f, 5f, 0.1f), OptionFormat.Times)
|
||||
.AutoSetupOption(ref DoReportAfterHypnosisEnds, true);
|
||||
}
|
||||
|
||||
public override void Init()
|
||||
@@ -67,6 +69,8 @@ namespace EHR.Impostor
|
||||
ActivateTS = Utils.TimeStamp;
|
||||
Utils.NotifyRoles(SpecifySeer: pc, SpecifyTarget: pc);
|
||||
Utils.SendRPC(CustomRPC.SyncRoleData, HypnotistId, ActivateTS);
|
||||
|
||||
if (DoReportAfterHypnosisEnds.GetBool()) ReportDeadBodyPatch.CanReport.SetAllValues(false);
|
||||
}
|
||||
|
||||
public override void OnFixedUpdate(PlayerControl pc)
|
||||
@@ -78,6 +82,7 @@ namespace EHR.Impostor
|
||||
ActivateTS = 0;
|
||||
notify = true;
|
||||
pc.RpcResetAbilityCooldown();
|
||||
if (DoReportAfterHypnosisEnds.GetBool()) ReportDeadBodyPatch.CanReport.SetAllValues(true);
|
||||
}
|
||||
else if (ActivateTS != 0 && Count++ >= 30 && timeLeft <= 6)
|
||||
{
|
||||
|
||||
+15
-4
@@ -111,6 +111,12 @@ public class Witch : RoleBase
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnPet(PlayerControl pc)
|
||||
{
|
||||
if (NowSwitchTrigger == SwitchTrigger.DoubleTrigger) return;
|
||||
SwitchMode(pc.PlayerId);
|
||||
}
|
||||
|
||||
void SwitchSpellMode(byte playerId, bool kill)
|
||||
{
|
||||
bool needSwitch = NowSwitchTrigger switch
|
||||
@@ -121,13 +127,18 @@ public class Witch : RoleBase
|
||||
};
|
||||
if (needSwitch)
|
||||
{
|
||||
SpellMode = !SpellMode;
|
||||
SendRPC(false, playerId);
|
||||
var pc = Utils.GetPlayerById(playerId);
|
||||
Utils.NotifyRoles(SpecifySeer: pc, SpecifyTarget: pc);
|
||||
SwitchMode(playerId);
|
||||
}
|
||||
}
|
||||
|
||||
void SwitchMode(byte playerId)
|
||||
{
|
||||
SpellMode = !SpellMode;
|
||||
SendRPC(false, playerId);
|
||||
var pc = Utils.GetPlayerById(playerId);
|
||||
Utils.NotifyRoles(SpecifySeer: pc, SpecifyTarget: pc);
|
||||
}
|
||||
|
||||
bool IsSpelled(byte target) => SpelledPlayer.Contains(target);
|
||||
|
||||
void SetSpelled(PlayerControl killer, PlayerControl target)
|
||||
|
||||
@@ -191,6 +191,9 @@ public class Amnesiac : RoleBase
|
||||
target.RpcGuardAndKill(amnesiac);
|
||||
target.RpcGuardAndKill(target);
|
||||
|
||||
if (role.IsRecruitingRole())
|
||||
amnesiac.SetAbilityUseLimit(0);
|
||||
|
||||
if (role.GetRoleTypes() == RoleTypes.Engineer)
|
||||
WasAmnesiac.Add(amnesiac.PlayerId);
|
||||
}
|
||||
|
||||
@@ -150,7 +150,8 @@ namespace EHR.Neutral
|
||||
public override void OnReportDeadBody()
|
||||
{
|
||||
if (!IsEnable) return;
|
||||
foreach (var pc in EncasedPlayers.Keys.Select(x => GetPlayerById(x)).Where(x => x != null && x.IsAlive())) pc.Suicide(PlayerState.DeathReason.Bombed, Bubble_);
|
||||
foreach (var pc in EncasedPlayers.Keys.Select(x => GetPlayerById(x)).Where(x => x != null && x.IsAlive()))
|
||||
pc.Suicide(PlayerState.DeathReason.Bombed, Bubble_);
|
||||
EncasedPlayers.Clear();
|
||||
SendRPC(clear: true);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,183 @@
|
||||
using System.Collections.Generic;
|
||||
using AmongUs.GameOptions;
|
||||
using EHR.Crewmate;
|
||||
using EHR.Patches;
|
||||
|
||||
namespace EHR.Neutral
|
||||
{
|
||||
public class Gaslighter : RoleBase
|
||||
{
|
||||
public static bool On;
|
||||
private static List<Gaslighter> Instances = [];
|
||||
|
||||
private static OptionItem KillCooldown;
|
||||
public static OptionItem WinCondition;
|
||||
public static OptionItem CycleRepeats;
|
||||
|
||||
static readonly string[] WinConditionOptions =
|
||||
[
|
||||
"GaslighterWinCondition.CrewLoses",
|
||||
"GaslighterWinCondition.IfAlive",
|
||||
"GaslighterWinCondition.LastStanding"
|
||||
];
|
||||
|
||||
private Round CurrentRound;
|
||||
private HashSet<byte> CursedPlayers;
|
||||
private bool CycleFinished;
|
||||
|
||||
private byte GaslighterId;
|
||||
private HashSet<byte> ShieldedPlayers;
|
||||
|
||||
public override bool IsEnable => On;
|
||||
|
||||
public override void SetupCustomOption()
|
||||
{
|
||||
StartSetup(648350, TabGroup.NeutralRoles, CustomRoles.Gaslighter)
|
||||
.AutoSetupOption(ref KillCooldown, 22.5f, new FloatValueRule(0f, 120f, 0.5f), OptionFormat.Seconds)
|
||||
.AutoSetupOption(ref WinCondition, 0, WinConditionOptions)
|
||||
.AutoSetupOption(ref CycleRepeats, false);
|
||||
}
|
||||
|
||||
public override void Init()
|
||||
{
|
||||
On = false;
|
||||
Instances = [];
|
||||
}
|
||||
|
||||
public override void Add(byte playerId)
|
||||
{
|
||||
On = true;
|
||||
Instances.Add(this);
|
||||
GaslighterId = playerId;
|
||||
CurrentRound = default;
|
||||
CursedPlayers = [];
|
||||
ShieldedPlayers = [];
|
||||
CycleFinished = false;
|
||||
}
|
||||
|
||||
public override void SetKillCooldown(byte id)
|
||||
{
|
||||
Main.AllPlayerKillCooldown[id] = CurrentRound switch
|
||||
{
|
||||
Round.Kill => KillCooldown.GetFloat(),
|
||||
Round.Knight => Monarch.KnightCooldown.GetFloat(),
|
||||
Round.Curse => Main.RealOptionsData.GetFloat(FloatOptionNames.KillCooldown),
|
||||
Round.Shield => Medic.CD.GetFloat(),
|
||||
_ => Options.DefaultKillCooldown
|
||||
};
|
||||
}
|
||||
|
||||
public static void OnExile(byte[] exileIds)
|
||||
{
|
||||
foreach (Gaslighter instance in Instances)
|
||||
{
|
||||
foreach (byte id in exileIds)
|
||||
{
|
||||
if (id == instance.GaslighterId)
|
||||
instance.CursedPlayers.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
List<byte> curseDeathList = [];
|
||||
foreach (PlayerControl pc in Main.AllAlivePlayerControls)
|
||||
{
|
||||
foreach (Gaslighter instance in Instances)
|
||||
{
|
||||
if (Main.AfterMeetingDeathPlayers.ContainsKey(pc.PlayerId)) continue;
|
||||
|
||||
var gaslighter = instance.GaslighterId.GetPlayer();
|
||||
if (instance.CursedPlayers.Contains(pc.PlayerId) && gaslighter != null && gaslighter.IsAlive())
|
||||
{
|
||||
pc.SetRealKiller(gaslighter);
|
||||
curseDeathList.Add(pc.PlayerId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CheckForEndVotingPatch.TryAddAfterMeetingDeathPlayers(PlayerState.DeathReason.Spell, [.. curseDeathList]);
|
||||
}
|
||||
|
||||
public override void AfterMeetingTasks()
|
||||
{
|
||||
ShieldedPlayers.Clear();
|
||||
CursedPlayers.Clear();
|
||||
|
||||
if (CurrentRound == Round.Shield)
|
||||
{
|
||||
CycleFinished = true;
|
||||
CurrentRound = Round.Kill;
|
||||
}
|
||||
else if (!CycleFinished || CycleRepeats.GetBool())
|
||||
{
|
||||
CurrentRound++;
|
||||
}
|
||||
|
||||
float limit = CurrentRound switch
|
||||
{
|
||||
Round.Knight => Monarch.KnightMax.GetFloat(),
|
||||
Round.Shield => Medic.SkillLimit,
|
||||
_ => 0
|
||||
};
|
||||
GaslighterId.SetAbilityUseLimit(limit);
|
||||
|
||||
var pc = GaslighterId.GetPlayer();
|
||||
pc?.ResetKillCooldown();
|
||||
pc?.Notify(Translator.GetString($"Gaslighter.{CurrentRound}"));
|
||||
}
|
||||
|
||||
public override bool OnCheckMurder(PlayerControl killer, PlayerControl target)
|
||||
{
|
||||
switch (CurrentRound)
|
||||
{
|
||||
case Round.Kill:
|
||||
return true;
|
||||
case Round.Knight when killer.GetAbilityUseLimit() > 0 && !target.Is(CustomRoles.Knighted):
|
||||
target.RpcSetCustomRole(CustomRoles.Knighted);
|
||||
killer.RpcRemoveAbilityUse();
|
||||
killer.SetKillCooldown();
|
||||
return false;
|
||||
case Round.Curse:
|
||||
CursedPlayers.Add(target.PlayerId);
|
||||
killer.SetKillCooldown();
|
||||
return false;
|
||||
case Round.Shield:
|
||||
ShieldedPlayers.Add(target.PlayerId);
|
||||
killer.SetKillCooldown();
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool IsShielded(PlayerControl target) => Instances.Exists(i => i.ShieldedPlayers.Contains(target.PlayerId));
|
||||
|
||||
public override string GetProgressText(byte playerId, bool comms)
|
||||
{
|
||||
return CurrentRound is Round.Knight or Round.Shield
|
||||
? base.GetProgressText(playerId, comms)
|
||||
: Utils.GetTaskCount(playerId, comms);
|
||||
}
|
||||
|
||||
public static string GetMark(PlayerControl seer, PlayerControl target)
|
||||
{
|
||||
if (!IsShielded(target)) return string.Empty;
|
||||
if (!seer.Is(CustomRoles.Gaslighter) && seer.PlayerId != target.PlayerId) return string.Empty;
|
||||
return $"<color={Utils.GetRoleColorCode(CustomRoles.Medic)}> ●</color>";
|
||||
}
|
||||
|
||||
public bool AddAsAdditionalWinner() => WinCondition.GetValue() switch
|
||||
{
|
||||
0 => CustomWinnerHolder.WinnerTeam != CustomWinner.Crewmate,
|
||||
1 => GaslighterId.GetPlayer()?.IsAlive() == true,
|
||||
_ => false
|
||||
};
|
||||
|
||||
enum Round
|
||||
{
|
||||
Kill,
|
||||
Knight,
|
||||
Curse,
|
||||
Shield
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -25,6 +25,7 @@ public class Romantic : RoleBase
|
||||
private static OptionItem ProtectDuration;
|
||||
private static OptionItem KnowTargetRole;
|
||||
private static OptionItem BetTargetKnowRomantic;
|
||||
private static OptionItem RomanticGetsPartnerConvertedAddons;
|
||||
private static OptionItem Arrows;
|
||||
private static OptionItem PartnerHasArrows;
|
||||
public static OptionItem VengefulKCD;
|
||||
@@ -63,23 +64,25 @@ public class Romantic : RoleBase
|
||||
.SetParent(CustomRoleSpawnChances[CustomRoles.Romantic]);
|
||||
BetTargetKnowRomantic = new BooleanOptionItem(Id + 14, "RomanticBetTargetKnowRomantic", true, TabGroup.NeutralRoles)
|
||||
.SetParent(CustomRoleSpawnChances[CustomRoles.Romantic]);
|
||||
Arrows = new BooleanOptionItem(Id + 15, "RomanticArrows", true, TabGroup.NeutralRoles)
|
||||
RomanticGetsPartnerConvertedAddons = new BooleanOptionItem(Id + 15, "RomanticGetsPartnerConvertedAddons", true, TabGroup.NeutralRoles)
|
||||
.SetParent(CustomRoleSpawnChances[CustomRoles.Romantic]);
|
||||
PartnerHasArrows = new BooleanOptionItem(Id + 16, "RomanticPartnerHasArrows", true, TabGroup.NeutralRoles)
|
||||
Arrows = new BooleanOptionItem(Id + 16, "RomanticArrows", true, TabGroup.NeutralRoles)
|
||||
.SetParent(CustomRoleSpawnChances[CustomRoles.Romantic]);
|
||||
VengefulKCD = new FloatOptionItem(Id + 17, "VengefulKCD", new(0f, 60f, 2.5f), 22.5f, TabGroup.NeutralRoles)
|
||||
PartnerHasArrows = new BooleanOptionItem(Id + 17, "RomanticPartnerHasArrows", true, TabGroup.NeutralRoles)
|
||||
.SetParent(CustomRoleSpawnChances[CustomRoles.Romantic]);
|
||||
VengefulKCD = new FloatOptionItem(Id + 18, "VengefulKCD", new(0f, 60f, 2.5f), 22.5f, TabGroup.NeutralRoles)
|
||||
.SetParent(CustomRoleSpawnChances[CustomRoles.Romantic])
|
||||
.SetValueFormat(OptionFormat.Seconds);
|
||||
VengefulCanVent = new BooleanOptionItem(Id + 18, "VengefulCanVent", true, TabGroup.NeutralRoles)
|
||||
VengefulCanVent = new BooleanOptionItem(Id + 19, "VengefulCanVent", true, TabGroup.NeutralRoles)
|
||||
.SetParent(CustomRoleSpawnChances[CustomRoles.Romantic]);
|
||||
VengefulHasImpVision = new BooleanOptionItem(Id + 19, "VengefulHasImpVision", true, TabGroup.NeutralRoles)
|
||||
VengefulHasImpVision = new BooleanOptionItem(Id + 20, "VengefulHasImpVision", true, TabGroup.NeutralRoles)
|
||||
.SetParent(CustomRoleSpawnChances[CustomRoles.Romantic]);
|
||||
RuthlessKCD = new FloatOptionItem(Id + 20, "RuthlessKCD", new(0f, 60f, 2.5f), 22.5f, TabGroup.NeutralRoles)
|
||||
RuthlessKCD = new FloatOptionItem(Id + 21, "RuthlessKCD", new(0f, 60f, 2.5f), 22.5f, TabGroup.NeutralRoles)
|
||||
.SetParent(CustomRoleSpawnChances[CustomRoles.Romantic])
|
||||
.SetValueFormat(OptionFormat.Seconds);
|
||||
RuthlessCanVent = new BooleanOptionItem(Id + 21, "RuthlessCanVent", true, TabGroup.NeutralRoles)
|
||||
RuthlessCanVent = new BooleanOptionItem(Id + 22, "RuthlessCanVent", true, TabGroup.NeutralRoles)
|
||||
.SetParent(CustomRoleSpawnChances[CustomRoles.Romantic]);
|
||||
RuthlessHasImpVision = new BooleanOptionItem(Id + 22, "RuthlessHasImpVision", true, TabGroup.NeutralRoles)
|
||||
RuthlessHasImpVision = new BooleanOptionItem(Id + 23, "RuthlessHasImpVision", true, TabGroup.NeutralRoles)
|
||||
.SetParent(CustomRoleSpawnChances[CustomRoles.Romantic]);
|
||||
}
|
||||
|
||||
@@ -150,13 +153,16 @@ public class Romantic : RoleBase
|
||||
RomanticPC.Notify(GetString("RomanticBetPlayer"));
|
||||
if (BetTargetKnowRomantic.GetBool()) target.Notify(Utils.ColorString(Utils.GetRoleColor(CustomRoles.Romantic), GetString("RomanticBetOnYou")));
|
||||
|
||||
if (RomanticGetsPartnerConvertedAddons.GetBool() && Partner.IsConverted())
|
||||
Partner.GetCustomSubRoles().DoIf(x => x.IsConverted() && !Partner.Is(x), x => RomanticPC.RpcSetCustomRole(x));
|
||||
|
||||
if (Arrows.GetBool())
|
||||
{
|
||||
TargetArrow.Add(RomanticId, PartnerId);
|
||||
if (PartnerHasArrows.GetBool() && BetTargetKnowRomantic.GetBool()) TargetArrow.Add(PartnerId, RomanticId);
|
||||
}
|
||||
|
||||
Logger.Info($"Partner picked: {RomanticPC.GetNameWithRole().RemoveHtmlTags()} => {target.GetNameWithRole().RemoveHtmlTags()}", "Romantic");
|
||||
Logger.Info($"Partner picked: {RomanticPC.GetNameWithRole().RemoveHtmlTags()} => {target.GetNameWithRole().RemoveHtmlTags()}", "Romantic");
|
||||
}
|
||||
else if (!IsPartnerProtected)
|
||||
{
|
||||
|
||||
@@ -0,0 +1,173 @@
|
||||
using System.Collections.Generic;
|
||||
using AmongUs.GameOptions;
|
||||
|
||||
namespace EHR.Neutral
|
||||
{
|
||||
public class Technician : RoleBase
|
||||
{
|
||||
public static bool On;
|
||||
|
||||
private static OptionItem WinsAlone;
|
||||
private static OptionItem RequiredPoints;
|
||||
public static OptionItem CanVent;
|
||||
private static OptionItem VentCooldown;
|
||||
private static OptionItem MaxInVentTime;
|
||||
private static readonly Dictionary<SystemTypes, OptionItem> PointGains = [];
|
||||
private bool fixedSabotage;
|
||||
|
||||
public bool IsWon;
|
||||
|
||||
private PlayerControl TechnicianPC;
|
||||
|
||||
public override bool IsEnable => On;
|
||||
|
||||
public override void SetupCustomOption()
|
||||
{
|
||||
StartSetup(646950, TabGroup.NeutralRoles, CustomRoles.Technician)
|
||||
.AutoSetupOption(ref WinsAlone, false)
|
||||
.AutoSetupOption(ref RequiredPoints, 5, new IntegerValueRule(1, 50, 1))
|
||||
.AutoSetupOption(ref CanVent, false)
|
||||
.AutoSetupOption(ref VentCooldown, 30f, new FloatValueRule(0f, 120f, 0.5f), OptionFormat.Seconds, overrideParent: CanVent)
|
||||
.AutoSetupOption(ref MaxInVentTime, 5f, new FloatValueRule(0f, 120f, 0.5f), OptionFormat.Seconds, overrideParent: CanVent);
|
||||
|
||||
int i = 0;
|
||||
foreach (var system in new[] { SystemTypes.Electrical, SystemTypes.Comms, SystemTypes.LifeSupp, SystemTypes.Reactor })
|
||||
{
|
||||
PointGains[system] = new IntegerOptionItem(646960 + i, $"TechnicianPointGain.{system}", new(0, 10, 1), 1, TabGroup.NeutralRoles)
|
||||
.SetParent(Options.CustomRoleSpawnChances[CustomRoles.Technician]);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
public override void Init()
|
||||
{
|
||||
On = false;
|
||||
}
|
||||
|
||||
public override void Add(byte playerId)
|
||||
{
|
||||
On = true;
|
||||
IsWon = false;
|
||||
TechnicianPC = playerId.GetPlayer();
|
||||
fixedSabotage = false;
|
||||
playerId.SetAbilityUseLimit(0);
|
||||
}
|
||||
|
||||
public override void ApplyGameOptions(IGameOptions opt, byte playerId)
|
||||
{
|
||||
if (CanVent.GetBool())
|
||||
{
|
||||
AURoleOptions.EngineerCooldown = VentCooldown.GetFloat();
|
||||
AURoleOptions.EngineerInVentMaxTime = MaxInVentTime.GetFloat();
|
||||
}
|
||||
}
|
||||
|
||||
private static SystemTypes GetActualSystemType(SystemTypes systemTypes) => systemTypes switch
|
||||
{
|
||||
SystemTypes.Laboratory => SystemTypes.Reactor,
|
||||
SystemTypes.HeliSabotage => SystemTypes.Reactor,
|
||||
_ => systemTypes
|
||||
};
|
||||
|
||||
private static bool GetsAnyPoint(SystemTypes systemType) => PointGains.TryGetValue(GetActualSystemType(systemType), out var pointGain) && pointGain.GetInt() > 0;
|
||||
|
||||
void IncreasePoints(SystemTypes systemType)
|
||||
{
|
||||
var actualSystemType = GetActualSystemType(systemType);
|
||||
TechnicianPC.RpcIncreaseAbilityUseLimitBy(PointGains[actualSystemType].GetInt());
|
||||
if (TechnicianPC.GetAbilityUseLimit() >= RequiredPoints.GetInt())
|
||||
{
|
||||
if (WinsAlone.GetBool())
|
||||
{
|
||||
CustomWinnerHolder.ResetAndSetWinner(CustomWinner.Technician);
|
||||
CustomWinnerHolder.WinnerIds.Add(TechnicianPC.PlayerId);
|
||||
}
|
||||
else IsWon = true;
|
||||
}
|
||||
}
|
||||
|
||||
public static void RepairSystem(byte playerId, SystemTypes systemType, byte amount)
|
||||
{
|
||||
if (Main.PlayerStates[playerId].Role is not Technician technician) return;
|
||||
if (!GetsAnyPoint(systemType) || technician.IsWon) return;
|
||||
|
||||
switch (systemType)
|
||||
{
|
||||
case SystemTypes.Reactor:
|
||||
case SystemTypes.Laboratory:
|
||||
{
|
||||
if (amount.HasAnyBit(ReactorSystemType.AddUserOp))
|
||||
{
|
||||
ShipStatus.Instance.UpdateSystem((MapNames)Main.NormalOptions.MapId == MapNames.Polus ? SystemTypes.Laboratory : SystemTypes.Reactor, playerId.GetPlayer(), ReactorSystemType.ClearCountdown);
|
||||
technician.IncreasePoints(systemType);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case SystemTypes.HeliSabotage:
|
||||
{
|
||||
var tags = (HeliSabotageSystem.Tags)(amount & HeliSabotageSystem.TagMask);
|
||||
if (tags == HeliSabotageSystem.Tags.ActiveBit)
|
||||
{
|
||||
technician.fixedSabotage = false;
|
||||
}
|
||||
|
||||
if (!technician.fixedSabotage && tags == HeliSabotageSystem.Tags.FixBit)
|
||||
{
|
||||
technician.fixedSabotage = true;
|
||||
var consoleId = amount & HeliSabotageSystem.IdMask;
|
||||
var otherConsoleId = (consoleId + 1) % 2;
|
||||
ShipStatus.Instance.UpdateSystem(SystemTypes.HeliSabotage, playerId.GetPlayer(), (byte)(otherConsoleId | (int)HeliSabotageSystem.Tags.FixBit));
|
||||
technician.IncreasePoints(systemType);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case SystemTypes.LifeSupp:
|
||||
{
|
||||
if (amount.HasAnyBit(LifeSuppSystemType.AddUserOp))
|
||||
{
|
||||
ShipStatus.Instance.UpdateSystem(SystemTypes.LifeSupp, playerId.GetPlayer(), LifeSuppSystemType.ClearCountdown);
|
||||
technician.IncreasePoints(systemType);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case SystemTypes.Comms:
|
||||
{
|
||||
if (Main.CurrentMap == MapNames.Mira)
|
||||
{
|
||||
var tags = (HqHudSystemType.Tags)(amount & HqHudSystemType.TagMask);
|
||||
if (tags == HqHudSystemType.Tags.ActiveBit)
|
||||
{
|
||||
technician.fixedSabotage = false;
|
||||
}
|
||||
|
||||
if (!technician.fixedSabotage && tags == HqHudSystemType.Tags.FixBit)
|
||||
{
|
||||
technician.fixedSabotage = true;
|
||||
var consoleId = amount & HqHudSystemType.IdMask;
|
||||
var otherConsoleId = (consoleId + 1) % 2;
|
||||
ShipStatus.Instance.UpdateSystem(SystemTypes.Comms, playerId.GetPlayer(), (byte)(otherConsoleId | (int)HqHudSystemType.Tags.FixBit));
|
||||
}
|
||||
}
|
||||
|
||||
technician.IncreasePoints(systemType);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void SwitchSystemRepair(byte playerId, SwitchSystem switchSystem, byte amount)
|
||||
{
|
||||
if (!GetsAnyPoint(SystemTypes.Electrical) || Main.PlayerStates[playerId].Role is not Technician technician) return;
|
||||
|
||||
if (amount.HasBit(SwitchSystem.DamageSystem)) return;
|
||||
|
||||
var fixbit = 1 << amount;
|
||||
switchSystem.ActualSwitches = (byte)(switchSystem.ExpectedSwitches ^ fixbit);
|
||||
|
||||
technician.IncreasePoints(SystemTypes.Electrical);
|
||||
}
|
||||
}
|
||||
}
|
||||
+12
-21
@@ -6,6 +6,7 @@ using System.Text;
|
||||
using AmongUs.GameOptions;
|
||||
using EHR.AddOns.Crewmate;
|
||||
using EHR.AddOns.Impostor;
|
||||
using EHR.GameMode.HideAndSeekRoles;
|
||||
using EHR.Neutral;
|
||||
|
||||
|
||||
@@ -80,7 +81,7 @@ namespace EHR
|
||||
{
|
||||
if (Options.CurrentGameMode == CustomGameMode.HideAndSeek && HnSManager.PlayerRoles[pc.PlayerId].Interface.Team == Team.Crewmate && pc.IsAlive())
|
||||
{
|
||||
int time = GameMode.HideAndSeekRoles.Hider.TimeDecreaseOnTaskComplete.GetInt();
|
||||
int time = Hider.TimeDecreaseOnTaskComplete.GetInt();
|
||||
HnSManager.TimeLeft -= time;
|
||||
pc.Notify(Translator.GetString("TimeDecreased"));
|
||||
if (60 - (HnSManager.TimeLeft % 60) <= time) Utils.NotifyRoles();
|
||||
@@ -203,33 +204,23 @@ namespace EHR
|
||||
public class OptionSetupHandler(int id, TabGroup tab, CustomRoles role)
|
||||
{
|
||||
private readonly OptionItem Parent = Options.CustomRoleSpawnChances[role];
|
||||
private int _id = id;
|
||||
|
||||
public OptionSetupHandler AutoSetupOption(ref OptionItem field, object defaultValue, object valueRule = null, OptionFormat format = OptionFormat.None, [CallerArgumentExpression("field")] string fieldName = "", string overrideName = "", OptionItem overrideParent = null, bool noTranslation = false)
|
||||
{
|
||||
try
|
||||
{
|
||||
var name = overrideName == "" ? IsGeneralOption() ? fieldName : $"{role}.{fieldName}" : overrideName;
|
||||
switch (valueRule, defaultValue)
|
||||
field = (valueRule, defaultValue) switch
|
||||
{
|
||||
case (null, bool bdv):
|
||||
field = new BooleanOptionItem(++id, name, bdv, tab);
|
||||
field.SetParent(overrideParent ?? Parent);
|
||||
break;
|
||||
case (IntegerValueRule ivr, int idv):
|
||||
field = new IntegerOptionItem(++id, name, ivr, idv, tab);
|
||||
field.SetParent(overrideParent ?? Parent);
|
||||
break;
|
||||
case (FloatValueRule fvr, float fdv):
|
||||
field = new FloatOptionItem(++id, name, fvr, fdv, tab);
|
||||
field.SetParent(overrideParent ?? Parent);
|
||||
break;
|
||||
case (IList<string> selections, int index):
|
||||
field = new StringOptionItem(++id, name, selections, index, tab, noTranslation: noTranslation);
|
||||
field.SetParent(overrideParent ?? Parent);
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentException("The valueRule and defaultValue combination is not supported.");
|
||||
}
|
||||
(null, bool bdv) => new BooleanOptionItem(++_id, name, bdv, tab),
|
||||
(IntegerValueRule ivr, int idv) => new IntegerOptionItem(++_id, name, ivr, idv, tab),
|
||||
(FloatValueRule fvr, float fdv) => new FloatOptionItem(++_id, name, fvr, fdv, tab),
|
||||
(IList<string> selections, int index) => new StringOptionItem(++_id, name, selections, index, tab, noTranslation: noTranslation),
|
||||
_ => throw new ArgumentException("The valueRule and defaultValue combination is not supported.")
|
||||
};
|
||||
|
||||
field.SetParent(overrideParent ?? Parent);
|
||||
|
||||
if (format != OptionFormat.None) field?.SetValueFormat(format);
|
||||
}
|
||||
|
||||
@@ -496,7 +496,9 @@ public class Main : BasePlugin
|
||||
{ CustomRoles.SchrodingersCat, "#616161" },
|
||||
{ CustomRoles.Shifter, "#777777" },
|
||||
{ CustomRoles.Impartial, "#4287f5" },
|
||||
{ CustomRoles.Gaslighter, "#b6aa82" },
|
||||
{ CustomRoles.Tank, "#176320" },
|
||||
{ CustomRoles.Technician, "#4e96f5" },
|
||||
{ CustomRoles.Backstabber, "#fcba03" },
|
||||
{ CustomRoles.Predator, "#c73906" },
|
||||
{ CustomRoles.Reckless, "#6e000d" },
|
||||
@@ -778,6 +780,7 @@ public enum CustomWinner
|
||||
Executioner = CustomRoles.Executioner,
|
||||
Arsonist = CustomRoles.Arsonist,
|
||||
Revolutionist = CustomRoles.Revolutionist,
|
||||
Technician = CustomRoles.Technician,
|
||||
Jackal = CustomRoles.Jackal,
|
||||
God = CustomRoles.God,
|
||||
Mario = CustomRoles.Mario,
|
||||
@@ -873,7 +876,9 @@ public enum AdditionalWinners
|
||||
Maverick = CustomRoles.Maverick,
|
||||
Postman = CustomRoles.Postman,
|
||||
Impartial = CustomRoles.Impartial,
|
||||
Gaslighter = CustomRoles.Gaslighter,
|
||||
Tank = CustomRoles.Tank,
|
||||
Technician = CustomRoles.Technician,
|
||||
Backstabber = CustomRoles.Backstabber,
|
||||
Predator = CustomRoles.Predator,
|
||||
SoulHunter = CustomRoles.SoulHunter,
|
||||
|
||||
Reference in new issue
Block a user